mirror of
https://github.com/YosysHQ/nextpnr.git
synced 2026-05-04 15:15:34 +00:00
Update placers to use new cluster APIs
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
@@ -142,8 +142,8 @@ 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(CellInfo *cell) const = 0;
|
||||
virtual bool isClusterStrict(CellInfo *cell) const = 0;
|
||||
virtual Loc getClusterOffset(const CellInfo *cell) const = 0;
|
||||
virtual bool isClusterStrict(const CellInfo *cell) const = 0;
|
||||
virtual bool getClusterPlacement(ClusterId cluster, BelId root_bel,
|
||||
std::vector<std::pair<CellInfo *, BelId>> &placement) const = 0;
|
||||
// Flow methods
|
||||
|
||||
@@ -393,13 +393,13 @@ template <typename R> struct BaseArch : ArchAPI<R>
|
||||
});
|
||||
}
|
||||
|
||||
virtual Loc getClusterOffset(CellInfo *cell) const override
|
||||
virtual Loc getClusterOffset(const 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 isClusterStrict(const CellInfo *cell) const override { return true; }
|
||||
|
||||
virtual bool getClusterPlacement(ClusterId cluster, BelId root_bel,
|
||||
std::vector<std::pair<CellInfo *, BelId>> &placement) const override
|
||||
|
||||
@@ -152,25 +152,6 @@ void BaseCtx::archInfoToAttributes()
|
||||
ci->attrs[id("NEXTPNR_BEL")] = getCtx()->getBelName(ci->bel).str(getCtx());
|
||||
ci->attrs[id("BEL_STRENGTH")] = (int)ci->belStrength;
|
||||
}
|
||||
if (ci->constr_x != ci->UNCONSTR)
|
||||
ci->attrs[id("CONSTR_X")] = ci->constr_x;
|
||||
if (ci->constr_y != ci->UNCONSTR)
|
||||
ci->attrs[id("CONSTR_Y")] = ci->constr_y;
|
||||
if (ci->constr_z != ci->UNCONSTR) {
|
||||
ci->attrs[id("CONSTR_Z")] = ci->constr_z;
|
||||
ci->attrs[id("CONSTR_ABS_Z")] = ci->constr_abs_z ? 1 : 0;
|
||||
}
|
||||
if (ci->constr_parent != nullptr)
|
||||
ci->attrs[id("CONSTR_PARENT")] = ci->constr_parent->name.str(this);
|
||||
if (!ci->constr_children.empty()) {
|
||||
std::string constr = "";
|
||||
for (auto &item : ci->constr_children) {
|
||||
if (!constr.empty())
|
||||
constr += std::string(";");
|
||||
constr += item->name.c_str(this);
|
||||
}
|
||||
ci->attrs[id("CONSTR_CHILDREN")] = constr;
|
||||
}
|
||||
}
|
||||
for (auto &net : getCtx()->nets) {
|
||||
auto ni = net.second.get();
|
||||
@@ -204,48 +185,6 @@ void BaseCtx::attributesToArchInfo()
|
||||
BelId b = getCtx()->getBelByNameStr(val->second.as_string());
|
||||
getCtx()->bindBel(b, ci, strength);
|
||||
}
|
||||
|
||||
val = ci->attrs.find(id("CONSTR_PARENT"));
|
||||
if (val != ci->attrs.end()) {
|
||||
auto parent = cells.find(id(val->second.str));
|
||||
if (parent != cells.end())
|
||||
ci->constr_parent = parent->second.get();
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
val = ci->attrs.find(id("CONSTR_X"));
|
||||
if (val != ci->attrs.end())
|
||||
ci->constr_x = val->second.as_int64();
|
||||
|
||||
val = ci->attrs.find(id("CONSTR_Y"));
|
||||
if (val != ci->attrs.end())
|
||||
ci->constr_y = val->second.as_int64();
|
||||
|
||||
val = ci->attrs.find(id("CONSTR_Z"));
|
||||
if (val != ci->attrs.end())
|
||||
ci->constr_z = val->second.as_int64();
|
||||
|
||||
val = ci->attrs.find(id("CONSTR_ABS_Z"));
|
||||
if (val != ci->attrs.end())
|
||||
ci->constr_abs_z = val->second.as_int64() == 1;
|
||||
|
||||
val = ci->attrs.find(id("CONSTR_PARENT"));
|
||||
if (val != ci->attrs.end()) {
|
||||
auto parent = cells.find(id(val->second.as_string()));
|
||||
if (parent != cells.end())
|
||||
ci->constr_parent = parent->second.get();
|
||||
}
|
||||
val = ci->attrs.find(id("CONSTR_CHILDREN"));
|
||||
if (val != ci->attrs.end()) {
|
||||
std::vector<std::string> strs;
|
||||
auto children = val->second.as_string();
|
||||
boost::split(strs, children, boost::is_any_of(";"));
|
||||
for (auto val : strs) {
|
||||
if (cells.count(id(val.c_str())))
|
||||
ci->constr_children.push_back(cells.find(id(val.c_str()))->second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto &net : getCtx()->nets) {
|
||||
auto ni = net.second.get();
|
||||
|
||||
@@ -44,26 +44,9 @@ void CellInfo::unsetParam(IdString name) { params.erase(name); }
|
||||
void CellInfo::setAttr(IdString name, Property value) { attrs[name] = value; }
|
||||
void CellInfo::unsetAttr(IdString name) { attrs.erase(name); }
|
||||
|
||||
bool CellInfo::isConstrained(bool include_abs_z_constr) const
|
||||
{
|
||||
return constr_parent != nullptr || !constr_children.empty() || (include_abs_z_constr && constr_abs_z);
|
||||
}
|
||||
|
||||
bool CellInfo::testRegion(BelId bel) const
|
||||
{
|
||||
return region == nullptr || !region->constr_bels || region->bels.count(bel);
|
||||
}
|
||||
Loc CellInfo::getConstrainedLoc(Loc parent_loc) const
|
||||
{
|
||||
NPNR_ASSERT(constr_parent != nullptr);
|
||||
Loc cloc = parent_loc;
|
||||
if (constr_x != UNCONSTR)
|
||||
cloc.x += constr_x;
|
||||
if (constr_y != UNCONSTR)
|
||||
cloc.y += constr_y;
|
||||
if (constr_z != UNCONSTR)
|
||||
cloc.z = constr_abs_z ? constr_z : (parent_loc.z + constr_z);
|
||||
return cloc;
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
@@ -178,14 +178,8 @@ struct CellInfo : ArchCellInfo
|
||||
void unsetParam(IdString name);
|
||||
void setAttr(IdString name, Property value);
|
||||
void unsetAttr(IdString name);
|
||||
|
||||
// return true if the cell has placement constraints (optionally excluding the case where the only case is an
|
||||
// absolute z constraint)
|
||||
bool isConstrained(bool include_abs_z_constr = true) const;
|
||||
// check whether a bel complies with the cell's region constraint
|
||||
bool testRegion(BelId bel) const;
|
||||
// get the constrained location for this cell given a provisional location for its parent
|
||||
Loc getConstrainedLoc(Loc parent_loc) const;
|
||||
};
|
||||
|
||||
enum TimingPortClass
|
||||
|
||||
@@ -179,6 +179,8 @@ class ConstraintLegaliseWorker
|
||||
Context *ctx;
|
||||
std::set<IdString> rippedCells;
|
||||
std::unordered_map<IdString, Loc> oldLocations;
|
||||
std::unordered_map<ClusterId, std::vector<CellInfo *>> cluster2cells;
|
||||
|
||||
class IncreasingDiameterSearch
|
||||
{
|
||||
public:
|
||||
@@ -228,83 +230,52 @@ class ConstraintLegaliseWorker
|
||||
typedef std::unordered_map<IdString, Loc> CellLocations;
|
||||
|
||||
// Check if a location would be suitable for a cell and all its constrained children
|
||||
// This also makes a crude attempt to "solve" unconstrained constraints, that is slow and horrible
|
||||
// and will need to be reworked if mixed constrained/unconstrained chains become common
|
||||
bool valid_loc_for(const CellInfo *cell, Loc loc, CellLocations &solution, std::unordered_set<Loc> &usedLocations)
|
||||
{
|
||||
BelId locBel = ctx->getBelByLocation(loc);
|
||||
if (locBel == BelId()) {
|
||||
if (locBel == BelId())
|
||||
return false;
|
||||
}
|
||||
if (!ctx->isValidBelForCellType(cell->type, locBel)) {
|
||||
return false;
|
||||
}
|
||||
if (!ctx->checkBelAvail(locBel)) {
|
||||
CellInfo *confCell = ctx->getConflictingBelCell(locBel);
|
||||
if (confCell->belStrength >= STRENGTH_STRONG) {
|
||||
|
||||
if (cell->cluster == ClusterId()) {
|
||||
if (!ctx->isValidBelForCellType(cell->type, locBel))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Don't place at tiles where any strongly bound Bels exist, as we might need to rip them up later
|
||||
for (auto tilebel : ctx->getBelsByTile(loc.x, loc.y)) {
|
||||
CellInfo *tcell = ctx->getBoundBelCell(tilebel);
|
||||
if (tcell && tcell->belStrength >= STRENGTH_STRONG)
|
||||
return false;
|
||||
}
|
||||
usedLocations.insert(loc);
|
||||
for (auto child : cell->constr_children) {
|
||||
IncreasingDiameterSearch xSearch, ySearch, zSearch;
|
||||
if (child->constr_x == child->UNCONSTR) {
|
||||
xSearch = IncreasingDiameterSearch(loc.x, 0, ctx->getGridDimX() - 1);
|
||||
} else {
|
||||
xSearch = IncreasingDiameterSearch(loc.x + child->constr_x);
|
||||
}
|
||||
if (child->constr_y == child->UNCONSTR) {
|
||||
ySearch = IncreasingDiameterSearch(loc.y, 0, ctx->getGridDimY() - 1);
|
||||
} else {
|
||||
ySearch = IncreasingDiameterSearch(loc.y + child->constr_y);
|
||||
}
|
||||
if (child->constr_z == child->UNCONSTR) {
|
||||
zSearch = IncreasingDiameterSearch(loc.z, 0, ctx->getTileBelDimZ(loc.x, loc.y));
|
||||
} else {
|
||||
if (child->constr_abs_z) {
|
||||
zSearch = IncreasingDiameterSearch(child->constr_z);
|
||||
} else {
|
||||
zSearch = IncreasingDiameterSearch(loc.z + child->constr_z);
|
||||
if (!ctx->checkBelAvail(locBel)) {
|
||||
CellInfo *confCell = ctx->getConflictingBelCell(locBel);
|
||||
if (confCell->belStrength >= STRENGTH_STRONG) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool success = false;
|
||||
while (!xSearch.done()) {
|
||||
Loc cloc;
|
||||
cloc.x = xSearch.get();
|
||||
cloc.y = ySearch.get();
|
||||
cloc.z = zSearch.get();
|
||||
|
||||
zSearch.next();
|
||||
if (zSearch.done()) {
|
||||
zSearch.reset();
|
||||
ySearch.next();
|
||||
if (ySearch.done()) {
|
||||
ySearch.reset();
|
||||
xSearch.next();
|
||||
// Don't place at tiles where any strongly bound Bels exist, as we might need to rip them up later
|
||||
for (auto tilebel : ctx->getBelsByTile(loc.x, loc.y)) {
|
||||
CellInfo *tcell = ctx->getBoundBelCell(tilebel);
|
||||
if (tcell && tcell->belStrength >= STRENGTH_STRONG)
|
||||
return false;
|
||||
}
|
||||
usedLocations.insert(loc);
|
||||
solution[cell->name] = loc;
|
||||
} else {
|
||||
std::vector<std::pair<CellInfo *, BelId>> placement;
|
||||
if (!ctx->getClusterPlacement(cell->cluster, locBel, placement))
|
||||
return false;
|
||||
for (auto &p : placement) {
|
||||
Loc p_loc = ctx->getBelLocation(p.second);
|
||||
if (!ctx->checkBelAvail(p.second)) {
|
||||
CellInfo *confCell = ctx->getConflictingBelCell(p.second);
|
||||
if (confCell->belStrength >= STRENGTH_STRONG) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (usedLocations.count(cloc))
|
||||
continue;
|
||||
if (valid_loc_for(child, cloc, solution, usedLocations)) {
|
||||
success = true;
|
||||
break;
|
||||
// Don't place at tiles where any strongly bound Bels exist, as we might need to rip them up later
|
||||
for (auto tilebel : ctx->getBelsByTile(p_loc.x, p_loc.y)) {
|
||||
CellInfo *tcell = ctx->getBoundBelCell(tilebel);
|
||||
if (tcell && tcell->belStrength >= STRENGTH_STRONG)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
usedLocations.erase(loc);
|
||||
return false;
|
||||
usedLocations.insert(p_loc);
|
||||
solution[p.first->name] = p_loc;
|
||||
}
|
||||
}
|
||||
if (solution.count(cell->name))
|
||||
usedLocations.erase(solution.at(cell->name));
|
||||
solution[cell->name] = loc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -312,18 +283,18 @@ class ConstraintLegaliseWorker
|
||||
void lockdown_chain(CellInfo *root)
|
||||
{
|
||||
root->belStrength = STRENGTH_STRONG;
|
||||
for (auto child : root->constr_children)
|
||||
lockdown_chain(child);
|
||||
if (root->cluster != ClusterId())
|
||||
for (auto child : cluster2cells.at(root->cluster))
|
||||
child->belStrength = STRENGTH_STRONG;
|
||||
}
|
||||
|
||||
// Legalise placement constraints on a cell
|
||||
bool legalise_cell(CellInfo *cell)
|
||||
{
|
||||
if (cell->constr_parent != nullptr)
|
||||
if (cell->cluster != ClusterId() && ctx->getClusterRootCell(cell->cluster) != cell)
|
||||
return true; // Only process chain roots
|
||||
if (constraints_satisfied(cell)) {
|
||||
if (cell->constr_children.size() > 0 || cell->constr_x != cell->UNCONSTR ||
|
||||
cell->constr_y != cell->UNCONSTR || cell->constr_z != cell->UNCONSTR)
|
||||
if (cell->cluster != ClusterId())
|
||||
lockdown_chain(cell);
|
||||
} else {
|
||||
IncreasingDiameterSearch xRootSearch, yRootSearch, zRootSearch;
|
||||
@@ -332,21 +303,10 @@ class ConstraintLegaliseWorker
|
||||
currentLoc = ctx->getBelLocation(cell->bel);
|
||||
else
|
||||
currentLoc = oldLocations[cell->name];
|
||||
if (cell->constr_x == cell->UNCONSTR)
|
||||
xRootSearch = IncreasingDiameterSearch(currentLoc.x, 0, ctx->getGridDimX() - 1);
|
||||
else
|
||||
xRootSearch = IncreasingDiameterSearch(cell->constr_x);
|
||||
xRootSearch = IncreasingDiameterSearch(currentLoc.x, 0, ctx->getGridDimX() - 1);
|
||||
yRootSearch = IncreasingDiameterSearch(currentLoc.y, 0, ctx->getGridDimY() - 1);
|
||||
zRootSearch = IncreasingDiameterSearch(currentLoc.z, 0, ctx->getTileBelDimZ(currentLoc.x, currentLoc.y));
|
||||
|
||||
if (cell->constr_y == cell->UNCONSTR)
|
||||
yRootSearch = IncreasingDiameterSearch(currentLoc.y, 0, ctx->getGridDimY() - 1);
|
||||
else
|
||||
yRootSearch = IncreasingDiameterSearch(cell->constr_y);
|
||||
|
||||
if (cell->constr_z == cell->UNCONSTR)
|
||||
zRootSearch =
|
||||
IncreasingDiameterSearch(currentLoc.z, 0, ctx->getTileBelDimZ(currentLoc.x, currentLoc.y));
|
||||
else
|
||||
zRootSearch = IncreasingDiameterSearch(cell->constr_z);
|
||||
while (!xRootSearch.done()) {
|
||||
Loc rootLoc;
|
||||
|
||||
@@ -415,29 +375,13 @@ class ConstraintLegaliseWorker
|
||||
bool constraints_satisfied(const CellInfo *cell) { return get_constraints_distance(ctx, cell) == 0; }
|
||||
|
||||
public:
|
||||
ConstraintLegaliseWorker(Context *ctx) : ctx(ctx){};
|
||||
|
||||
void print_chain(CellInfo *cell, int depth = 0)
|
||||
ConstraintLegaliseWorker(Context *ctx) : ctx(ctx)
|
||||
{
|
||||
for (int i = 0; i < depth; i++)
|
||||
log(" ");
|
||||
log("'%s' (", cell->name.c_str(ctx));
|
||||
if (cell->constr_x != cell->UNCONSTR)
|
||||
log("%d, ", cell->constr_x);
|
||||
else
|
||||
log("*, ");
|
||||
if (cell->constr_y != cell->UNCONSTR)
|
||||
log("%d, ", cell->constr_y);
|
||||
else
|
||||
log("*, ");
|
||||
if (cell->constr_z != cell->UNCONSTR)
|
||||
log("%d", cell->constr_z);
|
||||
else
|
||||
log("*");
|
||||
log(")\n");
|
||||
for (auto child : cell->constr_children)
|
||||
print_chain(child, depth + 1);
|
||||
}
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
if (cell.second->cluster != ClusterId())
|
||||
cluster2cells[cell.second->cluster].push_back(cell.second);
|
||||
}
|
||||
};
|
||||
|
||||
unsigned print_stats(const char *point)
|
||||
{
|
||||
@@ -476,8 +420,6 @@ class ConstraintLegaliseWorker
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
bool res = legalise_cell(cell.second);
|
||||
if (!res) {
|
||||
if (ctx->verbose)
|
||||
print_chain(cell.second);
|
||||
log_error("failed to place chain starting at cell '%s'\n", cell.first.c_str(ctx));
|
||||
return -1;
|
||||
}
|
||||
@@ -509,30 +451,36 @@ int get_constraints_distance(const Context *ctx, const CellInfo *cell)
|
||||
if (cell->bel == BelId())
|
||||
return 100000;
|
||||
Loc loc = ctx->getBelLocation(cell->bel);
|
||||
if (cell->constr_parent == nullptr) {
|
||||
if (cell->constr_x != cell->UNCONSTR)
|
||||
dist += std::abs(cell->constr_x - loc.x);
|
||||
if (cell->constr_y != cell->UNCONSTR)
|
||||
dist += std::abs(cell->constr_y - loc.y);
|
||||
if (cell->constr_z != cell->UNCONSTR)
|
||||
dist += std::abs(cell->constr_z - loc.z);
|
||||
} else {
|
||||
if (cell->constr_parent->bel == BelId())
|
||||
return 100000;
|
||||
Loc parent_loc = ctx->getBelLocation(cell->constr_parent->bel);
|
||||
if (cell->constr_x != cell->UNCONSTR)
|
||||
dist += std::abs(cell->constr_x - (loc.x - parent_loc.x));
|
||||
if (cell->constr_y != cell->UNCONSTR)
|
||||
dist += std::abs(cell->constr_y - (loc.y - parent_loc.y));
|
||||
if (cell->constr_z != cell->UNCONSTR) {
|
||||
if (cell->constr_abs_z)
|
||||
dist += std::abs(cell->constr_z - loc.z);
|
||||
else
|
||||
dist += std::abs(cell->constr_z - (loc.z - parent_loc.z));
|
||||
|
||||
if (cell->cluster != ClusterId()) {
|
||||
CellInfo *root = ctx->getClusterRootCell(cell->cluster);
|
||||
if (root == cell) {
|
||||
// parent
|
||||
std::vector<std::pair<CellInfo *, BelId>> placement;
|
||||
if (!ctx->getClusterPlacement(cell->cluster, cell->bel, placement)) {
|
||||
return 100000;
|
||||
} else {
|
||||
for (const auto &p : placement) {
|
||||
if (p.first->bel == BelId())
|
||||
return 100000;
|
||||
Loc c_loc = ctx->getBelLocation(p.first->bel);
|
||||
Loc p_loc = ctx->getBelLocation(p.second);
|
||||
dist += std::abs(c_loc.x - p_loc.x);
|
||||
dist += std::abs(c_loc.y - p_loc.y);
|
||||
dist += std::abs(c_loc.z - p_loc.z);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// child
|
||||
if (root->bel == BelId())
|
||||
return 100000;
|
||||
Loc root_loc = ctx->getBelLocation(root->bel);
|
||||
Loc offset = ctx->getClusterOffset(cell);
|
||||
dist += std::abs((root_loc.x + offset.x) - loc.x);
|
||||
dist += std::abs((root_loc.y + offset.y) - loc.y);
|
||||
}
|
||||
}
|
||||
for (auto child : cell->constr_children)
|
||||
dist += get_constraints_distance(ctx, child);
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
||||
@@ -225,14 +225,16 @@ class SAPlacer
|
||||
} else {
|
||||
for (auto &cell : ctx->cells) {
|
||||
CellInfo *ci = cell.second.get();
|
||||
if (ci->belStrength > STRENGTH_STRONG)
|
||||
if (ci->belStrength > STRENGTH_STRONG) {
|
||||
continue;
|
||||
else if (ci->constr_parent != nullptr)
|
||||
continue;
|
||||
else if (!ci->constr_children.empty() || ci->constr_z != ci->UNCONSTR)
|
||||
chain_basis.push_back(ci);
|
||||
else
|
||||
} else if (ci->cluster != ClusterId()) {
|
||||
if (ctx->getClusterRootCell(ci->cluster) == ci)
|
||||
chain_basis.push_back(ci);
|
||||
else
|
||||
continue;
|
||||
} else {
|
||||
autoplaced.push_back(ci);
|
||||
}
|
||||
}
|
||||
require_legal = false;
|
||||
diameter = 3;
|
||||
@@ -359,8 +361,8 @@ class SAPlacer
|
||||
autoplaced.clear();
|
||||
chain_basis.clear();
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
if (cell.second->belStrength <= STRENGTH_STRONG && cell.second->constr_parent == nullptr &&
|
||||
!cell.second->constr_children.empty())
|
||||
if (cell.second->belStrength <= STRENGTH_STRONG && cell.second->cluster != ClusterId() &&
|
||||
ctx->getClusterRootCell(cell.second->cluster) == cell.second)
|
||||
chain_basis.push_back(cell.second);
|
||||
else if (cell.second->belStrength < STRENGTH_STRONG)
|
||||
autoplaced.push_back(cell.second);
|
||||
@@ -507,12 +509,12 @@ class SAPlacer
|
||||
{
|
||||
static const double epsilon = 1e-20;
|
||||
moveChange.reset(this);
|
||||
if (!require_legal && cell->isConstrained(false))
|
||||
if (!require_legal && cell->cluster != ClusterId())
|
||||
return false;
|
||||
BelId oldBel = cell->bel;
|
||||
CellInfo *other_cell = ctx->getBoundBelCell(newBel);
|
||||
if (!require_legal && other_cell != nullptr &&
|
||||
(other_cell->isConstrained(false) || other_cell->belStrength > STRENGTH_WEAK)) {
|
||||
(other_cell->cluster != ClusterId() || other_cell->belStrength > STRENGTH_WEAK)) {
|
||||
return false;
|
||||
}
|
||||
int old_dist = get_constraints_distance(ctx, cell);
|
||||
@@ -612,9 +614,9 @@ class SAPlacer
|
||||
if (bound != nullptr)
|
||||
ctx->unbindBel(newBel);
|
||||
ctx->unbindBel(oldBel);
|
||||
ctx->bindBel(newBel, cell, cell->isConstrained(false) ? STRENGTH_STRONG : STRENGTH_WEAK);
|
||||
ctx->bindBel(newBel, cell, (cell->cluster != ClusterId()) ? STRENGTH_STRONG : STRENGTH_WEAK);
|
||||
if (bound != nullptr) {
|
||||
ctx->bindBel(oldBel, bound, bound->isConstrained(false) ? STRENGTH_STRONG : STRENGTH_WEAK);
|
||||
ctx->bindBel(oldBel, bound, (bound->cluster != ClusterId()) ? STRENGTH_STRONG : STRENGTH_WEAK);
|
||||
if (cfg.netShareWeight > 0)
|
||||
update_nets_by_tile(bound, ctx->getBelLocation(newBel), ctx->getBelLocation(oldBel));
|
||||
}
|
||||
@@ -623,16 +625,6 @@ class SAPlacer
|
||||
return oldBel;
|
||||
}
|
||||
|
||||
// Discover the relative positions of all cells in a chain
|
||||
void discover_chain(Loc baseLoc, CellInfo *cell, std::vector<std::pair<CellInfo *, Loc>> &cell_rel)
|
||||
{
|
||||
Loc cellLoc = ctx->getBelLocation(cell->bel);
|
||||
Loc rel{cellLoc.x - baseLoc.x, cellLoc.y - baseLoc.y, cellLoc.z};
|
||||
cell_rel.emplace_back(std::make_pair(cell, rel));
|
||||
for (auto child : cell->constr_children)
|
||||
discover_chain(baseLoc, child, cell_rel);
|
||||
}
|
||||
|
||||
// Attempt to swap a chain with a non-chain
|
||||
bool try_swap_chain(CellInfo *cell, BelId newBase)
|
||||
{
|
||||
@@ -647,32 +639,23 @@ class SAPlacer
|
||||
if (ctx->debug)
|
||||
log_info("finding cells for chain swap %s\n", cell->name.c_str(ctx));
|
||||
#endif
|
||||
Loc baseLoc = ctx->getBelLocation(cell->bel);
|
||||
discover_chain(baseLoc, cell, cell_rel);
|
||||
Loc newBaseLoc = ctx->getBelLocation(newBase);
|
||||
NPNR_ASSERT(newBaseLoc.z == baseLoc.z);
|
||||
for (const auto &cr : cell_rel)
|
||||
cells.insert(cr.first->name);
|
||||
if (!ctx->getClusterPlacement(cell->cluster, newBase, dest_bels))
|
||||
return false;
|
||||
|
||||
for (const auto &cr : cell_rel) {
|
||||
Loc targetLoc = {newBaseLoc.x + cr.second.x, newBaseLoc.y + cr.second.y, cr.second.z};
|
||||
BelId targetBel = ctx->getBelByLocation(targetLoc);
|
||||
if (targetBel == BelId())
|
||||
return false;
|
||||
if (!ctx->isValidBelForCellType(cell->type, targetBel))
|
||||
return false;
|
||||
CellInfo *bound = ctx->getBoundBelCell(targetBel);
|
||||
for (const auto &db : dest_bels)
|
||||
cells.insert(db.first->name);
|
||||
|
||||
for (const auto &db : dest_bels) {
|
||||
CellInfo *bound = ctx->getBoundBelCell(db.second);
|
||||
// We don't consider swapping chains with other chains, at least for the time being - unless it is
|
||||
// part of this chain
|
||||
if (bound != nullptr && !cells.count(bound->name) &&
|
||||
(bound->belStrength >= STRENGTH_STRONG || bound->isConstrained(false)))
|
||||
(bound->belStrength >= STRENGTH_STRONG || bound->cluster != ClusterId()))
|
||||
return false;
|
||||
|
||||
if (bound != nullptr)
|
||||
if (!ctx->isValidBelForCellType(bound->type, cr.first->bel))
|
||||
if (!ctx->isValidBelForCellType(bound->type, db.first->bel))
|
||||
return false;
|
||||
|
||||
dest_bels.emplace_back(std::make_pair(cr.first, targetBel));
|
||||
}
|
||||
#if 0
|
||||
if (ctx->debug)
|
||||
|
||||
@@ -145,6 +145,10 @@ class HeAPPlacer
|
||||
Eigen::initParallel();
|
||||
tmg.setup_only = true;
|
||||
tmg.setup();
|
||||
|
||||
for (auto cell : sorted(ctx->cells))
|
||||
if (cell.second->cluster != ClusterId())
|
||||
cluster2cells[cell.second->cluster].push_back(cell.second);
|
||||
}
|
||||
|
||||
bool place()
|
||||
@@ -386,14 +390,8 @@ class HeAPPlacer
|
||||
// cells of a certain type)
|
||||
std::vector<CellInfo *> solve_cells;
|
||||
|
||||
// For cells in a chain, this is the ultimate root cell of the chain (sometimes this is not constr_parent
|
||||
// where chains are within chains
|
||||
std::unordered_map<IdString, CellInfo *> chain_root;
|
||||
std::unordered_map<IdString, int> chain_size;
|
||||
|
||||
// The offset from chain_root to a cell in the chain
|
||||
std::unordered_map<IdString, std::pair<int, int>> cell_offsets;
|
||||
|
||||
std::unordered_map<ClusterId, std::vector<CellInfo *>> cluster2cells;
|
||||
std::unordered_map<ClusterId, int> chain_size;
|
||||
// Performance counting
|
||||
double solve_time = 0, cl_time = 0, sl_time = 0;
|
||||
|
||||
@@ -549,7 +547,7 @@ class HeAPPlacer
|
||||
cell_locs[cell.first].y = loc.y;
|
||||
cell_locs[cell.first].locked = true;
|
||||
cell_locs[cell.first].global = ctx->getBelGlobalBuf(ci->bel);
|
||||
} else if (ci->constr_parent == nullptr) {
|
||||
} else if (ci->cluster == ClusterId() || ctx->getClusterRootCell(ci->cluster) == ci) {
|
||||
bool placed = false;
|
||||
int attempt_count = 0;
|
||||
while (!placed) {
|
||||
@@ -629,40 +627,27 @@ class HeAPPlacer
|
||||
solve_cells.push_back(cell);
|
||||
}
|
||||
// Finally, update the udata of children
|
||||
for (auto chained : chain_root)
|
||||
ctx->cells.at(chained.first)->udata = chained.second->udata;
|
||||
for (auto &cluster : cluster2cells)
|
||||
for (auto child : cluster.second)
|
||||
child->udata = ctx->getClusterRootCell(cluster.first)->udata;
|
||||
return row;
|
||||
}
|
||||
|
||||
// Update the location of all children of a chain
|
||||
void update_chain(CellInfo *cell, CellInfo *root)
|
||||
{
|
||||
const auto &base = cell_locs[cell->name];
|
||||
for (auto child : cell->constr_children) {
|
||||
// FIXME: Improve handling of heterogeneous chains
|
||||
if (child->type == root->type)
|
||||
chain_size[root->name]++;
|
||||
if (child->constr_x != child->UNCONSTR)
|
||||
cell_locs[child->name].x = std::max(0, std::min(max_x, base.x + child->constr_x));
|
||||
else
|
||||
cell_locs[child->name].x = base.x; // better handling of UNCONSTR?
|
||||
if (child->constr_y != child->UNCONSTR)
|
||||
cell_locs[child->name].y = std::max(0, std::min(max_y, base.y + child->constr_y));
|
||||
else
|
||||
cell_locs[child->name].y = base.y; // better handling of UNCONSTR?
|
||||
chain_root[child->name] = root;
|
||||
if (!child->constr_children.empty())
|
||||
update_chain(child, root);
|
||||
}
|
||||
}
|
||||
|
||||
// Update all chains
|
||||
void update_all_chains()
|
||||
{
|
||||
for (auto cell : place_cells) {
|
||||
chain_size[cell->name] = 1;
|
||||
if (!cell->constr_children.empty())
|
||||
update_chain(cell, cell);
|
||||
if (cell->cluster != ClusterId()) {
|
||||
const auto &base = cell_locs[cell->name];
|
||||
for (auto child : cluster2cells.at(cell->cluster)) {
|
||||
if (child->type == cell->type && child != cell)
|
||||
chain_size[cell->name]++;
|
||||
Loc offset = ctx->getClusterOffset(child);
|
||||
cell_locs[child->name].x = std::max(0, std::min(max_x, base.x + offset.x));
|
||||
cell_locs[child->name].y = std::max(0, std::min(max_y, base.y + offset.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,10 +706,9 @@ class HeAPPlacer
|
||||
} else {
|
||||
es.add_rhs(row, -v_pos * weight);
|
||||
}
|
||||
if (cell_offsets.count(var.cell->name)) {
|
||||
es.add_rhs(row, -(yaxis ? cell_offsets.at(var.cell->name).second
|
||||
: cell_offsets.at(var.cell->name).first) *
|
||||
weight);
|
||||
if (var.cell->cluster != ClusterId()) {
|
||||
Loc offset = ctx->getClusterOffset(var.cell);
|
||||
es.add_rhs(row, -(yaxis ? offset.y : offset.x) * weight);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -827,8 +811,9 @@ class HeAPPlacer
|
||||
// Unbind all cells placed in this solution
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (ci->bel != BelId() && (ci->udata != dont_solve ||
|
||||
(chain_root.count(ci->name) && chain_root.at(ci->name)->udata != dont_solve)))
|
||||
if (ci->bel != BelId() &&
|
||||
(ci->udata != dont_solve ||
|
||||
(ci->cluster != ClusterId() && ctx->getClusterRootCell(ci->cluster)->udata != dont_solve)))
|
||||
ctx->unbindBel(ci->bel);
|
||||
}
|
||||
|
||||
@@ -955,7 +940,7 @@ class HeAPPlacer
|
||||
break;
|
||||
}
|
||||
|
||||
if (ci->constr_children.empty() && !ci->constr_abs_z) {
|
||||
if (ci->cluster == ClusterId()) {
|
||||
// The case where we have no relative constraints
|
||||
for (auto sz : fb->at(nx).at(ny)) {
|
||||
// Look through all bels in this tile; checking region constraint if applicable
|
||||
@@ -967,7 +952,7 @@ class HeAPPlacer
|
||||
CellInfo *bound = ctx->getBoundBelCell(sz);
|
||||
if (bound != nullptr) {
|
||||
// Only rip up cells without constraints
|
||||
if (bound->isConstrained())
|
||||
if (bound->cluster != ClusterId())
|
||||
continue;
|
||||
ctx->unbindBel(bound->bel);
|
||||
}
|
||||
@@ -1019,45 +1004,23 @@ class HeAPPlacer
|
||||
} else {
|
||||
// We do have relative constraints
|
||||
for (auto sz : fb->at(nx).at(ny)) {
|
||||
Loc loc = ctx->getBelLocation(sz);
|
||||
// Check that the absolute-z constraint is satisfied if applicable
|
||||
if (ci->constr_abs_z && loc.z != ci->constr_z)
|
||||
continue;
|
||||
// List of cells and their destination
|
||||
std::vector<std::pair<CellInfo *, BelId>> targets;
|
||||
// List of bels we placed things at; and the cell that was there before if applicable
|
||||
std::vector<std::pair<BelId, CellInfo *>> swaps_made;
|
||||
// List of (cell, new location) pairs to check
|
||||
std::queue<std::pair<CellInfo *, Loc>> visit;
|
||||
// FIXME: this approach of having a visit queue is designed to deal with recursively chained
|
||||
// cells. But is this a case we really want to care about given the complexity it adds? Start by
|
||||
// considering the root cell at the root location
|
||||
visit.emplace(ci, loc);
|
||||
while (!visit.empty()) {
|
||||
CellInfo *vc = visit.front().first;
|
||||
NPNR_ASSERT(vc->bel == BelId());
|
||||
Loc ploc = visit.front().second;
|
||||
visit.pop();
|
||||
// Get the bel we're going to place this cell at
|
||||
BelId target = ctx->getBelByLocation(ploc);
|
||||
|
||||
if (!ctx->getClusterPlacement(ci->cluster, sz, targets))
|
||||
continue;
|
||||
|
||||
for (auto &target : targets) {
|
||||
// Check it satisfies the region constraint if applicable
|
||||
if (!vc->testRegion(target))
|
||||
if (!target.first->testRegion(target.second))
|
||||
goto fail;
|
||||
CellInfo *bound;
|
||||
// Check that the target bel exists and is of a suitable type
|
||||
if (target == BelId() || !ctx->isValidBelForCellType(vc->type, target))
|
||||
goto fail;
|
||||
bound = ctx->getBoundBelCell(target);
|
||||
CellInfo *bound = ctx->getBoundBelCell(target.second);
|
||||
// Chains cannot overlap; so if we have to ripup a cell make sure it isn't part of a chain
|
||||
if (bound != nullptr)
|
||||
if (bound->isConstrained() || bound->belStrength > STRENGTH_WEAK)
|
||||
if (bound->cluster != ClusterId() || bound->belStrength > STRENGTH_WEAK)
|
||||
goto fail;
|
||||
targets.emplace_back(vc, target);
|
||||
for (auto child : vc->constr_children) {
|
||||
// For all the constrained children; compute the location we need to place them at and
|
||||
// add them to the queue
|
||||
visit.emplace(child, child->getConstrainedLoc(ploc));
|
||||
}
|
||||
}
|
||||
// Actually perform the move; keeping track of the moves we make so we can revert them if needed
|
||||
for (auto &target : targets) {
|
||||
@@ -1307,10 +1270,8 @@ class HeAPPlacer
|
||||
occupancy.at(cell_loc.second.x).at(cell_loc.second.y).at(cell_index(cell))++;
|
||||
|
||||
// Compute ultimate extent of each chain root
|
||||
if (p->chain_root.count(cell_name)) {
|
||||
set_chain_ext(p->chain_root.at(cell_name)->name, loc.x, loc.y);
|
||||
} else if (!ctx->cells.at(cell_name)->constr_children.empty()) {
|
||||
set_chain_ext(cell_name, loc.x, loc.y);
|
||||
if (cell.cluster != ClusterId()) {
|
||||
set_chain_ext(ctx->getClusterRootCell(cell.cluster)->name, loc.x, loc.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1328,10 +1289,8 @@ class HeAPPlacer
|
||||
|
||||
// Transfer chain extents to the actual chains structure
|
||||
ChainExtent *ce = nullptr;
|
||||
if (p->chain_root.count(cell_name)) {
|
||||
ce = &(cell_extents.at(p->chain_root.at(cell_name)->name));
|
||||
} else if (!ctx->cells.at(cell_name)->constr_children.empty()) {
|
||||
ce = &(cell_extents.at(cell_name));
|
||||
if (cell.cluster != ClusterId()) {
|
||||
ce = &(cell_extents.at(ctx->getClusterRootCell(cell.cluster)->name));
|
||||
}
|
||||
|
||||
if (ce) {
|
||||
|
||||
@@ -182,8 +182,7 @@ class TimingOptimiser
|
||||
CellInfo *bound = ctx->getBoundBelCell(bel);
|
||||
if (bound == nullptr) {
|
||||
free_bels_at_loc.push_back(bel);
|
||||
} else if (bound->belStrength <= STRENGTH_WEAK && bound->constr_parent == nullptr &&
|
||||
bound->constr_children.empty()) {
|
||||
} else if (bound->belStrength <= STRENGTH_WEAK && bound->cluster == ClusterId()) {
|
||||
bound_bels_at_loc.push_back(bel);
|
||||
}
|
||||
}
|
||||
@@ -378,7 +377,7 @@ class TimingOptimiser
|
||||
if (front_net != nullptr && front_net->driver.cell != nullptr) {
|
||||
auto front_cell = front_net->driver.cell;
|
||||
if (front_cell->belStrength <= STRENGTH_WEAK && cfg.cellTypes.count(front_cell->type) &&
|
||||
front_cell->constr_parent == nullptr && front_cell->constr_children.empty()) {
|
||||
front_cell->cluster == ClusterId()) {
|
||||
path_cells.push_back(front_cell->name);
|
||||
}
|
||||
}
|
||||
@@ -392,7 +391,7 @@ class TimingOptimiser
|
||||
if (std::find(path_cells.begin(), path_cells.end(), port->cell->name) != path_cells.end())
|
||||
continue;
|
||||
if (port->cell->belStrength > STRENGTH_WEAK || !cfg.cellTypes.count(port->cell->type) ||
|
||||
port->cell->constr_parent != nullptr || !port->cell->constr_children.empty())
|
||||
port->cell->cluster != ClusterId())
|
||||
continue;
|
||||
if (ctx->debug)
|
||||
log_info(" can move\n");
|
||||
|
||||
Reference in New Issue
Block a user