Merge remote-tracking branch 'origin/master' into timingapi

This commit is contained in:
Eddie Hung 2018-11-13 12:12:11 -08:00
commit 2d39cde17b
18 changed files with 1038 additions and 860 deletions

View File

@ -18,6 +18,7 @@
*/ */
#include "nextpnr.h" #include "nextpnr.h"
#include "log.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
@ -25,6 +26,7 @@ assertion_failure::assertion_failure(std::string msg, std::string expr_str, std:
: runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg), : runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg),
expr_str(expr_str), filename(filename), line(line) expr_str(expr_str), filename(filename), line(line)
{ {
log_flush();
} }
void IdString::set(const BaseCtx *ctx, const std::string &s) void IdString::set(const BaseCtx *ctx, const std::string &s)
@ -152,6 +154,30 @@ void BaseCtx::removeConstraint(IdString constrName)
constraints.erase(constrName); constraints.erase(constrName);
} }
const char *BaseCtx::nameOfBel(BelId bel) const
{
const Context *ctx = getCtx();
return ctx->getBelName(bel).c_str(ctx);
}
const char *BaseCtx::nameOfWire(WireId wire) const
{
const Context *ctx = getCtx();
return ctx->getWireName(wire).c_str(ctx);
}
const char *BaseCtx::nameOfPip(PipId pip) const
{
const Context *ctx = getCtx();
return ctx->getPipName(pip).c_str(ctx);
}
const char *BaseCtx::nameOfGroup(GroupId group) const
{
const Context *ctx = getCtx();
return ctx->getGroupName(group).c_str(ctx);
}
WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const
{ {
if (net_info->driver.cell == nullptr) if (net_info->driver.cell == nullptr)

View File

@ -288,7 +288,7 @@ struct ClockConstraint;
struct NetInfo : ArchNetInfo struct NetInfo : ArchNetInfo
{ {
IdString name; IdString name;
int32_t udata; int32_t udata = 0;
PortRef driver; PortRef driver;
std::vector<PortRef> users; std::vector<PortRef> users;
@ -579,13 +579,23 @@ 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) const char *nameOf(IdString name) const
{
return name.c_str(this);
}
template <typename T> const char *nameOf(const T *obj) const
{ {
if (obj == nullptr) if (obj == nullptr)
return ""; return "";
return obj->name.c_str(getCtx()); return obj->name.c_str(this);
} }
const char *nameOfBel(BelId bel) const;
const char *nameOfWire(WireId wire) const;
const char *nameOfPip(PipId pip) const;
const char *nameOfGroup(GroupId group) const;
// -------------------------------------------------------------- // --------------------------------------------------------------
bool allUiReload = true; bool allUiReload = true;
@ -657,6 +667,7 @@ struct Context : Arch, DeterministicRNG
delay_t getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &sink) const; delay_t getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &sink) const;
// provided by router1.cc // provided by router1.cc
bool checkRoutedDesign() const;
bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay = nullptr, bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay = nullptr,
std::unordered_map<WireId, PipId> *route = nullptr, bool useEstimate = true); std::unordered_map<WireId, PipId> *route = nullptr, bool useEstimate = true);

View File

