Add default base implementation of cluster API

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2021-04-28 14:49:26 +01:00
parent e1717bd771
commit 6a3eacddd6
6 changed files with 104 additions and 7 deletions

View File

@ -142,7 +142,7 @@ template <typename R> struct ArchAPI : BaseCtx
// Cluster methods
virtual CellInfo *getClusterRootCell(ClusterId cluster) const = 0;
virtual ArcBounds getClusterBounds(ClusterId cluster) const = 0;
virtual Loc getClusterOffset(ClusterId cluster, CellInfo *cell) const = 0;
virtual Loc getClusterOffset(CellInfo *cell) const = 0;
virtual bool isClusterStrict(CellInfo *cell) const = 0;
virtual bool getClusterPlacement(ClusterId cluster, BelId root_bel,
std::vector<std::pair<CellInfo *, BelId>> &placement) const = 0;

View File

@ -25,6 +25,7 @@
#include <vector>
#include "arch_api.h"
#include "base_clusterinfo.h"
#include "idstring.h"
#include "nextpnr_types.h"
@ -80,6 +81,36 @@ typename std::enable_if<!std::is_same<Tret, Tc>::value, Tret>::type return_if_ma
"respective range types are 'const std::vector&'");
}
// Default implementations of the clustering functions
template <typename Tid>
typename std::enable_if<std::is_same<Tid, IdString>::value, CellInfo *>::type get_cluster_root(const BaseCtx *ctx,
Tid cluster)
{
return ctx->cells.at(cluster).get();
}
template <typename Tid>
typename std::enable_if<!std::is_same<Tid, IdString>::value, CellInfo *>::type get_cluster_root(const BaseCtx *ctx,
Tid cluster)
{
NPNR_ASSERT_FALSE("default implementation of getClusterRootCell requires ClusterId to be IdString");
}
// Executes the lambda with the base cluster data, only if the derivation works
template <typename Tret, typename Tcell, typename Tfunc>
typename std::enable_if<std::is_base_of<BaseClusterInfo, Tcell>::value, Tret>::type
if_using_basecluster(const Tcell *cell, Tfunc func)
{
return func(static_cast<const BaseClusterInfo *>(cell));
}
template <typename Tret, typename Tcell, typename Tfunc>
typename std::enable_if<!std::is_base_of<BaseClusterInfo, Tcell>::value, Tret>::type
if_using_basecluster(const Tcell *cell, Tfunc func)
{
NPNR_ASSERT_FALSE(
"default implementation of cluster functions requires ArchCellInfo to derive from BaseClusterInfo");
}
} // namespace
// This contains the relevant range types for the default implementations of Arch functions
@ -343,6 +374,68 @@ template <typename R> struct BaseArch : ArchAPI<R>
return return_if_match<const std::vector<BelId> &, typename R::BucketBelRangeT>(bucket_bels.at(bucket));
}
// Cluster methods
virtual CellInfo *getClusterRootCell(ClusterId cluster) const override { return get_cluster_root(this, cluster); }
virtual ArcBounds getClusterBounds(ClusterId cluster) const override
{
return if_using_basecluster<ArcBounds>(get_cluster_root(this, cluster), [](const BaseClusterInfo *cluster) {
ArcBounds bounds(0, 0, 0, 0);
for (auto child : cluster->constr_children) {
if_using_basecluster<void>(child, [&](const BaseClusterInfo *child) {
bounds.x0 = std::min(bounds.x0, child->constr_x);
bounds.y0 = std::min(bounds.y0, child->constr_y);
bounds.x1 = std::max(bounds.x1, child->constr_x);
bounds.y1 = std::max(bounds.y1, child->constr_y);
});
}
return bounds;
});
}
virtual Loc getClusterOffset(CellInfo *cell) const override
{
return if_using_basecluster<Loc>(cell,
[](const BaseClusterInfo *c) { return Loc(c->constr_x, c->constr_y, 0); });
}
virtual bool isClusterStrict(CellInfo *cell) const override { return true; }
virtual bool getClusterPlacement(ClusterId cluster, BelId root_bel,
std::vector<std::pair<CellInfo *, BelId>> &placement) const override
{
CellInfo *root_cell = get_cluster_root(this, cluster);
return if_using_basecluster<bool>(root_cell, [&](const BaseClusterInfo *cluster) -> bool {
placement.clear();
NPNR_ASSERT(root_bel != BelId());
Loc root_loc = this->getBelLocation(root_bel);
if (cluster->constr_abs_z) {
// Coerce root to absolute z constraint
root_loc.z = cluster->constr_z;
root_bel = this->getBelByLocation(root_loc);
if (root_bel == BelId() || !this->isValidBelForCellType(root_cell->type, root_bel))
return false;
}
placement.emplace_back(root_cell, root_bel);
for (auto child : cluster->constr_children) {
Loc child_loc = if_using_basecluster<Loc>(child, [&](const BaseClusterInfo *child) {
Loc result;
result.x = root_loc.x + child->constr_x;
result.y = root_loc.y + child->constr_y;
result.z = child->constr_abs_z ? child->constr_z : (root_loc.z + child->constr_z);
return result;
});
BelId child_bel = this->getBelByLocation(child_loc);
if (child_bel == BelId() || !this->isValidBelForCellType(child->type, root_bel))
return false;
placement.emplace_back(child, child_bel);
}
return true;
});
}
// Flow methods
virtual void assignArchInfo() override{};

View File

@ -32,10 +32,9 @@ struct CellInfo;
struct BaseClusterInfo
{
std::vector<CellInfo *> constr_children;
const int UNCONSTR = INT_MIN;
int constr_x = UNCONSTR; // this.x - parent.x
int constr_y = UNCONSTR; // this.y - parent.y
int constr_z = UNCONSTR; // this.z - parent.z
int constr_x = 0; // this.x - parent.x
int constr_y = 0; // this.y - parent.y
int constr_z = 0; // this.z - parent.z
bool constr_abs_z = false; // parent.z := 0
};

View File

@ -48,6 +48,7 @@ typedef IdString PipId;
typedef IdString GroupId;
typedef IdString DecalId;
typedef IdString BelBucketId;
typedef IdString ClusterId;
struct ArchNetInfo
{

View File

@ -22,6 +22,7 @@
#include <boost/functional/hash.hpp>
#include "base_clusterinfo.h"
#include "idstring.h"
#include "nextpnr_namespaces.h"
@ -122,7 +123,7 @@ struct ArchNetInfo
struct NetInfo;
struct ArchCellInfo
struct ArchCellInfo : BaseClusterInfo
{
union
{
@ -154,6 +155,7 @@ struct ArchCellInfo
};
typedef IdString BelBucketId;
typedef IdString ClusterId;
NEXTPNR_NAMESPACE_END

View File

@ -292,12 +292,14 @@ class ChainConstrainer
// Place carry chain
chain.cells.at(0)->constr_abs_z = true;
chain.cells.at(0)->constr_z = 0;
chain.cells.at(0)->cluster = chain.cells.at(0)->name;
for (int i = 1; i < int(chain.cells.size()); i++) {
chain.cells.at(i)->constr_x = 0;
chain.cells.at(i)->constr_y = (i / 8);
chain.cells.at(i)->constr_z = i % 8;
chain.cells.at(i)->constr_abs_z = true;
chain.cells.at(i)->constr_parent = chain.cells.at(0);
chain.cells.at(i)->cluster = chain.cells.at(0)->name;
chain.cells.at(0)->constr_children.push_back(chain.cells.at(i));
}
}