Introduce proxies for locked access to ctx
This commit is contained in:
parent
9e4f97290a
commit
89809a8b81
@ -2,6 +2,7 @@
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||
* Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -24,84 +25,8 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
// Get the total estimated wirelength for a net
|
||||
wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns)
|
||||
{
|
||||
wirelen_t wirelength = 0;
|
||||
int driver_x, driver_y;
|
||||
bool driver_gb;
|
||||
CellInfo *driver_cell = net->driver.cell;
|
||||
if (!driver_cell)
|
||||
return 0;
|
||||
if (driver_cell->bel == BelId())
|
||||
return 0;
|
||||
ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb);
|
||||
WireId drv_wire = ctx->getWireBelPinUnlocked(driver_cell->bel, ctx->portPinFromId(net->driver.port));
|
||||
if (driver_gb)
|
||||
return 0;
|
||||
float worst_slack = 1000;
|
||||
int xmin = driver_x, xmax = driver_x, ymin = driver_y, ymax = driver_y;
|
||||
for (auto load : net->users) {
|
||||
if (load.cell == nullptr)
|
||||
continue;
|
||||
CellInfo *load_cell = load.cell;
|
||||
if (load_cell->bel == BelId())
|
||||
continue;
|
||||
if (ctx->timing_driven) {
|
||||
WireId user_wire = ctx->getWireBelPinUnlocked(load_cell->bel, ctx->portPinFromId(load.port));
|
||||
delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire);
|
||||
float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl);
|
||||
if (slack < 0)
|
||||
tns += slack;
|
||||
worst_slack = std::min(slack, worst_slack);
|
||||
}
|
||||
|
||||
int load_x, load_y;
|
||||
bool load_gb;
|
||||
ctx->estimatePosition(load_cell->bel, load_x, load_y, load_gb);
|
||||
if (load_gb)
|
||||
continue;
|
||||
xmin = std::min(xmin, load_x);
|
||||
ymin = std::min(ymin, load_y);
|
||||
xmax = std::max(xmax, load_x);
|
||||
ymax = std::max(ymax, load_y);
|
||||
}
|
||||
if (ctx->timing_driven) {
|
||||
wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-worst_slack / 5)))));
|
||||
} else {
|
||||
wirelength = wirelen_t((ymax - ymin) + (xmax - xmin));
|
||||
}
|
||||
|
||||
return wirelength;
|
||||
}
|
||||
|
||||
// Get the total wirelength for a cell
|
||||
wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
std::set<IdString> nets;
|
||||
for (auto p : cell->ports) {
|
||||
if (p.second.net)
|
||||
nets.insert(p.second.net->name);
|
||||
}
|
||||
wirelen_t wirelength = 0;
|
||||
float tns = 0;
|
||||
for (auto n : nets) {
|
||||
wirelength += get_net_wirelength(ctx, ctx->nets.at(n).get(), tns);
|
||||
}
|
||||
return wirelength;
|
||||
}
|
||||
|
||||
wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel)
|
||||
{
|
||||
BelId oldBel = cell->bel;
|
||||
cell->bel = bel;
|
||||
wirelen_t wirelen = get_cell_wirelength(ctx, cell);
|
||||
cell->bel = oldBel;
|
||||
return wirelen;
|
||||
}
|
||||
|
||||
// Placing a single cell
|
||||
bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality)
|
||||
bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality)
|
||||
{
|
||||
bool all_placed = false;
|
||||
int iters = 25;
|
||||
@ -112,13 +37,13 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality)
|
||||
CellInfo *ripup_target = nullptr;
|
||||
BelId ripup_bel = BelId();
|
||||
if (cell->bel != BelId()) {
|
||||
ctx->unbindBelUnlocked(cell->bel);
|
||||
proxy.unbindBel(cell->bel);
|
||||
}
|
||||
BelType targetType = ctx->belTypeFromId(cell->type);
|
||||
for (auto bel : ctx->getBels()) {
|
||||
if (ctx->getBelType(bel) == targetType && (!require_legality || ctx->isValidBelForCell(cell, bel))) {
|
||||
if (ctx->checkBelAvailUnlocked(bel)) {
|
||||
wirelen_t wirelen = get_cell_wirelength_at_bel(ctx, cell, bel);
|
||||
if (ctx->getBelType(bel) == targetType && (!require_legality || proxy.isValidBelForCell(cell, bel))) {
|
||||
if (proxy.checkBelAvail(bel)) {
|
||||
wirelen_t wirelen = get_cell_wirelength_at_bel(proxy, ctx, cell, bel);
|
||||
if (iters >= 4)
|
||||
wirelen += ctx->rng(25);
|
||||
if (wirelen <= best_wirelen) {
|
||||
@ -126,11 +51,11 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality)
|
||||
best_bel = bel;
|
||||
}
|
||||
} else {
|
||||
wirelen_t wirelen = get_cell_wirelength_at_bel(ctx, cell, bel);
|
||||
wirelen_t wirelen = get_cell_wirelength_at_bel(proxy, ctx, cell, bel);
|
||||
if (iters >= 4)
|
||||
wirelen += ctx->rng(25);
|
||||
if (wirelen <= best_ripup_wirelen) {
|
||||
ripup_target = ctx->cells.at(ctx->getBoundBelCellUnlocked(bel)).get();
|
||||
ripup_target = proxy.getCell(proxy.getBoundBelCell(bel));
|
||||
if (ripup_target->belStrength < STRENGTH_STRONG) {
|
||||
best_ripup_wirelen = wirelen;
|
||||
ripup_bel = bel;
|
||||
@ -148,12 +73,12 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality)
|
||||
log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||
}
|
||||
--iters;
|
||||
ctx->unbindBelUnlocked(ripup_target->bel);
|
||||
proxy.unbindBel(ripup_target->bel);
|
||||
best_bel = ripup_bel;
|
||||
} else {
|
||||
all_placed = true;
|
||||
}
|
||||
ctx->bindBelUnlocked(best_bel, cell->name, STRENGTH_WEAK);
|
||||
proxy.bindBel(best_bel, cell->name, STRENGTH_WEAK);
|
||||
|
||||
cell = ripup_target;
|
||||
}
|
||||
|
@ -22,21 +22,94 @@
|
||||
|
||||
#include "nextpnr.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
typedef int64_t wirelen_t;
|
||||
|
||||
// Return the wirelength of a net
|
||||
wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns);
|
||||
// Get the total estimated wirelength for a net
|
||||
template <typename T>
|
||||
wirelen_t get_net_wirelength(const T &proxy, const Context *ctx, const NetInfo *net, float &tns)
|
||||
{
|
||||
wirelen_t wirelength = 0;
|
||||
int driver_x, driver_y;
|
||||
bool driver_gb;
|
||||
CellInfo *driver_cell = net->driver.cell;
|
||||
if (!driver_cell)
|
||||
return 0;
|
||||
if (driver_cell->bel == BelId())
|
||||
return 0;
|
||||
ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb);
|
||||
WireId drv_wire = proxy.getWireBelPin(driver_cell->bel, ctx->portPinFromId(net->driver.port));
|
||||
if (driver_gb)
|
||||
return 0;
|
||||
float worst_slack = 1000;
|
||||
int xmin = driver_x, xmax = driver_x, ymin = driver_y, ymax = driver_y;
|
||||
for (auto load : net->users) {
|
||||
if (load.cell == nullptr)
|
||||
continue;
|
||||
CellInfo *load_cell = load.cell;
|
||||
if (load_cell->bel == BelId())
|
||||
continue;
|
||||
if (ctx->timing_driven) {
|
||||
WireId user_wire = proxy.getWireBelPin(load_cell->bel, ctx->portPinFromId(load.port));
|
||||
delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire);
|
||||
float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl);
|
||||
if (slack < 0)
|
||||
tns += slack;
|
||||
worst_slack = std::min(slack, worst_slack);
|
||||
}
|
||||
|
||||
int load_x, load_y;
|
||||
bool load_gb;
|
||||
ctx->estimatePosition(load_cell->bel, load_x, load_y, load_gb);
|
||||
if (load_gb)
|
||||
continue;
|
||||
xmin = std::min(xmin, load_x);
|
||||
ymin = std::min(ymin, load_y);
|
||||
xmax = std::max(xmax, load_x);
|
||||
ymax = std::max(ymax, load_y);
|
||||
}
|
||||
if (ctx->timing_driven) {
|
||||
wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-worst_slack / 5)))));
|
||||
} else {
|
||||
wirelength = wirelen_t((ymax - ymin) + (xmax - xmin));
|
||||
}
|
||||
|
||||
return wirelength;
|
||||
}
|
||||
|
||||
// Return the wirelength of all nets connected to a cell
|
||||
wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell);
|
||||
template <typename T>
|
||||
wirelen_t get_cell_wirelength(const T &proxy, const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
std::set<IdString> nets;
|
||||
for (auto p : cell->ports) {
|
||||
if (p.second.net)
|
||||
nets.insert(p.second.net->name);
|
||||
}
|
||||
wirelen_t wirelength = 0;
|
||||
float tns = 0;
|
||||
for (auto n : nets) {
|
||||
wirelength += get_net_wirelength(proxy, ctx, ctx->nets.at(n).get(), tns);
|
||||
}
|
||||
return wirelength;
|
||||
}
|
||||
|
||||
// Return the wirelength of all nets connected to a cell, when the cell is at a given bel
|
||||
wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel);
|
||||
template <typename T>
|
||||
wirelen_t get_cell_wirelength_at_bel(const T &proxy, const Context *ctx, CellInfo *cell, BelId bel)
|
||||
{
|
||||
BelId oldBel = cell->bel;
|
||||
cell->bel = bel;
|
||||
wirelen_t wirelen = get_cell_wirelength(proxy, ctx, cell);
|
||||
cell->bel = oldBel;
|
||||
return wirelen;
|
||||
}
|
||||
|
||||
// Place a single cell in the lowest wirelength Bel available, optionally requiring validity check
|
||||
bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality);
|
||||
bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality);
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
||||
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||
* Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
|
||||
*
|
||||
* Simulated annealing implementation based on arachne-pnr
|
||||
* Copyright (C) 2015-2018 Cotton Seed
|
||||
@ -79,30 +80,33 @@ class SAPlacer
|
||||
log_break();
|
||||
|
||||
size_t placed_cells = 0;
|
||||
// Initial constraints placer
|
||||
for (auto &cell_entry : ctx->cells) {
|
||||
CellInfo *cell = cell_entry.second.get();
|
||||
auto loc = cell->attrs.find(ctx->id("BEL"));
|
||||
if (loc != cell->attrs.end()) {
|
||||
std::string loc_name = loc->second;
|
||||
BelId bel = ctx->getBelByNameUnlocked(ctx->id(loc_name));
|
||||
if (bel == BelId()) {
|
||||
log_error("No Bel named \'%s\' located for "
|
||||
"this chip (processing BEL attribute on \'%s\')\n",
|
||||
loc_name.c_str(), cell->name.c_str(ctx));
|
||||
}
|
||||
{
|
||||
auto &&proxy = ctx->rwproxy();
|
||||
// Initial constraints placer
|
||||
for (auto &cell_entry : ctx->cells) {
|
||||
CellInfo *cell = cell_entry.second.get();
|
||||
auto loc = cell->attrs.find(ctx->id("BEL"));
|
||||
if (loc != cell->attrs.end()) {
|
||||
std::string loc_name = loc->second;
|
||||
BelId bel = proxy.getBelByName(ctx->id(loc_name));
|
||||
if (bel == BelId()) {
|
||||
log_error("No Bel named \'%s\' located for "
|
||||
"this chip (processing BEL attribute on \'%s\')\n",
|
||||
loc_name.c_str(), cell->name.c_str(ctx));
|
||||
}
|
||||
|
||||
BelType bel_type = ctx->getBelType(bel);
|
||||
if (bel_type != ctx->belTypeFromId(cell->type)) {
|
||||
log_error("Bel \'%s\' of type \'%s\' does not match cell "
|
||||
"\'%s\' of type \'%s\'",
|
||||
loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx),
|
||||
cell->type.c_str(ctx));
|
||||
}
|
||||
BelType bel_type = ctx->getBelType(bel);
|
||||
if (bel_type != ctx->belTypeFromId(cell->type)) {
|
||||
log_error("Bel \'%s\' of type \'%s\' does not match cell "
|
||||
"\'%s\' of type \'%s\'",
|
||||
loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx),
|
||||
cell->type.c_str(ctx));
|
||||
}
|
||||
|
||||
ctx->bindBelUnlocked(bel, cell->name, STRENGTH_USER);
|
||||
locked_bels.insert(bel);
|
||||
placed_cells++;
|
||||
proxy.bindBel(bel, cell->name, STRENGTH_USER);
|
||||
locked_bels.insert(bel);
|
||||
placed_cells++;
|
||||
}
|
||||
}
|
||||
}
|
||||
int constr_placed_cells = placed_cells;
|
||||
@ -122,12 +126,15 @@ class SAPlacer
|
||||
// Place cells randomly initially
|
||||
log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size()));
|
||||
|
||||
for (auto cell : autoplaced) {
|
||||
place_initial(cell);
|
||||
placed_cells++;
|
||||
if ((placed_cells - constr_placed_cells) % 500 == 0)
|
||||
log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
|
||||
int(autoplaced.size()));
|
||||
{
|
||||
auto &&proxy = ctx->rwproxy();
|
||||
for (auto cell : autoplaced) {
|
||||
place_initial(proxy, cell);
|
||||
placed_cells++;
|
||||
if ((placed_cells - constr_placed_cells) % 500 == 0)
|
||||
log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
|
||||
int(autoplaced.size()));
|
||||
}
|
||||
}
|
||||
if ((placed_cells - constr_placed_cells) % 500 != 0)
|
||||
log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
|
||||
@ -138,10 +145,13 @@ class SAPlacer
|
||||
// Calculate wirelength after initial placement
|
||||
curr_wirelength = 0;
|
||||
curr_tns = 0;
|
||||
for (auto &net : ctx->nets) {
|
||||
wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns);
|
||||
wirelengths[net.first] = wl;
|
||||
curr_wirelength += wl;
|
||||
{
|
||||
auto &&proxy = ctx->rproxy();
|
||||
for (auto &net : ctx->nets) {
|
||||
wirelen_t wl = get_net_wirelength(proxy, ctx, net.second.get(), curr_tns);
|
||||
wirelengths[net.first] = wl;
|
||||
curr_wirelength += wl;
|
||||
}
|
||||
}
|
||||
|
||||
int n_no_progress = 0;
|
||||
@ -158,15 +168,18 @@ class SAPlacer
|
||||
"%.0f, est tns = %.02fns\n",
|
||||
iter, temp, double(curr_wirelength), curr_tns);
|
||||
|
||||
for (int m = 0; m < 15; ++m) {
|
||||
// Loop through all automatically placed cells
|
||||
for (auto cell : autoplaced) {
|
||||
// Find another random Bel for this cell
|
||||
BelId try_bel = random_bel_for_cell(cell);
|
||||
// If valid, try and swap to a new position and see if
|
||||
// the new position is valid/worthwhile
|
||||
if (try_bel != BelId() && try_bel != cell->bel)
|
||||
try_swap_position(cell, try_bel);
|
||||
{
|
||||
auto &&proxy = ctx->rwproxy();
|
||||
for (int m = 0; m < 15; ++m) {
|
||||
// Loop through all automatically placed cells
|
||||
for (auto cell : autoplaced) {
|
||||
// Find another random Bel for this cell
|
||||
BelId try_bel = random_bel_for_cell(cell);
|
||||
// If valid, try and swap to a new position and see if
|
||||
// the new position is valid/worthwhile
|
||||
if (try_bel != BelId() && try_bel != cell->bel)
|
||||
try_swap_position(proxy, cell, try_bel);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Heuristic to improve placement on the 8k
|
||||
@ -227,27 +240,33 @@ class SAPlacer
|
||||
// accumulating over time
|
||||
curr_wirelength = 0;
|
||||
curr_tns = 0;
|
||||
for (auto &net : ctx->nets) {
|
||||
wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns);
|
||||
wirelengths[net.first] = wl;
|
||||
curr_wirelength += wl;
|
||||
{
|
||||
auto &&proxy = ctx->rproxy();
|
||||
for (auto &net : ctx->nets) {
|
||||
wirelen_t wl = get_net_wirelength(proxy, ctx, net.second.get(), curr_tns);
|
||||
wirelengths[net.first] = wl;
|
||||
curr_wirelength += wl;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Final post-pacement validitiy check
|
||||
for (auto bel : ctx->getBels()) {
|
||||
IdString cell = ctx->getBoundBelCellUnlocked(bel);
|
||||
if (!ctx->isBelLocationValid(bel)) {
|
||||
std::string cell_text = "no cell";
|
||||
if (cell != IdString())
|
||||
cell_text = std::string("cell '") + cell.str(ctx) + "'";
|
||||
if (ctx->force) {
|
||||
log_warning("post-placement validity check failed for Bel '%s' "
|
||||
"(%s)\n",
|
||||
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
|
||||
} else {
|
||||
log_error("post-placement validity check failed for Bel '%s' "
|
||||
"(%s)\n",
|
||||
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
|
||||
{
|
||||
// Final post-pacement validitiy check
|
||||
auto &&proxy = ctx->rproxy();
|
||||
for (auto bel : ctx->getBels()) {
|
||||
IdString cell = proxy.getBoundBelCell(bel);
|
||||
if (!proxy.isBelLocationValid(bel)) {
|
||||
std::string cell_text = "no cell";
|
||||
if (cell != IdString())
|
||||
cell_text = std::string("cell '") + cell.str(ctx) + "'";
|
||||
if (ctx->force) {
|
||||
log_warning("post-placement validity check failed for Bel '%s' "
|
||||
"(%s)\n",
|
||||
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
|
||||
} else {
|
||||
log_error("post-placement validity check failed for Bel '%s' "
|
||||
"(%s)\n",
|
||||
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -256,7 +275,7 @@ class SAPlacer
|
||||
|
||||
private:
|
||||
// Initial random placement
|
||||
void place_initial(CellInfo *cell)
|
||||
void place_initial(ArchRWProxy &proxy, CellInfo *cell)
|
||||
{
|
||||
bool all_placed = false;
|
||||
int iters = 25;
|
||||
@ -267,12 +286,12 @@ class SAPlacer
|
||||
CellInfo *ripup_target = nullptr;
|
||||
BelId ripup_bel = BelId();
|
||||
if (cell->bel != BelId()) {
|
||||
ctx->unbindBelUnlocked(cell->bel);
|
||||
proxy.unbindBel(cell->bel);
|
||||
}
|
||||
BelType targetType = ctx->belTypeFromId(cell->type);
|
||||
for (auto bel : ctx->getBels()) {
|
||||
if (ctx->getBelType(bel) == targetType && (ctx->isValidBelForCell(cell, bel) || !require_legal)) {
|
||||
if (ctx->checkBelAvailUnlocked(bel)) {
|
||||
if (ctx->getBelType(bel) == targetType && (proxy.isValidBelForCell(cell, bel) || !require_legal)) {
|
||||
if (proxy.checkBelAvail(bel)) {
|
||||
uint64_t score = ctx->rng64();
|
||||
if (score <= best_score) {
|
||||
best_score = score;
|
||||
@ -282,7 +301,7 @@ class SAPlacer
|
||||
uint64_t score = ctx->rng64();
|
||||
if (score <= best_ripup_score) {
|
||||
best_ripup_score = score;
|
||||
ripup_target = ctx->cells.at(ctx->getBoundBelCellUnlocked(bel)).get();
|
||||
ripup_target = ctx->cells.at(proxy.getBoundBelCell(bel)).get();
|
||||
ripup_bel = bel;
|
||||
}
|
||||
}
|
||||
@ -292,12 +311,12 @@ class SAPlacer
|
||||
if (iters == 0 || ripup_bel == BelId())
|
||||
log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||
--iters;
|
||||
ctx->unbindBelUnlocked(ripup_target->bel);
|
||||
proxy.unbindBel(ripup_target->bel);
|
||||
best_bel = ripup_bel;
|
||||
} else {
|
||||
all_placed = true;
|
||||
}
|
||||
ctx->bindBelUnlocked(best_bel, cell->name, STRENGTH_WEAK);
|
||||
proxy.bindBel(best_bel, cell->name, STRENGTH_WEAK);
|
||||
|
||||
// Back annotate location
|
||||
cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx);
|
||||
@ -306,14 +325,14 @@ class SAPlacer
|
||||
}
|
||||
|
||||
// Attempt a SA position swap, return true on success or false on failure
|
||||
bool try_swap_position(CellInfo *cell, BelId newBel)
|
||||
bool try_swap_position(ArchRWProxy &proxy, CellInfo *cell, BelId newBel)
|
||||
{
|
||||
static std::unordered_set<NetInfo *> update;
|
||||
static std::vector<std::pair<IdString, wirelen_t>> new_lengths;
|
||||
new_lengths.clear();
|
||||
update.clear();
|
||||
BelId oldBel = cell->bel;
|
||||
IdString other = ctx->getBoundBelCellUnlocked(newBel);
|
||||
IdString other = proxy.getBoundBelCell(newBel);
|
||||
CellInfo *other_cell = nullptr;
|
||||
if (other != IdString()) {
|
||||
other_cell = ctx->cells[other].get();
|
||||
@ -321,9 +340,9 @@ class SAPlacer
|
||||
return false;
|
||||
}
|
||||
wirelen_t new_wirelength = 0, delta;
|
||||
ctx->unbindBelUnlocked(oldBel);
|
||||
proxy.unbindBel(oldBel);
|
||||
if (other != IdString()) {
|
||||
ctx->unbindBelUnlocked(newBel);
|
||||
proxy.unbindBel(newBel);
|
||||
}
|
||||
|
||||
for (const auto &port : cell->ports)
|
||||
@ -336,16 +355,16 @@ class SAPlacer
|
||||
update.insert(port.second.net);
|
||||
}
|
||||
|
||||
ctx->bindBelUnlocked(newBel, cell->name, STRENGTH_WEAK);
|
||||
proxy.bindBel(newBel, cell->name, STRENGTH_WEAK);
|
||||
|
||||
if (other != IdString()) {
|
||||
ctx->bindBelUnlocked(oldBel, other_cell->name, STRENGTH_WEAK);
|
||||
proxy.bindBel(oldBel, other_cell->name, STRENGTH_WEAK);
|
||||
}
|
||||
if (require_legal) {
|
||||
if (!ctx->isBelLocationValid(newBel) || ((other != IdString() && !ctx->isBelLocationValid(oldBel)))) {
|
||||
ctx->unbindBelUnlocked(newBel);
|
||||
if (!proxy.isBelLocationValid(newBel) || ((other != IdString() && !proxy.isBelLocationValid(oldBel)))) {
|
||||
proxy.unbindBel(newBel);
|
||||
if (other != IdString())
|
||||
ctx->unbindBelUnlocked(oldBel);
|
||||
proxy.unbindBel(oldBel);
|
||||
goto swap_fail;
|
||||
}
|
||||
}
|
||||
@ -356,7 +375,7 @@ class SAPlacer
|
||||
for (auto net : update) {
|
||||
new_wirelength -= wirelengths.at(net->name);
|
||||
float temp_tns = 0;
|
||||
wirelen_t net_new_wl = get_net_wirelength(ctx, net, temp_tns);
|
||||
wirelen_t net_new_wl = get_net_wirelength<>(proxy, ctx, net, temp_tns);
|
||||
new_wirelength += net_new_wl;
|
||||
new_lengths.push_back(std::make_pair(net->name, net_new_wl));
|
||||
}
|
||||
@ -369,8 +388,8 @@ class SAPlacer
|
||||
improved = true;
|
||||
} else {
|
||||
if (other != IdString())
|
||||
ctx->unbindBelUnlocked(oldBel);
|
||||
ctx->unbindBelUnlocked(newBel);
|
||||
proxy.unbindBel(oldBel);
|
||||
proxy.unbindBel(newBel);
|
||||
goto swap_fail;
|
||||
}
|
||||
curr_wirelength = new_wirelength;
|
||||
@ -379,9 +398,9 @@ class SAPlacer
|
||||
|
||||
return true;
|
||||
swap_fail:
|
||||
ctx->bindBelUnlocked(oldBel, cell->name, STRENGTH_WEAK);
|
||||
proxy.bindBel(oldBel, cell->name, STRENGTH_WEAK);
|
||||
if (other != IdString()) {
|
||||
ctx->bindBelUnlocked(newBel, other, STRENGTH_WEAK);
|
||||
proxy.bindBel(newBel, other, STRENGTH_WEAK);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
||||
* Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -73,7 +74,7 @@ struct RipupScoreboard
|
||||
std::unordered_map<std::pair<IdString, PipId>, int, hash_id_pip> netPipScores;
|
||||
};
|
||||
|
||||
void ripup_net(Context *ctx, IdString net_name)
|
||||
void ripup_net(ArchRWProxy &proxy, Context *ctx, IdString net_name)
|
||||
{
|
||||
auto net_info = ctx->nets.at(net_name).get();
|
||||
std::vector<PipId> pips;
|
||||
@ -90,10 +91,10 @@ void ripup_net(Context *ctx, IdString net_name)
|
||||
}
|
||||
|
||||
for (auto pip : pips)
|
||||
ctx->unbindPipUnlocked(pip);
|
||||
proxy.unbindPip(pip);
|
||||
|
||||
for (auto wire : wires)
|
||||
ctx->unbindWireUnlocked(wire);
|
||||
proxy.unbindWire(wire);
|
||||
|
||||
NPNR_ASSERT(net_info->wires.empty());
|
||||
}
|
||||
@ -114,7 +115,7 @@ struct Router
|
||||
delay_t maxDelay = 0.0;
|
||||
WireId failedDest;
|
||||
|
||||
void route(const std::unordered_map<WireId, delay_t> &src_wires, WireId dst_wire)
|
||||
void route(ArchRWProxy &proxy, const std::unordered_map<WireId, delay_t> &src_wires, WireId dst_wire)
|
||||
{
|
||||
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;
|
||||
|
||||
@ -135,6 +136,7 @@ struct Router
|
||||
int thisVisitCnt = 0;
|
||||
int thisVisitCntLimit = 0;
|
||||
|
||||
|
||||
while (!queue.empty() && (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) {
|
||||
QueuedWire qw = queue.top();
|
||||
queue.pop();
|
||||
@ -148,10 +150,10 @@ struct Router
|
||||
bool foundRipupNet = false;
|
||||
thisVisitCnt++;
|
||||
|
||||
if (!ctx->checkWireAvailUnlocked(next_wire)) {
|
||||
if (!proxy.checkWireAvail(next_wire)) {
|
||||
if (!ripup)
|
||||
continue;
|
||||
IdString ripupWireNet = ctx->getConflictingWireNetUnlocked(next_wire);
|
||||
IdString ripupWireNet = proxy.getConflictingWireNet(next_wire);
|
||||
if (ripupWireNet == net_name || ripupWireNet == IdString())
|
||||
continue;
|
||||
|
||||
@ -166,10 +168,10 @@ struct Router
|
||||
foundRipupNet = true;
|
||||
}
|
||||
|
||||
if (!ctx->checkPipAvailUnlocked(pip)) {
|
||||
if (!proxy.checkPipAvail(pip)) {
|
||||
if (!ripup)
|
||||
continue;
|
||||
IdString ripupPipNet = ctx->getConflictingPipNetUnlocked(pip);
|
||||
IdString ripupPipNet = proxy.getConflictingPipNet(pip);
|
||||
if (ripupPipNet == net_name || ripupPipNet == IdString())
|
||||
continue;
|
||||
|
||||
@ -227,7 +229,10 @@ struct Router
|
||||
{
|
||||
std::unordered_map<WireId, delay_t> src_wires;
|
||||
src_wires[src_wire] = 0;
|
||||
route(src_wires, dst_wire);
|
||||
{
|
||||
auto &&proxy = ctx->rwproxy();
|
||||
route(proxy, src_wires, dst_wire);
|
||||
}
|
||||
routedOkay = visited.count(dst_wire);
|
||||
|
||||
if (ctx->debug) {
|
||||
@ -272,7 +277,7 @@ struct Router
|
||||
if (driver_port_it != net_info->driver.cell->pins.end())
|
||||
driver_port = driver_port_it->second;
|
||||
|
||||
auto src_wire = ctx->getWireBelPinUnlocked(src_bel, ctx->portPinFromId(driver_port));
|
||||
auto src_wire = ctx->rproxy().getWireBelPin(src_bel, ctx->portPinFromId(driver_port));
|
||||
|
||||
if (src_wire == WireId())
|
||||
log_error("No wire found for port %s (pin %s) on source cell %s "
|
||||
@ -286,8 +291,10 @@ struct Router
|
||||
std::unordered_map<WireId, delay_t> src_wires;
|
||||
src_wires[src_wire] = 0;
|
||||
|
||||
ripup_net(ctx, net_name);
|
||||
ctx->bindWireUnlocked(src_wire, net_name, STRENGTH_WEAK);
|
||||
auto &&proxy = ctx->rwproxy();
|
||||
|
||||
ripup_net(proxy, ctx, net_name);
|
||||
proxy.bindWire(src_wire, net_name, STRENGTH_WEAK);
|
||||
|
||||
std::vector<PortRef> users_array = net_info->users;
|
||||
ctx->shuffle(users_array);
|
||||
@ -312,7 +319,7 @@ struct Router
|
||||
if (user_port_it != user_it.cell->pins.end())
|
||||
user_port = user_port_it->second;
|
||||
|
||||
auto dst_wire = ctx->getWireBelPinUnlocked(dst_bel, ctx->portPinFromId(user_port));
|
||||
auto dst_wire = proxy.getWireBelPin(dst_bel, ctx->portPinFromId(user_port));
|
||||
|
||||
if (dst_wire == WireId())
|
||||
log_error("No wire found for port %s (pin %s) on destination "
|
||||
@ -325,7 +332,7 @@ struct Router
|
||||
log(" Path delay estimate: %.2f\n", float(ctx->estimateDelay(src_wire, dst_wire)));
|
||||
}
|
||||
|
||||
route(src_wires, dst_wire);
|
||||
route(proxy, src_wires, dst_wire);
|
||||
|
||||
if (visited.count(dst_wire) == 0) {
|
||||
if (ctx->debug)
|
||||
@ -334,7 +341,7 @@ struct Router
|
||||
else if (ripup)
|
||||
log_info("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx),
|
||||
ctx->getWireName(dst_wire).c_str(ctx));
|
||||
ripup_net(ctx, net_name);
|
||||
ripup_net(proxy, ctx, net_name);
|
||||
failedDest = dst_wire;
|
||||
return;
|
||||
}
|
||||
@ -355,15 +362,15 @@ struct Router
|
||||
if (src_wires.count(cursor))
|
||||
break;
|
||||
|
||||
IdString conflicting_wire_net = ctx->getConflictingWireNetUnlocked(cursor);
|
||||
IdString conflicting_wire_net = proxy.getConflictingWireNet(cursor);
|
||||
|
||||
if (conflicting_wire_net != IdString()) {
|
||||
NPNR_ASSERT(ripup);
|
||||
NPNR_ASSERT(conflicting_wire_net != net_name);
|
||||
|
||||
ctx->unbindWireUnlocked(cursor);
|
||||
if (!ctx->checkWireAvailUnlocked(cursor))
|
||||
ripup_net(ctx, conflicting_wire_net);
|
||||
proxy.unbindWire(cursor);
|
||||
if (!proxy.checkWireAvail(cursor))
|
||||
ripup_net(proxy, ctx, conflicting_wire_net);
|
||||
|
||||
rippedNets.insert(conflicting_wire_net);
|
||||
scores.wireScores[cursor]++;
|
||||
@ -372,15 +379,15 @@ struct Router
|
||||
}
|
||||
|
||||
PipId pip = visited[cursor].pip;
|
||||
IdString conflicting_pip_net = ctx->getConflictingPipNetUnlocked(pip);
|
||||
IdString conflicting_pip_net = proxy.getConflictingPipNet(pip);
|
||||
|
||||
if (conflicting_pip_net != IdString()) {
|
||||
NPNR_ASSERT(ripup);
|
||||
NPNR_ASSERT(conflicting_pip_net != net_name);
|
||||
|
||||
ctx->unbindPipUnlocked(pip);
|
||||
if (!ctx->checkPipAvailUnlocked(pip))
|
||||
ripup_net(ctx, conflicting_pip_net);
|
||||
proxy.unbindPip(pip);
|
||||
if (!proxy.checkPipAvail(pip))
|
||||
ripup_net(proxy, ctx, conflicting_pip_net);
|
||||
|
||||
rippedNets.insert(conflicting_pip_net);
|
||||
scores.pipScores[visited[cursor].pip]++;
|
||||
@ -388,7 +395,7 @@ struct Router
|
||||
scores.netPipScores[std::make_pair(conflicting_pip_net, visited[cursor].pip)]++;
|
||||
}
|
||||
|
||||
ctx->bindPipUnlocked(visited[cursor].pip, net_name, STRENGTH_WEAK);
|
||||
proxy.bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK);
|
||||
src_wires[cursor] = visited[cursor].delay;
|
||||
cursor = ctx->getPipSrcWire(visited[cursor].pip);
|
||||
}
|
||||
@ -437,45 +444,48 @@ bool router1(Context *ctx)
|
||||
delay_t estimatedTotalDelay = 0.0;
|
||||
int estimatedTotalDelayCnt = 0;
|
||||
|
||||
for (auto net_name : netsQueue) {
|
||||
auto net_info = ctx->nets.at(net_name).get();
|
||||
{
|
||||
auto &&proxy = ctx->rproxy();
|
||||
for (auto net_name : netsQueue) {
|
||||
auto net_info = ctx->nets.at(net_name).get();
|
||||
|
||||
auto src_bel = net_info->driver.cell->bel;
|
||||
auto src_bel = net_info->driver.cell->bel;
|
||||
|
||||
if (src_bel == BelId())
|
||||
continue;
|
||||
|
||||
IdString driver_port = net_info->driver.port;
|
||||
|
||||
auto driver_port_it = net_info->driver.cell->pins.find(driver_port);
|
||||
if (driver_port_it != net_info->driver.cell->pins.end())
|
||||
driver_port = driver_port_it->second;
|
||||
|
||||
auto src_wire = ctx->getWireBelPinUnlocked(src_bel, ctx->portPinFromId(driver_port));
|
||||
|
||||
if (src_wire == WireId())
|
||||
continue;
|
||||
|
||||
for (auto &user_it : net_info->users) {
|
||||
auto dst_bel = user_it.cell->bel;
|
||||
|
||||
if (dst_bel == BelId())
|
||||
if (src_bel == BelId())
|
||||
continue;
|
||||
|
||||
IdString user_port = user_it.port;
|
||||
IdString driver_port = net_info->driver.port;
|
||||
|
||||
auto user_port_it = user_it.cell->pins.find(user_port);
|
||||
auto driver_port_it = net_info->driver.cell->pins.find(driver_port);
|
||||
if (driver_port_it != net_info->driver.cell->pins.end())
|
||||
driver_port = driver_port_it->second;
|
||||
|
||||
if (user_port_it != user_it.cell->pins.end())
|
||||
user_port = user_port_it->second;
|
||||
auto src_wire = proxy.getWireBelPin(src_bel, ctx->portPinFromId(driver_port));
|
||||
|
||||
auto dst_wire = ctx->getWireBelPinUnlocked(dst_bel, ctx->portPinFromId(user_port));
|
||||
|
||||
if (dst_wire == WireId())
|
||||
if (src_wire == WireId())
|
||||
continue;
|
||||
|
||||
estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire);
|
||||
estimatedTotalDelayCnt++;
|
||||
for (auto &user_it : net_info->users) {
|
||||
auto dst_bel = user_it.cell->bel;
|
||||
|
||||
if (dst_bel == BelId())
|
||||
continue;
|
||||
|
||||
IdString user_port = user_it.port;
|
||||
|
||||
auto user_port_it = user_it.cell->pins.find(user_port);
|
||||
|
||||
if (user_port_it != user_it.cell->pins.end())
|
||||
user_port = user_port_it->second;
|
||||
|
||||
auto dst_wire = proxy.getWireBelPin(dst_bel, ctx->portPinFromId(user_port));
|
||||
|
||||
if (dst_wire == WireId())
|
||||
continue;
|
||||
|
||||
estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire);
|
||||
estimatedTotalDelayCnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
385
ice40/arch.cc
385
ice40/arch.cc
@ -2,6 +2,7 @@
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
||||
* Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -28,6 +29,16 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
ArchRWProxy Arch::rwproxy(void) {
|
||||
ArchRWProxy res(this);
|
||||
return res;
|
||||
}
|
||||
|
||||
ArchRProxy Arch::rproxy(void) const {
|
||||
ArchRProxy res(this);
|
||||
return res;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
IdString Arch::belTypeToId(BelType type) const
|
||||
@ -239,28 +250,6 @@ IdString Arch::archArgsToId(ArchArgs args) const
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
BelId Arch::getBelByName(IdString name) const
|
||||
{
|
||||
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return getBelByNameUnlocked(name);
|
||||
}
|
||||
|
||||
BelId Arch::getBelByNameUnlocked(IdString name) const
|
||||
{
|
||||
BelId ret;
|
||||
|
||||
if (bel_by_name.empty()) {
|
||||
for (int i = 0; i < chip_info->num_bels; i++)
|
||||
bel_by_name[id(chip_info->bel_data[i].name.get())] = i;
|
||||
}
|
||||
|
||||
auto it = bel_by_name.find(name);
|
||||
if (it != bel_by_name.end())
|
||||
ret.index = it->second;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BelRange Arch::getBelsAtSameTile(BelId bel) const
|
||||
{
|
||||
BelRange br;
|
||||
@ -279,81 +268,105 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const
|
||||
return br;
|
||||
}
|
||||
|
||||
WireId Arch::getWireBelPin(BelId bel, PortPin pin) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return getWireBelPinUnlocked(bel, pin);
|
||||
}
|
||||
|
||||
WireId Arch::getWireBelPinUnlocked(BelId bel, PortPin pin) const
|
||||
{
|
||||
WireId ret;
|
||||
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
|
||||
int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires;
|
||||
const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get();
|
||||
|
||||
for (int i = 0; i < num_bel_wires; i++)
|
||||
if (bel_wires[i].port == pin) {
|
||||
ret.index = bel_wires[i].wire_index;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Shorthands to ArchProxy
|
||||
|
||||
BelId Arch::getBelByName(IdString name) const
|
||||
{
|
||||
return rproxy().getBelByName(name);
|
||||
}
|
||||
|
||||
void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength)
|
||||
{
|
||||
rwproxy().bindWire(wire, net, strength);
|
||||
}
|
||||
|
||||
void Arch::unbindWire(WireId wire)
|
||||
{
|
||||
rwproxy().unbindWire(wire);
|
||||
}
|
||||
|
||||
void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) {
|
||||
rwproxy().bindBel(bel, cell, strength);
|
||||
}
|
||||
|
||||
void Arch::unbindBel(BelId bel)
|
||||
{
|
||||
rwproxy().unbindBel(bel);
|
||||
}
|
||||
|
||||
bool Arch::checkBelAvail(BelId bel) const
|
||||
{
|
||||
return rproxy().checkBelAvail(bel);
|
||||
}
|
||||
|
||||
IdString Arch::getBoundBelCell(BelId bel) const
|
||||
{
|
||||
return rproxy().getBoundBelCell(bel);
|
||||
}
|
||||
|
||||
IdString Arch::getConflictingBelCell(BelId bel) const
|
||||
{
|
||||
return rproxy().getConflictingBelCell(bel);
|
||||
}
|
||||
|
||||
WireId Arch::getWireByName(IdString name) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return getWireByNameUnlocked(name);
|
||||
return rproxy().getWireByName(name);
|
||||
}
|
||||
|
||||
WireId Arch::getWireByNameUnlocked(IdString name) const
|
||||
WireId Arch::getWireBelPin(BelId bel, PortPin pin) const
|
||||
{
|
||||
WireId ret;
|
||||
|
||||
if (wire_by_name.empty()) {
|
||||
for (int i = 0; i < chip_info->num_wires; i++)
|
||||
wire_by_name[id(chip_info->wire_data[i].name.get())] = i;
|
||||
}
|
||||
|
||||
auto it = wire_by_name.find(name);
|
||||
if (it != wire_by_name.end())
|
||||
ret.index = it->second;
|
||||
|
||||
return ret;
|
||||
return rproxy().getWireBelPin(bel, pin);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
bool Arch::checkWireAvail(WireId wire) const
|
||||
{
|
||||
return rproxy().checkWireAvail(wire);
|
||||
}
|
||||
|
||||
IdString Arch::getBoundWireNet(WireId wire) const
|
||||
{
|
||||
return rproxy().getBoundWireNet(wire);
|
||||
}
|
||||
|
||||
IdString Arch::getConflictingWireNet(WireId wire) const
|
||||
{
|
||||
return rproxy().getConflictingWireNet(wire);
|
||||
}
|
||||
|
||||
PipId Arch::getPipByName(IdString name) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return getPipByNameUnlocked(name);
|
||||
return rproxy().getPipByName(name);
|
||||
}
|
||||
|
||||
PipId Arch::getPipByNameUnlocked(IdString name) const
|
||||
void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength)
|
||||
{
|
||||
PipId ret;
|
||||
|
||||
if (pip_by_name.empty()) {
|
||||
for (int i = 0; i < chip_info->num_pips; i++) {
|
||||
PipId pip;
|
||||
pip.index = i;
|
||||
pip_by_name[getPipName(pip)] = i;
|
||||
}
|
||||
}
|
||||
|
||||
auto it = pip_by_name.find(name);
|
||||
if (it != pip_by_name.end())
|
||||
ret.index = it->second;
|
||||
|
||||
return ret;
|
||||
return rwproxy().bindPip(pip, net, strength);
|
||||
}
|
||||
|
||||
void Arch::unbindPip(PipId pip)
|
||||
{
|
||||
return rwproxy().unbindPip(pip);
|
||||
}
|
||||
|
||||
bool Arch::checkPipAvail(PipId pip) const
|
||||
{
|
||||
return rproxy().checkPipAvail(pip);
|
||||
}
|
||||
|
||||
IdString Arch::getBoundPipNet(PipId pip) const
|
||||
{
|
||||
return rproxy().getBoundPipNet(pip);
|
||||
}
|
||||
|
||||
IdString Arch::getConflictingPipNet(PipId pip) const
|
||||
{
|
||||
return rproxy().getConflictingPipNet(pip);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
IdString Arch::getPipName(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
@ -682,4 +695,216 @@ bool Arch::isGlobalNet(const NetInfo *net) const
|
||||
return net->driver.cell != nullptr && net->driver.port == id_glb_buf_out;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
bool ArchRProxyMethods::checkBelAvail(BelId bel) const
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
return parent_->bel_to_cell[bel.index] == IdString();
|
||||
}
|
||||
|
||||
IdString ArchRProxyMethods::getBoundBelCell(BelId bel) const
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
return parent_->bel_to_cell[bel.index];
|
||||
}
|
||||
|
||||
IdString ArchRProxyMethods::getConflictingBelCell(BelId bel) const
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
return parent_->bel_to_cell[bel.index];
|
||||
}
|
||||
|
||||
WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const
|
||||
{
|
||||
WireId ret;
|
||||
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
|
||||
int num_bel_wires = parent_->chip_info->bel_data[bel.index].num_bel_wires;
|
||||
const BelWirePOD *bel_wires = parent_->chip_info->bel_data[bel.index].bel_wires.get();
|
||||
|
||||
for (int i = 0; i < num_bel_wires; i++)
|
||||
if (bel_wires[i].port == pin) {
|
||||
ret.index = bel_wires[i].wire_index;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
WireId ArchRProxyMethods::getWireByName(IdString name) const
|
||||
{
|
||||
WireId ret;
|
||||
|
||||
if (parent_->wire_by_name.empty()) {
|
||||
for (int i = 0; i < parent_->chip_info->num_wires; i++)
|
||||
parent_->wire_by_name[parent_->id(parent_->chip_info->wire_data[i].name.get())] = i;
|
||||
}
|
||||
|
||||
auto it = parent_->wire_by_name.find(name);
|
||||
if (it != parent_->wire_by_name.end())
|
||||
ret.index = it->second;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ArchRProxyMethods::checkWireAvail(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
return parent_->wire_to_net[wire.index] == IdString();
|
||||
}
|
||||
|
||||
IdString ArchRProxyMethods::getBoundWireNet(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
return parent_->wire_to_net[wire.index];
|
||||
}
|
||||
|
||||
IdString ArchRProxyMethods::getConflictingWireNet(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
return parent_->wire_to_net[wire.index];
|
||||
}
|
||||
|
||||
PipId ArchRProxyMethods::getPipByName(IdString name) const
|
||||
{
|
||||
PipId ret;
|
||||
|
||||
if (parent_->pip_by_name.empty()) {
|
||||
for (int i = 0; i < parent_->chip_info->num_pips; i++) {
|
||||
PipId pip;
|
||||
pip.index = i;
|
||||
parent_->pip_by_name[parent_->getPipName(pip)] = i;
|
||||
}
|
||||
}
|
||||
|
||||
auto it = parent_->pip_by_name.find(name);
|
||||
if (it != parent_->pip_by_name.end())
|
||||
ret.index = it->second;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ArchRProxyMethods::checkPipAvail(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString();
|
||||
}
|
||||
|
||||
IdString ArchRProxyMethods::getBoundPipNet(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
return parent_->pip_to_net[pip.index];
|
||||
}
|
||||
|
||||
IdString ArchRProxyMethods::getConflictingPipNet(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index];
|
||||
}
|
||||
|
||||
BelId ArchRProxyMethods::getBelByName(IdString name) const
|
||||
{
|
||||
BelId ret;
|
||||
|
||||
if (parent_->bel_by_name.empty()) {
|
||||
for (int i = 0; i < parent_->chip_info->num_bels; i++)
|
||||
parent_->bel_by_name[parent_->id(parent_->chip_info->bel_data[i].name.get())] = i;
|
||||
}
|
||||
|
||||
auto it = parent_->bel_by_name.find(name);
|
||||
if (it != parent_->bel_by_name.end())
|
||||
ret.index = it->second;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength)
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
NPNR_ASSERT(parent_->wire_to_net[wire.index] == IdString());
|
||||
|
||||
parent_->wire_to_net[wire.index] = net;
|
||||
parent_->nets[net]->wires[wire].pip = PipId();
|
||||
parent_->nets[net]->wires[wire].strength = strength;
|
||||
}
|
||||
|
||||
void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength)
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
NPNR_ASSERT(parent_->bel_to_cell[bel.index] == IdString());
|
||||
parent_->bel_to_cell[bel.index] = cell;
|
||||
parent_->cells[cell]->bel = bel;
|
||||
parent_->cells[cell]->belStrength = strength;
|
||||
}
|
||||
|
||||
void ArchRWProxyMethods::unbindBel(BelId bel)
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
NPNR_ASSERT(parent_->bel_to_cell[bel.index] != IdString());
|
||||
parent_->cells[parent_->bel_to_cell[bel.index]]->bel = BelId();
|
||||
parent_->cells[parent_->bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
|
||||
parent_->bel_to_cell[bel.index] = IdString();
|
||||
}
|
||||
|
||||
void ArchRWProxyMethods::unbindWire(WireId wire)
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
NPNR_ASSERT(parent_->wire_to_net[wire.index] != IdString());
|
||||
|
||||
auto &net_wires = parent_->nets[parent_->wire_to_net[wire.index]]->wires;
|
||||
auto it = net_wires.find(wire);
|
||||
NPNR_ASSERT(it != net_wires.end());
|
||||
|
||||
auto pip = it->second.pip;
|
||||
if (pip != PipId()) {
|
||||
parent_->pip_to_net[pip.index] = IdString();
|
||||
parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString();
|
||||
}
|
||||
|
||||
net_wires.erase(it);
|
||||
parent_->wire_to_net[wire.index] = IdString();
|
||||
}
|
||||
|
||||
void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength)
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
NPNR_ASSERT(parent_->pip_to_net[pip.index] == IdString());
|
||||
NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString());
|
||||
|
||||
parent_->pip_to_net[pip.index] = net;
|
||||
parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = net;
|
||||
|
||||
WireId dst;
|
||||
dst.index = parent_->chip_info->pip_data[pip.index].dst;
|
||||
NPNR_ASSERT(parent_->wire_to_net[dst.index] == IdString());
|
||||
parent_->wire_to_net[dst.index] = net;
|
||||
parent_->nets[net]->wires[dst].pip = pip;
|
||||
parent_->nets[net]->wires[dst].strength = strength;
|
||||
}
|
||||
|
||||
void ArchRWProxyMethods::unbindPip(PipId pip)
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
NPNR_ASSERT(parent_->pip_to_net[pip.index] != IdString());
|
||||
NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] != IdString());
|
||||
|
||||
WireId dst;
|
||||
dst.index = parent_->chip_info->pip_data[pip.index].dst;
|
||||
NPNR_ASSERT(parent_->wire_to_net[dst.index] != IdString());
|
||||
parent_->wire_to_net[dst.index] = IdString();
|
||||
parent_->nets[parent_->pip_to_net[pip.index]]->wires.erase(dst);
|
||||
|
||||
parent_->pip_to_net[pip.index] = IdString();
|
||||
parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString();
|
||||
}
|
||||
|
||||
CellInfo *ArchRWProxyMethods::getCell(IdString cell)
|
||||
{
|
||||
return parent_->cells.at(cell).get();
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
391
ice40/arch.h
391
ice40/arch.h
@ -2,6 +2,7 @@
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
||||
* Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -327,27 +328,40 @@ struct ArchArgs
|
||||
std::string package;
|
||||
};
|
||||
|
||||
class ArchRWProxyMethods;
|
||||
class ArchRProxyMethods;
|
||||
class ArchRWProxy;
|
||||
class ArchRProxy;
|
||||
|
||||
class Arch : public BaseCtx
|
||||
{
|
||||
friend class ArchRWProxyMethods;
|
||||
friend class ArchRProxyMethods;
|
||||
friend class ArchRWProxy;
|
||||
friend class ArchRProxy;
|
||||
private:
|
||||
// All of the following...
|
||||
std::vector<IdString> bel_to_cell;
|
||||
std::vector<IdString> wire_to_net;
|
||||
std::vector<IdString> pip_to_net;
|
||||
std::vector<IdString> switches_locked;
|
||||
// ... are guarded by the following lock:
|
||||
mutable boost::shared_mutex mtx_;
|
||||
public:
|
||||
const ChipInfoPOD *chip_info;
|
||||
const PackageInfoPOD *package_info;
|
||||
|
||||
mutable std::unordered_map<IdString, int> bel_by_name;
|
||||
mutable std::unordered_map<IdString, int> wire_by_name;
|
||||
mutable std::unordered_map<IdString, int> pip_by_name;
|
||||
|
||||
// ... are guarded by the following lock:
|
||||
mutable boost::shared_mutex mtx_;
|
||||
|
||||
public:
|
||||
const ChipInfoPOD *chip_info;
|
||||
const PackageInfoPOD *package_info;
|
||||
|
||||
ArchArgs args;
|
||||
Arch(ArchArgs args);
|
||||
|
||||
ArchRWProxy rwproxy(void);
|
||||
ArchRProxy rproxy(void) const;
|
||||
|
||||
std::string getChipName();
|
||||
|
||||
IdString archId() const { return id("ice40"); }
|
||||
@ -361,8 +375,33 @@ public:
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
/// Wrappers around getting a r(w)proxy and calling a single method.
|
||||
// Deprecated: please acquire a proxy yourself and call the methods
|
||||
// you want on it.
|
||||
void unbindWire(WireId wire);
|
||||
void unbindPip(PipId pip);
|
||||
void unbindBel(BelId bel);
|
||||
void bindWire(WireId wire, IdString net, PlaceStrength strength);
|
||||
void bindPip(PipId pip, IdString net, PlaceStrength strength);
|
||||
void bindBel(BelId bel, IdString cell, PlaceStrength strength);
|
||||
bool checkWireAvail(WireId wire) const;
|
||||
bool checkPipAvail(PipId pip) const;
|
||||
bool checkBelAvail(BelId bel) const;
|
||||
WireId getWireByName(IdString name) const;
|
||||
WireId getWireBelPin(BelId bel, PortPin pin) const;
|
||||
PipId getPipByName(IdString name) const;
|
||||
IdString getConflictingWireNet(WireId wire) const;
|
||||
IdString getConflictingPipNet(PipId pip) const;
|
||||
IdString getConflictingBelCell(BelId bel) const;
|
||||
IdString getBoundWireNet(WireId wire) const;
|
||||
IdString getBoundPipNet(PipId pip) const;
|
||||
IdString getBoundBelCell(BelId bel) const;
|
||||
BelId getBelByName(IdString name) const;
|
||||
BelId getBelByNameUnlocked(IdString name) const;
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
/// Methods to get chip info - don't need to use a wrapper, as these are
|
||||
/// static per lifetime of object.
|
||||
|
||||
IdString getBelName(BelId bel) const
|
||||
{
|
||||
@ -370,71 +409,9 @@ public:
|
||||
return id(chip_info->bel_data[bel.index].name.get());
|
||||
}
|
||||
|
||||
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
||||
|
||||
void bindBel(BelId bel, IdString cell, PlaceStrength strength) {
|
||||
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
bindBelUnlocked(bel, cell, strength);
|
||||
}
|
||||
|
||||
void bindBelUnlocked(BelId bel, IdString cell, PlaceStrength strength)
|
||||
uint32_t getBelChecksum(BelId bel) const
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
NPNR_ASSERT(bel_to_cell[bel.index] == IdString());
|
||||
bel_to_cell[bel.index] = cell;
|
||||
cells[cell]->bel = bel;
|
||||
cells[cell]->belStrength = strength;
|
||||
}
|
||||
|
||||
void unbindBel(BelId bel)
|
||||
{
|
||||
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
unbindBelUnlocked(bel);
|
||||
}
|
||||
|
||||
void unbindBelUnlocked(BelId bel)
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
NPNR_ASSERT(bel_to_cell[bel.index] != IdString());
|
||||
cells[bel_to_cell[bel.index]]->bel = BelId();
|
||||
cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
|
||||
bel_to_cell[bel.index] = IdString();
|
||||
}
|
||||
|
||||
bool checkBelAvail(BelId bel) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return checkBelAvailUnlocked(bel);
|
||||
}
|
||||
|
||||
bool checkBelAvailUnlocked(BelId bel) const
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
return bel_to_cell[bel.index] == IdString();
|
||||
}
|
||||
|
||||
IdString getBoundBelCell(BelId bel) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return getBoundBelCellUnlocked(bel);
|
||||
}
|
||||
|
||||
IdString getBoundBelCellUnlocked(BelId bel) const
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
return bel_to_cell[bel.index];
|
||||
}
|
||||
|
||||
IdString getConflictingBelCell(BelId bel) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return getConflictingBelCellUnlocked(bel);
|
||||
}
|
||||
|
||||
IdString getConflictingBelCellUnlocked(BelId bel) const
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
return bel_to_cell[bel.index];
|
||||
return bel.index;
|
||||
}
|
||||
|
||||
BelRange getBels() const
|
||||
@ -467,8 +444,6 @@ public:
|
||||
return chip_info->bel_data[bel.index].type;
|
||||
}
|
||||
|
||||
WireId getWireBelPin(BelId bel, PortPin pin) const;
|
||||
WireId getWireBelPinUnlocked(BelId bel, PortPin pin) const;
|
||||
|
||||
BelPin getBelPinUphill(WireId wire) const
|
||||
{
|
||||
@ -494,9 +469,6 @@ public:
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
WireId getWireByName(IdString name) const;
|
||||
WireId getWireByNameUnlocked(IdString name) const;
|
||||
|
||||
IdString getWireName(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
@ -505,82 +477,6 @@ public:
|
||||
|
||||
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
|
||||
|
||||
void bindWire(WireId wire, IdString net, PlaceStrength strength)
|
||||
{
|
||||
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
bindWireUnlocked(wire, net, strength);
|
||||
}
|
||||
|
||||
void bindWireUnlocked(WireId wire, IdString net, PlaceStrength strength)
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
NPNR_ASSERT(wire_to_net[wire.index] == IdString());
|
||||
|
||||
wire_to_net[wire.index] = net;
|
||||
nets[net]->wires[wire].pip = PipId();
|
||||
nets[net]->wires[wire].strength = strength;
|
||||
}
|
||||
|
||||
void unbindWire(WireId wire)
|
||||
{
|
||||
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
unbindWireUnlocked(wire);
|
||||
}
|
||||
|
||||
void unbindWireUnlocked(WireId wire)
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
NPNR_ASSERT(wire_to_net[wire.index] != IdString());
|
||||
|
||||
auto &net_wires = nets[wire_to_net[wire.index]]->wires;
|
||||
auto it = net_wires.find(wire);
|
||||
NPNR_ASSERT(it != net_wires.end());
|
||||
|
||||
auto pip = it->second.pip;
|
||||
if (pip != PipId()) {
|
||||
pip_to_net[pip.index] = IdString();
|
||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
|
||||
}
|
||||
|
||||
net_wires.erase(it);
|
||||
wire_to_net[wire.index] = IdString();
|
||||
}
|
||||
|
||||
bool checkWireAvail(WireId wire) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return checkWireAvailUnlocked(wire);
|
||||
}
|
||||
|
||||
bool checkWireAvailUnlocked(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
return wire_to_net[wire.index] == IdString();
|
||||
}
|
||||
|
||||
IdString getBoundWireNet(WireId wire) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return getBoundWireNetUnlocked(wire);
|
||||
}
|
||||
|
||||
IdString getBoundWireNetUnlocked(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
return wire_to_net[wire.index];
|
||||
}
|
||||
|
||||
IdString getConflictingWireNet(WireId wire) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return getConflictingWireNetUnlocked(wire);
|
||||
}
|
||||
|
||||
IdString getConflictingWireNetUnlocked(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
return wire_to_net[wire.index];
|
||||
}
|
||||
|
||||
WireRange getWires() const
|
||||
{
|
||||
@ -592,93 +488,10 @@ public:
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
PipId getPipByName(IdString name) const;
|
||||
PipId getPipByNameUnlocked(IdString name) const;
|
||||
IdString getPipName(PipId pip) const;
|
||||
|
||||
uint32_t getPipChecksum(PipId pip) const { return pip.index; }
|
||||
|
||||
void bindPip(PipId pip, IdString net, PlaceStrength strength)
|
||||
{
|
||||
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
bindPipUnlocked(pip, net, strength);
|
||||
}
|
||||
|
||||
void bindPipUnlocked(PipId pip, IdString net, PlaceStrength strength)
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
NPNR_ASSERT(pip_to_net[pip.index] == IdString());
|
||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString());
|
||||
|
||||
pip_to_net[pip.index] = net;
|
||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
|
||||
|
||||
WireId dst;
|
||||
dst.index = chip_info->pip_data[pip.index].dst;
|
||||
NPNR_ASSERT(wire_to_net[dst.index] == IdString());
|
||||
wire_to_net[dst.index] = net;
|
||||
nets[net]->wires[dst].pip = pip;
|
||||
nets[net]->wires[dst].strength = strength;
|
||||
}
|
||||
|
||||
void unbindPip(PipId pip)
|
||||
{
|
||||
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
unbindPipUnlocked(pip);
|
||||
}
|
||||
|
||||
void unbindPipUnlocked(PipId pip)
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
NPNR_ASSERT(pip_to_net[pip.index] != IdString());
|
||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString());
|
||||
|
||||
WireId dst;
|
||||
dst.index = chip_info->pip_data[pip.index].dst;
|
||||
NPNR_ASSERT(wire_to_net[dst.index] != IdString());
|
||||
wire_to_net[dst.index] = IdString();
|
||||
nets[pip_to_net[pip.index]]->wires.erase(dst);
|
||||
|
||||
pip_to_net[pip.index] = IdString();
|
||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
|
||||
}
|
||||
|
||||
bool checkPipAvail(PipId pip) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return checkPipAvailUnlocked(pip);
|
||||
}
|
||||
|
||||
bool checkPipAvailUnlocked(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString();
|
||||
}
|
||||
|
||||
IdString getBoundPipNet(PipId pip) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return getBoundPipNetUnlocked(pip);
|
||||
}
|
||||
|
||||
IdString getBoundPipNetUnlocked(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
return pip_to_net[pip.index];
|
||||
}
|
||||
|
||||
IdString getConflictingPipNet(PipId pip) const
|
||||
{
|
||||
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||
return getConflictingPipNetUnlocked(pip);
|
||||
}
|
||||
|
||||
IdString getConflictingPipNetUnlocked(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
return switches_locked[chip_info->pip_data[pip.index].switch_index];
|
||||
}
|
||||
|
||||
AllPipRange getPips() const
|
||||
{
|
||||
AllPipRange range;
|
||||
@ -789,7 +602,26 @@ public:
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc)
|
||||
IdString id_glb_buf_out;
|
||||
IdString id_icestorm_lc, id_sb_io, id_sb_gb;
|
||||
IdString id_cen, id_clk, id_sr;
|
||||
IdString id_i0, id_i1, id_i2, id_i3;
|
||||
IdString id_dff_en, id_neg_clk;
|
||||
};
|
||||
|
||||
class ArchRProxyMethods {
|
||||
friend class ArchRProxy;
|
||||
friend class ArchRWProxy;
|
||||
private:
|
||||
const Arch *parent_;
|
||||
ArchRProxyMethods(const Arch *parent) : parent_(parent) {}
|
||||
ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : parent_(other.parent_) {}
|
||||
ArchRProxyMethods(const ArchRProxyMethods &other) : parent_(other.parent_) {}
|
||||
|
||||
public:
|
||||
~ArchRProxyMethods() noexcept { }
|
||||
|
||||
/// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc)
|
||||
|
||||
// Whether or not a given cell can be placed at a given Bel
|
||||
// This is not intended for Bel type checks, but finer-grained constraints
|
||||
@ -802,11 +634,88 @@ public:
|
||||
// Helper function for above
|
||||
bool logicCellsCompatible(const std::vector<const CellInfo *> &cells) const;
|
||||
|
||||
IdString id_glb_buf_out;
|
||||
IdString id_icestorm_lc, id_sb_io, id_sb_gb;
|
||||
IdString id_cen, id_clk, id_sr;
|
||||
IdString id_i0, id_i1, id_i2, id_i3;
|
||||
IdString id_dff_en, id_neg_clk;
|
||||
bool checkWireAvail(WireId wire) const;
|
||||
bool checkPipAvail(PipId pip) const;
|
||||
bool checkBelAvail(BelId bel) const;
|
||||
|
||||
WireId getWireByName(IdString name) const;
|
||||
WireId getWireBelPin(BelId bel, PortPin pin) const;
|
||||
PipId getPipByName(IdString name) const;
|
||||
|
||||
|
||||
IdString getConflictingWireNet(WireId wire) const;
|
||||
IdString getConflictingPipNet(PipId pip) const;
|
||||
IdString getConflictingBelCell(BelId bel) const;
|
||||
|
||||
IdString getBoundWireNet(WireId wire) const;
|
||||
IdString getBoundPipNet(PipId pip) const;
|
||||
IdString getBoundBelCell(BelId bel) const;
|
||||
|
||||
BelId getBelByName(IdString name) const;
|
||||
};
|
||||
|
||||
class ArchRProxy : public ArchRProxyMethods {
|
||||
friend class Arch;
|
||||
friend class ArchRWProxy;
|
||||
private:
|
||||
boost::shared_mutex *lock_;
|
||||
ArchRProxy(const Arch *parent) : ArchRProxyMethods(parent), lock_(&parent->mtx_)
|
||||
{
|
||||
lock_->lock_shared();
|
||||
}
|
||||
|
||||
public:
|
||||
~ArchRProxy() {
|
||||
if (lock_ != nullptr) {
|
||||
lock_->unlock_shared();
|
||||
}
|
||||
}
|
||||
ArchRProxy(ArchRProxy &&other) : ArchRProxyMethods(other), lock_(other.lock_)
|
||||
{
|
||||
other.lock_ = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
class ArchRWProxyMethods {
|
||||
friend class ArchRWProxy;
|
||||
private:
|
||||
Arch *parent_;
|
||||
ArchRWProxyMethods(Arch *parent) : parent_(parent) {}
|
||||
ArchRWProxyMethods(ArchRWProxyMethods &&other) : parent_(other.parent_) {}
|
||||
ArchRWProxyMethods(const ArchRWProxyMethods &other) : parent_(other.parent_) {}
|
||||
public:
|
||||
~ArchRWProxyMethods() {}
|
||||
|
||||
void unbindWire(WireId wire);
|
||||
void unbindPip(PipId pip);
|
||||
void unbindBel(BelId bel);
|
||||
void bindWire(WireId wire, IdString net, PlaceStrength strength);
|
||||
void bindPip(PipId pip, IdString net, PlaceStrength strength);
|
||||
void bindBel(BelId bel, IdString cell, PlaceStrength strength);
|
||||
CellInfo *getCell(IdString cell);
|
||||
};
|
||||
|
||||
class ArchRWProxy : public ArchRProxyMethods, public ArchRWProxyMethods {
|
||||
friend class Arch;
|
||||
private:
|
||||
boost::shared_mutex *lock_;
|
||||
ArchRWProxy(Arch *parent) : ArchRProxyMethods(parent), ArchRWProxyMethods(parent), lock_(&parent->mtx_) {
|
||||
lock_->lock();
|
||||
}
|
||||
|
||||
public:
|
||||
ArchRWProxy(ArchRWProxy &&other) : ArchRProxyMethods(other), ArchRWProxyMethods(other), lock_(other.lock_)
|
||||
{
|
||||
other.lock_ = nullptr;
|
||||
}
|
||||
~ArchRWProxy()
|
||||
{
|
||||
if (lock_ != nullptr) {
|
||||
lock_->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
||||
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||
* Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -24,44 +25,44 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
bool Arch::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const
|
||||
bool ArchRProxyMethods::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const
|
||||
{
|
||||
bool dffs_exist = false, dffs_neg = false;
|
||||
const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr;
|
||||
int locals_count = 0;
|
||||
|
||||
for (auto cell : cells) {
|
||||
if (bool_or_default(cell->params, id_dff_en)) {
|
||||
if (bool_or_default(cell->params, parent_->id_dff_en)) {
|
||||
if (!dffs_exist) {
|
||||
dffs_exist = true;
|
||||
cen = get_net_or_empty(cell, id_cen);
|
||||
clk = get_net_or_empty(cell, id_clk);
|
||||
sr = get_net_or_empty(cell, id_sr);
|
||||
cen = get_net_or_empty(cell, parent_->id_cen);
|
||||
clk = get_net_or_empty(cell, parent_->id_clk);
|
||||
sr = get_net_or_empty(cell, parent_->id_sr);
|
||||
|
||||
if (!isGlobalNet(cen) && cen != nullptr)
|
||||
if (!parent_->isGlobalNet(cen) && cen != nullptr)
|
||||
locals_count++;
|
||||
if (!isGlobalNet(clk) && clk != nullptr)
|
||||
if (!parent_->isGlobalNet(clk) && clk != nullptr)
|
||||
locals_count++;
|
||||
if (!isGlobalNet(sr) && sr != nullptr)
|
||||
if (!parent_->isGlobalNet(sr) && sr != nullptr)
|
||||
locals_count++;
|
||||
|
||||
if (bool_or_default(cell->params, id_neg_clk)) {
|
||||
if (bool_or_default(cell->params, parent_->id_neg_clk)) {
|
||||
dffs_neg = true;
|
||||
}
|
||||
} else {
|
||||
if (cen != get_net_or_empty(cell, id_cen))
|
||||
if (cen != get_net_or_empty(cell, parent_->id_cen))
|
||||
return false;
|
||||
if (clk != get_net_or_empty(cell, id_clk))
|
||||
if (clk != get_net_or_empty(cell, parent_->id_clk))
|
||||
return false;
|
||||
if (sr != get_net_or_empty(cell, id_sr))
|
||||
if (sr != get_net_or_empty(cell, parent_->id_sr))
|
||||
return false;
|
||||
if (dffs_neg != bool_or_default(cell->params, id_neg_clk))
|
||||
if (dffs_neg != bool_or_default(cell->params, parent_->id_neg_clk))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const NetInfo *i0 = get_net_or_empty(cell, id_i0), *i1 = get_net_or_empty(cell, id_i1),
|
||||
*i2 = get_net_or_empty(cell, id_i2), *i3 = get_net_or_empty(cell, id_i3);
|
||||
const NetInfo *i0 = get_net_or_empty(cell, parent_->id_i0), *i1 = get_net_or_empty(cell, parent_->id_i1),
|
||||
*i2 = get_net_or_empty(cell, parent_->id_i2), *i3 = get_net_or_empty(cell, parent_->id_i3);
|
||||
if (i0 != nullptr)
|
||||
locals_count++;
|
||||
if (i1 != nullptr)
|
||||
@ -75,57 +76,57 @@ bool Arch::logicCellsCompatible(const std::vector<const CellInfo *> &cells) cons
|
||||
return locals_count <= 32;
|
||||
}
|
||||
|
||||
bool Arch::isBelLocationValid(BelId bel) const
|
||||
bool ArchRProxyMethods::isBelLocationValid(BelId bel) const
|
||||
{
|
||||
if (getBelType(bel) == TYPE_ICESTORM_LC) {
|
||||
if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) {
|
||||
std::vector<const CellInfo *> bel_cells;
|
||||
for (auto bel_other : getBelsAtSameTile(bel)) {
|
||||
IdString cell_other = getBoundBelCellUnlocked(bel_other);
|
||||
for (auto bel_other : parent_->getBelsAtSameTile(bel)) {
|
||||
IdString cell_other = getBoundBelCell(bel_other);
|
||||
if (cell_other != IdString()) {
|
||||
const CellInfo *ci_other = cells.at(cell_other).get();
|
||||
const CellInfo *ci_other = parent_->cells.at(cell_other).get();
|
||||
bel_cells.push_back(ci_other);
|
||||
}
|
||||
}
|
||||
return logicCellsCompatible(bel_cells);
|
||||
} else {
|
||||
IdString cellId = getBoundBelCellUnlocked(bel);
|
||||
IdString cellId = getBoundBelCell(bel);
|
||||
if (cellId == IdString())
|
||||
return true;
|
||||
else
|
||||
return isValidBelForCell(cells.at(cellId).get(), bel);
|
||||
return isValidBelForCell(parent_->cells.at(cellId).get(), bel);
|
||||
}
|
||||
}
|
||||
|
||||
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
||||
bool ArchRProxyMethods::isValidBelForCell(CellInfo *cell, BelId bel) const
|
||||
{
|
||||
if (cell->type == id_icestorm_lc) {
|
||||
NPNR_ASSERT(getBelType(bel) == TYPE_ICESTORM_LC);
|
||||
if (cell->type == parent_->id_icestorm_lc) {
|
||||
NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC);
|
||||
|
||||
std::vector<const CellInfo *> bel_cells;
|
||||
|
||||
for (auto bel_other : getBelsAtSameTile(bel)) {
|
||||
IdString cell_other = getBoundBelCellUnlocked(bel_other);
|
||||
for (auto bel_other : parent_->getBelsAtSameTile(bel)) {
|
||||
IdString cell_other = getBoundBelCell(bel_other);
|
||||
if (cell_other != IdString() && bel_other != bel) {
|
||||
const CellInfo *ci_other = cells.at(cell_other).get();
|
||||
const CellInfo *ci_other = parent_->cells.at(cell_other).get();
|
||||
bel_cells.push_back(ci_other);
|
||||
}
|
||||
}
|
||||
|
||||
bel_cells.push_back(cell);
|
||||
return logicCellsCompatible(bel_cells);
|
||||
} else if (cell->type == id_sb_io) {
|
||||
return getBelPackagePin(bel) != "";
|
||||
} else if (cell->type == id_sb_gb) {
|
||||
} else if (cell->type == parent_->id_sb_io) {
|
||||
return parent_->getBelPackagePin(bel) != "";
|
||||
} else if (cell->type == parent_->id_sb_gb) {
|
||||
bool is_reset = false, is_cen = false;
|
||||
NPNR_ASSERT(cell->ports.at(id_glb_buf_out).net != nullptr);
|
||||
for (auto user : cell->ports.at(id_glb_buf_out).net->users) {
|
||||
if (is_reset_port(this, user))
|
||||
NPNR_ASSERT(cell->ports.at(parent_->id_glb_buf_out).net != nullptr);
|
||||
for (auto user : cell->ports.at(parent_->id_glb_buf_out).net->users) {
|
||||
if (is_reset_port(parent_, user))
|
||||
is_reset = true;
|
||||
if (is_enable_port(this, user))
|
||||
if (is_enable_port(parent_, user))
|
||||
is_cen = true;
|
||||
}
|
||||
IdString glb_net = getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
|
||||
int glb_id = std::stoi(std::string("") + glb_net.str(this).back());
|
||||
IdString glb_net = parent_->getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
|
||||
int glb_id = std::stoi(std::string("") + glb_net.str(parent_).back());
|
||||
if (is_reset && is_cen)
|
||||
return false;
|
||||
else if (is_reset)
|
||||
|
@ -119,13 +119,17 @@ class PlacementLegaliser
|
||||
|
||||
bool legalise()
|
||||
{
|
||||
log_info("Legalising design..\n");
|
||||
log_info("Legalising logic cells...\n");
|
||||
init_logic_cells();
|
||||
log_info("Legalising carries...\n");
|
||||
bool legalised_carries = legalise_carries();
|
||||
if (!legalised_carries && !ctx->force)
|
||||
return false;
|
||||
log_info("Legalising others...\n");
|
||||
legalise_others();
|
||||
log_info("Legalising logic tiles...\n");
|
||||
legalise_logic_tiles();
|
||||
log_info("Replacing cells...\n");
|
||||
bool replaced_cells = replace_cells();
|
||||
return legalised_carries && replaced_cells;
|
||||
}
|
||||
@ -133,6 +137,7 @@ class PlacementLegaliser
|
||||
private:
|
||||
void init_logic_cells()
|
||||
{
|
||||
auto &&proxy = ctx->rproxy();
|
||||
for (auto bel : ctx->getBels()) {
|
||||
// Initialise the logic bels vector with unavailable invalid bels, dimensions [0..width][0..height[0..7]
|
||||
logic_bels.resize(ctx->chip_info->width + 1,
|
||||
@ -143,7 +148,7 @@ class PlacementLegaliser
|
||||
// Using the non-standard API here to get (x, y, z) rather than just (x, y)
|
||||
auto bi = ctx->chip_info->bel_data[bel.index];
|
||||
int x = bi.x, y = bi.y, z = bi.z;
|
||||
IdString cell = ctx->getBoundBelCellUnlocked(bel);
|
||||
IdString cell = proxy.getBoundBelCell(bel);
|
||||
if (cell != IdString() && ctx->cells.at(cell)->belStrength >= STRENGTH_FIXED)
|
||||
logic_bels.at(x).at(y).at(z) = std::make_pair(bel, true); // locked out of use
|
||||
else
|
||||
@ -195,28 +200,33 @@ class PlacementLegaliser
|
||||
}
|
||||
}
|
||||
bool success = true;
|
||||
|
||||
// Find midpoints for all chains, before we start tearing them up
|
||||
std::vector<CellChain> all_chains;
|
||||
for (auto &base_chain : carry_chains) {
|
||||
if (ctx->verbose) {
|
||||
log_info("Found carry chain: \n");
|
||||
for (auto entry : base_chain.cells)
|
||||
log_info(" %s\n", entry->name.c_str(ctx));
|
||||
log_info("\n");
|
||||
}
|
||||
std::vector<CellChain> split_chains = split_carry_chain(base_chain);
|
||||
for (auto &chain : split_chains) {
|
||||
get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y);
|
||||
all_chains.push_back(chain);
|
||||
{
|
||||
auto &&proxy = ctx->rproxy();
|
||||
for (auto &base_chain : carry_chains) {
|
||||
if (ctx->verbose) {
|
||||
log_info("Found carry chain: \n");
|
||||
for (auto entry : base_chain.cells)
|
||||
log_info(" %s\n", entry->name.c_str(ctx));
|
||||
log_info("\n");
|
||||
}
|
||||
std::vector<CellChain> split_chains = split_carry_chain(proxy, base_chain);
|
||||
for (auto &chain : split_chains) {
|
||||
get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y);
|
||||
all_chains.push_back(chain);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Actual chain placement
|
||||
auto &&proxy = ctx->rwproxy();
|
||||
for (auto &chain : all_chains) {
|
||||
if (ctx->verbose)
|
||||
log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx));
|
||||
float base_x = chain.mid_x, base_y = chain.mid_y - (chain.cells.size() / 16.0f);
|
||||
// Find Bel meeting requirements closest to the target base, returning location as <x, y, z>
|
||||
auto chain_origin_bel = find_closest_bel(base_x, base_y, chain);
|
||||
auto chain_origin_bel = find_closest_bel(proxy, base_x, base_y, chain);
|
||||
int place_x = std::get<0>(chain_origin_bel), place_y = std::get<1>(chain_origin_bel),
|
||||
place_z = std::get<2>(chain_origin_bel);
|
||||
if (place_x == -1) {
|
||||
@ -233,7 +243,7 @@ class PlacementLegaliser
|
||||
// Place carry chain
|
||||
for (int i = 0; i < int(chain.cells.size()); i++) {
|
||||
int target_z = place_y * 8 + place_z + i;
|
||||
place_lc(chain.cells.at(i), place_x, target_z / 8, target_z % 8);
|
||||
place_lc(proxy, chain.cells.at(i), place_x, target_z / 8, target_z % 8);
|
||||
if (ctx->verbose)
|
||||
log_info(" Cell '%s' placed at (%d, %d, %d)\n", chain.cells.at(i)->name.c_str(ctx), place_x,
|
||||
target_z / 8, target_z % 8);
|
||||
@ -243,7 +253,7 @@ class PlacementLegaliser
|
||||
}
|
||||
|
||||
// Find Bel closest to a location, meeting chain requirements
|
||||
std::tuple<int, int, int> find_closest_bel(float target_x, float target_y, CellChain &chain)
|
||||
std::tuple<int, int, int> find_closest_bel(ArchRWProxy &proxy, float target_x, float target_y, CellChain &chain)
|
||||
{
|
||||
std::tuple<int, int, int> best_origin = std::make_tuple(-1, -1, -1);
|
||||
wirelen_t best_wirelength = std::numeric_limits<wirelen_t>::max();
|
||||
@ -260,7 +270,7 @@ class PlacementLegaliser
|
||||
valid = false;
|
||||
break;
|
||||
} else {
|
||||
wirelen += get_cell_wirelength_at_bel(ctx, chain.cells.at(k), lb.first);
|
||||
wirelen += get_cell_wirelength_at_bel(proxy, ctx, chain.cells.at(k), lb.first);
|
||||
}
|
||||
}
|
||||
if (valid && wirelen < best_wirelength) {
|
||||
@ -273,7 +283,7 @@ class PlacementLegaliser
|
||||
}
|
||||
|
||||
// Split a carry chain into multiple legal chains
|
||||
std::vector<CellChain> split_carry_chain(CellChain &carryc)
|
||||
std::vector<CellChain> split_carry_chain(const ArchRProxy &proxy, CellChain &carryc)
|
||||
{
|
||||
bool start_of_chain = true;
|
||||
std::vector<CellChain> chains;
|
||||
@ -298,7 +308,7 @@ class PlacementLegaliser
|
||||
}
|
||||
tile.push_back(cell);
|
||||
chains.back().cells.push_back(cell);
|
||||
bool split_chain = (!ctx->logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length);
|
||||
bool split_chain = (!proxy.logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length);
|
||||
if (split_chain) {
|
||||
CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT")));
|
||||
tile.pop_back();
|
||||
@ -325,22 +335,22 @@ class PlacementLegaliser
|
||||
}
|
||||
|
||||
// Place a logic cell at a given grid location, handling rip-up etc
|
||||
void place_lc(CellInfo *cell, int x, int y, int z)
|
||||
void place_lc(ArchRWProxy &proxy, CellInfo *cell, int x, int y, int z)
|
||||
{
|
||||
auto &loc = logic_bels.at(x).at(y).at(z);
|
||||
NPNR_ASSERT(!loc.second);
|
||||
BelId bel = loc.first;
|
||||
// Check if there is a cell presently at the location, which we will need to rip up
|
||||
IdString existing = ctx->getBoundBelCellUnlocked(bel);
|
||||
IdString existing = proxy.getBoundBelCell(bel);
|
||||
if (existing != IdString()) {
|
||||
// TODO: keep track of the previous position of the ripped up cell, as a hint
|
||||
rippedCells.insert(existing);
|
||||
ctx->unbindBelUnlocked(bel);
|
||||
proxy.unbindBel(bel);
|
||||
}
|
||||
if (cell->bel != BelId()) {
|
||||
ctx->unbindBelUnlocked(cell->bel);
|
||||
proxy.unbindBel(cell->bel);
|
||||
}
|
||||
ctx->bindBelUnlocked(bel, cell->name, STRENGTH_LOCKED);
|
||||
proxy.bindBel(bel, cell->name, STRENGTH_LOCKED);
|
||||
rippedCells.erase(cell->name); // If cell was ripped up previously, no need to re-place
|
||||
loc.second = true; // Bel is now unavailable for further use
|
||||
}
|
||||
@ -423,19 +433,20 @@ class PlacementLegaliser
|
||||
// Legalise logic tiles
|
||||
void legalise_logic_tiles()
|
||||
{
|
||||
auto &&proxy = ctx->rwproxy();
|
||||
int width = ctx->chip_info->width, height = ctx->chip_info->height;
|
||||
for (int x = 1; x < width; x++) {
|
||||
for (int y = 1; y < height; y++) {
|
||||
BelId tileBel = logic_bels.at(x).at(y).at(0).first;
|
||||
if (tileBel != BelId()) {
|
||||
bool changed = true;
|
||||
while (!ctx->isBelLocationValid(tileBel) && changed) {
|
||||
while (!proxy.isBelLocationValid(tileBel) && changed) {
|
||||
changed = false;
|
||||
int max_score = 0;
|
||||
CellInfo *target = nullptr;
|
||||
for (int z = 0; z < 8; z++) {
|
||||
BelId bel = logic_bels.at(x).at(y).at(z).first;
|
||||
IdString cell = ctx->getBoundBelCellUnlocked(bel);
|
||||
IdString cell = proxy.getBoundBelCell(bel);
|
||||
if (cell != IdString()) {
|
||||
CellInfo *ci = ctx->cells.at(cell).get();
|
||||
if (ci->belStrength >= STRENGTH_STRONG)
|
||||
@ -448,7 +459,7 @@ class PlacementLegaliser
|
||||
}
|
||||
}
|
||||
if (target != nullptr) {
|
||||
ctx->unbindBelUnlocked(target->bel);
|
||||
proxy.unbindBel(target->bel);
|
||||
rippedCells.insert(target->name);
|
||||
changed = true;
|
||||
}
|
||||
@ -461,13 +472,14 @@ class PlacementLegaliser
|
||||
// Legalise other tiles
|
||||
void legalise_others()
|
||||
{
|
||||
auto &&proxy = ctx->rwproxy();
|
||||
std::vector<CellInfo *> legalised_others;
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (!is_lc(ctx, ci)) {
|
||||
if (ci->belStrength < STRENGTH_STRONG && ci->bel != BelId()) {
|
||||
if (!ctx->isValidBelForCell(ci, ci->bel)) {
|
||||
place_single_cell(ctx, ci, true);
|
||||
if (!proxy.isValidBelForCell(ci, ci->bel)) {
|
||||
place_single_cell(proxy, ctx, ci, true);
|
||||
}
|
||||
legalised_others.push_back(ci);
|
||||
}
|
||||
@ -482,10 +494,11 @@ class PlacementLegaliser
|
||||
// Replace ripped-up cells
|
||||
bool replace_cells()
|
||||
{
|
||||
auto &&proxy = ctx->rwproxy();
|
||||
bool success = true;
|
||||
for (auto cell : sorted(rippedCells)) {
|
||||
CellInfo *ci = ctx->cells.at(cell).get();
|
||||
bool placed = place_single_cell(ctx, ci, true);
|
||||
bool placed = place_single_cell(proxy, ctx, ci, true);
|
||||
if (!placed) {
|
||||
if (ctx->force) {
|
||||
log_warning("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), ci->type.c_str(ctx));
|
||||
|
Loading…
Reference in New Issue
Block a user