@ -28,19 +28,19 @@ NEXTPNR_NAMESPACE_BEGIN
wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type, float &tns) wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type, float &tns)
{ {
wirelen_t wirelength = 0; wirelen_t wirelength = 0;
Loc driver_loc;
bool driver_gb;
CellInfo *driver_cell = net->driver.cell; CellInfo *driver_cell = net->driver.cell;
if (!driver_cell) if (!driver_cell)
return 0; return 0;
if (driver_cell->bel == BelId()) if (driver_cell->bel == BelId())
return 0; return 0;
driver_gb = ctx->getBelGlobalBuf(driver_cell->bel); bool driver_gb = ctx->getBelGlobalBuf(driver_cell->bel);
driver_loc = ctx->getBelLocation(driver_cell->bel);
if (driver_gb) if (driver_gb)
return 0; return 0;
IdString clock_port;
bool timing_driven = ctx->timing_driven && type == MetricType::COST && ctx->getPortTimingClass(driver_cell, net->driver.port, clock_port) != TMG_IGNORE;
delay_t negative_slack = 0; delay_t negative_slack = 0;
delay_t worst_slack = std::numeric_limits<delay_t>::max(); delay_t worst_slack = std::numeric_limits<delay_t>::max();
Loc driver_loc = ctx->getBelLocation(driver_cell->bel);
int xmin = driver_loc.x, xmax = driver_loc.x, ymin = driver_loc.y, ymax = driver_loc.y; int xmin = driver_loc.x, xmax = driver_loc.x, ymin = driver_loc.y, ymax = driver_loc.y;
for (auto load : net->users) { for (auto load : net->users) {
if (load.cell == nullptr) if (load.cell == nullptr)
@ -48,7 +48,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type
CellInfo *load_cell = load.cell; CellInfo *load_cell = load.cell;
if (load_cell->bel == BelId()) if (load_cell->bel == BelId())
continue; continue;
if (ctx->timing_driven && type == MetricType::COST) { if (timing_driven) {
delay_t net_delay = ctx->predictDelay(net, load); delay_t net_delay = ctx->predictDelay(net, load);
auto slack = load.budget - net_delay; auto slack = load.budget - net_delay;
if (slack < 0) if (slack < 0)
@ -65,7 +65,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type
xmax = std::max(xmax, load_loc.x); xmax = std::max(xmax, load_loc.x);
ymax = std::max(ymax, load_loc.y); ymax = std::max(ymax, load_loc.y);
} }
if (ctx->timing_driven && type == MetricType::COST) { if (timing_driven) {
wirelength = wirelen_t( wirelength = wirelen_t(
(((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-ctx->getDelayNS(worst_slack) / 5))))); (((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-ctx->getDelayNS(worst_slack) / 5)))));
} else { } else {

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,10 @@ struct Router1Cfg : Settings
bool cleanupReroute; bool cleanupReroute;
bool fullCleanupReroute; bool fullCleanupReroute;
bool useEstimate; bool useEstimate;
delay_t wireRipupPenalty;
delay_t netRipupPenalty;
delay_t reuseBonus;
delay_t estimatePrecision;
}; };
extern bool router1(Context *ctx, const Router1Cfg &cfg); extern bool router1(Context *ctx, const Router1Cfg &cfg);

View File

@ -30,15 +30,15 @@ delay_t maxDelay() const { return delay; }
### BelId ### BelId
A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<BelId>`. A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<BelId>`.
### WireId ### WireId
A type representing a wire name. `WireId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<WireId>`. A type representing a wire name. `WireId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<WireId>`.
### PipId ### PipId
A type representing a pip name. `PipId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<PipId>`. A type representing a pip name. `PipId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<PipId>`.
### GroupId ### GroupId
@ -215,14 +215,15 @@ Return true if the wire is available, i.e. can be bound to a net.
Return the net a wire is bound to. Return the net a wire is bound to.
### NetInfo \*getConflictingWireNet(WireId wire) const ### WireId getConflictingWireWire(WireId wire) const
If this returns a non-nullptr, then unbinding that net If this returns a non-WireId(), then unbinding that wire
will make the given wire available. will make the given wire available.
This returns nullptr if the wire is already available, ### NetInfo \*getConflictingWireNet(WireId wire) const
or if there is no single net that can be unbound to make this
wire available. If this returns a non-nullptr, then unbinding that entire net
will make the given wire available.
### DelayInfo getWireDelay(WireId wire) const ### DelayInfo getWireDelay(WireId wire) const
@ -282,18 +283,23 @@ 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.
Users must also check if the pip destination wire is available
with `checkWireAvail(getPipDstWire(pip))` before binding the
pip to a net.
### NetInfo \*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.
### WireId getConflictingPipWire(PipId pip) const
If this returns a non-WireId(), then unbinding that wire
will make the given pip available.
### NetInfo \*getConflictingPipNet(PipId pip) const ### NetInfo \*getConflictingPipNet(PipId pip) const
Return the net that needs to be unbound in order to make this If this returns a non-nullptr, then unbinding that entire net
pip available. will make the given pip available.
This does not need to (but may) return the conflicting wire if the conflict is
limited to the conflicting wire being bound to the destination wire for this
pip.
### const\_range\<PipId\> getPips() const ### const\_range\<PipId\> getPips() const

View File

@ -38,7 +38,94 @@ For nextpnr we are using the following terminology.
Adding new architectures to nextpnr Adding new architectures to nextpnr
----------------------------------- -----------------------------------
TBD ### Implementing new architectures
Each nextpnr architecture must implement the *nextpnr architecture API*.
See [archapi.md](archapi.md) for a complete reference of the architecture API.
### Delay Estimates
Each architecture must implement a `estimateDelay()` method that estimates the expected delay for a path from given `src` to `dst` wires.
*It is very important that this method slightly overestimates the expected delay.* Furthermore, it should overestimate the expected delay
by a slightly larger margin for longer paths than for shorter paths. Otherwise there will be performance issues with the router.
The delays estimates returned by that method should also be as fine-grain as possible. It definitely pays off to spend some time improving the `estimateDelay()`
for your architecture once implementing small designs work.
### Ripup Information
The `getConflictingWireWire()`, `getConflictingWireNet()`, `getConflictingPipWire()`, and `getConflictingPipNet()` methods are used by the router
to determine which resources to rip up in order to make a given routing resource (wire or pip) available.
The architecture must guanrantee that the following invariants hold.
**Invariant 1:**
```
if (!ctx->checkWireAvail(wire)) {
WireId w = getConflictingWireWire(wire);
if (w != WireId()) {
ctx->unbindWire(w);
assert(ctx->checkWireAvail(wire));
}
}
```
**Invariant 2:**
```
if (!ctx->checkWireAvail(wire)) {
NetInfo *n = getConflictingWireNet(wire);
if (n != nullptr) {
for (auto &it : n->wires)
ctx->unbindWire(it.first);
assert(ctx->checkWireAvail(wire));
}
}
```
**Invariant 3:**
```
if (!ctx->checkPipAvail(pip)) {
WireId w = getConflictingPipWire(pip);
if (w != WireId()) {
ctx->unbindWire(w);
assert(ctx->checkPipAvail(pip));
}
}
```
**Invariant 4:**
```
if (!ctx->checkPipAvail(pip)) {
NetInfo *n = getConflictingPipNet(pip);
if (n != nullptr) {
for (auto &it : n->wires)
ctx->unbindWire(it.first);
assert(ctx->checkPipAvail(pip));
}
}
```
**Invariant 5:**
```
if (ctx->checkWireAvail(wire)) {
// bind is guaranteed to succeed
ctx->bindWire(wire, net, strength);
}
```
**Invariant 6:**
```
if (ctx->checkPipAvail(pip) && ctx->checkWireAvail(ctx->getPipDstWire(pip))) {
// bind is guaranteed to succeed
ctx->bindPip(pip, net, strength);
}
```
Nextpnr and other tools Nextpnr and other tools
----------------------- -----------------------

View File

@ -400,7 +400,7 @@ BelId Arch::getBelByLocation(Loc loc) const
delay_t Arch::estimateDelay(WireId src, WireId dst) const delay_t Arch::estimateDelay(WireId src, WireId dst) const
{ {
return 100 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y)); return 170 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y));
} }
delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
@ -409,7 +409,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
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);
return 100 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y)); return 170 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y));
} }
bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; } bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; }

