Merge branch 'xc7-router_improve' into xc7
This commit is contained in:
commit
e19ad23ef4
@ -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)
|
||||||
@ -51,6 +53,30 @@ void IdString::initialize_add(const BaseCtx *ctx, const char *s, int idx)
|
|||||||
ctx->idstring_idx_to_str->push_back(&insert_rc.first->first);
|
ctx->idstring_idx_to_str->push_back(&insert_rc.first->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
@ -269,7 +269,7 @@ struct PipMap
|
|||||||
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;
|
||||||
@ -487,13 +487,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;
|
||||||
@ -541,6 +551,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);
|
||||||
|
|
||||||
|
1634
common/router1.cc
1634
common/router1.cc
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||||
|
@ -405,7 +405,26 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_path)
|
|||||||
log_info("%4.1f %4.1f Net %s budget %f ns (%d,%d) -> (%d,%d)\n", ctx->getDelayNS(net_delay),
|
log_info("%4.1f %4.1f Net %s budget %f ns (%d,%d) -> (%d,%d)\n", ctx->getDelayNS(net_delay),
|
||||||
ctx->getDelayNS(total), net->name.c_str(ctx), ctx->getDelayNS(sink->budget), driver_loc.x,
|
ctx->getDelayNS(total), net->name.c_str(ctx), ctx->getDelayNS(sink->budget), driver_loc.x,
|
||||||
driver_loc.y, sink_loc.x, sink_loc.y);
|
driver_loc.y, sink_loc.x, sink_loc.y);
|
||||||
log_info(" Sink %s.%s\n", sink_cell->name.c_str(ctx), sink->port.c_str(ctx));
|
log_info(" Sink %s.%s\n", sink_cell->name.c_str(ctx), sink->port.c_str(ctx));
|
||||||
|
if (ctx->verbose) {
|
||||||
|
auto driver_wire = ctx->getNetinfoSourceWire(net);
|
||||||
|
auto sink_wire = ctx->getNetinfoSinkWire(net, *sink);
|
||||||
|
log_info(" prediction: %f ns estimate: %f ns\n",
|
||||||
|
ctx->getDelayNS(ctx->predictDelay(net, *sink)), ctx->getDelayNS(ctx->estimateDelay(driver_wire, sink_wire)));
|
||||||
|
auto cursor = sink_wire;
|
||||||
|
delay_t cursor_delay;
|
||||||
|
while (driver_wire != cursor) {
|
||||||
|
cursor_delay = ctx->getWireDelay(cursor).maxDelay();
|
||||||
|
log_info(" %1.3f %30s\n", ctx->getDelayNS(cursor_delay), ctx->getWireName(cursor).c_str(ctx));
|
||||||
|
auto it = net->wires.find(cursor);
|
||||||
|
assert(it != net->wires.end());
|
||||||
|
auto pip = it->second.pip;
|
||||||
|
NPNR_ASSERT(pip != PipId());
|
||||||
|
cursor = ctx->getPipSrcWire(pip);
|
||||||
|
}
|
||||||
|
cursor_delay = ctx->getWireDelay(cursor).maxDelay();
|
||||||
|
log_info(" %1.3f %30s\n", ctx->getDelayNS(cursor_delay), ctx->getWireName(cursor).c_str(ctx));
|
||||||
|
}
|
||||||
last_port = sink->port;
|
last_port = sink->port;
|
||||||
}
|
}
|
||||||
log_break();
|
log_break();
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
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
|
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
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -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; }
|
||||||
|
@ -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());
|
||||||
|
@ -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
|
||||||
|
@ -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; }
|
||||||
|
@ -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;
|
||||||
|
@ -453,6 +453,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
|||||||
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);
|
||||||
|
|
||||||
@ -513,6 +515,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
|||||||
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),
|
||||||
|
54
ice40/arch.h
54
ice40/arch.h
@ -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
|
||||||
|
@ -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
|
||||||
|
141
xc7/arch.cc
141
xc7/arch.cc
@ -41,7 +41,7 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string
|
|||||||
site_index_to_type(construct_site_index_to_type(ctx, sites)),
|
site_index_to_type(construct_site_index_to_type(ctx, sites)),
|
||||||
bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)),
|
bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)),
|
||||||
wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)),
|
wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)),
|
||||||
num_wires(wire_to_tilewire.size()), wire_to_delay(construct_wire_to_delay(wire_to_tilewire, *ddb)),
|
num_wires(wire_to_tilewire.size()), wire_to_delay(construct_wire_to_delay(tiles, wire_to_tilewire, *ddb)),
|
||||||
pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)),
|
pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)),
|
||||||
num_pips(pip_to_arc.size())
|
num_pips(pip_to_arc.size())
|
||||||
{
|
{
|
||||||
@ -108,7 +108,7 @@ std::vector<Loc> TorcInfo::construct_bel_to_loc(const Sites &sites, const Tiles
|
|||||||
for (SiteIndex i(0); i < site_index_to_type.size(); ++i) {
|
for (SiteIndex i(0); i < site_index_to_type.size(); ++i) {
|
||||||
const auto &site = sites.getSite(i);
|
const auto &site = sites.getSite(i);
|
||||||
const auto &tile_info = tiles.getTileInfo(site.getTileIndex());
|
const auto &tile_info = tiles.getTileInfo(site.getTileIndex());
|
||||||
const auto x = tile_info.getCol();
|
const auto x = (tile_info.getCol() + 1) / 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs
|
||||||
const auto y = tile_info.getRow();
|
const auto y = tile_info.getRow();
|
||||||
|
|
||||||
if (site_index_to_type[i] == id_SLICE_LUT6) {
|
if (site_index_to_type[i] == id_SLICE_LUT6) {
|
||||||
@ -163,7 +163,7 @@ TorcInfo::construct_wire_to_tilewire(const Segments &segments, const Tiles &tile
|
|||||||
wire_to_tilewire.shrink_to_fit();
|
wire_to_tilewire.shrink_to_fit();
|
||||||
return wire_to_tilewire;
|
return wire_to_tilewire;
|
||||||
}
|
}
|
||||||
std::vector<DelayInfo> TorcInfo::construct_wire_to_delay(const std::vector<Tilewire> &wire_to_tilewire, const DDB &ddb)
|
std::vector<DelayInfo> TorcInfo::construct_wire_to_delay(const Tiles &tiles, const std::vector<Tilewire> &wire_to_tilewire, const DDB &ddb)
|
||||||
{
|
{
|
||||||
std::vector<DelayInfo> wire_to_delay;
|
std::vector<DelayInfo> wire_to_delay;
|
||||||
wire_to_delay.reserve(wire_to_tilewire.size());
|
wire_to_delay.reserve(wire_to_tilewire.size());
|
||||||
@ -174,45 +174,62 @@ std::vector<DelayInfo> TorcInfo::construct_wire_to_delay(const std::vector<Tilew
|
|||||||
const boost::regex re_BYP_B = boost::regex("BYP_[BL]\\d");
|
const boost::regex re_BYP_B = boost::regex("BYP_[BL]\\d");
|
||||||
const boost::regex re_BOUNCE_NS = boost::regex("(BYP|FAN)_BOUNCE_[NS]3_\\d");
|
const boost::regex re_BOUNCE_NS = boost::regex("(BYP|FAN)_BOUNCE_[NS]3_\\d");
|
||||||
const boost::regex re_FAN = boost::regex("FAN(_ALT)?\\d");
|
const boost::regex re_FAN = boost::regex("FAN(_ALT)?\\d");
|
||||||
|
const boost::regex re_CLB_I1_6 = boost::regex("CLBL[LM]_(L|LL|M)_[A-D]([1-6])");
|
||||||
|
|
||||||
|
std::unordered_map</*TileTypeIndex*/unsigned, std::vector<delay_t>> delay_lookup;
|
||||||
|
|
||||||
boost::cmatch what;
|
boost::cmatch what;
|
||||||
ExtendedWireInfo ewi(ddb);
|
|
||||||
for (const auto &tw : wire_to_tilewire) {
|
for (const auto &tw : wire_to_tilewire) {
|
||||||
ewi.set(tw);
|
const TileInfo& tileInfo = tiles.getTileInfo(tw.getTileIndex());
|
||||||
DelayInfo d;
|
auto tile_type_index = tileInfo.getTypeIndex();
|
||||||
if (boost::regex_match(ewi.mWireName, what, re_124)) {
|
|
||||||
switch (what.str(2)[0]) {
|
auto it = delay_lookup.find(tile_type_index);
|
||||||
case '1':
|
if (it == delay_lookup.end()) {
|
||||||
d.delay = 150;
|
auto wireCount = tiles.getWireCount(tile_type_index);
|
||||||
break;
|
std::vector<delay_t> tile_delays(wireCount);
|
||||||
case '2':
|
for (WireIndex wireIndex(0); wireIndex < wireCount; wireIndex++) {
|
||||||
d.delay = 170;
|
const WireInfo& wireInfo = tiles.getWireInfo(tile_type_index, wireIndex);
|
||||||
break;
|
auto wire_name = wireInfo.getName();
|
||||||
case '4':
|
if (boost::regex_match(wire_name, what, re_124)) {
|
||||||
d.delay = 210;
|
switch (what.str(2)[0]) {
|
||||||
break;
|
case '1': tile_delays[wireIndex] = 150; break;
|
||||||
case '6':
|
case '2': tile_delays[wireIndex] = 170; break;
|
||||||
d.delay = 210;
|
case '4': tile_delays[wireIndex] = 210; break;
|
||||||
break;
|
case '6': tile_delays[wireIndex] = 210; break;
|
||||||
default:
|
default: throw;
|
||||||
throw;
|
}
|
||||||
|
} else if (boost::regex_match(wire_name, what, re_L)) {
|
||||||
|
std::string l(what[2]);
|
||||||
|
if (l == "H")
|
||||||
|
tile_delays[wireIndex] = 360;
|
||||||
|
else if (l == "VB")
|
||||||
|
tile_delays[wireIndex] = 300;
|
||||||
|
else if (l == "V")
|
||||||
|
tile_delays[wireIndex] = 350;
|
||||||
|
else
|
||||||
|
throw;
|
||||||
|
} else if (boost::regex_match(wire_name, what, re_BYP)) {
|
||||||
|
tile_delays[wireIndex] = 190;
|
||||||
|
} else if (boost::regex_match(wire_name, what, re_BYP_B)) {
|
||||||
|
} else if (boost::regex_match(wire_name, what, re_FAN)) {
|
||||||
|
tile_delays[wireIndex] = 190;
|
||||||
|
} else if (boost::regex_match(wire_name, what, re_CLB_I1_6)) {
|
||||||
|
switch (what.str(2)[0]) {
|
||||||
|
case '1': tile_delays[wireIndex] = 280; break;
|
||||||
|
case '2': tile_delays[wireIndex] = 280; break;
|
||||||
|
case '3': tile_delays[wireIndex] = 180; break;
|
||||||
|
case '4': tile_delays[wireIndex] = 180; break;
|
||||||
|
case '5': tile_delays[wireIndex] = 80; break;
|
||||||
|
case '6': tile_delays[wireIndex] = 40; break;
|
||||||
|
default: throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (boost::regex_match(ewi.mWireName, what, re_L)) {
|
it = delay_lookup.emplace(tile_type_index, std::move(tile_delays)).first;
|
||||||
std::string l(what[2]);
|
|
||||||
if (l == "H")
|
|
||||||
d.delay = 360;
|
|
||||||
else if (l == "VB")
|
|
||||||
d.delay = 300;
|
|
||||||
else if (l == "V")
|
|
||||||
d.delay = 350;
|
|
||||||
else
|
|
||||||
throw;
|
|
||||||
} else if (boost::regex_match(ewi.mWireName, what, re_BYP)) {
|
|
||||||
d.delay = 190;
|
|
||||||
} else if (boost::regex_match(ewi.mWireName, what, re_BYP_B)) {
|
|
||||||
} else if (boost::regex_match(ewi.mWireName, what, re_FAN)) {
|
|
||||||
d.delay = 190;
|
|
||||||
}
|
}
|
||||||
|
assert(it != delay_lookup.end());
|
||||||
|
DelayInfo d;
|
||||||
|
d.delay = it->second[tw.getWireIndex()];
|
||||||
wire_to_delay.emplace_back(std::move(d));
|
wire_to_delay.emplace_back(std::move(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,20 +617,26 @@ IdString Arch::getPipName(PipId pip) const
|
|||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
|
|
||||||
#if 1
|
ExtendedWireInfo ewi_src(*torc_info->ddb, torc_info->pip_to_arc[pip.index].getSourceTilewire());
|
||||||
int x = chip_info->pip_data[pip.index].x;
|
ExtendedWireInfo ewi_dst(*torc_info->ddb, torc_info->pip_to_arc[pip.index].getSinkTilewire());
|
||||||
int y = chip_info->pip_data[pip.index].y;
|
std::stringstream pip_name;
|
||||||
|
pip_name << ewi_src.mTileName << "." << ewi_src.mWireName << ".->." << ewi_dst.mWireName;
|
||||||
|
return id(pip_name.str());
|
||||||
|
|
||||||
std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get();
|
//#if 1
|
||||||
std::replace(src_name.begin(), src_name.end(), '/', '.');
|
// int x = chip_info->pip_data[pip.index].x;
|
||||||
|
// int y = chip_info->pip_data[pip.index].y;
|
||||||
std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get();
|
//
|
||||||
std::replace(dst_name.begin(), dst_name.end(), '/', '.');
|
// std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get();
|
||||||
|
// std::replace(src_name.begin(), src_name.end(), '/', '.');
|
||||||
return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name);
|
//
|
||||||
#else
|
// std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get();
|
||||||
return id(chip_info->pip_data[pip.index].name.get());
|
// std::replace(dst_name.begin(), dst_name.end(), '/', '.');
|
||||||
#endif
|
//
|
||||||
|
// return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name);
|
||||||
|
//#else
|
||||||
|
// return id(chip_info->pip_data[pip.index].name.get());
|
||||||
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
@ -957,8 +980,22 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
|
|||||||
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
||||||
{
|
{
|
||||||
if (cell->type == id_SLICE_LUT6) {
|
if (cell->type == id_SLICE_LUT6) {
|
||||||
if (fromPort.index >= id_I1.index && fromPort.index <= id_I6.index)
|
if (fromPort.index >= id_I1.index && fromPort.index <= id_I6.index) {
|
||||||
return toPort == id_O || toPort == id_OQ;
|
if (toPort == id_O) {
|
||||||
|
delay.delay = 124; // Tilo
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (toPort == id_OQ) {
|
||||||
|
delay.delay = 95; // Tas
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fromPort == id_CLK) {
|
||||||
|
if (toPort == id_OQ) {
|
||||||
|
delay.delay = 456; // Tcko
|
||||||
|
return false; // No path CLK->OQ, but this fn is used for getting clkToQ delay
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (cell->type == id_BUFGCTRL) {
|
} else if (cell->type == id_BUFGCTRL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
12
xc7/arch.h
12
xc7/arch.h
@ -331,7 +331,7 @@ struct TorcInfo
|
|||||||
construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles,
|
construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles,
|
||||||
std::unordered_map<Segments::SegmentReference, int> &segment_to_wire,
|
std::unordered_map<Segments::SegmentReference, int> &segment_to_wire,
|
||||||
std::unordered_map<Tilewire, int> &trivial_to_wire);
|
std::unordered_map<Tilewire, int> &trivial_to_wire);
|
||||||
static std::vector<DelayInfo> construct_wire_to_delay(const std::vector<Tilewire> &wire_to_tilewire,
|
static std::vector<DelayInfo> construct_wire_to_delay(const Tiles &tiles, const std::vector<Tilewire> &wire_to_tilewire,
|
||||||
const DDB &ddb);
|
const DDB &ddb);
|
||||||
static std::vector<Arc> construct_pip_to_arc(const std::vector<Tilewire> &wire_to_tilewire, const DDB &ddb,
|
static std::vector<Arc> construct_pip_to_arc(const std::vector<Tilewire> &wire_to_tilewire, const DDB &ddb,
|
||||||
std::vector<std::vector<int>> &wire_to_pips_uphill,
|
std::vector<std::vector<int>> &wire_to_pips_uphill,
|
||||||
@ -677,6 +677,11 @@ 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());
|
||||||
@ -773,6 +778,11 @@ struct Arch : BaseCtx
|
|||||||
return pip_to_net[pip.index];
|
return pip_to_net[pip.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
@ -70,6 +70,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
|
||||||
@ -78,6 +79,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
|
||||||
@ -86,6 +88,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
|
||||||
|
@ -4,5 +4,5 @@ COMP "led2" LOCATE = SITE "G14" LEVEL 1;
|
|||||||
COMP "led3" LOCATE = SITE "D18" LEVEL 1;
|
COMP "led3" LOCATE = SITE "D18" LEVEL 1;
|
||||||
COMP "clki" LOCATE = SITE "K17" LEVEL 1;
|
COMP "clki" LOCATE = SITE "K17" LEVEL 1;
|
||||||
NET "clki" PERIOD = 8 nS ;
|
NET "clki" PERIOD = 8 nS ;
|
||||||
PIN "clki_pin" = BEL "clki$iob.PAD" PINNAME PAD;
|
PIN "clki_pin" = BEL "clki.PAD" PINNAME PAD;
|
||||||
PIN "clki_pin" CLOCK_DEDICATED_ROUTE = FALSE;
|
PIN "clki_pin" CLOCK_DEDICATED_ROUTE = FALSE;
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -ex
|
set -ex
|
||||||
yosys blinky.ys
|
yosys blinky.ys
|
||||||
../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 250
|
../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 150
|
||||||
xdl -xdl2ncd blinky.xdl
|
xdl -xdl2ncd blinky.xdl
|
||||||
bitgen -w blinky.ncd -g UnconstrainedPins:Allow
|
bitgen -w blinky.ncd -g UnconstrainedPins:Allow
|
||||||
trce blinky.ncd -v 10
|
trce blinky.ncd -v 10
|
||||||
netgen -ofmt verilog -w blinky.ncd blinky_chip.v -tm blinky
|
#netgen -ofmt verilog -w blinky.ncd blinky_chip.v -tm blinky -insert_glbl true
|
||||||
iverilog -o blinky_tb blinky_chip.v blinky_tb.v -y/opt/Xilinx/14.7/ISE_DS/ISE/verilog/src/simprims/ -insert_glbl true
|
#iverilog -o blinky_tb blinky_chip.v blinky_tb.v -y/opt/Xilinx/14.7/ISE_DS/ISE/verilog/src/simprims/
|
||||||
vvp -N ./blinky_tb
|
#vvp -N ./blinky_tb
|
||||||
|
|
||||||
|
#xdl -xdl2ncd blinky.xdl -nopips blinky_map.ncd
|
||||||
|
#par -w blinky_map.ncd blinky_par.ncd blinky.pcf
|
||||||
|
#bitgen -w blinky_par.ncd -g UnconstrainedPins:Allow
|
||||||
|
@ -5,7 +5,7 @@ module blinky (
|
|||||||
output led2,
|
output led2,
|
||||||
output led3
|
output led3
|
||||||
);
|
);
|
||||||
`include "ps7.vh"
|
//`include "ps7.vh"
|
||||||
|
|
||||||
BUFGCTRL clk_gb (
|
BUFGCTRL clk_gb (
|
||||||
.I0(clki),
|
.I0(clki),
|
||||||
@ -19,7 +19,7 @@ module blinky (
|
|||||||
);
|
);
|
||||||
|
|
||||||
localparam BITS = 4;
|
localparam BITS = 4;
|
||||||
localparam LOG2DELAY = 21;
|
localparam LOG2DELAY = 23;
|
||||||
|
|
||||||
reg [BITS+LOG2DELAY-1:0] counter = 0;
|
reg [BITS+LOG2DELAY-1:0] counter = 0;
|
||||||
reg [BITS-1:0] outcnt;
|
reg [BITS-1:0] outcnt;
|
||||||
@ -29,5 +29,5 @@ module blinky (
|
|||||||
outcnt <= counter >> LOG2DELAY;
|
outcnt <= counter >> LOG2DELAY;
|
||||||
end
|
end
|
||||||
|
|
||||||
assign {led0, led1, led2, led3} = outcnt ^ (outcnt >> 1);
|
assign {led0, led1, led2, led3} = outcnt /*^ (outcnt >> 1)*/;
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -4,12 +4,12 @@ module blinky_tb;
|
|||||||
|
|
||||||
wire led0, led1, led2, led3;
|
wire led0, led1, led2, led3;
|
||||||
|
|
||||||
chip uut (
|
blinky uut (
|
||||||
.\clki$iob.PAD.PAD (clk),
|
.\clki.PAD.PAD (clk),
|
||||||
.\led0$iob.OUTBUF.OUT (led0),
|
.\led0.OUTBUF.OUT (led0),
|
||||||
.\led1$iob.OUTBUF.OUT (led1),
|
.\led1.OUTBUF.OUT (led1),
|
||||||
.\led2$iob.OUTBUF.OUT (led2),
|
.\led2.OUTBUF.OUT (led2),
|
||||||
.\led3$iob.OUTBUF.OUT (led3)
|
.\led3.OUTBUF.OUT (led3)
|
||||||
);
|
);
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
|
12
xc7/cells.cc
12
xc7/cells.cc
@ -259,17 +259,17 @@ std::unique_ptr<CellInfo> create_xc7_cell(Context *ctx, IdString type, std::stri
|
|||||||
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff)
|
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff)
|
||||||
{
|
{
|
||||||
lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")];
|
lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")];
|
||||||
replace_port(lut, ctx->id("I0"), lc, id_I1);
|
replace_port(lut, ctx->id("I0"), lc, id_I6);
|
||||||
if (get_net_or_empty(lut, id_I1))
|
if (get_net_or_empty(lut, id_I1))
|
||||||
replace_port(lut, id_I1, lc, id_I2);
|
replace_port(lut, id_I1, lc, id_I5);
|
||||||
if (get_net_or_empty(lut, id_I2))
|
if (get_net_or_empty(lut, id_I2))
|
||||||
replace_port(lut, id_I2, lc, id_I3);
|
replace_port(lut, id_I2, lc, id_I4);
|
||||||
if (get_net_or_empty(lut, id_I3))
|
if (get_net_or_empty(lut, id_I3))
|
||||||
replace_port(lut, id_I3, lc, id_I4);
|
replace_port(lut, id_I3, lc, id_I3);
|
||||||
if (get_net_or_empty(lut, id_I4))
|
if (get_net_or_empty(lut, id_I4))
|
||||||
replace_port(lut, id_I4, lc, id_I5);
|
replace_port(lut, id_I4, lc, id_I2);
|
||||||
if (get_net_or_empty(lut, id_I5))
|
if (get_net_or_empty(lut, id_I5))
|
||||||
replace_port(lut, id_I5, lc, id_I6);
|
replace_port(lut, id_I5, lc, id_I1);
|
||||||
if (no_dff) {
|
if (no_dff) {
|
||||||
replace_port(lut, id_O, lc, id_O);
|
replace_port(lut, id_O, lc, id_O);
|
||||||
lc->params[ctx->id("DFF_ENABLE")] = "0";
|
lc->params[ctx->id("DFF_ENABLE")] = "0";
|
||||||
|
46
xc7/delay.cc
46
xc7/delay.cc
@ -104,8 +104,27 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const
|
|||||||
const auto &src_info = torc_info->tiles.getTileInfo(src_tw.getTileIndex());
|
const auto &src_info = torc_info->tiles.getTileInfo(src_tw.getTileIndex());
|
||||||
const auto &dst_tw = torc_info->wire_to_tilewire[dst.index];
|
const auto &dst_tw = torc_info->wire_to_tilewire[dst.index];
|
||||||
const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex());
|
const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex());
|
||||||
|
auto abs_delta_x = (abs(src_info.getCol() - dst_info.getCol()) + 1)/ 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs
|
||||||
return 100 * (abs(src_info.getCol() - dst_info.getCol()) + abs(src_info.getRow() - dst_info.getRow()));
|
auto abs_delta_y = abs(src_info.getRow() - dst_info.getRow());
|
||||||
|
#if 1
|
||||||
|
auto div_LH = std::div(abs_delta_x, 12);
|
||||||
|
auto div_LV = std::div(abs_delta_y, 18);
|
||||||
|
auto div_LVB = std::div(div_LV.rem, 12);
|
||||||
|
auto div_H6 = std::div(div_LH.rem, 6);
|
||||||
|
auto div_V6 = std::div(div_LVB.rem, 6);
|
||||||
|
auto div_H4 = std::div(div_H6.rem, 4);
|
||||||
|
auto div_V4 = std::div(div_V6.rem, 4);
|
||||||
|
auto div_H2 = std::div(div_H4.rem, 2);
|
||||||
|
auto div_V2 = std::div(div_V4.rem, 2);
|
||||||
|
auto num_H1 = div_H2.rem;
|
||||||
|
auto num_V1 = div_V2.rem;
|
||||||
|
return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350
|
||||||
|
+ (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210
|
||||||
|
+ (div_H2.quot + div_V2.quot) * 170
|
||||||
|
+ (num_H1 + num_V1) * 150;
|
||||||
|
#else
|
||||||
|
return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
||||||
@ -113,8 +132,27 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
|||||||
const auto &driver = net_info->driver;
|
const auto &driver = net_info->driver;
|
||||||
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);
|
||||||
|
auto abs_delta_x = abs(driver_loc.x - sink_loc.x);
|
||||||
return 100 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y));
|
auto abs_delta_y = abs(driver_loc.y - sink_loc.y);
|
||||||
|
#if 1
|
||||||
|
auto div_LH = std::div(abs_delta_x, 12);
|
||||||
|
auto div_LV = std::div(abs_delta_y, 18);
|
||||||
|
auto div_LVB = std::div(div_LV.rem, 12);
|
||||||
|
auto div_H6 = std::div(div_LH.rem, 6);
|
||||||
|
auto div_V6 = std::div(div_LVB.rem, 6);
|
||||||
|
auto div_H4 = std::div(div_H6.rem, 4);
|
||||||
|
auto div_V4 = std::div(div_V6.rem, 4);
|
||||||
|
auto div_H2 = std::div(div_H4.rem, 2);
|
||||||
|
auto div_V2 = std::div(div_V4.rem, 2);
|
||||||
|
auto num_H1 = div_H2.rem;
|
||||||
|
auto num_V1 = div_V2.rem;
|
||||||
|
return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350
|
||||||
|
+ (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210
|
||||||
|
+ (div_H2.quot + div_V2.quot) * 170
|
||||||
|
+ (num_H1 + num_V1) * 150;
|
||||||
|
#else
|
||||||
|
return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -421,7 +421,7 @@ static void pack_io(Context *ctx)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create a IOBUF buffer
|
// Create a IOBUF buffer
|
||||||
std::unique_ptr<CellInfo> ice_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx) + "$iob");
|
std::unique_ptr<CellInfo> ice_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx));
|
||||||
nxio_to_sb(ctx, ci, ice_cell.get());
|
nxio_to_sb(ctx, ci, ice_cell.get());
|
||||||
new_cells.push_back(std::move(ice_cell));
|
new_cells.push_back(std::move(ice_cell));
|
||||||
sb = new_cells.back().get();
|
sb = new_cells.back().get();
|
||||||
|
3
xc7/picorv32.pcf
Normal file
3
xc7/picorv32.pcf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
NET "clk" PERIOD = 8 nS ;
|
||||||
|
PIN "clk_pin" = BEL "clk.PAD" PINNAME PAD;
|
||||||
|
PIN "clk_pin" CLOCK_DEDICATED_ROUTE = FALSE;
|
@ -3,6 +3,7 @@ set -ex
|
|||||||
rm -f picorv32.v
|
rm -f picorv32.v
|
||||||
wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v
|
wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v
|
||||||
yosys picorv32.ys
|
yosys picorv32.ys
|
||||||
../nextpnr-xc7 --json picorv32.json --xdl picorv32.xdl
|
../nextpnr-xc7 --json picorv32.json --xdl picorv32.xdl --pcf picorv32.pcf --freq 150
|
||||||
#../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json
|
xdl -xdl2ncd picorv32.xdl
|
||||||
#icetime -d hx8k -t picorv32.asc
|
#bitgen -w blinky.ncd -g UnconstrainedPins:Allow
|
||||||
|
trce picorv32.ncd -v 10
|
||||||
|
Loading…
Reference in New Issue
Block a user