Merge remote-tracking branch 'origin/master' into timingapi
This commit is contained in:
commit
2d39cde17b
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "nextpnr.h"
|
||||
#include "log.h"
|
||||
|
||||
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),
|
||||
expr_str(expr_str), filename(filename), line(line)
|
||||
{
|
||||
log_flush();
|
||||
}
|
||||
|
||||
void IdString::set(const BaseCtx *ctx, const std::string &s)
|
||||
@ -152,6 +154,30 @@ void BaseCtx::removeConstraint(IdString 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
|
||||
{
|
||||
if (net_info->driver.cell == nullptr)
|
||||
|
@ -288,7 +288,7 @@ struct ClockConstraint;
|
||||
struct NetInfo : ArchNetInfo
|
||||
{
|
||||
IdString name;
|
||||
int32_t udata;
|
||||
int32_t udata = 0;
|
||||
|
||||
PortRef driver;
|
||||
std::vector<PortRef> users;
|
||||
@ -579,13 +579,23 @@ struct BaseCtx
|
||||
|
||||
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)
|
||||
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;
|
||||
@ -657,6 +667,7 @@ struct Context : Arch, DeterministicRNG
|
||||
delay_t getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &sink) const;
|
||||
|
||||
// provided by router1.cc
|
||||
bool checkRoutedDesign() const;
|
||||
bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay = nullptr,
|
||||
std::unordered_map<WireId, PipId> *route = nullptr, bool useEstimate = true);
|
||||
|
||||
|
@ -28,19 +28,19 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type, float &tns)
|
||||
{
|
||||
wirelen_t wirelength = 0;
|
||||
Loc driver_loc;
|
||||
bool driver_gb;
|
||||
CellInfo *driver_cell = net->driver.cell;
|
||||
if (!driver_cell)
|
||||
return 0;
|
||||
if (driver_cell->bel == BelId())
|
||||
return 0;
|
||||
driver_gb = ctx->getBelGlobalBuf(driver_cell->bel);
|
||||
driver_loc = ctx->getBelLocation(driver_cell->bel);
|
||||
bool driver_gb = ctx->getBelGlobalBuf(driver_cell->bel);
|
||||
if (driver_gb)
|
||||
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 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;
|
||||
for (auto load : net->users) {
|
||||
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;
|
||||
if (load_cell->bel == BelId())
|
||||
continue;
|
||||
if (ctx->timing_driven && type == MetricType::COST) {
|
||||
if (timing_driven) {
|
||||
delay_t net_delay = ctx->predictDelay(net, load);
|
||||
auto slack = load.budget - net_delay;
|
||||
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);
|
||||
ymax = std::max(ymax, load_loc.y);
|
||||
}
|
||||
if (ctx->timing_driven && type == MetricType::COST) {
|
||||
if (timing_driven) {
|
||||
wirelength = wirelen_t(
|
||||
(((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-ctx->getDelayNS(worst_slack) / 5)))));
|
||||
} else {
|
||||
|
1601
common/router1.cc
1601
common/router1.cc
File diff suppressed because it is too large
Load Diff
@ -33,6 +33,10 @@ struct Router1Cfg : Settings
|
||||
bool cleanupReroute;
|
||||
bool fullCleanupReroute;
|
||||
bool useEstimate;
|
||||
delay_t wireRipupPenalty;
|
||||
delay_t netRipupPenalty;
|
||||
delay_t reuseBonus;
|
||||
delay_t estimatePrecision;
|
||||
};
|
||||
|
||||
extern bool router1(Context *ctx, const Router1Cfg &cfg);
|
||||
|
@ -30,15 +30,15 @@ delay_t maxDelay() const { return delay; }
|
||||
|
||||
### 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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@ -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.
|
||||
|
||||
### 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.
|
||||
|
||||
This returns nullptr if the wire is already available,
|
||||
or if there is no single net that can be unbound to make this
|
||||
wire available.
|
||||
### NetInfo \*getConflictingWireNet(WireId wire) const
|
||||
|
||||
If this returns a non-nullptr, then unbinding that entire net
|
||||
will make the given wire available.
|
||||
|
||||
### 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.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
Return the net that needs to be unbound in order to make this
|
||||
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.
|
||||
If this returns a non-nullptr, then unbinding that entire net
|
||||
will make the given pip available.
|
||||
|
||||
### const\_range\<PipId\> getPips() const
|
||||
|
||||
|
89
docs/faq.md
89
docs/faq.md
@ -38,7 +38,94 @@ For nextpnr we are using the following terminology.
|
||||
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
|
||||
-----------------------
|
||||
|
@ -400,7 +400,7 @@ BelId Arch::getBelByLocation(Loc loc) 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
|
||||
@ -409,7 +409,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
||||
auto driver_loc = getBelLocation(driver.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; }
|
||||
|
@ -619,6 +619,8 @@ struct Arch : BaseCtx
|
||||
return wire_to_net.at(wire);
|
||||
}
|
||||
|
||||
WireId getConflictingWireWire(WireId wire) const { return wire; }
|
||||
|
||||
NetInfo *getConflictingWireNet(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
@ -724,6 +726,8 @@ struct Arch : BaseCtx
|
||||
return pip_to_net.at(pip);
|
||||
}
|
||||
|
||||
WireId getConflictingPipWire(PipId pip) const { return WireId(); }
|
||||
|
||||
NetInfo *getConflictingPipNet(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
|
@ -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 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); }
|
||||
@ -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 location == other.location ? index < other.index : location < other.location; }
|
||||
};
|
||||
|
||||
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 location == other.location ? index < other.index : location < other.location; }
|
||||
};
|
||||
|
||||
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 location == other.location ? index < other.index : location < other.location; }
|
||||
};
|
||||
|
||||
struct GroupId
|
||||
|
@ -40,7 +40,7 @@ class ECP5CommandHandler : public CommandHandler
|
||||
void customBitstream(Context *ctx) override;
|
||||
|
||||
protected:
|
||||
po::options_description getArchOptions();
|
||||
po::options_description getArchOptions() override;
|
||||
};
|
||||
|
||||
ECP5CommandHandler::ECP5CommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {}
|
||||
|
@ -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; }
|
||||
|
||||
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; }
|
||||
|
||||
Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; }
|
||||
|
@ -172,6 +172,7 @@ struct Arch : BaseCtx
|
||||
void unbindWire(WireId wire);
|
||||
bool checkWireAvail(WireId wire) const;
|
||||
NetInfo *getBoundWireNet(WireId wire) const;
|
||||
WireId getConflictingWireWire(WireId wire) const { return wire; }
|
||||
NetInfo *getConflictingWireNet(WireId wire) const;
|
||||
DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); }
|
||||
const std::vector<WireId> &getWires() const;
|
||||
@ -186,6 +187,7 @@ struct Arch : BaseCtx
|
||||
void unbindPip(PipId pip);
|
||||
bool checkPipAvail(PipId pip) const;
|
||||
NetInfo *getBoundPipNet(PipId pip) const;
|
||||
WireId getConflictingPipWire(PipId pip) const;
|
||||
NetInfo *getConflictingPipNet(PipId pip) const;
|
||||
const std::vector<PipId> &getPips() const;
|
||||
Loc getPipLocation(PipId pip) const;
|
||||
|
@ -37,7 +37,7 @@ class GenericCommandHandler : public CommandHandler
|
||||
void customBitstream(Context *ctx) override;
|
||||
|
||||
protected:
|
||||
po::options_description getArchOptions();
|
||||
po::options_description getArchOptions() override;
|
||||
};
|
||||
|
||||
GenericCommandHandler::GenericCommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {}
|
||||
|
@ -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::Bool, "Available", ctx->checkWireAvail(wire));
|
||||
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)),
|
||||
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::Bool, "Available", ctx->checkPipAvail(pip));
|
||||
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)),
|
||||
ElementType::NET);
|
||||
addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx),
|
||||
|
52
ice40/arch.h
52
ice40/arch.h
@ -404,7 +404,7 @@ struct Arch : BaseCtx
|
||||
std::vector<CellInfo *> bel_to_cell;
|
||||
std::vector<NetInfo *> wire_to_net;
|
||||
std::vector<NetInfo *> pip_to_net;
|
||||
std::vector<NetInfo *> switches_locked;
|
||||
std::vector<WireId> switches_locked;
|
||||
|
||||
ArchArgs args;
|
||||
Arch(ArchArgs args);
|
||||
@ -546,7 +546,7 @@ struct Arch : BaseCtx
|
||||
auto pip = it->second.pip;
|
||||
if (pip != PipId()) {
|
||||
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);
|
||||
@ -566,6 +566,8 @@ struct Arch : BaseCtx
|
||||
return wire_to_net[wire.index];
|
||||
}
|
||||
|
||||
WireId getConflictingWireWire(WireId wire) const { return wire; }
|
||||
|
||||
NetInfo *getConflictingWireNet(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
@ -608,14 +610,15 @@ struct Arch : BaseCtx
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
NPNR_ASSERT(pip_to_net[pip.index] == nullptr);
|
||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr);
|
||||
|
||||
pip_to_net[pip.index] = net;
|
||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
|
||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == WireId());
|
||||
|
||||
WireId dst;
|
||||
dst.index = chip_info->pip_data[pip.index].dst;
|
||||
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;
|
||||
net->wires[dst].pip = pip;
|
||||
net->wires[dst].strength = strength;
|
||||
@ -627,7 +630,7 @@ struct Arch : BaseCtx
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
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;
|
||||
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] = 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);
|
||||
refreshUiWire(dst);
|
||||
}
|
||||
|
||||
bool checkPipAvail(PipId pip) const
|
||||
bool ice40_pip_hard_unavail(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
auto &pi = chip_info->pip_data[pip.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) {
|
||||
NPNR_ASSERT(si.bel >= 0);
|
||||
if (bel_to_cell[si.bel] != nullptr)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.flags & PipInfoPOD::FLAG_NOCARRY) {
|
||||
NPNR_ASSERT(si.bel >= 0);
|
||||
if (bel_carry[si.bel])
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
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
|
||||
@ -671,10 +680,21 @@ struct Arch : BaseCtx
|
||||
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
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
return switches_locked[chip_info->pip_data[pip.index].switch_index];
|
||||
if (ice40_pip_hard_unavail(pip))
|
||||
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
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
struct GroupId
|
||||
|
@ -43,7 +43,7 @@ class Ice40CommandHandler : public CommandHandler
|
||||
void customBitstream(Context *ctx) override;
|
||||
|
||||
protected:
|
||||
po::options_description getArchOptions();
|
||||
po::options_description getArchOptions() override;
|
||||
};
|
||||
|
||||
Ice40CommandHandler::Ice40CommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {}
|
||||
|
Loading…
Reference in New Issue
Block a user