View File

@ -619,6 +619,8 @@ struct Arch : BaseCtx
return wire_to_net.at(wire); return wire_to_net.at(wire);
} }
WireId getConflictingWireWire(WireId wire) const { return wire; }
NetInfo *getConflictingWireNet(WireId wire) const NetInfo *getConflictingWireNet(WireId wire) const
{ {
NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire != WireId());
@ -724,6 +726,8 @@ struct Arch : BaseCtx
return pip_to_net.at(pip); return pip_to_net.at(pip);
} }
WireId getConflictingPipWire(PipId pip) const { return WireId(); }
NetInfo *getConflictingPipNet(PipId pip) const NetInfo *getConflictingPipNet(PipId pip) const
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());

View File

@ -75,6 +75,7 @@ struct Location
bool operator==(const Location &other) const { return x == other.x && y == other.y; } bool operator==(const Location &other) const { return x == other.x && y == other.y; }
bool operator!=(const Location &other) const { return x != other.x || y != other.y; } bool operator!=(const Location &other) const { return x != other.x || y != other.y; }
bool operator<(const Location &other) const { return y == other.y ? x < other.x : y < other.y; }
}; };
inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); }
@ -86,6 +87,7 @@ struct BelId
bool operator==(const BelId &other) const { return index == other.index && location == other.location; } bool operator==(const BelId &other) const { return index == other.index && location == other.location; }
bool operator!=(const BelId &other) const { return index != other.index || location != other.location; } bool operator!=(const BelId &other) const { return index != other.index || location != other.location; }
bool operator<(const BelId &other) const { return location == other.location ? index < other.index : location < other.location; }
}; };
struct WireId struct WireId
@ -95,6 +97,7 @@ struct WireId
bool operator==(const WireId &other) const { return index == other.index && location == other.location; } bool operator==(const WireId &other) const { return index == other.index && location == other.location; }
bool operator!=(const WireId &other) const { return index != other.index || location != other.location; } bool operator!=(const WireId &other) const { return index != other.index || location != other.location; }
bool operator<(const WireId &other) const { return location == other.location ? index < other.index : location < other.location; }
}; };
struct PipId struct PipId
@ -104,6 +107,7 @@ struct PipId
bool operator==(const PipId &other) const { return index == other.index && location == other.location; } bool operator==(const PipId &other) const { return index == other.index && location == other.location; }
bool operator!=(const PipId &other) const { return index != other.index || location != other.location; } bool operator!=(const PipId &other) const { return index != other.index || location != other.location; }
bool operator<(const PipId &other) const { return location == other.location ? index < other.index : location < other.location; }
}; };
struct GroupId struct GroupId

