Merge remote-tracking branch 'origin/master' into common_main
# Conflicts: # ecp5/main.cc # ice40/main.cc
This commit is contained in:
commit
5df90bc5a5
@ -192,6 +192,7 @@ int CommandHandler::executeMain(std::unique_ptr<Context> ctx)
|
|||||||
if (vm.count("json") || vm.count("load")) {
|
if (vm.count("json") || vm.count("load")) {
|
||||||
if (!ctx->pack() && !ctx->force)
|
if (!ctx->pack() && !ctx->force)
|
||||||
log_error("Packing design failed.\n");
|
log_error("Packing design failed.\n");
|
||||||
|
assign_budget(ctx.get());
|
||||||
ctx->check();
|
ctx->check();
|
||||||
print_utilisation(ctx.get());
|
print_utilisation(ctx.get());
|
||||||
if (!vm.count("pack-only")) {
|
if (!vm.count("pack-only")) {
|
||||||
|
@ -232,25 +232,26 @@ void Context::check() const
|
|||||||
auto ni = n.second.get();
|
auto ni = n.second.get();
|
||||||
NPNR_ASSERT(n.first == ni->name);
|
NPNR_ASSERT(n.first == ni->name);
|
||||||
for (auto &w : ni->wires) {
|
for (auto &w : ni->wires) {
|
||||||
NPNR_ASSERT(n.first == getBoundWireNet(w.first));
|
NPNR_ASSERT(ni == getBoundWireNet(w.first));
|
||||||
if (w.second.pip != PipId()) {
|
if (w.second.pip != PipId()) {
|
||||||
NPNR_ASSERT(w.first == getPipDstWire(w.second.pip));
|
NPNR_ASSERT(w.first == getPipDstWire(w.second.pip));
|
||||||
NPNR_ASSERT(n.first == getBoundPipNet(w.second.pip));
|
NPNR_ASSERT(ni == getBoundPipNet(w.second.pip));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto w : getWires()) {
|
for (auto w : getWires()) {
|
||||||
IdString net = getBoundWireNet(w);
|
auto ni = getBoundWireNet(w);
|
||||||
if (net != IdString()) {
|
if (ni != nullptr) {
|
||||||
NPNR_ASSERT(nets.at(net)->wires.count(w));
|
NPNR_ASSERT(ni->wires.count(w));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &c : cells) {
|
for (auto &c : cells) {
|
||||||
NPNR_ASSERT(c.first == c.second->name);
|
auto ci = c.second.get();
|
||||||
if (c.second->bel != BelId())
|
NPNR_ASSERT(c.first == ci->name);
|
||||||
NPNR_ASSERT(getBoundBelCell(c.second->bel) == c.first);
|
if (ci->bel != BelId())
|
||||||
|
NPNR_ASSERT(getBoundBelCell(c.second->bel) == ci);
|
||||||
for (auto &port : c.second->ports) {
|
for (auto &port : c.second->ports) {
|
||||||
NetInfo *net = port.second.net;
|
NetInfo *net = port.second.net;
|
||||||
if (net != nullptr) {
|
if (net != nullptr) {
|
||||||
|
@ -437,6 +437,13 @@ struct BaseCtx
|
|||||||
|
|
||||||
const Context *getCtx() const { return reinterpret_cast<const Context *>(this); }
|
const Context *getCtx() const { return reinterpret_cast<const Context *>(this); }
|
||||||
|
|
||||||
|
template<typename T> const char *nameOf(const T *obj)
|
||||||
|
{
|
||||||
|
if (obj == nullptr)
|
||||||
|
return "";
|
||||||
|
return obj->name.c_str(getCtx());
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
bool allUiReload = true;
|
bool allUiReload = true;
|
||||||
|
@ -131,7 +131,7 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality)
|
|||||||
if (iters >= 4)
|
if (iters >= 4)
|
||||||
wirelen += ctx->rng(25);
|
wirelen += ctx->rng(25);
|
||||||
if (wirelen <= best_ripup_wirelen) {
|
if (wirelen <= best_ripup_wirelen) {
|
||||||
CellInfo *curr_cell = ctx->cells.at(ctx->getBoundBelCell(bel)).get();
|
CellInfo *curr_cell = ctx->getBoundBelCell(bel);
|
||||||
if (curr_cell->belStrength < STRENGTH_STRONG) {
|
if (curr_cell->belStrength < STRENGTH_STRONG) {
|
||||||
best_ripup_wirelen = wirelen;
|
best_ripup_wirelen = wirelen;
|
||||||
ripup_bel = bel;
|
ripup_bel = bel;
|
||||||
@ -158,7 +158,7 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality)
|
|||||||
if (ctx->verbose)
|
if (ctx->verbose)
|
||||||
log_info(" placed single cell '%s' at '%s'\n", cell->name.c_str(ctx),
|
log_info(" placed single cell '%s' at '%s'\n", cell->name.c_str(ctx),
|
||||||
ctx->getBelName(best_bel).c_str(ctx));
|
ctx->getBelName(best_bel).c_str(ctx));
|
||||||
ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK);
|
ctx->bindBel(best_bel, cell, STRENGTH_WEAK);
|
||||||
|
|
||||||
cell = ripup_target;
|
cell = ripup_target;
|
||||||
}
|
}
|
||||||
@ -232,8 +232,8 @@ class ConstraintLegaliseWorker
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ctx->checkBelAvail(locBel)) {
|
if (!ctx->checkBelAvail(locBel)) {
|
||||||
IdString confCell = ctx->getConflictingBelCell(locBel);
|
CellInfo *confCell = ctx->getConflictingBelCell(locBel);
|
||||||
if (ctx->cells[confCell]->belStrength >= STRENGTH_STRONG) {
|
if (confCell->belStrength >= STRENGTH_STRONG) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,20 +362,31 @@ class ConstraintLegaliseWorker
|
|||||||
cp.second.y, cp.second.z);
|
cp.second.y, cp.second.z);
|
||||||
BelId target = ctx->getBelByLocation(cp.second);
|
BelId target = ctx->getBelByLocation(cp.second);
|
||||||
if (!ctx->checkBelAvail(target)) {
|
if (!ctx->checkBelAvail(target)) {
|
||||||
IdString conflicting = ctx->getConflictingBelCell(target);
|
CellInfo *confl_cell = ctx->getConflictingBelCell(target);
|
||||||
if (conflicting != IdString()) {
|
if (confl_cell != nullptr) {
|
||||||
CellInfo *confl_cell = ctx->cells.at(conflicting).get();
|
|
||||||
if (ctx->verbose)
|
if (ctx->verbose)
|
||||||
log_info(" '%s' already placed at '%s'\n", conflicting.c_str(ctx),
|
log_info(" '%s' already placed at '%s'\n", ctx->nameOf(confl_cell),
|
||||||
ctx->getBelName(confl_cell->bel).c_str(ctx));
|
ctx->getBelName(confl_cell->bel).c_str(ctx));
|
||||||
NPNR_ASSERT(confl_cell->belStrength < STRENGTH_STRONG);
|
NPNR_ASSERT(confl_cell->belStrength < STRENGTH_STRONG);
|
||||||
ctx->unbindBel(target);
|
ctx->unbindBel(target);
|
||||||
rippedCells.insert(conflicting);
|
rippedCells.insert(confl_cell->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx->bindBel(target, cp.first, STRENGTH_LOCKED);
|
ctx->bindBel(target, ctx->cells.at(cp.first).get(), STRENGTH_LOCKED);
|
||||||
rippedCells.erase(cp.first);
|
rippedCells.erase(cp.first);
|
||||||
}
|
}
|
||||||
|
for (auto cp : solution) {
|
||||||
|
for (auto bel : ctx->getBelsByTile(cp.second.x, cp.second.y)) {
|
||||||
|
CellInfo *belCell = ctx->getBoundBelCell(bel);
|
||||||
|
if (belCell != nullptr && !solution.count(belCell->name)) {
|
||||||
|
if (!ctx->isValidBelForCell(belCell, bel)) {
|
||||||
|
NPNR_ASSERT(belCell->belStrength < STRENGTH_STRONG);
|
||||||
|
ctx->unbindBel(bel);
|
||||||
|
rippedCells.insert(belCell->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
NPNR_ASSERT(constraints_satisfied(cell));
|
NPNR_ASSERT(constraints_satisfied(cell));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ class SAPlacer
|
|||||||
cell->type.c_str(ctx));
|
cell->type.c_str(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->bindBel(bel, cell->name, STRENGTH_USER);
|
ctx->bindBel(bel, cell, STRENGTH_USER);
|
||||||
locked_bels.insert(bel);
|
locked_bels.insert(bel);
|
||||||
placed_cells++;
|
placed_cells++;
|
||||||
}
|
}
|
||||||
@ -138,7 +138,8 @@ class SAPlacer
|
|||||||
if ((placed_cells - constr_placed_cells) % 500 != 0)
|
if ((placed_cells - constr_placed_cells) % 500 != 0)
|
||||||
log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
|
log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
|
||||||
int(autoplaced.size()));
|
int(autoplaced.size()));
|
||||||
assign_budget(ctx);
|
if (ctx->slack_redist_iter > 0)
|
||||||
|
assign_budget(ctx);
|
||||||
ctx->yield();
|
ctx->yield();
|
||||||
|
|
||||||
log_info("Running simulated annealing placer.\n");
|
log_info("Running simulated annealing placer.\n");
|
||||||
@ -256,11 +257,11 @@ class SAPlacer
|
|||||||
// Final post-pacement validitiy check
|
// Final post-pacement validitiy check
|
||||||
ctx->yield();
|
ctx->yield();
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
IdString cell = ctx->getBoundBelCell(bel);
|
CellInfo *cell = ctx->getBoundBelCell(bel);
|
||||||
if (!ctx->isBelLocationValid(bel)) {
|
if (!ctx->isBelLocationValid(bel)) {
|
||||||
std::string cell_text = "no cell";
|
std::string cell_text = "no cell";
|
||||||
if (cell != IdString())
|
if (cell != nullptr)
|
||||||
cell_text = std::string("cell '") + cell.str(ctx) + "'";
|
cell_text = std::string("cell '") + ctx->nameOf(cell) + "'";
|
||||||
if (ctx->force) {
|
if (ctx->force) {
|
||||||
log_warning("post-placement validity check failed for Bel '%s' "
|
log_warning("post-placement validity check failed for Bel '%s' "
|
||||||
"(%s)\n",
|
"(%s)\n",
|
||||||
@ -309,7 +310,7 @@ class SAPlacer
|
|||||||
uint64_t score = ctx->rng64();
|
uint64_t score = ctx->rng64();
|
||||||
if (score <= best_ripup_score) {
|
if (score <= best_ripup_score) {
|
||||||
best_ripup_score = score;
|
best_ripup_score = score;
|
||||||
ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel)).get();
|
ripup_target = ctx->getBoundBelCell(bel);
|
||||||
ripup_bel = bel;
|
ripup_bel = bel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,7 +325,7 @@ class SAPlacer
|
|||||||
} else {
|
} else {
|
||||||
all_placed = true;
|
all_placed = true;
|
||||||
}
|
}
|
||||||
ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK);
|
ctx->bindBel(best_bel, cell, STRENGTH_WEAK);
|
||||||
|
|
||||||
// Back annotate location
|
// Back annotate location
|
||||||
cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx);
|
cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx);
|
||||||
@ -340,20 +341,17 @@ class SAPlacer
|
|||||||
new_lengths.clear();
|
new_lengths.clear();
|
||||||
update.clear();
|
update.clear();
|
||||||
BelId oldBel = cell->bel;
|
BelId oldBel = cell->bel;
|
||||||
IdString other = ctx->getBoundBelCell(newBel);
|
CellInfo *other_cell = ctx->getBoundBelCell(newBel);
|
||||||
CellInfo *other_cell = nullptr;
|
if (other_cell != nullptr && other_cell->belStrength > STRENGTH_WEAK) {
|
||||||
if (other != IdString()) {
|
return false;
|
||||||
other_cell = ctx->cells[other].get();
|
|
||||||
if (other_cell->belStrength > STRENGTH_WEAK)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
int old_dist = get_constraints_distance(ctx, cell);
|
int old_dist = get_constraints_distance(ctx, cell);
|
||||||
int new_dist;
|
int new_dist;
|
||||||
if (other != IdString())
|
if (other_cell != nullptr)
|
||||||
old_dist += get_constraints_distance(ctx, other_cell);
|
old_dist += get_constraints_distance(ctx, other_cell);
|
||||||
wirelen_t new_metric = 0, delta;
|
wirelen_t new_metric = 0, delta;
|
||||||
ctx->unbindBel(oldBel);
|
ctx->unbindBel(oldBel);
|
||||||
if (other != IdString()) {
|
if (other_cell != nullptr) {
|
||||||
ctx->unbindBel(newBel);
|
ctx->unbindBel(newBel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,20 +359,20 @@ class SAPlacer
|
|||||||
if (port.second.net != nullptr)
|
if (port.second.net != nullptr)
|
||||||
update.insert(port.second.net);
|
update.insert(port.second.net);
|
||||||
|
|
||||||
if (other != IdString()) {
|
if (other_cell != nullptr) {
|
||||||
for (const auto &port : other_cell->ports)
|
for (const auto &port : other_cell->ports)
|
||||||
if (port.second.net != nullptr)
|
if (port.second.net != nullptr)
|
||||||
update.insert(port.second.net);
|
update.insert(port.second.net);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->bindBel(newBel, cell->name, STRENGTH_WEAK);
|
ctx->bindBel(newBel, cell, STRENGTH_WEAK);
|
||||||
|
|
||||||
if (other != IdString()) {
|
if (other_cell != nullptr) {
|
||||||
ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK);
|
ctx->bindBel(oldBel, other_cell, STRENGTH_WEAK);
|
||||||
}
|
}
|
||||||
if (!ctx->isBelLocationValid(newBel) || ((other != IdString() && !ctx->isBelLocationValid(oldBel)))) {
|
if (!ctx->isBelLocationValid(newBel) || ((other_cell != nullptr && !ctx->isBelLocationValid(oldBel)))) {
|
||||||
ctx->unbindBel(newBel);
|
ctx->unbindBel(newBel);
|
||||||
if (other != IdString())
|
if (other_cell != nullptr)
|
||||||
ctx->unbindBel(oldBel);
|
ctx->unbindBel(oldBel);
|
||||||
goto swap_fail;
|
goto swap_fail;
|
||||||
}
|
}
|
||||||
@ -391,7 +389,7 @@ class SAPlacer
|
|||||||
}
|
}
|
||||||
|
|
||||||
new_dist = get_constraints_distance(ctx, cell);
|
new_dist = get_constraints_distance(ctx, cell);
|
||||||
if (other != IdString())
|
if (other_cell != nullptr)
|
||||||
new_dist += get_constraints_distance(ctx, other_cell);
|
new_dist += get_constraints_distance(ctx, other_cell);
|
||||||
delta = new_metric - curr_metric;
|
delta = new_metric - curr_metric;
|
||||||
delta += (cfg.constraintWeight / temp) * (new_dist - old_dist);
|
delta += (cfg.constraintWeight / temp) * (new_dist - old_dist);
|
||||||
@ -400,7 +398,7 @@ class SAPlacer
|
|||||||
if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / temp))) {
|
if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / temp))) {
|
||||||
n_accept++;
|
n_accept++;
|
||||||
} else {
|
} else {
|
||||||
if (other != IdString())
|
if (other_cell != nullptr)
|
||||||
ctx->unbindBel(oldBel);
|
ctx->unbindBel(oldBel);
|
||||||
ctx->unbindBel(newBel);
|
ctx->unbindBel(newBel);
|
||||||
goto swap_fail;
|
goto swap_fail;
|
||||||
@ -411,9 +409,9 @@ class SAPlacer
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
swap_fail:
|
swap_fail:
|
||||||
ctx->bindBel(oldBel, cell->name, STRENGTH_WEAK);
|
ctx->bindBel(oldBel, cell, STRENGTH_WEAK);
|
||||||
if (other != IdString()) {
|
if (other_cell != nullptr) {
|
||||||
ctx->bindBel(newBel, other, STRENGTH_WEAK);
|
ctx->bindBel(newBel, other_cell, STRENGTH_WEAK);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,14 @@ template <typename T> struct deref_and_wrap
|
|||||||
using ret_type = ContextualWrapper<T &>;
|
using ret_type = ContextualWrapper<T &>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T> struct addr_and_unwrap
|
||||||
|
{
|
||||||
|
inline T *operator()(Context *ctx, ContextualWrapper<T &> x) { return &(x.base); }
|
||||||
|
|
||||||
|
using arg_type = ContextualWrapper<T &>;
|
||||||
|
using ret_type = T *;
|
||||||
|
};
|
||||||
|
|
||||||
// Function wrapper
|
// Function wrapper
|
||||||
// Zero parameters, one return
|
// Zero parameters, one return
|
||||||
template <typename Class, typename FuncT, FuncT fn, typename rv_conv> struct fn_wrapper_0a
|
template <typename Class, typename FuncT, FuncT fn, typename rv_conv> struct fn_wrapper_0a
|
||||||
|
@ -159,15 +159,15 @@ struct Router
|
|||||||
if (!ctx->checkWireAvail(next_wire)) {
|
if (!ctx->checkWireAvail(next_wire)) {
|
||||||
if (!ripup)
|
if (!ripup)
|
||||||
continue;
|
continue;
|
||||||
IdString ripupWireNet = ctx->getConflictingWireNet(next_wire);
|
NetInfo *ripupWireNet = ctx->getConflictingWireNet(next_wire);
|
||||||
if (ripupWireNet == net_name || ripupWireNet == IdString())
|
if (ripupWireNet == nullptr || ripupWireNet->name == net_name)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto it1 = scores.wireScores.find(next_wire);
|
auto it1 = scores.wireScores.find(next_wire);
|
||||||
if (it1 != scores.wireScores.end())
|
if (it1 != scores.wireScores.end())
|
||||||
next_delay += (it1->second * ripup_penalty) / 8;
|
next_delay += (it1->second * ripup_penalty) / 8;
|
||||||
|
|
||||||
auto it2 = scores.netWireScores.find(std::make_pair(ripupWireNet, next_wire));
|
auto it2 = scores.netWireScores.find(std::make_pair(ripupWireNet->name, next_wire));
|
||||||
if (it2 != scores.netWireScores.end())
|
if (it2 != scores.netWireScores.end())
|
||||||
next_delay += it2->second * ripup_penalty;
|
next_delay += it2->second * ripup_penalty;
|
||||||
|
|
||||||
@ -177,15 +177,15 @@ struct Router
|
|||||||
if (!ctx->checkPipAvail(pip)) {
|
if (!ctx->checkPipAvail(pip)) {
|
||||||
if (!ripup)
|
if (!ripup)
|
||||||
continue;
|
continue;
|
||||||
IdString ripupPipNet = ctx->getConflictingPipNet(pip);
|
NetInfo *ripupPipNet = ctx->getConflictingPipNet(pip);
|
||||||
if (ripupPipNet == net_name || ripupPipNet == IdString())
|
if (ripupPipNet == nullptr || ripupPipNet->name == net_name)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto it1 = scores.pipScores.find(pip);
|
auto it1 = scores.pipScores.find(pip);
|
||||||
if (it1 != scores.pipScores.end())
|
if (it1 != scores.pipScores.end())
|
||||||
next_delay += (it1->second * ripup_penalty) / 8;
|
next_delay += (it1->second * ripup_penalty) / 8;
|
||||||
|
|
||||||
auto it2 = scores.netPipScores.find(std::make_pair(ripupPipNet, pip));
|
auto it2 = scores.netPipScores.find(std::make_pair(ripupPipNet->name, pip));
|
||||||
if (it2 != scores.netPipScores.end())
|
if (it2 != scores.netPipScores.end())
|
||||||
next_delay += it2->second * ripup_penalty;
|
next_delay += it2->second * ripup_penalty;
|
||||||
|
|
||||||
@ -294,12 +294,12 @@ struct Router
|
|||||||
if (reroute) {
|
if (reroute) {
|
||||||
// complete ripup
|
// complete ripup
|
||||||
ripup_net(ctx, net_name);
|
ripup_net(ctx, net_name);
|
||||||
ctx->bindWire(src_wire, net_name, STRENGTH_WEAK);
|
ctx->bindWire(src_wire, ctx->nets.at(net_name).get(), STRENGTH_WEAK);
|
||||||
src_wires[src_wire] = ctx->getWireDelay(src_wire).maxDelay();
|
src_wires[src_wire] = ctx->getWireDelay(src_wire).maxDelay();
|
||||||
} else {
|
} else {
|
||||||
// re-use existing routes as much as possible
|
// re-use existing routes as much as possible
|
||||||
if (net_info->wires.count(src_wire) == 0)
|
if (net_info->wires.count(src_wire) == 0)
|
||||||
ctx->bindWire(src_wire, net_name, STRENGTH_WEAK);
|
ctx->bindWire(src_wire, ctx->nets.at(net_name).get(), STRENGTH_WEAK);
|
||||||
src_wires[src_wire] = ctx->getWireDelay(src_wire).maxDelay();
|
src_wires[src_wire] = ctx->getWireDelay(src_wire).maxDelay();
|
||||||
|
|
||||||
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
||||||
@ -399,42 +399,42 @@ struct Router
|
|||||||
if (src_wires.count(cursor))
|
if (src_wires.count(cursor))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
IdString conflicting_wire_net = ctx->getConflictingWireNet(cursor);
|
NetInfo *conflicting_wire_net = ctx->getConflictingWireNet(cursor);
|
||||||
|
|
||||||
if (conflicting_wire_net != IdString()) {
|
if (conflicting_wire_net != nullptr) {
|
||||||
NPNR_ASSERT(ripup);
|
NPNR_ASSERT(ripup);
|
||||||
NPNR_ASSERT(conflicting_wire_net != net_name);
|
NPNR_ASSERT(conflicting_wire_net->name != net_name);
|
||||||
|
|
||||||
ctx->unbindWire(cursor);
|
ctx->unbindWire(cursor);
|
||||||
if (!ctx->checkWireAvail(cursor))
|
if (!ctx->checkWireAvail(cursor))
|
||||||
ripup_net(ctx, conflicting_wire_net);
|
ripup_net(ctx, conflicting_wire_net->name);
|
||||||
|
|
||||||
rippedNets.insert(conflicting_wire_net);
|
rippedNets.insert(conflicting_wire_net->name);
|
||||||
scores.wireScores[cursor]++;
|
scores.wireScores[cursor]++;
|
||||||
scores.netWireScores[std::make_pair(net_name, cursor)]++;
|
scores.netWireScores[std::make_pair(net_name, cursor)]++;
|
||||||
scores.netWireScores[std::make_pair(conflicting_wire_net, cursor)]++;
|
scores.netWireScores[std::make_pair(conflicting_wire_net->name, cursor)]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
PipId pip = visited[cursor].pip;
|
PipId pip = visited[cursor].pip;
|
||||||
IdString conflicting_pip_net = ctx->getConflictingPipNet(pip);
|
NetInfo *conflicting_pip_net = ctx->getConflictingPipNet(pip);
|
||||||
|
|
||||||
if (conflicting_pip_net != IdString()) {
|
if (conflicting_pip_net != nullptr) {
|
||||||
NPNR_ASSERT(ripup);
|
NPNR_ASSERT(ripup);
|
||||||
NPNR_ASSERT(conflicting_pip_net != net_name);
|
NPNR_ASSERT(conflicting_pip_net->name != net_name);
|
||||||
|
|
||||||
if (ctx->getBoundPipNet(pip) == conflicting_pip_net)
|
if (ctx->getBoundPipNet(pip) == conflicting_pip_net)
|
||||||
ctx->unbindPip(pip);
|
ctx->unbindPip(pip);
|
||||||
|
|
||||||
if (!ctx->checkPipAvail(pip))
|
if (!ctx->checkPipAvail(pip))
|
||||||
ripup_net(ctx, conflicting_pip_net);
|
ripup_net(ctx, conflicting_pip_net->name);
|
||||||
|
|
||||||
rippedNets.insert(conflicting_pip_net);
|
rippedNets.insert(conflicting_pip_net->name);
|
||||||
scores.pipScores[visited[cursor].pip]++;
|
scores.pipScores[visited[cursor].pip]++;
|
||||||
scores.netPipScores[std::make_pair(net_name, visited[cursor].pip)]++;
|
scores.netPipScores[std::make_pair(net_name, visited[cursor].pip)]++;
|
||||||
scores.netPipScores[std::make_pair(conflicting_pip_net, visited[cursor].pip)]++;
|
scores.netPipScores[std::make_pair(conflicting_pip_net->name, visited[cursor].pip)]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK);
|
ctx->bindPip(visited[cursor].pip, ctx->nets.at(net_name).get(), STRENGTH_WEAK);
|
||||||
src_wires[cursor] = visited[cursor].delay;
|
src_wires[cursor] = visited[cursor].delay;
|
||||||
cursor = ctx->getPipSrcWire(visited[cursor].pip);
|
cursor = ctx->getPipSrcWire(visited[cursor].pip);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
|
* Copyright (C) 2018 Eddie Hung <eddieh@ece.ubc.ca>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -32,36 +33,42 @@ typedef std::map<int, unsigned> DelayFrequency;
|
|||||||
struct Timing
|
struct Timing
|
||||||
{
|
{
|
||||||
Context *ctx;
|
Context *ctx;
|
||||||
|
bool net_delays;
|
||||||
bool update;
|
bool update;
|
||||||
delay_t min_slack;
|
delay_t min_slack;
|
||||||
PortRefVector current_path;
|
PortRefVector current_path;
|
||||||
PortRefVector *crit_path;
|
PortRefVector *crit_path;
|
||||||
DelayFrequency *slack_histogram;
|
DelayFrequency *slack_histogram;
|
||||||
|
|
||||||
Timing(Context *ctx, bool update, PortRefVector *crit_path = nullptr, DelayFrequency *slack_histogram = nullptr)
|
Timing(Context *ctx, bool net_delays, bool update, PortRefVector *crit_path = nullptr,
|
||||||
: ctx(ctx), update(update), min_slack(1.0e12 / ctx->target_freq), crit_path(crit_path),
|
DelayFrequency *slack_histogram = nullptr)
|
||||||
slack_histogram(slack_histogram)
|
: ctx(ctx), net_delays(net_delays), update(update), min_slack(1.0e12 / ctx->target_freq),
|
||||||
|
crit_path(crit_path), slack_histogram(slack_histogram)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
delay_t follow_net(NetInfo *net, int path_length, delay_t slack)
|
delay_t follow_net(NetInfo *net, int path_length, delay_t slack)
|
||||||
{
|
{
|
||||||
delay_t net_budget = slack / (path_length + 1);
|
const delay_t default_budget = slack / (path_length + 1);
|
||||||
|
delay_t net_budget = default_budget;
|
||||||
for (auto &usr : net->users) {
|
for (auto &usr : net->users) {
|
||||||
|
auto delay = net_delays ? ctx->getNetinfoRouteDelay(net, usr) : delay_t();
|
||||||
if (crit_path)
|
if (crit_path)
|
||||||
current_path.push_back(&usr);
|
current_path.push_back(&usr);
|
||||||
// If budget override is less than existing budget, then do not increment
|
// If budget override exists, use that value and do not increment path_length
|
||||||
// path length
|
auto budget = default_budget;
|
||||||
int pl = path_length + 1;
|
if (ctx->getBudgetOverride(net, usr, budget)) {
|
||||||
auto budget = ctx->getBudgetOverride(net, usr, net_budget);
|
if (update)
|
||||||
if (budget < net_budget) {
|
usr.budget = std::min(usr.budget, budget);
|
||||||
net_budget = budget;
|
budget = follow_user_port(usr, path_length, slack - budget);
|
||||||
pl = std::max(1, path_length);
|
net_budget = std::min(net_budget, budget);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
budget = follow_user_port(usr, path_length + 1, slack - delay);
|
||||||
|
net_budget = std::min(net_budget, budget);
|
||||||
|
if (update)
|
||||||
|
usr.budget = std::min(usr.budget, delay + budget);
|
||||||
}
|
}
|
||||||
auto delay = ctx->getNetinfoRouteDelay(net, usr);
|
|
||||||
net_budget = std::min(net_budget, follow_user_port(usr, pl, slack - delay));
|
|
||||||
if (update)
|
|
||||||
usr.budget = std::min(usr.budget, delay + net_budget);
|
|
||||||
if (crit_path)
|
if (crit_path)
|
||||||
current_path.pop_back();
|
current_path.pop_back();
|
||||||
}
|
}
|
||||||
@ -149,10 +156,10 @@ void assign_budget(Context *ctx, bool quiet)
|
|||||||
{
|
{
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
log_break();
|
log_break();
|
||||||
log_info("Annotating ports with timing budgets for target frequency %.2f MHz\n", ctx->target_freq/1e6);
|
log_info("Annotating ports with timing budgets for target frequency %.2f MHz\n", ctx->target_freq / 1e6);
|
||||||
}
|
}
|
||||||
|
|
||||||
Timing timing(ctx, true /* update */);
|
Timing timing(ctx, ctx->slack_redist_iter > 0 /* net_delays */, true /* update */);
|
||||||
timing.assign_budget();
|
timing.assign_budget();
|
||||||
|
|
||||||
if (!quiet || ctx->verbose) {
|
if (!quiet || ctx->verbose) {
|
||||||
@ -194,7 +201,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_path)
|
|||||||
PortRefVector crit_path;
|
PortRefVector crit_path;
|
||||||
DelayFrequency slack_histogram;
|
DelayFrequency slack_histogram;
|
||||||
|
|
||||||
Timing timing(ctx, false /* update */, print_path ? &crit_path : nullptr,
|
Timing timing(ctx, true /* net_delays */, false /* update */, print_path ? &crit_path : nullptr,
|
||||||
print_histogram ? &slack_histogram : nullptr);
|
print_histogram ? &slack_histogram : nullptr);
|
||||||
auto min_slack = timing.walk_paths();
|
auto min_slack = timing.walk_paths();
|
||||||
|
|
||||||
@ -238,7 +245,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_path)
|
|||||||
delay_t default_slack = delay_t(1.0e12 / ctx->target_freq);
|
delay_t default_slack = delay_t(1.0e12 / ctx->target_freq);
|
||||||
log_info("estimated Fmax = %.2f MHz\n", 1e6 / (default_slack - min_slack));
|
log_info("estimated Fmax = %.2f MHz\n", 1e6 / (default_slack - min_slack));
|
||||||
|
|
||||||
if (print_histogram) {
|
if (print_histogram && slack_histogram.size() > 0) {
|
||||||
constexpr unsigned num_bins = 20;
|
constexpr unsigned num_bins = 20;
|
||||||
unsigned bar_width = 60;
|
unsigned bar_width = 60;
|
||||||
auto min_slack = slack_histogram.begin()->first;
|
auto min_slack = slack_histogram.begin()->first;
|
||||||
@ -256,9 +263,11 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_path)
|
|||||||
log_break();
|
log_break();
|
||||||
log_info("Slack histogram:\n");
|
log_info("Slack histogram:\n");
|
||||||
log_info(" legend: * represents %d endpoint(s)\n", max_freq / bar_width);
|
log_info(" legend: * represents %d endpoint(s)\n", max_freq / bar_width);
|
||||||
|
log_info(" + represents [1,%d) endpoint(s)\n", max_freq / bar_width);
|
||||||
for (unsigned i = 0; i < bins.size(); ++i)
|
for (unsigned i = 0; i < bins.size(); ++i)
|
||||||
log_info("%6d < ps < %6d |%s\n", min_slack + bin_size * i, min_slack + bin_size * (i + 1),
|
log_info("[%6d, %6d) |%s%c\n", min_slack + bin_size * i, min_slack + bin_size * (i + 1),
|
||||||
std::string(bins[i] * bar_width / max_freq, '*').c_str());
|
std::string(bins[i] * bar_width / max_freq, '*').c_str(),
|
||||||
|
(bins[i] * bar_width) % max_freq > 0 ? '+' : ' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,11 +139,11 @@ Returns true if the given bel is a global buffer. A global buffer does not "pull
|
|||||||
|
|
||||||
Return a (preferably unique) number that represents this bel. This is used in design state checksum calculations.
|
Return a (preferably unique) number that represents this bel. This is used in design state checksum calculations.
|
||||||
|
|
||||||
### void bindBel(BelId bel, IdString cell, PlaceStrength strength)
|
### void bindBel(BelId bel, CellInfo \*cell, PlaceStrength strength)
|
||||||
|
|
||||||
Bind a given bel to a given cell with the given strength.
|
Bind a given bel to a given cell with the given strength.
|
||||||
|
|
||||||
This method must also update `CellInfo::bel` and `CellInfo::belStrength`.
|
This method must also update `cell->bel` and `cell->belStrength`.
|
||||||
|
|
||||||
### void unbindBel(BelId bel)
|
### void unbindBel(BelId bel)
|
||||||
|
|
||||||
@ -155,13 +155,13 @@ This method must also update `CellInfo::bel` and `CellInfo::belStrength`.
|
|||||||
|
|
||||||
Returns true if the bel is available. A bel can be unavailable because it is bound, or because it is exclusive to some other resource that is bound.
|
Returns true if the bel is available. A bel can be unavailable because it is bound, or because it is exclusive to some other resource that is bound.
|
||||||
|
|
||||||
### IdString getBoundBelCell(BelId bel) const
|
### CellInfo \*getBoundBelCell(BelId bel) const
|
||||||
|
|
||||||
Return the cell the given bel is bound to, or `IdString()` if the bel is not bound.
|
Return the cell the given bel is bound to, or nullptr if the bel is not bound.
|
||||||
|
|
||||||
### IdString getConflictingBelCell(BelId bel) const
|
### CellInfo \*getConflictingBelCell(BelId bel) const
|
||||||
|
|
||||||
If the bel is unavailable, and unbinding a single cell would make it available, then this method must return the name of that cell.
|
If the bel is unavailable, and unbinding a single cell would make it available, then this method must return that cell.
|
||||||
|
|
||||||
### const\_range\<BelId\> getBels() const
|
### const\_range\<BelId\> getBels() const
|
||||||
|
|
||||||
@ -204,12 +204,12 @@ simply return `IdString()`.
|
|||||||
|
|
||||||
Return a (preferably unique) number that represents this wire. This is used in design state checksum calculations.
|
Return a (preferably unique) number that represents this wire. This is used in design state checksum calculations.
|
||||||
|
|
||||||
### void bindWire(WireId wire, IdString net, PlaceStrength strength)
|
### void bindWire(WireId wire, NetInfo \*net, PlaceStrength strength)
|
||||||
|
|
||||||
Bind a wire to a net. This method must be used when binding a wire that is driven by a bel pin. Use `binPip()`
|
Bind a wire to a net. This method must be used when binding a wire that is driven by a bel pin. Use `binPip()`
|
||||||
when binding a wire that is driven by a pip.
|
when binding a wire that is driven by a pip.
|
||||||
|
|
||||||
This method must also update `NetInfo::wires`.
|
This method must also update `net->wires`.
|
||||||
|
|
||||||
### void unbindWire(WireId wire)
|
### void unbindWire(WireId wire)
|
||||||
|
|
||||||
@ -221,16 +221,16 @@ This method must also update `NetInfo::wires`.
|
|||||||
|
|
||||||
Return true if the wire is available, i.e. can be bound to a net.
|
Return true if the wire is available, i.e. can be bound to a net.
|
||||||
|
|
||||||
### IdString getBoundWireNet(WireId wire) const
|
### NetInfo \*getBoundWireNet(WireId wire) const
|
||||||
|
|
||||||
Return the net a wire is bound to.
|
Return the net a wire is bound to.
|
||||||
|
|
||||||
### IdString getConflictingWireNet(WireId wire) const
|
### NetInfo \*getConflictingWireNet(WireId wire) const
|
||||||
|
|
||||||
If this returns a non-empty IdString, then unbinding that net
|
If this returns a non-nullptr, then unbinding that net
|
||||||
will make the given wire available.
|
will make the given wire available.
|
||||||
|
|
||||||
This returns an empty IdString if the wire is already available,
|
This returns nullptr if the wire is already available,
|
||||||
or if there is no single net that can be unbound to make this
|
or if there is no single net that can be unbound to make this
|
||||||
wire available.
|
wire available.
|
||||||
|
|
||||||
@ -266,11 +266,11 @@ implementations may simply return `IdString()`.
|
|||||||
|
|
||||||
Return a (preferably unique) number that represents this pip. This is used in design state checksum calculations.
|
Return a (preferably unique) number that represents this pip. This is used in design state checksum calculations.
|
||||||
|
|
||||||
### void bindPip(PipId pip, IdString net, PlaceStrength strength)
|
### void bindPip(PipId pip, NetInfo \*net, PlaceStrength strength)
|
||||||
|
|
||||||
Bid a pip to a net. This also bind the destination wire of that pip.
|
Bid a pip to a net. This also bind the destination wire of that pip.
|
||||||
|
|
||||||
This method must also update `NetInfo::wires`.
|
This method must also update `net->wires`.
|
||||||
|
|
||||||
### void unbindPip(PipId pip)
|
### void unbindPip(PipId pip)
|
||||||
|
|
||||||
@ -282,11 +282,11 @@ This method must also update `NetInfo::wires`.
|
|||||||
|
|
||||||
Returns true if the given pip is available to be bound to a net.
|
Returns true if the given pip is available to be bound to a net.
|
||||||
|
|
||||||
### IdString getBoundPipNet(PipId pip) const
|
### NetInfo \*getBoundPipNet(PipId pip) const
|
||||||
|
|
||||||
Return the net this pip is bound to.
|
Return the net this pip is bound to.
|
||||||
|
|
||||||
### IdString getConflictingPipNet(PipId pip) const
|
### NetInfo \*getConflictingPipNet(PipId pip) const
|
||||||
|
|
||||||
Return the net that needs to be unbound in order to make this
|
Return the net that needs to be unbound in order to make this
|
||||||
pip available.
|
pip available.
|
||||||
@ -402,9 +402,9 @@ Convert an `delay_t` to an actual real-world delay in nanoseconds.
|
|||||||
|
|
||||||
Convert a `delay_t` to an integer for checksum calculations.
|
Convert a `delay_t` to an integer for checksum calculations.
|
||||||
|
|
||||||
### delay\_t getBudgetOverride(const NetInfo \*net\_info, const PortRef &sink, delay\_t budget) const
|
### bool getBudgetOverride(const NetInfo \*net\_info, const PortRef &sink, delay\_t &budget) const
|
||||||
|
|
||||||
Overwrite or modify the timing budget for a given arc. Returns the new budget.
|
Overwrite or modify (in-place) the timing budget for a given arc. Returns a bool to indicate whether this was done.
|
||||||
|
|
||||||
Flow Methods
|
Flow Methods
|
||||||
------------
|
------------
|
||||||
|
@ -422,7 +422,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
|||||||
return 200 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y));
|
return 200 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
delay_t Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t budget) const { return budget; }
|
bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; }
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
@ -479,7 +479,7 @@ DecalXY Arch::getBelDecal(BelId bel) const
|
|||||||
decalxy.decal.type = DecalId::TYPE_BEL;
|
decalxy.decal.type = DecalId::TYPE_BEL;
|
||||||
decalxy.decal.location = bel.location;
|
decalxy.decal.location = bel.location;
|
||||||
decalxy.decal.z = bel.index;
|
decalxy.decal.z = bel.index;
|
||||||
decalxy.decal.active = bel_to_cell.count(bel) && (bel_to_cell.at(bel) != IdString());
|
decalxy.decal.active = bel_to_cell.count(bel) && (bel_to_cell.at(bel) != nullptr);
|
||||||
return decalxy;
|
return decalxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
91
ecp5/arch.h
91
ecp5/arch.h
@ -404,10 +404,9 @@ struct Arch : BaseCtx
|
|||||||
mutable std::unordered_map<IdString, WireId> wire_by_name;
|
mutable std::unordered_map<IdString, WireId> wire_by_name;
|
||||||
mutable std::unordered_map<IdString, PipId> pip_by_name;
|
mutable std::unordered_map<IdString, PipId> pip_by_name;
|
||||||
|
|
||||||
std::unordered_map<BelId, IdString> bel_to_cell;
|
std::unordered_map<BelId, CellInfo *> bel_to_cell;
|
||||||
std::unordered_map<WireId, IdString> wire_to_net;
|
std::unordered_map<WireId, NetInfo *> wire_to_net;
|
||||||
std::unordered_map<PipId, IdString> pip_to_net;
|
std::unordered_map<PipId, NetInfo *> pip_to_net;
|
||||||
std::unordered_map<PipId, IdString> switches_locked;
|
|
||||||
|
|
||||||
ArchArgs args;
|
ArchArgs args;
|
||||||
Arch(ArchArgs args);
|
Arch(ArchArgs args);
|
||||||
@ -448,23 +447,23 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
||||||
|
|
||||||
void bindBel(BelId bel, IdString cell, PlaceStrength strength)
|
void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
NPNR_ASSERT(bel_to_cell[bel] == IdString());
|
NPNR_ASSERT(bel_to_cell[bel] == nullptr);
|
||||||
bel_to_cell[bel] = cell;
|
bel_to_cell[bel] = cell;
|
||||||
cells[cell]->bel = bel;
|
cell->bel = bel;
|
||||||
cells[cell]->belStrength = strength;
|
cell->belStrength = strength;
|
||||||
refreshUiBel(bel);
|
refreshUiBel(bel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unbindBel(BelId bel)
|
void unbindBel(BelId bel)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
NPNR_ASSERT(bel_to_cell[bel] != IdString());
|
NPNR_ASSERT(bel_to_cell[bel] != nullptr);
|
||||||
cells[bel_to_cell[bel]]->bel = BelId();
|
bel_to_cell[bel]->bel = BelId();
|
||||||
cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE;
|
bel_to_cell[bel]->belStrength = STRENGTH_NONE;
|
||||||
bel_to_cell[bel] = IdString();
|
bel_to_cell[bel] = nullptr;
|
||||||
refreshUiBel(bel);
|
refreshUiBel(bel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,23 +484,23 @@ struct Arch : BaseCtx
|
|||||||
bool checkBelAvail(BelId bel) const
|
bool checkBelAvail(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == IdString();
|
return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getBoundBelCell(BelId bel) const
|
CellInfo *getBoundBelCell(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
if (bel_to_cell.find(bel) == bel_to_cell.end())
|
if (bel_to_cell.find(bel) == bel_to_cell.end())
|
||||||
return IdString();
|
return nullptr;
|
||||||
else
|
else
|
||||||
return bel_to_cell.at(bel);
|
return bel_to_cell.at(bel);
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getConflictingBelCell(BelId bel) const
|
CellInfo *getConflictingBelCell(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
if (bel_to_cell.find(bel) == bel_to_cell.end())
|
if (bel_to_cell.find(bel) == bel_to_cell.end())
|
||||||
return IdString();
|
return nullptr;
|
||||||
else
|
else
|
||||||
return bel_to_cell.at(bel);
|
return bel_to_cell.at(bel);
|
||||||
}
|
}
|
||||||
@ -558,53 +557,53 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
|
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
|
||||||
|
|
||||||
void bindWire(WireId wire, IdString net, PlaceStrength strength)
|
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
NPNR_ASSERT(wire_to_net[wire] == IdString());
|
NPNR_ASSERT(wire_to_net[wire] == nullptr);
|
||||||
wire_to_net[wire] = net;
|
wire_to_net[wire] = net;
|
||||||
nets[net]->wires[wire].pip = PipId();
|
net->wires[wire].pip = PipId();
|
||||||
nets[net]->wires[wire].strength = strength;
|
net->wires[wire].strength = strength;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unbindWire(WireId wire)
|
void unbindWire(WireId wire)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
NPNR_ASSERT(wire_to_net[wire] != IdString());
|
NPNR_ASSERT(wire_to_net[wire] != nullptr);
|
||||||
|
|
||||||
auto &net_wires = nets[wire_to_net[wire]]->wires;
|
auto &net_wires = wire_to_net[wire]->wires;
|
||||||
auto it = net_wires.find(wire);
|
auto it = net_wires.find(wire);
|
||||||
NPNR_ASSERT(it != net_wires.end());
|
NPNR_ASSERT(it != net_wires.end());
|
||||||
|
|
||||||
auto pip = it->second.pip;
|
auto pip = it->second.pip;
|
||||||
if (pip != PipId()) {
|
if (pip != PipId()) {
|
||||||
pip_to_net[pip] = IdString();
|
pip_to_net[pip] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_wires.erase(it);
|
net_wires.erase(it);
|
||||||
wire_to_net[wire] = IdString();
|
wire_to_net[wire] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkWireAvail(WireId wire) const
|
bool checkWireAvail(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == IdString();
|
return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getBoundWireNet(WireId wire) const
|
NetInfo *getBoundWireNet(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
if (wire_to_net.find(wire) == wire_to_net.end())
|
if (wire_to_net.find(wire) == wire_to_net.end())
|
||||||
return IdString();
|
return nullptr;
|
||||||
else
|
else
|
||||||
return wire_to_net.at(wire);
|
return wire_to_net.at(wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getConflictingWireNet(WireId wire) const
|
NetInfo *getConflictingWireNet(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
if (wire_to_net.find(wire) == wire_to_net.end())
|
if (wire_to_net.find(wire) == wire_to_net.end())
|
||||||
return IdString();
|
return nullptr;
|
||||||
else
|
else
|
||||||
return wire_to_net.at(wire);
|
return wire_to_net.at(wire);
|
||||||
}
|
}
|
||||||
@ -638,57 +637,57 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
uint32_t getPipChecksum(PipId pip) const { return pip.index; }
|
uint32_t getPipChecksum(PipId pip) const { return pip.index; }
|
||||||
|
|
||||||
void bindPip(PipId pip, IdString net, PlaceStrength strength)
|
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
NPNR_ASSERT(pip_to_net[pip] == IdString());
|
NPNR_ASSERT(pip_to_net[pip] == nullptr);
|
||||||
|
|
||||||
pip_to_net[pip] = net;
|
pip_to_net[pip] = net;
|
||||||
|
|
||||||
WireId dst;
|
WireId dst;
|
||||||
dst.index = locInfo(pip)->pip_data[pip.index].dst_idx;
|
dst.index = locInfo(pip)->pip_data[pip.index].dst_idx;
|
||||||
dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc;
|
dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc;
|
||||||
NPNR_ASSERT(wire_to_net[dst] == IdString());
|
NPNR_ASSERT(wire_to_net[dst] == nullptr);
|
||||||
wire_to_net[dst] = net;
|
wire_to_net[dst] = net;
|
||||||
nets[net]->wires[dst].pip = pip;
|
net->wires[dst].pip = pip;
|
||||||
nets[net]->wires[dst].strength = strength;
|
net->wires[dst].strength = strength;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unbindPip(PipId pip)
|
void unbindPip(PipId pip)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
NPNR_ASSERT(pip_to_net[pip] != IdString());
|
NPNR_ASSERT(pip_to_net[pip] != nullptr);
|
||||||
|
|
||||||
WireId dst;
|
WireId dst;
|
||||||
dst.index = locInfo(pip)->pip_data[pip.index].dst_idx;
|
dst.index = locInfo(pip)->pip_data[pip.index].dst_idx;
|
||||||
dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc;
|
dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc;
|
||||||
NPNR_ASSERT(wire_to_net[dst] != IdString());
|
NPNR_ASSERT(wire_to_net[dst] != nullptr);
|
||||||
wire_to_net[dst] = IdString();
|
wire_to_net[dst] = nullptr;
|
||||||
nets[pip_to_net[pip]]->wires.erase(dst);
|
pip_to_net[pip]->wires.erase(dst);
|
||||||
|
|
||||||
pip_to_net[pip] = IdString();
|
pip_to_net[pip] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkPipAvail(PipId pip) const
|
bool checkPipAvail(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == IdString();
|
return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getBoundPipNet(PipId pip) const
|
NetInfo *getBoundPipNet(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
if (pip_to_net.find(pip) == pip_to_net.end())
|
if (pip_to_net.find(pip) == pip_to_net.end())
|
||||||
return IdString();
|
return nullptr;
|
||||||
else
|
else
|
||||||
return pip_to_net.at(pip);
|
return pip_to_net.at(pip);
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getConflictingPipNet(PipId pip) const
|
NetInfo *getConflictingPipNet(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
if (pip_to_net.find(pip) == pip_to_net.end())
|
if (pip_to_net.find(pip) == pip_to_net.end())
|
||||||
return IdString();
|
return nullptr;
|
||||||
else
|
else
|
||||||
return pip_to_net.at(pip);
|
return pip_to_net.at(pip);
|
||||||
}
|
}
|
||||||
@ -807,7 +806,7 @@ struct Arch : BaseCtx
|
|||||||
delay_t getRipupDelayPenalty() const { return 200; }
|
delay_t getRipupDelayPenalty() const { return 200; }
|
||||||
float getDelayNS(delay_t v) const { return v * 0.001; }
|
float getDelayNS(delay_t v) const { return v * 0.001; }
|
||||||
uint32_t getDelayChecksum(delay_t v) const { return v; }
|
uint32_t getDelayChecksum(delay_t v) const { return v; }
|
||||||
delay_t getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t budget) const;
|
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const;
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
|
@ -68,19 +68,18 @@ bool Arch::isBelLocationValid(BelId bel) const
|
|||||||
std::vector<const CellInfo *> bel_cells;
|
std::vector<const CellInfo *> bel_cells;
|
||||||
Loc bel_loc = getBelLocation(bel);
|
Loc bel_loc = getBelLocation(bel);
|
||||||
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
||||||
IdString cell_other = getBoundBelCell(bel_other);
|
CellInfo *cell_other = getBoundBelCell(bel_other);
|
||||||
if (cell_other != IdString()) {
|
if (cell_other != nullptr) {
|
||||||
const CellInfo *ci_other = cells.at(cell_other).get();
|
bel_cells.push_back(cell_other);
|
||||||
bel_cells.push_back(ci_other);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return slicesCompatible(bel_cells);
|
return slicesCompatible(bel_cells);
|
||||||
} else {
|
} else {
|
||||||
IdString cellId = getBoundBelCell(bel);
|
CellInfo *cell = getBoundBelCell(bel);
|
||||||
if (cellId == IdString())
|
if (cell == nullptr)
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return isValidBelForCell(cells.at(cellId).get(), bel);
|
return isValidBelForCell(cell, bel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,10 +91,9 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
|||||||
std::vector<const CellInfo *> bel_cells;
|
std::vector<const CellInfo *> bel_cells;
|
||||||
Loc bel_loc = getBelLocation(bel);
|
Loc bel_loc = getBelLocation(bel);
|
||||||
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
||||||
IdString cell_other = getBoundBelCell(bel_other);
|
CellInfo *cell_other = getBoundBelCell(bel_other);
|
||||||
if (cell_other != IdString() && bel_other != bel) {
|
if (cell_other != nullptr && bel_other != bel) {
|
||||||
const CellInfo *ci_other = cells.at(cell_other).get();
|
bel_cells.push_back(cell_other);
|
||||||
bel_cells.push_back(ci_other);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,13 +60,13 @@ void arch_wrap_python()
|
|||||||
fn_wrapper_1a<Context, decltype(&Context::getBelChecksum), &Context::getBelChecksum, pass_through<uint32_t>,
|
fn_wrapper_1a<Context, decltype(&Context::getBelChecksum), &Context::getBelChecksum, pass_through<uint32_t>,
|
||||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelChecksum");
|
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelChecksum");
|
||||||
fn_wrapper_3a_v<Context, decltype(&Context::bindBel), &Context::bindBel, conv_from_str<BelId>,
|
fn_wrapper_3a_v<Context, decltype(&Context::bindBel), &Context::bindBel, conv_from_str<BelId>,
|
||||||
conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindBel");
|
addr_and_unwrap<CellInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindBel");
|
||||||
fn_wrapper_1a_v<Context, decltype(&Context::unbindBel), &Context::unbindBel, conv_from_str<BelId>>::def_wrap(
|
fn_wrapper_1a_v<Context, decltype(&Context::unbindBel), &Context::unbindBel, conv_from_str<BelId>>::def_wrap(
|
||||||
ctx_cls, "unbindBel");
|
ctx_cls, "unbindBel");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getBoundBelCell), &Context::getBoundBelCell, conv_to_str<IdString>,
|
fn_wrapper_1a<Context, decltype(&Context::getBoundBelCell), &Context::getBoundBelCell, deref_and_wrap<CellInfo>,
|
||||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBoundBelCell");
|
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBoundBelCell");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getConflictingBelCell), &Context::getConflictingBelCell,
|
fn_wrapper_1a<Context, decltype(&Context::getConflictingBelCell), &Context::getConflictingBelCell,
|
||||||
conv_to_str<IdString>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getConflictingBelCell");
|
deref_and_wrap<CellInfo>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getConflictingBelCell");
|
||||||
fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels, wrap_context<BelRange>>::def_wrap(ctx_cls,
|
fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels, wrap_context<BelRange>>::def_wrap(ctx_cls,
|
||||||
"getBels");
|
"getBels");
|
||||||
|
|
||||||
@ -78,15 +78,15 @@ void arch_wrap_python()
|
|||||||
fn_wrapper_1a<Context, decltype(&Context::getWireChecksum), &Context::getWireChecksum, pass_through<uint32_t>,
|
fn_wrapper_1a<Context, decltype(&Context::getWireChecksum), &Context::getWireChecksum, pass_through<uint32_t>,
|
||||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireChecksum");
|
conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireChecksum");
|
||||||
fn_wrapper_3a_v<Context, decltype(&Context::bindWire), &Context::bindWire, conv_from_str<WireId>,
|
fn_wrapper_3a_v<Context, decltype(&Context::bindWire), &Context::bindWire, conv_from_str<WireId>,
|
||||||
conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindWire");
|
addr_and_unwrap<NetInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindWire");
|
||||||
fn_wrapper_1a_v<Context, decltype(&Context::unbindWire), &Context::unbindWire, conv_from_str<WireId>>::def_wrap(
|
fn_wrapper_1a_v<Context, decltype(&Context::unbindWire), &Context::unbindWire, conv_from_str<WireId>>::def_wrap(
|
||||||
ctx_cls, "unbindWire");
|
ctx_cls, "unbindWire");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::checkWireAvail), &Context::checkWireAvail, pass_through<bool>,
|
fn_wrapper_1a<Context, decltype(&Context::checkWireAvail), &Context::checkWireAvail, pass_through<bool>,
|
||||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "checkWireAvail");
|
conv_from_str<WireId>>::def_wrap(ctx_cls, "checkWireAvail");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getBoundWireNet), &Context::getBoundWireNet, conv_to_str<IdString>,
|
fn_wrapper_1a<Context, decltype(&Context::getBoundWireNet), &Context::getBoundWireNet, deref_and_wrap<NetInfo>,
|
||||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "getBoundWireNet");
|
conv_from_str<WireId>>::def_wrap(ctx_cls, "getBoundWireNet");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getConflictingWireNet), &Context::getConflictingWireNet,
|
fn_wrapper_1a<Context, decltype(&Context::getConflictingWireNet), &Context::getConflictingWireNet,
|
||||||
conv_to_str<IdString>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getConflictingWireNet");
|
deref_and_wrap<NetInfo>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getConflictingWireNet");
|
||||||
|
|
||||||
fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires, wrap_context<WireRange>>::def_wrap(
|
fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires, wrap_context<WireRange>>::def_wrap(
|
||||||
ctx_cls, "getWires");
|
ctx_cls, "getWires");
|
||||||
@ -96,15 +96,15 @@ void arch_wrap_python()
|
|||||||
fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>,
|
fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum");
|
||||||
fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>,
|
fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>,
|
||||||
conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindPip");
|
addr_and_unwrap<NetInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindPip");
|
||||||
fn_wrapper_1a_v<Context, decltype(&Context::unbindPip), &Context::unbindPip, conv_from_str<PipId>>::def_wrap(
|
fn_wrapper_1a_v<Context, decltype(&Context::unbindPip), &Context::unbindPip, conv_from_str<PipId>>::def_wrap(
|
||||||
ctx_cls, "unbindPip");
|
ctx_cls, "unbindPip");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::checkPipAvail), &Context::checkPipAvail, pass_through<bool>,
|
fn_wrapper_1a<Context, decltype(&Context::checkPipAvail), &Context::checkPipAvail, pass_through<bool>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "checkPipAvail");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "checkPipAvail");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getBoundPipNet), &Context::getBoundPipNet, conv_to_str<IdString>,
|
fn_wrapper_1a<Context, decltype(&Context::getBoundPipNet), &Context::getBoundPipNet, deref_and_wrap<NetInfo>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getBoundPipNet");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getBoundPipNet");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getConflictingPipNet), &Context::getConflictingPipNet,
|
fn_wrapper_1a<Context, decltype(&Context::getConflictingPipNet), &Context::getConflictingPipNet,
|
||||||
conv_to_str<IdString>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getConflictingPipNet");
|
deref_and_wrap<NetInfo>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getConflictingPipNet");
|
||||||
|
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getPipsDownhill), &Context::getPipsDownhill, wrap_context<PipRange>,
|
fn_wrapper_1a<Context, decltype(&Context::getPipsDownhill), &Context::getPipsDownhill, wrap_context<PipRange>,
|
||||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "getPipsDownhill");
|
conv_from_str<WireId>>::def_wrap(ctx_cls, "getPipsDownhill");
|
||||||
|
@ -163,7 +163,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
|
|
||||||
// Add all set, configurable pips to the config
|
// Add all set, configurable pips to the config
|
||||||
for (auto pip : ctx->getPips()) {
|
for (auto pip : ctx->getPips()) {
|
||||||
if (ctx->getBoundPipNet(pip) != IdString()) {
|
if (ctx->getBoundPipNet(pip) != nullptr) {
|
||||||
if (ctx->getPipClass(pip) == 0) { // ignore fixed pips
|
if (ctx->getPipClass(pip) == 0) { // ignore fixed pips
|
||||||
std::string tile = ctx->getPipTilename(pip);
|
std::string tile = ctx->getPipTilename(pip);
|
||||||
std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip));
|
std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip));
|
||||||
@ -244,9 +244,9 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
cc.tiles[tname].add_enum(slice + ".REG1.REGSET",
|
cc.tiles[tname].add_enum(slice + ".REG1.REGSET",
|
||||||
str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET"));
|
str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET"));
|
||||||
cc.tiles[tname].add_enum(slice + ".CEMUX", str_or_default(ci->params, ctx->id("CEMUX"), "1"));
|
cc.tiles[tname].add_enum(slice + ".CEMUX", str_or_default(ci->params, ctx->id("CEMUX"), "1"));
|
||||||
IdString lsrnet;
|
NetInfo *lsrnet = nullptr;
|
||||||
if (ci->ports.find(ctx->id("LSR")) != ci->ports.end() && ci->ports.at(ctx->id("LSR")).net != nullptr)
|
if (ci->ports.find(ctx->id("LSR")) != ci->ports.end() && ci->ports.at(ctx->id("LSR")).net != nullptr)
|
||||||
lsrnet = ci->ports.at(ctx->id("LSR")).net->name;
|
lsrnet = ci->ports.at(ctx->id("LSR")).net;
|
||||||
if (ctx->getBoundWireNet(ctx->getWireByName(
|
if (ctx->getBoundWireNet(ctx->getWireByName(
|
||||||
ctx->id(fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/LSR0")))) == lsrnet) {
|
ctx->id(fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/LSR0")))) == lsrnet) {
|
||||||
cc.tiles[tname].add_enum("LSR0.SRMODE", str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE"));
|
cc.tiles[tname].add_enum("LSR0.SRMODE", str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE"));
|
||||||
|
@ -214,27 +214,27 @@ uint32_t Arch::getBelChecksum(BelId bel) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength)
|
void Arch::bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
bels.at(bel).bound_cell = cell;
|
bels.at(bel).bound_cell = cell;
|
||||||
cells.at(cell)->bel = bel;
|
cell->bel = bel;
|
||||||
cells.at(cell)->belStrength = strength;
|
cell->belStrength = strength;
|
||||||
refreshUiBel(bel);
|
refreshUiBel(bel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::unbindBel(BelId bel)
|
void Arch::unbindBel(BelId bel)
|
||||||
{
|
{
|
||||||
cells.at(bels.at(bel).bound_cell)->bel = BelId();
|
bels.at(bel).bound_cell->bel = BelId();
|
||||||
cells.at(bels.at(bel).bound_cell)->belStrength = STRENGTH_NONE;
|
bels.at(bel).bound_cell->belStrength = STRENGTH_NONE;
|
||||||
bels.at(bel).bound_cell = IdString();
|
bels.at(bel).bound_cell = nullptr;
|
||||||
refreshUiBel(bel);
|
refreshUiBel(bel);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arch::checkBelAvail(BelId bel) const { return bels.at(bel).bound_cell == IdString(); }
|
bool Arch::checkBelAvail(BelId bel) const { return bels.at(bel).bound_cell == nullptr; }
|
||||||
|
|
||||||
IdString Arch::getBoundBelCell(BelId bel) const { return bels.at(bel).bound_cell; }
|
CellInfo *Arch::getBoundBelCell(BelId bel) const { return bels.at(bel).bound_cell; }
|
||||||
|
|
||||||
IdString Arch::getConflictingBelCell(BelId bel) const { return bels.at(bel).bound_cell; }
|
CellInfo *Arch::getConflictingBelCell(BelId bel) const { return bels.at(bel).bound_cell; }
|
||||||
|
|
||||||
const std::vector<BelId> &Arch::getBels() const { return bel_ids; }
|
const std::vector<BelId> &Arch::getBels() const { return bel_ids; }
|
||||||
|
|
||||||
@ -271,34 +271,34 @@ uint32_t Arch::getWireChecksum(WireId wire) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength)
|
void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
wires.at(wire).bound_net = net;
|
wires.at(wire).bound_net = net;
|
||||||
nets.at(net)->wires[wire].pip = PipId();
|
net->wires[wire].pip = PipId();
|
||||||
nets.at(net)->wires[wire].strength = strength;
|
net->wires[wire].strength = strength;
|
||||||
refreshUiWire(wire);
|
refreshUiWire(wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::unbindWire(WireId wire)
|
void Arch::unbindWire(WireId wire)
|
||||||
{
|
{
|
||||||
auto &net_wires = nets[wires.at(wire).bound_net]->wires;
|
auto &net_wires = wires.at(wire).bound_net->wires;
|
||||||
|
|
||||||
auto pip = net_wires.at(wire).pip;
|
auto pip = net_wires.at(wire).pip;
|
||||||
if (pip != PipId()) {
|
if (pip != PipId()) {
|
||||||
pips.at(pip).bound_net = IdString();
|
pips.at(pip).bound_net = nullptr;
|
||||||
refreshUiPip(pip);
|
refreshUiPip(pip);
|
||||||
}
|
}
|
||||||
|
|
||||||
net_wires.erase(wire);
|
net_wires.erase(wire);
|
||||||
wires.at(wire).bound_net = IdString();
|
wires.at(wire).bound_net = nullptr;
|
||||||
refreshUiWire(wire);
|
refreshUiWire(wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arch::checkWireAvail(WireId wire) const { return wires.at(wire).bound_net == IdString(); }
|
bool Arch::checkWireAvail(WireId wire) const { return wires.at(wire).bound_net == nullptr; }
|
||||||
|
|
||||||
IdString Arch::getBoundWireNet(WireId wire) const { return wires.at(wire).bound_net; }
|
NetInfo *Arch::getBoundWireNet(WireId wire) const { return wires.at(wire).bound_net; }
|
||||||
|
|
||||||
IdString Arch::getConflictingWireNet(WireId wire) const { return wires.at(wire).bound_net; }
|
NetInfo *Arch::getConflictingWireNet(WireId wire) const { return wires.at(wire).bound_net; }
|
||||||
|
|
||||||
const std::vector<BelPin> &Arch::getWireBelPins(WireId wire) const { return wires.at(wire).bel_pins; }
|
const std::vector<BelPin> &Arch::getWireBelPins(WireId wire) const { return wires.at(wire).bel_pins; }
|
||||||
|
|
||||||
@ -323,13 +323,13 @@ uint32_t Arch::getPipChecksum(PipId wire) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength)
|
void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
WireId wire = pips.at(pip).dstWire;
|
WireId wire = pips.at(pip).dstWire;
|
||||||
pips.at(pip).bound_net = net;
|
pips.at(pip).bound_net = net;
|
||||||
wires.at(wire).bound_net = net;
|
wires.at(wire).bound_net = net;
|
||||||
nets.at(net)->wires[wire].pip = pip;
|
net->wires[wire].pip = pip;
|
||||||
nets.at(net)->wires[wire].strength = strength;
|
net->wires[wire].strength = strength;
|
||||||
refreshUiPip(pip);
|
refreshUiPip(pip);
|
||||||
refreshUiWire(wire);
|
refreshUiWire(wire);
|
||||||
}
|
}
|
||||||
@ -337,18 +337,18 @@ void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength)
|
|||||||
void Arch::unbindPip(PipId pip)
|
void Arch::unbindPip(PipId pip)
|
||||||
{
|
{
|
||||||
WireId wire = pips.at(pip).dstWire;
|
WireId wire = pips.at(pip).dstWire;
|
||||||
nets.at(wires.at(wire).bound_net)->wires.erase(wire);
|
wires.at(wire).bound_net->wires.erase(wire);
|
||||||
pips.at(pip).bound_net = IdString();
|
pips.at(pip).bound_net = nullptr;
|
||||||
wires.at(wire).bound_net = IdString();
|
wires.at(wire).bound_net = nullptr;
|
||||||
refreshUiPip(pip);
|
refreshUiPip(pip);
|
||||||
refreshUiWire(wire);
|
refreshUiWire(wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arch::checkPipAvail(PipId pip) const { return pips.at(pip).bound_net == IdString(); }
|
bool Arch::checkPipAvail(PipId pip) const { return pips.at(pip).bound_net == nullptr; }
|
||||||
|
|
||||||
IdString Arch::getBoundPipNet(PipId pip) const { return pips.at(pip).bound_net; }
|
NetInfo *Arch::getBoundPipNet(PipId pip) const { return pips.at(pip).bound_net; }
|
||||||
|
|
||||||
IdString Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; }
|
NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; }
|
||||||
|
|
||||||
const std::vector<PipId> &Arch::getPips() const { return pip_ids; }
|
const std::vector<PipId> &Arch::getPips() const { return pip_ids; }
|
||||||
|
|
||||||
@ -408,7 +408,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
|||||||
return (dx + dy) * grid_distance_to_delay;
|
return (dx + dy) * grid_distance_to_delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
delay_t Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t budget) const { return budget; }
|
bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; }
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@ struct WireInfo;
|
|||||||
|
|
||||||
struct PipInfo
|
struct PipInfo
|
||||||
{
|
{
|
||||||
IdString name, type, bound_net;
|
IdString name, type;
|
||||||
|
NetInfo *bound_net;
|
||||||
WireId srcWire, dstWire;
|
WireId srcWire, dstWire;
|
||||||
DelayInfo delay;
|
DelayInfo delay;
|
||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
@ -39,7 +40,8 @@ struct PipInfo
|
|||||||
|
|
||||||
struct WireInfo
|
struct WireInfo
|
||||||
{
|
{
|
||||||
IdString name, type, bound_net;
|
IdString name, type;
|
||||||
|
NetInfo *bound_net;
|
||||||
std::vector<PipId> downhill, uphill, aliases;
|
std::vector<PipId> downhill, uphill, aliases;
|
||||||
BelPin uphill_bel_pin;
|
BelPin uphill_bel_pin;
|
||||||
std::vector<BelPin> downhill_bel_pins;
|
std::vector<BelPin> downhill_bel_pins;
|
||||||
@ -57,7 +59,8 @@ struct PinInfo
|
|||||||
|
|
||||||
struct BelInfo
|
struct BelInfo
|
||||||
{
|
{
|
||||||
IdString name, type, bound_cell;
|
IdString name, type;
|
||||||
|
CellInfo *bound_cell;
|
||||||
std::unordered_map<IdString, PinInfo> pins;
|
std::unordered_map<IdString, PinInfo> pins;
|
||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
@ -144,11 +147,11 @@ struct Arch : BaseCtx
|
|||||||
const std::vector<BelId> &getBelsByTile(int x, int y) const;
|
const std::vector<BelId> &getBelsByTile(int x, int y) const;
|
||||||
bool getBelGlobalBuf(BelId bel) const;
|
bool getBelGlobalBuf(BelId bel) const;
|
||||||
uint32_t getBelChecksum(BelId bel) const;
|
uint32_t getBelChecksum(BelId bel) const;
|
||||||
void bindBel(BelId bel, IdString cell, PlaceStrength strength);
|
void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength);
|
||||||
void unbindBel(BelId bel);
|
void unbindBel(BelId bel);
|
||||||
bool checkBelAvail(BelId bel) const;
|
bool checkBelAvail(BelId bel) const;
|
||||||
IdString getBoundBelCell(BelId bel) const;
|
CellInfo *getBoundBelCell(BelId bel) const;
|
||||||
IdString getConflictingBelCell(BelId bel) const;
|
CellInfo *getConflictingBelCell(BelId bel) const;
|
||||||
const std::vector<BelId> &getBels() const;
|
const std::vector<BelId> &getBels() const;
|
||||||
BelType getBelType(BelId bel) const;
|
BelType getBelType(BelId bel) const;
|
||||||
WireId getBelPinWire(BelId bel, PortPin pin) const;
|
WireId getBelPinWire(BelId bel, PortPin pin) const;
|
||||||
@ -159,11 +162,11 @@ struct Arch : BaseCtx
|
|||||||
IdString getWireName(WireId wire) const;
|
IdString getWireName(WireId wire) const;
|
||||||
IdString getWireType(WireId wire) const;
|
IdString getWireType(WireId wire) const;
|
||||||
uint32_t getWireChecksum(WireId wire) const;
|
uint32_t getWireChecksum(WireId wire) const;
|
||||||
void bindWire(WireId wire, IdString net, PlaceStrength strength);
|
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength);
|
||||||
void unbindWire(WireId wire);
|
void unbindWire(WireId wire);
|
||||||
bool checkWireAvail(WireId wire) const;
|
bool checkWireAvail(WireId wire) const;
|
||||||
IdString getBoundWireNet(WireId wire) const;
|
NetInfo *getBoundWireNet(WireId wire) const;
|
||||||
IdString getConflictingWireNet(WireId wire) const;
|
NetInfo *getConflictingWireNet(WireId wire) const;
|
||||||
DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); }
|
DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); }
|
||||||
const std::vector<WireId> &getWires() const;
|
const std::vector<WireId> &getWires() const;
|
||||||
const std::vector<BelPin> &getWireBelPins(WireId wire) const;
|
const std::vector<BelPin> &getWireBelPins(WireId wire) const;
|
||||||
@ -172,11 +175,11 @@ struct Arch : BaseCtx
|
|||||||
IdString getPipName(PipId pip) const;
|
IdString getPipName(PipId pip) const;
|
||||||
IdString getPipType(PipId pip) const;
|
IdString getPipType(PipId pip) const;
|
||||||
uint32_t getPipChecksum(PipId pip) const;
|
uint32_t getPipChecksum(PipId pip) const;
|
||||||
void bindPip(PipId pip, IdString net, PlaceStrength strength);
|
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength);
|
||||||
void unbindPip(PipId pip);
|
void unbindPip(PipId pip);
|
||||||
bool checkPipAvail(PipId pip) const;
|
bool checkPipAvail(PipId pip) const;
|
||||||
IdString getBoundPipNet(PipId pip) const;
|
NetInfo *getBoundPipNet(PipId pip) const;
|
||||||
IdString getConflictingPipNet(PipId pip) const;
|
NetInfo *getConflictingPipNet(PipId pip) const;
|
||||||
const std::vector<PipId> &getPips() const;
|
const std::vector<PipId> &getPips() const;
|
||||||
WireId getPipSrcWire(PipId pip) const;
|
WireId getPipSrcWire(PipId pip) const;
|
||||||
WireId getPipDstWire(PipId pip) const;
|
WireId getPipDstWire(PipId pip) const;
|
||||||
@ -199,7 +202,7 @@ struct Arch : BaseCtx
|
|||||||
delay_t getRipupDelayPenalty() const { return 1.0; }
|
delay_t getRipupDelayPenalty() const { return 1.0; }
|
||||||
float getDelayNS(delay_t v) const { return v; }
|
float getDelayNS(delay_t v) const { return v; }
|
||||||
uint32_t getDelayChecksum(delay_t v) const { return 0; }
|
uint32_t getDelayChecksum(delay_t v) const { return 0; }
|
||||||
delay_t getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t budget) const;
|
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const;
|
||||||
|
|
||||||
bool pack() { return true; }
|
bool pack() { return true; }
|
||||||
bool place();
|
bool place();
|
||||||
|
@ -407,8 +407,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
|||||||
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
|
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
|
||||||
addProperty(topItem, QVariant::String, "Type", ctx->belTypeToId(ctx->getBelType(bel)).c_str(ctx));
|
addProperty(topItem, QVariant::String, "Type", ctx->belTypeToId(ctx->getBelType(bel)).c_str(ctx));
|
||||||
addProperty(topItem, QVariant::Bool, "Available", ctx->checkBelAvail(bel));
|
addProperty(topItem, QVariant::Bool, "Available", ctx->checkBelAvail(bel));
|
||||||
addProperty(topItem, QVariant::String, "Bound Cell", ctx->getBoundBelCell(bel).c_str(ctx), ElementType::CELL);
|
addProperty(topItem, QVariant::String, "Bound Cell", ctx->nameOf(ctx->getBoundBelCell(bel)), ElementType::CELL);
|
||||||
addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->getConflictingBelCell(bel).c_str(ctx),
|
addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->nameOf(ctx->getConflictingBelCell(bel)),
|
||||||
ElementType::CELL);
|
ElementType::CELL);
|
||||||
|
|
||||||
QtProperty *belpinsItem = addSubGroup(topItem, "Ports");
|
QtProperty *belpinsItem = addSubGroup(topItem, "Ports");
|
||||||
@ -429,8 +429,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
|||||||
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
|
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
|
||||||
addProperty(topItem, QVariant::String, "Type", ctx->getWireType(wire).c_str(ctx));
|
addProperty(topItem, QVariant::String, "Type", ctx->getWireType(wire).c_str(ctx));
|
||||||
addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire));
|
addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire));
|
||||||
addProperty(topItem, QVariant::String, "Bound Net", ctx->getBoundWireNet(wire).c_str(ctx), ElementType::NET);
|
addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundWireNet(wire)), ElementType::NET);
|
||||||
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingWireNet(wire).c_str(ctx),
|
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)),
|
||||||
ElementType::NET);
|
ElementType::NET);
|
||||||
|
|
||||||
DelayInfo delay = ctx->getWireDelay(wire);
|
DelayInfo delay = ctx->getWireDelay(wire);
|
||||||
@ -484,8 +484,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
|||||||
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
|
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
|
||||||
addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx));
|
addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx));
|
||||||
addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip));
|
addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip));
|
||||||
addProperty(topItem, QVariant::String, "Bound Net", ctx->getBoundPipNet(pip).c_str(ctx), ElementType::NET);
|
addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET);
|
||||||
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingPipNet(pip).c_str(ctx),
|
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)),
|
||||||
ElementType::NET);
|
ElementType::NET);
|
||||||
addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx),
|
addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx),
|
||||||
ElementType::WIRE);
|
ElementType::WIRE);
|
||||||
|
@ -637,17 +637,34 @@ std::vector<GroupId> Arch::getGroupGroups(GroupId group) const
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
delay_t Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t budget) const
|
bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const
|
||||||
{
|
{
|
||||||
const auto &driver = net_info->driver;
|
const auto &driver = net_info->driver;
|
||||||
if (driver.port == id_cout) {
|
if (driver.port == id_cout && sink.port == id_cin) {
|
||||||
auto driver_loc = getBelLocation(driver.cell->bel);
|
auto driver_loc = getBelLocation(driver.cell->bel);
|
||||||
auto sink_loc = getBelLocation(sink.cell->bel);
|
auto sink_loc = getBelLocation(sink.cell->bel);
|
||||||
if (driver_loc.y == sink_loc.y)
|
if (driver_loc.y == sink_loc.y)
|
||||||
return 0;
|
budget = 0;
|
||||||
return 250;
|
else switch (args.type) {
|
||||||
|
#ifndef ICE40_HX1K_ONLY
|
||||||
|
case ArchArgs::HX8K:
|
||||||
|
#endif
|
||||||
|
case ArchArgs::HX1K:
|
||||||
|
budget = 190; break;
|
||||||
|
#ifndef ICE40_HX1K_ONLY
|
||||||
|
case ArchArgs::LP384:
|
||||||
|
case ArchArgs::LP1K:
|
||||||
|
case ArchArgs::LP8K:
|
||||||
|
budget = 290; break;
|
||||||
|
case ArchArgs::UP5K:
|
||||||
|
budget = 560; break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
log_error("Unsupported iCE40 chip type.\n");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return budget;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
@ -672,7 +689,7 @@ DecalXY Arch::getBelDecal(BelId bel) const
|
|||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
decalxy.decal.type = DecalId::TYPE_BEL;
|
decalxy.decal.type = DecalId::TYPE_BEL;
|
||||||
decalxy.decal.index = bel.index;
|
decalxy.decal.index = bel.index;
|
||||||
decalxy.decal.active = bel_to_cell.at(bel.index) != IdString();
|
decalxy.decal.active = bel_to_cell.at(bel.index) != nullptr;
|
||||||
return decalxy;
|
return decalxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,7 +698,7 @@ DecalXY Arch::getWireDecal(WireId wire) const
|
|||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
decalxy.decal.type = DecalId::TYPE_WIRE;
|
decalxy.decal.type = DecalId::TYPE_WIRE;
|
||||||
decalxy.decal.index = wire.index;
|
decalxy.decal.index = wire.index;
|
||||||
decalxy.decal.active = wire_to_net.at(wire.index) != IdString();
|
decalxy.decal.active = wire_to_net.at(wire.index) != nullptr;
|
||||||
return decalxy;
|
return decalxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,7 +707,7 @@ DecalXY Arch::getPipDecal(PipId pip) const
|
|||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
decalxy.decal.type = DecalId::TYPE_PIP;
|
decalxy.decal.type = DecalId::TYPE_PIP;
|
||||||
decalxy.decal.index = pip.index;
|
decalxy.decal.index = pip.index;
|
||||||
decalxy.decal.active = pip_to_net.at(pip.index) != IdString();
|
decalxy.decal.active = pip_to_net.at(pip.index) != nullptr;
|
||||||
return decalxy;
|
return decalxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
93
ice40/arch.h
93
ice40/arch.h
@ -400,10 +400,10 @@ struct Arch : BaseCtx
|
|||||||
mutable std::unordered_map<Loc, int> bel_by_loc;
|
mutable std::unordered_map<Loc, int> bel_by_loc;
|
||||||
|
|
||||||
std::vector<bool> bel_carry;
|
std::vector<bool> bel_carry;
|
||||||
std::vector<IdString> bel_to_cell;
|
std::vector<CellInfo*> bel_to_cell;
|
||||||
std::vector<IdString> wire_to_net;
|
std::vector<NetInfo*> wire_to_net;
|
||||||
std::vector<IdString> pip_to_net;
|
std::vector<NetInfo*> pip_to_net;
|
||||||
std::vector<IdString> switches_locked;
|
std::vector<NetInfo*> switches_locked;
|
||||||
|
|
||||||
ArchArgs args;
|
ArchArgs args;
|
||||||
Arch(ArchArgs args);
|
Arch(ArchArgs args);
|
||||||
@ -438,26 +438,25 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
||||||
|
|
||||||
void bindBel(BelId bel, IdString cell, PlaceStrength strength)
|
void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
NPNR_ASSERT(bel_to_cell[bel.index] == IdString());
|
NPNR_ASSERT(bel_to_cell[bel.index] == nullptr);
|
||||||
auto &c = cells[cell];
|
|
||||||
|
|
||||||
bel_to_cell[bel.index] = cell;
|
bel_to_cell[bel.index] = cell;
|
||||||
bel_carry[bel.index] = (c->type == id_icestorm_lc && c->lcInfo.carryEnable);
|
bel_carry[bel.index] = (cell->type == id_icestorm_lc && cell->lcInfo.carryEnable);
|
||||||
c->bel = bel;
|
cell->bel = bel;
|
||||||
c->belStrength = strength;
|
cell->belStrength = strength;
|
||||||
refreshUiBel(bel);
|
refreshUiBel(bel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unbindBel(BelId bel)
|
void unbindBel(BelId bel)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
NPNR_ASSERT(bel_to_cell[bel.index] != IdString());
|
NPNR_ASSERT(bel_to_cell[bel.index] != nullptr);
|
||||||
cells[bel_to_cell[bel.index]]->bel = BelId();
|
bel_to_cell[bel.index]->bel = BelId();
|
||||||
cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
|
bel_to_cell[bel.index]->belStrength = STRENGTH_NONE;
|
||||||
bel_to_cell[bel.index] = IdString();
|
bel_to_cell[bel.index] = nullptr;
|
||||||
bel_carry[bel.index] = false;
|
bel_carry[bel.index] = false;
|
||||||
refreshUiBel(bel);
|
refreshUiBel(bel);
|
||||||
}
|
}
|
||||||
@ -465,16 +464,16 @@ struct Arch : BaseCtx
|
|||||||
bool checkBelAvail(BelId bel) const
|
bool checkBelAvail(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
return bel_to_cell[bel.index] == IdString();
|
return bel_to_cell[bel.index] == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getBoundBelCell(BelId bel) const
|
CellInfo *getBoundBelCell(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
return bel_to_cell[bel.index];
|
return bel_to_cell[bel.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getConflictingBelCell(BelId bel) const
|
CellInfo *getConflictingBelCell(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
return bel_to_cell[bel.index];
|
return bel_to_cell[bel.index];
|
||||||
@ -526,49 +525,49 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
|
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
|
||||||
|
|
||||||
void bindWire(WireId wire, IdString net, PlaceStrength strength)
|
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
NPNR_ASSERT(wire_to_net[wire.index] == IdString());
|
NPNR_ASSERT(wire_to_net[wire.index] == nullptr);
|
||||||
wire_to_net[wire.index] = net;
|
wire_to_net[wire.index] = net;
|
||||||
nets[net]->wires[wire].pip = PipId();
|
net->wires[wire].pip = PipId();
|
||||||
nets[net]->wires[wire].strength = strength;
|
net->wires[wire].strength = strength;
|
||||||
refreshUiWire(wire);
|
refreshUiWire(wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unbindWire(WireId wire)
|
void unbindWire(WireId wire)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
NPNR_ASSERT(wire_to_net[wire.index] != IdString());
|
NPNR_ASSERT(wire_to_net[wire.index] != nullptr);
|
||||||
|
|
||||||
auto &net_wires = nets[wire_to_net[wire.index]]->wires;
|
auto &net_wires = wire_to_net[wire.index]->wires;
|
||||||
auto it = net_wires.find(wire);
|
auto it = net_wires.find(wire);
|
||||||
NPNR_ASSERT(it != net_wires.end());
|
NPNR_ASSERT(it != net_wires.end());
|
||||||
|
|
||||||
auto pip = it->second.pip;
|
auto pip = it->second.pip;
|
||||||
if (pip != PipId()) {
|
if (pip != PipId()) {
|
||||||
pip_to_net[pip.index] = IdString();
|
pip_to_net[pip.index] = nullptr;
|
||||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
|
switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_wires.erase(it);
|
net_wires.erase(it);
|
||||||
wire_to_net[wire.index] = IdString();
|
wire_to_net[wire.index] = nullptr;
|
||||||
refreshUiWire(wire);
|
refreshUiWire(wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkWireAvail(WireId wire) const
|
bool checkWireAvail(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
return wire_to_net[wire.index] == IdString();
|
return wire_to_net[wire.index] == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getBoundWireNet(WireId wire) const
|
NetInfo *getBoundWireNet(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
return wire_to_net[wire.index];
|
return wire_to_net[wire.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getConflictingWireNet(WireId wire) const
|
NetInfo *getConflictingWireNet(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
return wire_to_net[wire.index];
|
return wire_to_net[wire.index];
|
||||||
@ -606,21 +605,21 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
PipId getPipByName(IdString name) const;
|
PipId getPipByName(IdString name) const;
|
||||||
|
|
||||||
void bindPip(PipId pip, IdString net, PlaceStrength strength)
|
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
NPNR_ASSERT(pip_to_net[pip.index] == IdString());
|
NPNR_ASSERT(pip_to_net[pip.index] == nullptr);
|
||||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString());
|
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr);
|
||||||
|
|
||||||
pip_to_net[pip.index] = net;
|
pip_to_net[pip.index] = net;
|
||||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
|
switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
|
||||||
|
|
||||||
WireId dst;
|
WireId dst;
|
||||||
dst.index = chip_info->pip_data[pip.index].dst;
|
dst.index = chip_info->pip_data[pip.index].dst;
|
||||||
NPNR_ASSERT(wire_to_net[dst.index] == IdString());
|
NPNR_ASSERT(wire_to_net[dst.index] == nullptr);
|
||||||
wire_to_net[dst.index] = net;
|
wire_to_net[dst.index] = net;
|
||||||
nets[net]->wires[dst].pip = pip;
|
net->wires[dst].pip = pip;
|
||||||
nets[net]->wires[dst].strength = strength;
|
net->wires[dst].strength = strength;
|
||||||
refreshUiPip(pip);
|
refreshUiPip(pip);
|
||||||
refreshUiWire(dst);
|
refreshUiWire(dst);
|
||||||
}
|
}
|
||||||
@ -628,17 +627,17 @@ struct Arch : BaseCtx
|
|||||||
void unbindPip(PipId pip)
|
void unbindPip(PipId pip)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
NPNR_ASSERT(pip_to_net[pip.index] != IdString());
|
NPNR_ASSERT(pip_to_net[pip.index] != nullptr);
|
||||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString());
|
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr);
|
||||||
|
|
||||||
WireId dst;
|
WireId dst;
|
||||||
dst.index = chip_info->pip_data[pip.index].dst;
|
dst.index = chip_info->pip_data[pip.index].dst;
|
||||||
NPNR_ASSERT(wire_to_net[dst.index] != IdString());
|
NPNR_ASSERT(wire_to_net[dst.index] != nullptr);
|
||||||
wire_to_net[dst.index] = IdString();
|
wire_to_net[dst.index] = nullptr;
|
||||||
nets[pip_to_net[pip.index]]->wires.erase(dst);
|
pip_to_net[pip.index]->wires.erase(dst);
|
||||||
|
|
||||||
pip_to_net[pip.index] = IdString();
|
pip_to_net[pip.index] = nullptr;
|
||||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
|
switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr;
|
||||||
refreshUiPip(pip);
|
refreshUiPip(pip);
|
||||||
refreshUiWire(dst);
|
refreshUiWire(dst);
|
||||||
}
|
}
|
||||||
@ -649,12 +648,12 @@ struct Arch : BaseCtx
|
|||||||
auto &pi = chip_info->pip_data[pip.index];
|
auto &pi = chip_info->pip_data[pip.index];
|
||||||
auto &si = chip_info->bits_info->switches[pi.switch_index];
|
auto &si = chip_info->bits_info->switches[pi.switch_index];
|
||||||
|
|
||||||
if (switches_locked[pi.switch_index] != IdString())
|
if (switches_locked[pi.switch_index] != nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) {
|
if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) {
|
||||||
NPNR_ASSERT(si.bel >= 0);
|
NPNR_ASSERT(si.bel >= 0);
|
||||||
if (bel_to_cell[si.bel] != IdString())
|
if (bel_to_cell[si.bel] != nullptr)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,13 +666,13 @@ struct Arch : BaseCtx
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getBoundPipNet(PipId pip) const
|
NetInfo *getBoundPipNet(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
return pip_to_net[pip.index];
|
return pip_to_net[pip.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getConflictingPipNet(PipId pip) const
|
NetInfo *getConflictingPipNet(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
return switches_locked[chip_info->pip_data[pip.index].switch_index];
|
return switches_locked[chip_info->pip_data[pip.index].switch_index];
|
||||||
@ -768,7 +767,7 @@ struct Arch : BaseCtx
|
|||||||
delay_t getRipupDelayPenalty() const { return 200; }
|
delay_t getRipupDelayPenalty() const { return 200; }
|
||||||
float getDelayNS(delay_t v) const { return v * 0.001; }
|
float getDelayNS(delay_t v) const { return v * 0.001; }
|
||||||
uint32_t getDelayChecksum(delay_t v) const { return v; }
|
uint32_t getDelayChecksum(delay_t v) const { return v; }
|
||||||
delay_t getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t budget) const;
|
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const;
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
|
@ -74,19 +74,18 @@ bool Arch::isBelLocationValid(BelId bel) const
|
|||||||
std::vector<const CellInfo *> bel_cells;
|
std::vector<const CellInfo *> bel_cells;
|
||||||
Loc bel_loc = getBelLocation(bel);
|
Loc bel_loc = getBelLocation(bel);
|
||||||
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
||||||
IdString cell_other = getBoundBelCell(bel_other);
|
CellInfo *ci_other = getBoundBelCell(bel_other);
|
||||||
if (cell_other != IdString()) {
|
if (ci_other != nullptr) {
|
||||||
const CellInfo *ci_other = cells.at(cell_other).get();
|
|
||||||
bel_cells.push_back(ci_other);
|
bel_cells.push_back(ci_other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return logicCellsCompatible(bel_cells);
|
return logicCellsCompatible(bel_cells);
|
||||||
} else {
|
} else {
|
||||||
IdString cellId = getBoundBelCell(bel);
|
CellInfo *ci = getBoundBelCell(bel);
|
||||||
if (cellId == IdString())
|
if (ci == nullptr)
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return isValidBelForCell(cells.at(cellId).get(), bel);
|
return isValidBelForCell(ci, bel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,9 +97,8 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
|||||||
std::vector<const CellInfo *> bel_cells;
|
std::vector<const CellInfo *> bel_cells;
|
||||||
Loc bel_loc = getBelLocation(bel);
|
Loc bel_loc = getBelLocation(bel);
|
||||||
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
||||||
IdString cell_other = getBoundBelCell(bel_other);
|
CellInfo *ci_other = getBoundBelCell(bel_other);
|
||||||
if (cell_other != IdString() && bel_other != bel) {
|
if (ci_other != nullptr && bel_other != bel) {
|
||||||
const CellInfo *ci_other = cells.at(cell_other).get();
|
|
||||||
bel_cells.push_back(ci_other);
|
bel_cells.push_back(ci_other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,12 +124,12 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
|||||||
if (pll_bel.index != -1) {
|
if (pll_bel.index != -1) {
|
||||||
auto pll_cell = getBoundBelCell(pll_bel);
|
auto pll_cell = getBoundBelCell(pll_bel);
|
||||||
// Is a PLL placed in this PLL bel?
|
// Is a PLL placed in this PLL bel?
|
||||||
if (pll_cell != IdString()) {
|
if (pll_cell != nullptr) {
|
||||||
// Is the shared port driving a net?
|
// Is the shared port driving a net?
|
||||||
auto pi = cells.at(pll_cell)->ports[portPinToId(pll_bel_pin)];
|
auto pi = pll_cell->ports[portPinToId(pll_bel_pin)];
|
||||||
if (pi.net != nullptr) {
|
if (pi.net != nullptr) {
|
||||||
// Are we perhaps a PAD INPUT Bel that can be placed here?
|
// Are we perhaps a PAD INPUT Bel that can be placed here?
|
||||||
if (cells.at(pll_cell)->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(this)) {
|
if (pll_cell->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(this)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -70,13 +70,13 @@ void arch_wrap_python()
|
|||||||
fn_wrapper_1a<Context, decltype(&Context::getBelChecksum), &Context::getBelChecksum, pass_through<uint32_t>,
|
fn_wrapper_1a<Context, decltype(&Context::getBelChecksum), &Context::getBelChecksum, pass_through<uint32_t>,
|
||||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelChecksum");
|
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelChecksum");
|
||||||
fn_wrapper_3a_v<Context, decltype(&Context::bindBel), &Context::bindBel, conv_from_str<BelId>,
|
fn_wrapper_3a_v<Context, decltype(&Context::bindBel), &Context::bindBel, conv_from_str<BelId>,
|
||||||
conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindBel");
|
addr_and_unwrap<CellInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindBel");
|
||||||
fn_wrapper_1a_v<Context, decltype(&Context::unbindBel), &Context::unbindBel, conv_from_str<BelId>>::def_wrap(
|
fn_wrapper_1a_v<Context, decltype(&Context::unbindBel), &Context::unbindBel, conv_from_str<BelId>>::def_wrap(
|
||||||
ctx_cls, "unbindBel");
|
ctx_cls, "unbindBel");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getBoundBelCell), &Context::getBoundBelCell, conv_to_str<IdString>,
|
fn_wrapper_1a<Context, decltype(&Context::getBoundBelCell), &Context::getBoundBelCell, deref_and_wrap<CellInfo>,
|
||||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBoundBelCell");
|
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBoundBelCell");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getConflictingBelCell), &Context::getConflictingBelCell,
|
fn_wrapper_1a<Context, decltype(&Context::getConflictingBelCell), &Context::getConflictingBelCell,
|
||||||
conv_to_str<IdString>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getConflictingBelCell");
|
deref_and_wrap<CellInfo>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getConflictingBelCell");
|
||||||
fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels, wrap_context<BelRange>>::def_wrap(ctx_cls,
|
fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels, wrap_context<BelRange>>::def_wrap(ctx_cls,
|
||||||
"getBels");
|
"getBels");
|
||||||
|
|
||||||
@ -88,15 +88,15 @@ void arch_wrap_python()
|
|||||||
fn_wrapper_1a<Context, decltype(&Context::getWireChecksum), &Context::getWireChecksum, pass_through<uint32_t>,
|
fn_wrapper_1a<Context, decltype(&Context::getWireChecksum), &Context::getWireChecksum, pass_through<uint32_t>,
|
||||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireChecksum");
|
conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireChecksum");
|
||||||
fn_wrapper_3a_v<Context, decltype(&Context::bindWire), &Context::bindWire, conv_from_str<WireId>,
|
fn_wrapper_3a_v<Context, decltype(&Context::bindWire), &Context::bindWire, conv_from_str<WireId>,
|
||||||
conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindWire");
|
addr_and_unwrap<NetInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindWire");
|
||||||
fn_wrapper_1a_v<Context, decltype(&Context::unbindWire), &Context::unbindWire, conv_from_str<WireId>>::def_wrap(
|
fn_wrapper_1a_v<Context, decltype(&Context::unbindWire), &Context::unbindWire, conv_from_str<WireId>>::def_wrap(
|
||||||
ctx_cls, "unbindWire");
|
ctx_cls, "unbindWire");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::checkWireAvail), &Context::checkWireAvail, pass_through<bool>,
|
fn_wrapper_1a<Context, decltype(&Context::checkWireAvail), &Context::checkWireAvail, pass_through<bool>,
|
||||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "checkWireAvail");
|
conv_from_str<WireId>>::def_wrap(ctx_cls, "checkWireAvail");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getBoundWireNet), &Context::getBoundWireNet, conv_to_str<IdString>,
|
fn_wrapper_1a<Context, decltype(&Context::getBoundWireNet), &Context::getBoundWireNet, deref_and_wrap<NetInfo>,
|
||||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "getBoundWireNet");
|
conv_from_str<WireId>>::def_wrap(ctx_cls, "getBoundWireNet");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getConflictingWireNet), &Context::getConflictingWireNet,
|
fn_wrapper_1a<Context, decltype(&Context::getConflictingWireNet), &Context::getConflictingWireNet,
|
||||||
conv_to_str<IdString>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getConflictingWireNet");
|
deref_and_wrap<NetInfo>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getConflictingWireNet");
|
||||||
|
|
||||||
fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires, wrap_context<WireRange>>::def_wrap(
|
fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires, wrap_context<WireRange>>::def_wrap(
|
||||||
ctx_cls, "getWires");
|
ctx_cls, "getWires");
|
||||||
@ -106,15 +106,15 @@ void arch_wrap_python()
|
|||||||
fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>,
|
fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum");
|
||||||
fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>,
|
fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>,
|
||||||
conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindPip");
|
addr_and_unwrap<NetInfo>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindPip");
|
||||||
fn_wrapper_1a_v<Context, decltype(&Context::unbindPip), &Context::unbindPip, conv_from_str<PipId>>::def_wrap(
|
fn_wrapper_1a_v<Context, decltype(&Context::unbindPip), &Context::unbindPip, conv_from_str<PipId>>::def_wrap(
|
||||||
ctx_cls, "unbindPip");
|
ctx_cls, "unbindPip");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::checkPipAvail), &Context::checkPipAvail, pass_through<bool>,
|
fn_wrapper_1a<Context, decltype(&Context::checkPipAvail), &Context::checkPipAvail, pass_through<bool>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "checkPipAvail");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "checkPipAvail");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getBoundPipNet), &Context::getBoundPipNet, conv_to_str<IdString>,
|
fn_wrapper_1a<Context, decltype(&Context::getBoundPipNet), &Context::getBoundPipNet, deref_and_wrap<NetInfo>,
|
||||||
conv_from_str<PipId>>::def_wrap(ctx_cls, "getBoundPipNet");
|
conv_from_str<PipId>>::def_wrap(ctx_cls, "getBoundPipNet");
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getConflictingPipNet), &Context::getConflictingPipNet,
|
fn_wrapper_1a<Context, decltype(&Context::getConflictingPipNet), &Context::getConflictingPipNet,
|
||||||
conv_to_str<IdString>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getConflictingPipNet");
|
deref_and_wrap<NetInfo>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getConflictingPipNet");
|
||||||
|
|
||||||
fn_wrapper_1a<Context, decltype(&Context::getPipsDownhill), &Context::getPipsDownhill, wrap_context<PipRange>,
|
fn_wrapper_1a<Context, decltype(&Context::getPipsDownhill), &Context::getPipsDownhill, wrap_context<PipRange>,
|
||||||
conv_from_str<WireId>>::def_wrap(ctx_cls, "getPipsDownhill");
|
conv_from_str<WireId>>::def_wrap(ctx_cls, "getPipsDownhill");
|
||||||
|
@ -291,7 +291,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
}
|
}
|
||||||
// Set pips
|
// Set pips
|
||||||
for (auto pip : ctx->getPips()) {
|
for (auto pip : ctx->getPips()) {
|
||||||
if (ctx->pip_to_net[pip.index] != IdString()) {
|
if (ctx->pip_to_net[pip.index] != nullptr) {
|
||||||
const PipInfoPOD &pi = ci.pip_data[pip.index];
|
const PipInfoPOD &pi = ci.pip_data[pip.index];
|
||||||
const SwitchInfoPOD &swi = bi.switches[pi.switch_index];
|
const SwitchInfoPOD &swi = bi.switches[pi.switch_index];
|
||||||
int sw_bel_idx = swi.bel;
|
int sw_bel_idx = swi.bel;
|
||||||
@ -310,7 +310,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
|
|
||||||
WireId permWire;
|
WireId permWire;
|
||||||
for (auto permPip : ctx->getPipsUphill(ctx->getPipSrcWire(pip))) {
|
for (auto permPip : ctx->getPipsUphill(ctx->getPipSrcWire(pip))) {
|
||||||
if (ctx->getBoundPipNet(permPip) != IdString()) {
|
if (ctx->getBoundPipNet(permPip) != nullptr) {
|
||||||
permWire = ctx->getPipSrcWire(permPip);
|
permWire = ctx->getPipSrcWire(permPip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -384,7 +384,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
WireId lut_wire = ctx->getBelPinWire(bel, PortPin(PIN_I0 + i));
|
WireId lut_wire = ctx->getBelPinWire(bel, PortPin(PIN_I0 + i));
|
||||||
for (auto pip : ctx->getPipsUphill(lut_wire)) {
|
for (auto pip : ctx->getPipsUphill(lut_wire)) {
|
||||||
if (ctx->getBoundPipNet(pip) != IdString()) {
|
if (ctx->getBoundPipNet(pip) != nullptr) {
|
||||||
std::string name = ci.wire_data[ctx->getPipSrcWire(pip).index].name.get();
|
std::string name = ci.wire_data[ctx->getPipSrcWire(pip).index].name.get();
|
||||||
switch (name.back()) {
|
switch (name.back()) {
|
||||||
case '0':
|
case '0':
|
||||||
@ -458,8 +458,8 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
NPNR_ASSERT(iez != -1);
|
NPNR_ASSERT(iez != -1);
|
||||||
|
|
||||||
bool input_en = false;
|
bool input_en = false;
|
||||||
if ((ctx->wire_to_net[ctx->getBelPinWire(bel, PIN_D_IN_0).index] != IdString()) ||
|
if ((ctx->wire_to_net[ctx->getBelPinWire(bel, PIN_D_IN_0).index] != nullptr) ||
|
||||||
(ctx->wire_to_net[ctx->getBelPinWire(bel, PIN_D_IN_1).index] != IdString())) {
|
(ctx->wire_to_net[ctx->getBelPinWire(bel, PIN_D_IN_1).index] != nullptr)) {
|
||||||
input_en = true;
|
input_en = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,7 +618,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
}
|
}
|
||||||
// Set config bits in unused IO and RAM
|
// Set config bits in unused IO and RAM
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_SB_IO) {
|
if (ctx->bel_to_cell[bel.index] == nullptr && ctx->getBelType(bel) == TYPE_SB_IO) {
|
||||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
||||||
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||||
int x = beli.x, y = beli.y, z = beli.z;
|
int x = beli.x, y = beli.y, z = beli.z;
|
||||||
@ -633,7 +633,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true);
|
set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true);
|
||||||
set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false);
|
set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false);
|
||||||
}
|
}
|
||||||
} else if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) {
|
} else if (ctx->bel_to_cell[bel.index] == nullptr && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) {
|
||||||
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||||
int x = beli.x, y = beli.y;
|
int x = beli.x, y = beli.y;
|
||||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB];
|
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB];
|
||||||
@ -751,9 +751,9 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
// Write symbols
|
// Write symbols
|
||||||
// const bool write_symbols = 1;
|
// const bool write_symbols = 1;
|
||||||
for (auto wire : ctx->getWires()) {
|
for (auto wire : ctx->getWires()) {
|
||||||
IdString net = ctx->getBoundWireNet(wire);
|
NetInfo *net = ctx->getBoundWireNet(wire);
|
||||||
if (net != IdString())
|
if (net != nullptr)
|
||||||
out << ".sym " << wire.index << " " << net.str(ctx) << std::endl;
|
out << ".sym " << wire.index << " " << net->name.str(ctx) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,7 +825,7 @@ void read_config(Context *ctx, std::istream &in, chipconfig_t &config)
|
|||||||
|
|
||||||
WireId wire;
|
WireId wire;
|
||||||
wire.index = wireIndex;
|
wire.index = wireIndex;
|
||||||
ctx->bindWire(wire, netName, STRENGTH_WEAK);
|
ctx->bindWire(wire, ctx->nets.at(netName).get(), STRENGTH_WEAK);
|
||||||
}
|
}
|
||||||
} else if (line_nr >= 0 && strlen(buffer) > 0) {
|
} else if (line_nr >= 0 && strlen(buffer) > 0) {
|
||||||
if (line_nr > int(config.at(tile_y).at(tile_x).size() - 1))
|
if (line_nr > int(config.at(tile_y).at(tile_x).size() - 1))
|
||||||
@ -869,7 +869,7 @@ bool read_asc(Context *ctx, std::istream &in)
|
|||||||
isUsed &= !(bool(cbit) ^ val);
|
isUsed &= !(bool(cbit) ^ val);
|
||||||
}
|
}
|
||||||
if (isUsed) {
|
if (isUsed) {
|
||||||
IdString net = ctx->wire_to_net[pi.dst];
|
NetInfo *net = ctx->wire_to_net[pi.dst];
|
||||||
WireId wire;
|
WireId wire;
|
||||||
wire.index = pi.dst;
|
wire.index = pi.dst;
|
||||||
ctx->unbindWire(wire);
|
ctx->unbindWire(wire);
|
||||||
@ -896,7 +896,7 @@ bool read_asc(Context *ctx, std::istream &in)
|
|||||||
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("ICESTORM_LC"));
|
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("ICESTORM_LC"));
|
||||||
IdString name = created->name;
|
IdString name = created->name;
|
||||||
ctx->cells[name] = std::move(created);
|
ctx->cells[name] = std::move(created);
|
||||||
ctx->bindBel(bel, name, STRENGTH_WEAK);
|
ctx->bindBel(bel, ctx->cells[name].get(), STRENGTH_WEAK);
|
||||||
// TODO: Add port mapping to nets and assign values of properties
|
// TODO: Add port mapping to nets and assign values of properties
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -916,7 +916,7 @@ bool read_asc(Context *ctx, std::istream &in)
|
|||||||
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_IO"));
|
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_IO"));
|
||||||
IdString name = created->name;
|
IdString name = created->name;
|
||||||
ctx->cells[name] = std::move(created);
|
ctx->cells[name] = std::move(created);
|
||||||
ctx->bindBel(bel, name, STRENGTH_WEAK);
|
ctx->bindBel(bel, ctx->cells[name].get(), STRENGTH_WEAK);
|
||||||
// TODO: Add port mapping to nets and assign values of properties
|
// TODO: Add port mapping to nets and assign values of properties
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -933,35 +933,35 @@ bool read_asc(Context *ctx, std::istream &in)
|
|||||||
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("ICESTORM_LC"));
|
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("ICESTORM_LC"));
|
||||||
IdString name = created->name;
|
IdString name = created->name;
|
||||||
ctx->cells[name] = std::move(created);
|
ctx->cells[name] = std::move(created);
|
||||||
ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
|
ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK);
|
||||||
// TODO: Add port mapping to nets
|
// TODO: Add port mapping to nets
|
||||||
}
|
}
|
||||||
if (ctx->getBelType(belpin.bel) == TYPE_SB_IO) {
|
if (ctx->getBelType(belpin.bel) == TYPE_SB_IO) {
|
||||||
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_IO"));
|
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_IO"));
|
||||||
IdString name = created->name;
|
IdString name = created->name;
|
||||||
ctx->cells[name] = std::move(created);
|
ctx->cells[name] = std::move(created);
|
||||||
ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
|
ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK);
|
||||||
// TODO: Add port mapping to nets
|
// TODO: Add port mapping to nets
|
||||||
}
|
}
|
||||||
if (ctx->getBelType(belpin.bel) == TYPE_SB_GB) {
|
if (ctx->getBelType(belpin.bel) == TYPE_SB_GB) {
|
||||||
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_GB"));
|
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_GB"));
|
||||||
IdString name = created->name;
|
IdString name = created->name;
|
||||||
ctx->cells[name] = std::move(created);
|
ctx->cells[name] = std::move(created);
|
||||||
ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
|
ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK);
|
||||||
// TODO: Add port mapping to nets
|
// TODO: Add port mapping to nets
|
||||||
}
|
}
|
||||||
if (ctx->getBelType(belpin.bel) == TYPE_SB_WARMBOOT) {
|
if (ctx->getBelType(belpin.bel) == TYPE_SB_WARMBOOT) {
|
||||||
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_WARMBOOT"));
|
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_WARMBOOT"));
|
||||||
IdString name = created->name;
|
IdString name = created->name;
|
||||||
ctx->cells[name] = std::move(created);
|
ctx->cells[name] = std::move(created);
|
||||||
ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
|
ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK);
|
||||||
// TODO: Add port mapping to nets
|
// TODO: Add port mapping to nets
|
||||||
}
|
}
|
||||||
if (ctx->getBelType(belpin.bel) == TYPE_ICESTORM_LFOSC) {
|
if (ctx->getBelType(belpin.bel) == TYPE_ICESTORM_LFOSC) {
|
||||||
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"));
|
std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"));
|
||||||
IdString name = created->name;
|
IdString name = created->name;
|
||||||
ctx->cells[name] = std::move(created);
|
ctx->cells[name] = std::move(created);
|
||||||
ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
|
ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK);
|
||||||
// TODO: Add port mapping to nets
|
// TODO: Add port mapping to nets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -975,17 +975,17 @@ bool read_asc(Context *ctx, std::istream &in)
|
|||||||
PortPin pin = ctx->portPinFromId(port.first);
|
PortPin pin = ctx->portPinFromId(port.first);
|
||||||
WireId wire = ctx->getBelPinWire(cell.second->bel, pin);
|
WireId wire = ctx->getBelPinWire(cell.second->bel, pin);
|
||||||
if (wire != WireId()) {
|
if (wire != WireId()) {
|
||||||
IdString name = ctx->getBoundWireNet(wire);
|
NetInfo *net = ctx->getBoundWireNet(wire);
|
||||||
if (name != IdString()) {
|
if (net != nullptr) {
|
||||||
port.second.net = ctx->nets[name].get();
|
port.second.net = net;
|
||||||
PortRef ref;
|
PortRef ref;
|
||||||
ref.cell = cell.second.get();
|
ref.cell = cell.second.get();
|
||||||
ref.port = port.second.name;
|
ref.port = port.second.name;
|
||||||
|
|
||||||
if (port.second.type == PORT_OUT)
|
if (port.second.type == PORT_OUT)
|
||||||
ctx->nets[name]->driver = ref;
|
net->driver = ref;
|
||||||
else
|
else
|
||||||
ctx->nets[name]->users.push_back(ref);
|
net->users.push_back(ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user