Refactor header structures in FPGA interchange Arch.
Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
parent
f52b522964
commit
2cd5bacca0
@ -38,16 +38,19 @@
|
||||
#define NPNR_NORETURN __attribute__((noreturn))
|
||||
#define NPNR_DEPRECATED __attribute__((deprecated))
|
||||
#define NPNR_PACKED_STRUCT(...) __VA_ARGS__ __attribute__((packed))
|
||||
#define NPNR_ALWAYS_INLINE NPNR_ATTRIBUTE(__always_inline__)
|
||||
#elif defined(_MSC_VER)
|
||||
#define NPNR_ATTRIBUTE(...)
|
||||
#define NPNR_NORETURN __declspec(noreturn)
|
||||
#define NPNR_DEPRECATED __declspec(deprecated)
|
||||
#define NPNR_PACKED_STRUCT(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop))
|
||||
#define NPNR_ALWAYS_INLINE
|
||||
#else
|
||||
#define NPNR_ATTRIBUTE(...)
|
||||
#define NPNR_NORETURN
|
||||
#define NPNR_DEPRECATED
|
||||
#define NPNR_PACKED_STRUCT(...) __VA_ARGS__
|
||||
#define NPNR_ALWAYS_INLINE
|
||||
#endif
|
||||
|
||||
#endif /* NEXTPNR_NAMESPACES_H */
|
||||
|
@ -19,6 +19,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
@ -37,6 +39,9 @@
|
||||
#include "util.h"
|
||||
#include "xdc.h"
|
||||
|
||||
// Include tcl.h late because it messed with defines and let them leave the
|
||||
// scope of the header.
|
||||
#include <tcl.h>
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
struct SiteBelPair
|
||||
{
|
||||
@ -90,6 +95,10 @@ Arch::Arch(ArchArgs args) : args(args)
|
||||
log_error("Unable to read chipdb %s\n", args.chipdb.c_str());
|
||||
}
|
||||
|
||||
if (chip_info->version != kExpectedChipInfoVersion) {
|
||||
log_error("Expected chipdb with version %d found version %d\n", kExpectedChipInfoVersion, chip_info->version);
|
||||
}
|
||||
|
||||
// Read strings from constids into IdString database, checking that list
|
||||
// is unique and matches expected constid value.
|
||||
const RelSlice<RelPtr<char>> &constids = *chip_info->constids;
|
||||
@ -254,6 +263,8 @@ IdString Arch::archArgsToId(ArchArgs args) const { return IdString(); }
|
||||
|
||||
void Arch::setup_byname() const
|
||||
{
|
||||
by_name_mutex.lock();
|
||||
|
||||
if (tile_by_name.empty()) {
|
||||
for (int i = 0; i < chip_info->tiles.ssize(); i++) {
|
||||
tile_by_name[id(chip_info->tiles[i].name.get())] = i;
|
||||
@ -270,6 +281,8 @@ void Arch::setup_byname() const
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
by_name_mutex.unlock();
|
||||
}
|
||||
|
||||
BelId Arch::getBelByName(IdStringList name) const
|
||||
@ -416,7 +429,8 @@ PipId Arch::getPipByName(IdStringList name) const
|
||||
int tile;
|
||||
int site;
|
||||
std::tie(tile, site) = site_by_name.at(site_name);
|
||||
auto &tile_info = chip_info->tile_types[chip_info->tiles[tile].type];
|
||||
auto tile_type_idx = chip_info->tiles[tile].type;
|
||||
auto &tile_info = chip_info->tile_types[tile_type_idx];
|
||||
|
||||
std::array<IdString, 2> ids{name.ids[0], belname};
|
||||
BelId bel = getBelByName(IdStringList(ids));
|
||||
@ -444,7 +458,8 @@ PipId Arch::getPipByName(IdStringList name) const
|
||||
int tile;
|
||||
int site;
|
||||
std::tie(tile, site) = iter->second;
|
||||
auto &tile_info = chip_info->tile_types[chip_info->tiles[tile].type];
|
||||
auto tile_type_idx = chip_info->tiles[tile].type;
|
||||
auto &tile_info = chip_info->tile_types[tile_type_idx];
|
||||
|
||||
std::string pip_second = name.ids[1].str(this);
|
||||
auto split = pip_second.find('.');
|
||||
@ -500,7 +515,8 @@ PipId Arch::getPipByName(IdStringList name) const
|
||||
}
|
||||
} else {
|
||||
int tile = tile_by_name.at(name.ids[0]);
|
||||
auto &tile_info = chip_info->tile_types[chip_info->tiles[tile].type];
|
||||
size_t tile_type_idx = chip_info->tiles[tile].type;
|
||||
auto &tile_info = chip_info->tile_types[tile_type_idx];
|
||||
|
||||
std::string pip_second = name.ids[1].str(this);
|
||||
auto spn = split_identifier_name_dot(pip_second);
|
||||
@ -618,11 +634,14 @@ ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const
|
||||
int dst_tile = dst.tile == -1 ? chip_info->nodes[dst.index].tile_wires[0].tile : dst.tile;
|
||||
int src_tile = src.tile == -1 ? chip_info->nodes[src.index].tile_wires[0].tile : src.tile;
|
||||
|
||||
int x0, x1, y0, y1;
|
||||
x0 = src_tile % chip_info->width;
|
||||
x1 = x0;
|
||||
y0 = src_tile / chip_info->width;
|
||||
y1 = y0;
|
||||
int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
|
||||
|
||||
int src_x, src_y;
|
||||
get_tile_x_y(src_tile, &src_x, &src_y);
|
||||
|
||||
int dst_x, dst_y;
|
||||
get_tile_x_y(dst_tile, &dst_x, &dst_y);
|
||||
|
||||
auto expand = [&](int x, int y) {
|
||||
x0 = std::min(x0, x);
|
||||
x1 = std::max(x1, x);
|
||||
@ -630,7 +649,8 @@ ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const
|
||||
y1 = std::max(y1, y);
|
||||
};
|
||||
|
||||
expand(dst_tile % chip_info->width, dst_tile / chip_info->width);
|
||||
expand(src_x, src_y);
|
||||
expand(dst_x, dst_y);
|
||||
|
||||
if (source_locs.count(src))
|
||||
expand(source_locs.at(src).x, source_locs.at(src).y);
|
||||
@ -1331,6 +1351,262 @@ void Arch::decode_lut_cells()
|
||||
}
|
||||
}
|
||||
|
||||
void Arch::assign_net_to_wire(WireId wire, NetInfo *net, const char *src, bool require_empty)
|
||||
{
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Assigning wire %s to %s from %s\n", nameOfWire(wire), net->name.c_str(this), src);
|
||||
}
|
||||
#endif
|
||||
NPNR_ASSERT(net != nullptr);
|
||||
auto result = wire_to_net.emplace(wire, net);
|
||||
if (!result.second) {
|
||||
// This wire was already in the map, make sure this assignment was
|
||||
// legal.
|
||||
if (require_empty) {
|
||||
NPNR_ASSERT(result.first->second == nullptr);
|
||||
} else {
|
||||
NPNR_ASSERT(result.first->second == nullptr || result.first->second == net);
|
||||
}
|
||||
result.first->second = net;
|
||||
}
|
||||
}
|
||||
|
||||
void Arch::unassign_wire(WireId wire)
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("unassign_wire %s\n", nameOfWire(wire));
|
||||
}
|
||||
#endif
|
||||
|
||||
auto iter = wire_to_net.find(wire);
|
||||
NPNR_ASSERT(iter != wire_to_net.end());
|
||||
|
||||
NetInfo *net = iter->second;
|
||||
NPNR_ASSERT(net != nullptr);
|
||||
|
||||
auto &net_wires = net->wires;
|
||||
auto it = net_wires.find(wire);
|
||||
NPNR_ASSERT(it != net_wires.end());
|
||||
|
||||
auto pip = it->second.pip;
|
||||
if (pip != PipId()) {
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Removing pip %s because it was used to reach wire %s\n", nameOfPip(pip), nameOfWire(wire));
|
||||
}
|
||||
#endif
|
||||
auto pip_iter = pip_to_net.find(pip);
|
||||
NPNR_ASSERT(pip_iter != pip_to_net.end());
|
||||
NPNR_ASSERT(pip_iter->second == net);
|
||||
pip_iter->second = nullptr;
|
||||
}
|
||||
|
||||
net_wires.erase(it);
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Removing %s from net %s in unassign_wire\n", nameOfWire(wire), net->name.c_str(this));
|
||||
}
|
||||
#endif
|
||||
iter->second = nullptr;
|
||||
}
|
||||
|
||||
void Arch::unbindPip(PipId pip)
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("unbindPip %s\n", nameOfPip(pip));
|
||||
}
|
||||
#endif
|
||||
|
||||
auto pip_iter = pip_to_net.find(pip);
|
||||
NPNR_ASSERT(pip_iter != pip_to_net.end());
|
||||
NetInfo *net = pip_iter->second;
|
||||
NPNR_ASSERT(net != nullptr);
|
||||
|
||||
WireId dst = getPipDstWire(pip);
|
||||
auto wire_iter = wire_to_net.find(dst);
|
||||
NPNR_ASSERT(wire_iter != wire_to_net.end());
|
||||
|
||||
// Clear the net now.
|
||||
pip_iter->second = nullptr;
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Removing %s from net %s in unbindPip\n", nameOfWire(dst), net->name.c_str(this));
|
||||
}
|
||||
#endif
|
||||
wire_iter->second = nullptr;
|
||||
NPNR_ASSERT(net->wires.erase(dst) == 1);
|
||||
|
||||
refreshUiPip(pip);
|
||||
refreshUiWire(dst);
|
||||
}
|
||||
|
||||
void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("bindPip %s (%d/%d) to net %s\n", nameOfPip(pip), pip.tile, pip.index, net->name.c_str(this));
|
||||
}
|
||||
#endif
|
||||
WireId dst = getPipDstWire(pip);
|
||||
NPNR_ASSERT(dst != WireId());
|
||||
|
||||
{
|
||||
// Pip should not already be assigned to anything.
|
||||
auto result = pip_to_net.emplace(pip, net);
|
||||
if (!result.second) {
|
||||
NPNR_ASSERT(result.first->second == nullptr);
|
||||
result.first->second = net;
|
||||
}
|
||||
}
|
||||
|
||||
assign_net_to_wire(dst, net, "bindPip", /*require_empty=*/true);
|
||||
|
||||
{
|
||||
auto result = net->wires.emplace(dst, PipMap{pip, strength});
|
||||
NPNR_ASSERT(result.second);
|
||||
}
|
||||
|
||||
refreshUiPip(pip);
|
||||
refreshUiWire(dst);
|
||||
}
|
||||
|
||||
void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("bindWire %s to net %s\n", nameOfWire(wire), net->name.c_str(this));
|
||||
}
|
||||
#endif
|
||||
assign_net_to_wire(wire, net, "bindWire", /*require_empty=*/true);
|
||||
auto &pip_map = net->wires[wire];
|
||||
pip_map.pip = PipId();
|
||||
pip_map.strength = strength;
|
||||
refreshUiWire(wire);
|
||||
}
|
||||
|
||||
bool Arch::check_pip_avail_for_net(PipId pip, NetInfo *net) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
auto pip_iter = pip_to_net.find(pip);
|
||||
if (pip_iter != pip_to_net.end() && pip_iter->second != nullptr) {
|
||||
bool pip_blocked = false;
|
||||
if (net == nullptr) {
|
||||
pip_blocked = true;
|
||||
} else {
|
||||
if (net != pip_iter->second) {
|
||||
pip_blocked = true;
|
||||
}
|
||||
}
|
||||
if (pip_blocked) {
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Pip %s (%d/%d) is not available, tied to net %s\n", getCtx()->nameOfPip(pip), pip.tile,
|
||||
pip.index, pip_iter->second->name.c_str(getCtx()));
|
||||
}
|
||||
#endif
|
||||
NPNR_ASSERT(pip_iter->first == pip);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
WireId dst = getPipDstWire(pip);
|
||||
|
||||
auto wire_iter = wire_to_net.find(dst);
|
||||
if (wire_iter != wire_to_net.end()) {
|
||||
NetInfo *wire_net = wire_iter->second;
|
||||
if (wire_net != nullptr) {
|
||||
auto net_iter = wire_net->wires.find(dst);
|
||||
if (net_iter != wire_net->wires.end()) {
|
||||
if (net == nullptr) {
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Pip %s (%d/%d) is not available, dst wire %s is tied to net %s\n",
|
||||
getCtx()->nameOfPip(pip), pip.tile, pip.index, getCtx()->nameOfWire(dst),
|
||||
wire_net->name.c_str(getCtx()));
|
||||
}
|
||||
#endif
|
||||
// dst is already driven in this net, do not allow!
|
||||
return false;
|
||||
} else {
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose && net_iter->second.pip != pip) {
|
||||
log_info("Pip %s (%d/%d) is not available, dst wire %s is tied to net %s\n",
|
||||
getCtx()->nameOfPip(pip), pip.tile, pip.index, getCtx()->nameOfWire(dst),
|
||||
wire_net->name.c_str(getCtx()));
|
||||
}
|
||||
#endif
|
||||
// This pip is available if this pip is already bound to
|
||||
// this.
|
||||
return net_iter->second.pip == pip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const PipInfoPOD &pip_data = pip_info(chip_info, pip);
|
||||
if (pip_data.site != -1 && net != nullptr) {
|
||||
NPNR_ASSERT(net->driver.cell != nullptr);
|
||||
NPNR_ASSERT(net->driver.cell->bel != BelId());
|
||||
|
||||
bool valid_pip = false;
|
||||
if (pip.tile == net->driver.cell->bel.tile) {
|
||||
auto &bel_data = bel_info(chip_info, net->driver.cell->bel);
|
||||
if (bel_data.site == pip_data.site) {
|
||||
valid_pip = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid_pip) {
|
||||
// See if one users can enter this site.
|
||||
auto &tile_type = loc_info(chip_info, pip);
|
||||
auto &src_wire_data = tile_type.wire_data[pip_data.src_index];
|
||||
auto &dst_wire_data = tile_type.wire_data[pip_data.dst_index];
|
||||
|
||||
if (dst_wire_data.site == -1) {
|
||||
// This is an output site port, but not for the driver net.
|
||||
// Disallow.
|
||||
NPNR_ASSERT(src_wire_data.site == pip_data.site);
|
||||
} else {
|
||||
// This might be a valid pip, scan users.
|
||||
for (auto &user : net->users) {
|
||||
NPNR_ASSERT(user.cell != nullptr);
|
||||
if (user.cell->bel == BelId()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto &bel_data = bel_info(chip_info, user.cell->bel);
|
||||
if (bel_data.site == pip_data.site) {
|
||||
valid_pip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid_pip) {
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Pip %s is within a site and not available not right now\n", getCtx()->nameOfPip(pip));
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Arch::checkPipAvail(PipId pip) const { return check_pip_avail_for_net(pip, nullptr); }
|
||||
|
||||
Arch::~Arch() {}
|
||||
|
||||
// Instance constraint templates.
|
||||
template void Arch::ArchConstraints::bindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange);
|
||||
template void Arch::ArchConstraints::unbindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange);
|
||||
|
File diff suppressed because it is too large
Load Diff
497
fpga_interchange/arch_iterators.h
Normal file
497
fpga_interchange/arch_iterators.h
Normal file
@ -0,0 +1,497 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ARCH_ITERATORS_H
|
||||
#define ARCH_ITERATORS_H
|
||||
|
||||
#include "chipdb.h"
|
||||
#include "nextpnr_namespaces.h"
|
||||
#include "nextpnr_types.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
struct BelIterator
|
||||
{
|
||||
const ChipInfoPOD *chip;
|
||||
int cursor_index;
|
||||
int cursor_tile;
|
||||
|
||||
BelIterator operator++()
|
||||
{
|
||||
cursor_index++;
|
||||
while (cursor_tile < chip->tiles.ssize() && cursor_index >= tile_info(chip, cursor_tile).bel_data.ssize()) {
|
||||
cursor_index = 0;
|
||||
cursor_tile++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
BelIterator operator++(int)
|
||||
{
|
||||
BelIterator prior(*this);
|
||||
++(*this);
|
||||
return prior;
|
||||
}
|
||||
|
||||
bool operator!=(const BelIterator &other) const
|
||||
{
|
||||
return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile;
|
||||
}
|
||||
|
||||
bool operator==(const BelIterator &other) const
|
||||
{
|
||||
return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile;
|
||||
}
|
||||
|
||||
BelId operator*() const
|
||||
{
|
||||
BelId ret;
|
||||
ret.tile = cursor_tile;
|
||||
ret.index = cursor_index;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct BelRange
|
||||
{
|
||||
BelIterator b, e;
|
||||
BelIterator begin() const { return b; }
|
||||
BelIterator end() const { return e; }
|
||||
};
|
||||
|
||||
struct FilteredBelIterator
|
||||
{
|
||||
std::function<bool(BelId)> filter;
|
||||
BelIterator b, e;
|
||||
|
||||
FilteredBelIterator operator++()
|
||||
{
|
||||
++b;
|
||||
while (b != e) {
|
||||
if (filter(*b)) {
|
||||
break;
|
||||
}
|
||||
|
||||
++b;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!=(const FilteredBelIterator &other) const
|
||||
{
|
||||
NPNR_ASSERT(e == other.e);
|
||||
return b != other.b;
|
||||
}
|
||||
|
||||
bool operator==(const FilteredBelIterator &other) const
|
||||
{
|
||||
NPNR_ASSERT(e == other.e);
|
||||
return b == other.b;
|
||||
}
|
||||
|
||||
BelId operator*() const
|
||||
{
|
||||
BelId bel = *b;
|
||||
NPNR_ASSERT(filter(bel));
|
||||
return bel;
|
||||
}
|
||||
};
|
||||
|
||||
struct FilteredBelRange
|
||||
{
|
||||
FilteredBelRange(BelIterator bel_b, BelIterator bel_e, std::function<bool(BelId)> filter)
|
||||
{
|
||||
b.filter = filter;
|
||||
b.b = bel_b;
|
||||
b.e = bel_e;
|
||||
|
||||
if (b.b != b.e && !filter(*b.b)) {
|
||||
++b;
|
||||
}
|
||||
|
||||
e.b = bel_e;
|
||||
e.e = bel_e;
|
||||
|
||||
if (b != e) {
|
||||
NPNR_ASSERT(filter(*b.b));
|
||||
}
|
||||
}
|
||||
|
||||
FilteredBelIterator b, e;
|
||||
FilteredBelIterator begin() const { return b; }
|
||||
FilteredBelIterator end() const { return e; }
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Iterate over TileWires for a wire (will be more than one if nodal)
|
||||
struct TileWireIterator
|
||||
{
|
||||
const ChipInfoPOD *chip;
|
||||
WireId baseWire;
|
||||
int cursor = -1;
|
||||
|
||||
void operator++() { cursor++; }
|
||||
|
||||
bool operator==(const TileWireIterator &other) const { return cursor == other.cursor; }
|
||||
bool operator!=(const TileWireIterator &other) const { return cursor != other.cursor; }
|
||||
|
||||
// Returns a *denormalised* identifier always pointing to a tile wire rather than a node
|
||||
WireId operator*() const
|
||||
{
|
||||
if (baseWire.tile == -1) {
|
||||
WireId tw;
|
||||
const auto &node_wire = chip->nodes[baseWire.index].tile_wires[cursor];
|
||||
tw.tile = node_wire.tile;
|
||||
tw.index = node_wire.index;
|
||||
return tw;
|
||||
} else {
|
||||
return baseWire;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct TileWireRange
|
||||
{
|
||||
TileWireIterator b, e;
|
||||
TileWireIterator begin() const { return b; }
|
||||
TileWireIterator end() const { return e; }
|
||||
};
|
||||
|
||||
NPNR_ALWAYS_INLINE inline WireId canonical_wire(const ChipInfoPOD *chip_info, int32_t tile, int32_t wire)
|
||||
{
|
||||
WireId id;
|
||||
|
||||
if (wire >= chip_info->tiles[tile].tile_wire_to_node.ssize()) {
|
||||
// Cannot be a nodal wire
|
||||
id.tile = tile;
|
||||
id.index = wire;
|
||||
} else {
|
||||
int32_t node = chip_info->tiles[tile].tile_wire_to_node[wire];
|
||||
if (node == -1) {
|
||||
// Not a nodal wire
|
||||
id.tile = tile;
|
||||
id.index = wire;
|
||||
} else {
|
||||
// Is a nodal wire, set tile to -1
|
||||
id.tile = -1;
|
||||
id.index = node;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
struct WireIterator
|
||||
{
|
||||
const ChipInfoPOD *chip;
|
||||
int cursor_index = 0;
|
||||
int cursor_tile = -1;
|
||||
|
||||
WireIterator operator++()
|
||||
{
|
||||
// Iterate over nodes first, then tile wires that aren't nodes
|
||||
do {
|
||||
cursor_index++;
|
||||
if (cursor_tile == -1 && cursor_index >= chip->nodes.ssize()) {
|
||||
cursor_tile = 0;
|
||||
cursor_index = 0;
|
||||
}
|
||||
while (cursor_tile != -1 && cursor_tile < chip->tiles.ssize() &&
|
||||
cursor_index >= chip->tile_types[chip->tiles[cursor_tile].type].wire_data.ssize()) {
|
||||
cursor_index = 0;
|
||||
cursor_tile++;
|
||||
}
|
||||
|
||||
} while ((cursor_tile != -1 && cursor_tile < chip->tiles.ssize() &&
|
||||
cursor_index < chip->tiles[cursor_tile].tile_wire_to_node.ssize() &&
|
||||
chip->tiles[cursor_tile].tile_wire_to_node[cursor_index] != -1));
|
||||
|
||||
return *this;
|
||||
}
|
||||
WireIterator operator++(int)
|
||||
{
|
||||
WireIterator prior(*this);
|
||||
++(*this);
|
||||
return prior;
|
||||
}
|
||||
|
||||
bool operator!=(const WireIterator &other) const
|
||||
{
|
||||
return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile;
|
||||
}
|
||||
|
||||
bool operator==(const WireIterator &other) const
|
||||
{
|
||||
return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile;
|
||||
}
|
||||
|
||||
WireId operator*() const
|
||||
{
|
||||
WireId ret;
|
||||
ret.tile = cursor_tile;
|
||||
ret.index = cursor_index;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct WireRange
|
||||
{
|
||||
WireIterator b, e;
|
||||
WireIterator begin() const { return b; }
|
||||
WireIterator end() const { return e; }
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
struct AllPipIterator
|
||||
{
|
||||
const ChipInfoPOD *chip;
|
||||
int cursor_index;
|
||||
int cursor_tile;
|
||||
|
||||
AllPipIterator operator++()
|
||||
{
|
||||
cursor_index++;
|
||||
while (cursor_tile < chip->tiles.ssize() &&
|
||||
cursor_index >= chip->tile_types[chip->tiles[cursor_tile].type].pip_data.ssize()) {
|
||||
cursor_index = 0;
|
||||
cursor_tile++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
AllPipIterator operator++(int)
|
||||
{
|
||||
AllPipIterator prior(*this);
|
||||
++(*this);
|
||||
return prior;
|
||||
}
|
||||
|
||||
bool operator!=(const AllPipIterator &other) const
|
||||
{
|
||||
return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile;
|
||||
}
|
||||
|
||||
bool operator==(const AllPipIterator &other) const
|
||||
{
|
||||
return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile;
|
||||
}
|
||||
|
||||
PipId operator*() const
|
||||
{
|
||||
PipId ret;
|
||||
ret.tile = cursor_tile;
|
||||
ret.index = cursor_index;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct AllPipRange
|
||||
{
|
||||
AllPipIterator b, e;
|
||||
AllPipIterator begin() const { return b; }
|
||||
AllPipIterator end() const { return e; }
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
struct UphillPipIterator
|
||||
{
|
||||
const ChipInfoPOD *chip;
|
||||
TileWireIterator twi, twi_end;
|
||||
int cursor = -1;
|
||||
|
||||
void operator++()
|
||||
{
|
||||
cursor++;
|
||||
while (true) {
|
||||
if (!(twi != twi_end))
|
||||
break;
|
||||
WireId w = *twi;
|
||||
auto &tile = chip->tile_types[chip->tiles[w.tile].type];
|
||||
if (cursor < tile.wire_data[w.index].pips_uphill.ssize())
|
||||
break;
|
||||
++twi;
|
||||
cursor = 0;
|
||||
}
|
||||
}
|
||||
bool operator!=(const UphillPipIterator &other) const { return twi != other.twi || cursor != other.cursor; }
|
||||
|
||||
PipId operator*() const
|
||||
{
|
||||
PipId ret;
|
||||
WireId w = *twi;
|
||||
ret.tile = w.tile;
|
||||
ret.index = chip->tile_types[chip->tiles[w.tile].type].wire_data[w.index].pips_uphill[cursor];
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct UphillPipRange
|
||||
{
|
||||
UphillPipIterator b, e;
|
||||
UphillPipIterator begin() const { return b; }
|
||||
UphillPipIterator end() const { return e; }
|
||||
};
|
||||
|
||||
struct DownhillPipIterator
|
||||
{
|
||||
const ChipInfoPOD *chip;
|
||||
TileWireIterator twi, twi_end;
|
||||
int cursor = -1;
|
||||
|
||||
int32_t tile;
|
||||
int32_t tile_type;
|
||||
const RelSlice<int32_t> *pips_downhill = nullptr;
|
||||
|
||||
void operator++()
|
||||
{
|
||||
cursor++;
|
||||
while (true) {
|
||||
if (!(twi != twi_end))
|
||||
break;
|
||||
|
||||
if (pips_downhill == nullptr) {
|
||||
WireId w = *twi;
|
||||
tile_type = chip->tiles[w.tile].type;
|
||||
const TileTypeInfoPOD &type = chip->tile_types[tile_type];
|
||||
|
||||
tile = w.tile;
|
||||
pips_downhill = &type.wire_data[w.index].pips_downhill;
|
||||
}
|
||||
|
||||
if (cursor < pips_downhill->ssize())
|
||||
break;
|
||||
|
||||
++twi;
|
||||
cursor = 0;
|
||||
pips_downhill = nullptr;
|
||||
}
|
||||
}
|
||||
bool operator!=(const DownhillPipIterator &other) const { return twi != other.twi || cursor != other.cursor; }
|
||||
|
||||
PipId operator*() const
|
||||
{
|
||||
PipId ret;
|
||||
ret.tile = tile;
|
||||
ret.index = (*pips_downhill)[cursor];
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct DownhillPipRange
|
||||
{
|
||||
DownhillPipIterator b, e;
|
||||
DownhillPipIterator begin() const { return b; }
|
||||
DownhillPipIterator end() const { return e; }
|
||||
};
|
||||
|
||||
struct BelPinIterator
|
||||
{
|
||||
const ChipInfoPOD *chip;
|
||||
TileWireIterator twi, twi_end;
|
||||
int cursor = -1;
|
||||
|
||||
void operator++()
|
||||
{
|
||||
cursor++;
|
||||
|
||||
while (twi != twi_end) {
|
||||
WireId w = *twi;
|
||||
auto &tile = tile_info(chip, w.tile);
|
||||
if (cursor < tile.wire_data[w.index].bel_pins.ssize())
|
||||
break;
|
||||
|
||||
++twi;
|
||||
cursor = 0;
|
||||
}
|
||||
}
|
||||
bool operator!=(const BelPinIterator &other) const { return twi != other.twi || cursor != other.cursor; }
|
||||
|
||||
BelPin operator*() const
|
||||
{
|
||||
BelPin ret;
|
||||
WireId w = *twi;
|
||||
ret.bel.tile = w.tile;
|
||||
ret.bel.index = tile_info(chip, w.tile).wire_data[w.index].bel_pins[cursor].bel_index;
|
||||
ret.pin.index = tile_info(chip, w.tile).wire_data[w.index].bel_pins[cursor].port;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct BelPinRange
|
||||
{
|
||||
BelPinIterator b, e;
|
||||
BelPinIterator begin() const { return b; }
|
||||
BelPinIterator end() const { return e; }
|
||||
};
|
||||
|
||||
struct IdStringIterator : std::iterator<std::forward_iterator_tag,
|
||||
/*T=*/IdString,
|
||||
/*Distance=*/ptrdiff_t,
|
||||
/*pointer=*/IdString *,
|
||||
/*reference=*/IdString>
|
||||
{
|
||||
const int32_t *cursor;
|
||||
|
||||
void operator++() { cursor += 1; }
|
||||
|
||||
bool operator!=(const IdStringIterator &other) const { return cursor != other.cursor; }
|
||||
|
||||
bool operator==(const IdStringIterator &other) const { return cursor == other.cursor; }
|
||||
|
||||
IdString operator*() const { return IdString(*cursor); }
|
||||
};
|
||||
|
||||
struct IdStringRange
|
||||
{
|
||||
IdStringIterator b, e;
|
||||
IdStringIterator begin() const { return b; }
|
||||
IdStringIterator end() const { return e; }
|
||||
};
|
||||
|
||||
struct BelBucketIterator
|
||||
{
|
||||
IdStringIterator cursor;
|
||||
|
||||
void operator++() { ++cursor; }
|
||||
|
||||
bool operator!=(const BelBucketIterator &other) const { return cursor != other.cursor; }
|
||||
|
||||
bool operator==(const BelBucketIterator &other) const { return cursor == other.cursor; }
|
||||
|
||||
BelBucketId operator*() const
|
||||
{
|
||||
BelBucketId bucket;
|
||||
bucket.name = IdString(*cursor);
|
||||
return bucket;
|
||||
}
|
||||
};
|
||||
|
||||
struct BelBucketRange
|
||||
{
|
||||
BelBucketIterator b, e;
|
||||
BelBucketIterator begin() const { return b; }
|
||||
BelBucketIterator end() const { return e; }
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif /* ARCH_ITERATORS_H */
|
@ -24,6 +24,7 @@
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
#include "hash_table.h"
|
||||
#include "luts.h"
|
||||
#include "nextpnr_namespaces.h"
|
||||
|
||||
@ -108,8 +109,8 @@ struct ArchCellInfo
|
||||
ArchCellInfo() : cell_mapping(-1) {}
|
||||
|
||||
int32_t cell_mapping;
|
||||
std::unordered_map<IdString, std::vector<IdString>> cell_bel_pins;
|
||||
std::unordered_set<IdString> const_ports;
|
||||
HashTables::HashMap<IdString, std::vector<IdString>> cell_bel_pins;
|
||||
HashTables::HashSet<IdString> const_ports;
|
||||
LutCell lut_cell;
|
||||
};
|
||||
|
||||
|
310
fpga_interchange/chipdb.h
Normal file
310
fpga_interchange/chipdb.h
Normal file
@ -0,0 +1,310 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHIPDB_H
|
||||
#define CHIPDB_H
|
||||
|
||||
#include "archdefs.h"
|
||||
#include "nextpnr_namespaces.h"
|
||||
#include "relptr.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
/* !!! Everything in this section must be kept in sync !!!
|
||||
* !!! with fpga_interchange/chip_info.py !!!
|
||||
*
|
||||
* When schema changes, bump version number in chip_info.py and
|
||||
* kExpectedChipInfoVersion
|
||||
*/
|
||||
|
||||
static constexpr int32_t kExpectedChipInfoVersion = 1;
|
||||
|
||||
// Flattened site indexing.
|
||||
//
|
||||
// To enable flat BelId.z spaces, every tile and sites within that tile are
|
||||
// flattened.
|
||||
//
|
||||
// This has implications on BelId's, WireId's and PipId's.
|
||||
// The flattened site space works as follows:
|
||||
// - Objects that belong to the tile are first. BELs are always part of Sites,
|
||||
// so no BEL objects are in this category.
|
||||
// - All site alternative modes are exposed as a "full" site.
|
||||
// - Each site appends it's BEL's, wires (site wires) and PIP's.
|
||||
// - Sites add two types of pips. Sites will add pip data first for site
|
||||
// pips, and then for site pin edges.
|
||||
// 1. The first type is site pips, which connect site wires to other site
|
||||
// wires.
|
||||
// 2. The second type is site pin edges, which connect site wires to tile
|
||||
// wires (or vise-versa).
|
||||
|
||||
NPNR_PACKED_STRUCT(struct BelInfoPOD {
|
||||
int32_t name; // bel name (in site) constid
|
||||
int32_t type; // Type name constid
|
||||
int32_t bel_bucket; // BEL bucket constid.
|
||||
|
||||
int32_t num_bel_wires;
|
||||
RelPtr<int32_t> ports; // port name constid
|
||||
RelPtr<int32_t> types; // port type (IN/OUT/BIDIR)
|
||||
RelPtr<int32_t> wires; // connected wire index in tile, or -1 if NA
|
||||
|
||||
int16_t site;
|
||||
int16_t site_variant; // some sites have alternative types
|
||||
int16_t category;
|
||||
int8_t synthetic;
|
||||
int8_t lut_element;
|
||||
|
||||
RelPtr<int32_t> pin_map; // Index into CellMapPOD::cell_bel_map
|
||||
});
|
||||
|
||||
enum BELCategory
|
||||
{
|
||||
// BEL is a logic element
|
||||
BEL_CATEGORY_LOGIC = 0,
|
||||
// BEL is a site routing mux
|
||||
BEL_CATEGORY_ROUTING = 1,
|
||||
// BEL is a site port, e.g. boundry between site and routing graph.
|
||||
BEL_CATEGORY_SITE_PORT = 2
|
||||
};
|
||||
|
||||
NPNR_PACKED_STRUCT(struct BelPortPOD {
|
||||
int32_t bel_index;
|
||||
int32_t port;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct TileWireInfoPOD {
|
||||
int32_t name; // wire name constid
|
||||
|
||||
// Pip index inside tile
|
||||
RelSlice<int32_t> pips_uphill;
|
||||
|
||||
// Pip index inside tile
|
||||
RelSlice<int32_t> pips_downhill;
|
||||
|
||||
// Bel index inside tile
|
||||
RelSlice<BelPortPOD> bel_pins;
|
||||
|
||||
int16_t site; // site index in tile
|
||||
int16_t site_variant; // site variant index in tile
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct PipInfoPOD {
|
||||
int32_t src_index, dst_index;
|
||||
int16_t site; // site index in tile
|
||||
int16_t site_variant; // site variant index in tile
|
||||
int16_t bel; // BEL this pip belongs to if site pip.
|
||||
int16_t extra_data;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct ConstraintTagPOD {
|
||||
int32_t tag_prefix; // constid
|
||||
int32_t default_state; // constid
|
||||
RelSlice<int32_t> states; // constid
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct LutBelPOD {
|
||||
uint32_t name; // constid
|
||||
RelSlice<int32_t> pins; // constid
|
||||
uint32_t low_bit;
|
||||
uint32_t high_bit;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct LutElementPOD {
|
||||
int32_t width;
|
||||
RelSlice<LutBelPOD> lut_bels;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct TileTypeInfoPOD {
|
||||
int32_t name; // Tile type constid
|
||||
|
||||
RelSlice<BelInfoPOD> bel_data;
|
||||
|
||||
RelSlice<TileWireInfoPOD> wire_data;
|
||||
|
||||
RelSlice<PipInfoPOD> pip_data;
|
||||
|
||||
RelSlice<ConstraintTagPOD> tags;
|
||||
|
||||
RelSlice<LutElementPOD> lut_elements;
|
||||
|
||||
RelSlice<int32_t> site_types; // constid
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct SiteInstInfoPOD {
|
||||
RelPtr<char> name;
|
||||
RelPtr<char> site_name;
|
||||
|
||||
// Which site type is this site instance?
|
||||
// constid
|
||||
int32_t site_type;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct TileInstInfoPOD {
|
||||
// Name of this tile.
|
||||
RelPtr<char> name;
|
||||
|
||||
// Index into root.tile_types.
|
||||
int32_t type;
|
||||
|
||||
// This array is root.tile_types[type].site_types.size() long.
|
||||
// Index into root.sites
|
||||
RelSlice<int32_t> sites;
|
||||
|
||||
// Number of tile wires; excluding any site-internal wires
|
||||
// which come after general wires and are not stored here
|
||||
// as they will never be nodal
|
||||
// -1 if a tile-local wire; node index if nodal wire
|
||||
RelSlice<int32_t> tile_wire_to_node;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct TileWireRefPOD {
|
||||
int32_t tile;
|
||||
int32_t index;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct NodeInfoPOD { RelSlice<TileWireRefPOD> tile_wires; });
|
||||
|
||||
NPNR_PACKED_STRUCT(struct CellBelPinPOD {
|
||||
int32_t cell_pin; // constid
|
||||
int32_t bel_pin; // constid
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct ParameterPinsPOD {
|
||||
int32_t key; // constid
|
||||
int32_t value; // constid
|
||||
RelSlice<CellBelPinPOD> pins;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct CellConstraintPOD {
|
||||
int32_t tag; // Tag index
|
||||
int32_t constraint_type; // Constraint::ConstraintType
|
||||
RelSlice<int32_t> states; // State indicies
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct CellBelMapPOD {
|
||||
RelSlice<CellBelPinPOD> common_pins;
|
||||
RelSlice<ParameterPinsPOD> parameter_pins;
|
||||
RelSlice<CellConstraintPOD> constraints;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct LutCellPOD {
|
||||
int32_t cell; // constid
|
||||
RelSlice<int32_t> input_pins; // constids
|
||||
int32_t parameter;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct CellMapPOD {
|
||||
// Cell names supported in this arch.
|
||||
RelSlice<int32_t> cell_names; // constids
|
||||
RelSlice<int32_t> cell_bel_buckets; // constids
|
||||
|
||||
RelSlice<CellBelMapPOD> cell_bel_map;
|
||||
|
||||
RelSlice<LutCellPOD> lut_cells;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct PackagePinPOD {
|
||||
int32_t package_pin; // constid
|
||||
int32_t site; // constid
|
||||
int32_t bel; // constid
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct PackagePOD {
|
||||
int32_t package; // constid
|
||||
RelSlice<PackagePinPOD> pins;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct ConstantsPOD {
|
||||
// Cell type and port for the GND and VCC global source.
|
||||
int32_t gnd_cell_name; // constid
|
||||
int32_t gnd_cell_port; // constid
|
||||
|
||||
int32_t vcc_cell_name; // constid
|
||||
int32_t vcc_cell_port; // constid
|
||||
|
||||
int32_t gnd_bel_tile;
|
||||
int32_t gnd_bel_index;
|
||||
int32_t gnd_bel_pin; // constid
|
||||
|
||||
int32_t vcc_bel_tile;
|
||||
int32_t vcc_bel_index;
|
||||
int32_t vcc_bel_pin; // constid
|
||||
|
||||
// Name to use for the global GND constant net
|
||||
int32_t gnd_net_name; // constid
|
||||
|
||||
// Name to use for the global VCC constant net
|
||||
int32_t vcc_net_name; // constid
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct ChipInfoPOD {
|
||||
RelPtr<char> name;
|
||||
RelPtr<char> generator;
|
||||
|
||||
int32_t version;
|
||||
int32_t width, height;
|
||||
|
||||
RelSlice<TileTypeInfoPOD> tile_types;
|
||||
RelSlice<SiteInstInfoPOD> sites;
|
||||
RelSlice<TileInstInfoPOD> tiles;
|
||||
RelSlice<NodeInfoPOD> nodes;
|
||||
RelSlice<PackagePOD> packages;
|
||||
|
||||
// BEL bucket constids.
|
||||
RelSlice<int32_t> bel_buckets;
|
||||
|
||||
RelPtr<CellMapPOD> cell_map;
|
||||
RelPtr<ConstantsPOD> constants;
|
||||
|
||||
// Constid string data.
|
||||
RelPtr<RelSlice<RelPtr<char>>> constids;
|
||||
});
|
||||
|
||||
/************************ End of chipdb section. ************************/
|
||||
|
||||
inline const TileTypeInfoPOD &tile_info(const ChipInfoPOD *chip_info, int32_t tile)
|
||||
{
|
||||
return chip_info->tile_types[chip_info->tiles[tile].type];
|
||||
}
|
||||
|
||||
template <typename Id> const TileTypeInfoPOD &loc_info(const ChipInfoPOD *chip_info, Id &id)
|
||||
{
|
||||
return chip_info->tile_types[chip_info->tiles[id.tile].type];
|
||||
}
|
||||
|
||||
NPNR_ALWAYS_INLINE inline const BelInfoPOD &bel_info(const ChipInfoPOD *chip_info, BelId bel)
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
return loc_info(chip_info, bel).bel_data[bel.index];
|
||||
}
|
||||
|
||||
inline const PipInfoPOD &pip_info(const ChipInfoPOD *chip_info, PipId pip)
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
return loc_info(chip_info, pip).pip_data[pip.index];
|
||||
}
|
||||
|
||||
inline const SiteInstInfoPOD &site_inst_info(const ChipInfoPOD *chip_info, int32_t tile, int32_t site)
|
||||
{
|
||||
return chip_info->sites[chip_info->tiles[tile].sites[site]];
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif /* CHIPDB_H */
|
@ -122,6 +122,8 @@ struct LutPin
|
||||
bool operator<(const LutPin &other) const { return max_pin < other.max_pin; }
|
||||
};
|
||||
|
||||
//#define DEBUG_LUT_ROTATION
|
||||
|
||||
bool LutMapper::remap_luts(const Context *ctx)
|
||||
{
|
||||
std::unordered_map<NetInfo *, LutPin> lut_pin_map;
|
||||
@ -262,11 +264,25 @@ bool LutMapper::remap_luts(const Context *ctx)
|
||||
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]);
|
||||
cell->lut_cell.vcc_pins.emplace(lut_bel.pins.at(bel_pin_idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LUT_ROTATION
|
||||
log_info("Final mapping:\n");
|
||||
for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
|
||||
CellInfo *cell = cells[cell_idx];
|
||||
for (auto &cell_pin_pair : cell->cell_bel_pins) {
|
||||
log_info("%s %s %s =>", cell->type.c_str(ctx), cell->name.c_str(ctx), cell_pin_pair.first.c_str(ctx));
|
||||
for (auto bel_pin : cell_pin_pair.second) {
|
||||
log(" %s", bel_pin.c_str(ctx));
|
||||
}
|
||||
log("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,15 @@
|
||||
*/
|
||||
|
||||
#include "xdc.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "context.h"
|
||||
#include "log.h"
|
||||
#include "nextpnr.h"
|
||||
|
||||
// Include tcl.h late because it messed with #define's and lets them leave the
|
||||
// scope of the header.
|
||||
#include <tcl.h>
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -17,11 +17,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <tcl.h>
|
||||
#include "nextpnr.h"
|
||||
#ifndef XDC_H
|
||||
#define XDC_H
|
||||
|
||||
#include "nextpnr_namespaces.h"
|
||||
|
||||
struct Tcl_Interp;
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
struct Context;
|
||||
|
||||
struct TclInterp
|
||||
{
|
||||
TclInterp(Context *ctx);
|
||||
@ -31,3 +37,5 @@ struct TclInterp
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user