View File

@ -40,7 +40,7 @@ class ECP5CommandHandler : public CommandHandler
void customBitstream(Context *ctx) override; void customBitstream(Context *ctx) override;
protected: protected:
po::options_description getArchOptions(); po::options_description getArchOptions() override;
}; };
ECP5CommandHandler::ECP5CommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {} ECP5CommandHandler::ECP5CommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {}

View File

@ -373,6 +373,8 @@ NetInfo *Arch::getBoundPipNet(PipId pip) const { return pips.at(pip).bound_net;
NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; } NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; }
WireId Arch::getConflictingPipWire(PipId pip) const { return pips.at(pip).bound_net ? pips.at(pip).dstWire : WireId(); }
const std::vector<PipId> &Arch::getPips() const { return pip_ids; } const std::vector<PipId> &Arch::getPips() const { return pip_ids; }
Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; } Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; }

View File

@ -172,6 +172,7 @@ struct Arch : BaseCtx
void unbindWire(WireId wire); void unbindWire(WireId wire);
bool checkWireAvail(WireId wire) const; bool checkWireAvail(WireId wire) const;
NetInfo *getBoundWireNet(WireId wire) const; NetInfo *getBoundWireNet(WireId wire) const;
WireId getConflictingWireWire(WireId wire) const { return wire; }
NetInfo *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;
@ -186,6 +187,7 @@ struct Arch : BaseCtx
void unbindPip(PipId pip); void unbindPip(PipId pip);
bool checkPipAvail(PipId pip) const; bool checkPipAvail(PipId pip) const;
NetInfo *getBoundPipNet(PipId pip) const; NetInfo *getBoundPipNet(PipId pip) const;
WireId getConflictingPipWire(PipId pip) const;
NetInfo *getConflictingPipNet(PipId pip) const; NetInfo *getConflictingPipNet(PipId pip) const;
const std::vector<PipId> &getPips() const; const std::vector<PipId> &getPips() const;
Loc getPipLocation(PipId pip) const; Loc getPipLocation(PipId pip) const;

