aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-04-28 14:49:26 +0100
committergatecat <gatecat@ds0.me>2021-05-06 11:47:06 +0100
commit6a3eacddd60713d9c0d470d13a54a0c42f7d87c9 (patch)
tree52452bdd4993a2885b4fd886263435ac1e87a54c /common
parente1717bd771f51e3a2c370ffa64d50de6b8ee6ca6 (diff)
downloadnextpnr-6a3eacddd60713d9c0d470d13a54a0c42f7d87c9.tar.gz
nextpnr-6a3eacddd60713d9c0d470d13a54a0c42f7d87c9.tar.bz2
nextpnr-6a3eacddd60713d9c0d470d13a54a0c42f7d87c9.zip
Add default base implementation of cluster API
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'common')
-rw-r--r--common/arch_api.h2
-rw-r--r--common/base_arch.h93
-rw-r--r--common/base_clusterinfo.h7
3 files changed, 97 insertions, 5 deletions
diff --git a/common/arch_api.h b/common/arch_api.h
index 76b78c62..f8e6d0ae 100644
--- a/common/arch_api.h
+++ b/common/arch_api.h
@@ -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;
diff --git a/common/base_arch.h b/common/base_arch.h
index d4efe9ce..35500c1d 100644
--- a/common/base_arch.h
+++ b/common/base_arch.h
@@ -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{};
diff --git a/common/base_clusterinfo.h b/common/base_clusterinfo.h
index a79f2686..32e6f87e 100644
--- a/common/base_clusterinfo.h
+++ b/common/base_clusterinfo.h
@@ -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
};