View File

@ -37,7 +37,7 @@ class GenericCommandHandler : public CommandHandler
void customBitstream(Context *ctx) override; void customBitstream(Context *ctx) override;
protected: protected:
po::options_description getArchOptions(); po::options_description getArchOptions() override;
}; };
GenericCommandHandler::GenericCommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {} GenericCommandHandler::GenericCommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {}

View File

@ -638,6 +638,8 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
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->nameOf(ctx->getBoundWireNet(wire)), ElementType::NET); addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundWireNet(wire)), ElementType::NET);
addProperty(topItem, QVariant::String, "Conflicting Wire",
ctx->getWireName(ctx->getConflictingWireWire(wire)).c_str(ctx), ElementType::WIRE);
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)), addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)),
ElementType::NET); ElementType::NET);
@ -698,6 +700,8 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
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->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET); addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET);
addProperty(topItem, QVariant::String, "Conflicting Wire",
ctx->getWireName(ctx->getConflictingPipWire(pip)).c_str(ctx), ElementType::WIRE);
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)), 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),

View File

@ -404,7 +404,7 @@ struct Arch : BaseCtx
std::vector<CellInfo *> bel_to_cell; std::vector<CellInfo *> bel_to_cell;
std::vector<NetInfo *> wire_to_net; std::vector<NetInfo *> wire_to_net;
std::vector<NetInfo *> pip_to_net; std::vector<NetInfo *> pip_to_net;
std::vector<NetInfo *> switches_locked; std::vector<WireId> switches_locked;
ArchArgs args; ArchArgs args;
Arch(ArchArgs args); Arch(ArchArgs args);
@ -546,7 +546,7 @@ struct Arch : BaseCtx
auto pip = it->second.pip; auto pip = it->second.pip;
if (pip != PipId()) { if (pip != PipId()) {
pip_to_net[pip.index] = nullptr; pip_to_net[pip.index] = nullptr;
switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; switches_locked[chip_info->pip_data[pip.index].switch_index] = WireId();
} }
net_wires.erase(it); net_wires.erase(it);
@ -566,6 +566,8 @@ struct Arch : BaseCtx
return wire_to_net[wire.index]; return wire_to_net[wire.index];
} }
WireId getConflictingWireWire(WireId wire) const { return wire; }
NetInfo *getConflictingWireNet(WireId wire) const NetInfo *getConflictingWireNet(WireId wire) const
{ {
NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire != WireId());
@ -608,14 +610,15 @@ struct Arch : BaseCtx
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
NPNR_ASSERT(pip_to_net[pip.index] == nullptr); NPNR_ASSERT(pip_to_net[pip.index] == nullptr);
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == WireId());
pip_to_net[pip.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] == nullptr); NPNR_ASSERT(wire_to_net[dst.index] == nullptr);
pip_to_net[pip.index] = net;
switches_locked[chip_info->pip_data[pip.index].switch_index] = dst;
wire_to_net[dst.index] = net; wire_to_net[dst.index] = net;
net->wires[dst].pip = pip; net->wires[dst].pip = pip;
net->wires[dst].strength = strength; net->wires[dst].strength = strength;
@ -627,7 +630,7 @@ struct Arch : BaseCtx
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
NPNR_ASSERT(pip_to_net[pip.index] != nullptr); NPNR_ASSERT(pip_to_net[pip.index] != nullptr);
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != WireId());
WireId dst; WireId dst;
dst.index = chip_info->pip_data[pip.index].dst; dst.index = chip_info->pip_data[pip.index].dst;
@ -636,33 +639,39 @@ struct Arch : BaseCtx
pip_to_net[pip.index]->wires.erase(dst); pip_to_net[pip.index]->wires.erase(dst);
pip_to_net[pip.index] = nullptr; pip_to_net[pip.index] = nullptr;
switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; switches_locked[chip_info->pip_data[pip.index].switch_index] = WireId();
refreshUiPip(pip); refreshUiPip(pip);
refreshUiWire(dst); refreshUiWire(dst);
} }
bool checkPipAvail(PipId pip) const bool ice40_pip_hard_unavail(PipId pip) const
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
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] != nullptr)
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] != nullptr) if (bel_to_cell[si.bel] != nullptr)
return false; return true;
} }
if (pi.flags & PipInfoPOD::FLAG_NOCARRY) { if (pi.flags & PipInfoPOD::FLAG_NOCARRY) {
NPNR_ASSERT(si.bel >= 0); NPNR_ASSERT(si.bel >= 0);
if (bel_carry[si.bel]) if (bel_carry[si.bel])
return false; return true;
} }
return true; return false;
}
bool checkPipAvail(PipId pip) const
{
if (ice40_pip_hard_unavail(pip))
return false;
auto &pi = chip_info->pip_data[pip.index];
return switches_locked[pi.switch_index] == WireId();
} }
NetInfo *getBoundPipNet(PipId pip) const NetInfo *getBoundPipNet(PipId pip) const
@ -671,10 +680,21 @@ struct Arch : BaseCtx
return pip_to_net[pip.index]; return pip_to_net[pip.index];
} }
WireId getConflictingPipWire(PipId pip) const
{
if (ice40_pip_hard_unavail(pip))
return WireId();
return switches_locked[chip_info->pip_data[pip.index].switch_index];
}
NetInfo *getConflictingPipNet(PipId pip) const NetInfo *getConflictingPipNet(PipId pip) const
{ {
NPNR_ASSERT(pip != PipId()); if (ice40_pip_hard_unavail(pip))
return switches_locked[chip_info->pip_data[pip.index].switch_index]; return nullptr;
WireId wire = switches_locked[chip_info->pip_data[pip.index].switch_index];
return wire == WireId() ? nullptr : wire_to_net[wire.index];
} }
AllPipRange getPips() const AllPipRange getPips() const

View File

@ -66,6 +66,7 @@ struct BelId
bool operator==(const BelId &other) const { return index == other.index; } bool operator==(const BelId &other) const { return index == other.index; }
bool operator!=(const BelId &other) const { return index != other.index; } bool operator!=(const BelId &other) const { return index != other.index; }
bool operator<(const BelId &other) const { return index < other.index; }
}; };
struct WireId struct WireId
@ -74,6 +75,7 @@ struct WireId
bool operator==(const WireId &other) const { return index == other.index; } bool operator==(const WireId &other) const { return index == other.index; }
bool operator!=(const WireId &other) const { return index != other.index; } bool operator!=(const WireId &other) const { return index != other.index; }
bool operator<(const WireId &other) const { return index < other.index; }
}; };
struct PipId struct PipId
@ -82,6 +84,7 @@ struct PipId
bool operator==(const PipId &other) const { return index == other.index; } bool operator==(const PipId &other) const { return index == other.index; }
bool operator!=(const PipId &other) const { return index != other.index; } bool operator!=(const PipId &other) const { return index != other.index; }
bool operator<(const PipId &other) const { return index < other.index; }
}; };
struct GroupId struct GroupId

View File

@ -43,7 +43,7 @@ class Ice40CommandHandler : public CommandHandler
void customBitstream(Context *ctx) override; void customBitstream(Context *ctx) override;
protected: protected:
po::options_description getArchOptions(); po::options_description getArchOptions() override;
}; };
Ice40CommandHandler::Ice40CommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {} Ice40CommandHandler::Ice40CommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {}