aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/chain_utils.h68
-rw-r--r--common/design_utils.cc52
-rw-r--r--common/design_utils.h9
-rw-r--r--common/log.cc11
-rw-r--r--common/nextpnr.cc12
-rw-r--r--common/place_common.cc3
-rw-r--r--common/placer1.cc14
-rw-r--r--common/router1.cc6
-rw-r--r--common/settings.h4
-rw-r--r--common/timing.cc16
10 files changed, 182 insertions, 13 deletions
diff --git a/common/chain_utils.h b/common/chain_utils.h
new file mode 100644
index 00000000..b783e30b
--- /dev/null
+++ b/common/chain_utils.h
@@ -0,0 +1,68 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 David Shah <david@symbioticeda.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef CHAIN_UTILS_H
+#define CHAIN_UTILS_H
+
+#include "nextpnr.h"
+#include "util.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+struct CellChain
+{
+ std::vector<CellInfo *> cells;
+};
+
+// Generic chain finder
+template <typename F1, typename F2, typename F3>
+std::vector<CellChain> find_chains(const Context *ctx, F1 cell_type_predicate, F2 get_previous, F3 get_next,
+ size_t min_length = 2)
+{
+ std::set<IdString> chained;
+ std::vector<CellChain> chains;
+ for (auto cell : sorted(ctx->cells)) {
+ if (chained.find(cell.first) != chained.end())
+ continue;
+ CellInfo *ci = cell.second;
+ if (cell_type_predicate(ctx, ci)) {
+ CellInfo *start = ci;
+ CellInfo *prev_start = ci;
+ while (prev_start != nullptr) {
+ start = prev_start;
+ prev_start = get_previous(ctx, start);
+ }
+ CellChain chain;
+ CellInfo *end = start;
+ while (end != nullptr) {
+ chain.cells.push_back(end);
+ end = get_next(ctx, end);
+ }
+ if (chain.cells.size() >= min_length) {
+ chains.push_back(chain);
+ for (auto c : chain.cells)
+ chained.insert(c->name);
+ }
+ }
+ }
+ return chains;
+}
+
+NEXTPNR_NAMESPACE_END
+#endif
diff --git a/common/design_utils.cc b/common/design_utils.cc
index 21c9dcc4..a0b87764 100644
--- a/common/design_utils.cc
+++ b/common/design_utils.cc
@@ -19,6 +19,7 @@
*/
#include "design_utils.h"
+#include <algorithm>
#include <map>
#include "log.h"
#include "util.h"
@@ -73,4 +74,55 @@ void print_utilisation(const Context *ctx)
log_break();
}
+// Connect a net to a port
+void connect_port(const Context *ctx, NetInfo *net, CellInfo *cell, IdString port_name)
+{
+ if (net == nullptr)
+ return;
+ PortInfo &port = cell->ports.at(port_name);
+ NPNR_ASSERT(port.net == nullptr);
+ port.net = net;
+ if (port.type == PORT_OUT) {
+ NPNR_ASSERT(net->driver.cell == nullptr);
+ net->driver.cell = cell;
+ net->driver.port = port_name;
+ } else if (port.type == PORT_IN) {
+ PortRef user;
+ user.cell = cell;
+ user.port = port_name;
+ net->users.push_back(user);
+ } else {
+ NPNR_ASSERT_FALSE("invalid port type for connect_port");
+ }
+}
+
+void disconnect_port(const Context *ctx, CellInfo *cell, IdString port_name)
+{
+ if (!cell->ports.count(port_name))
+ return;
+ PortInfo &port = cell->ports.at(port_name);
+ if (port.net != nullptr) {
+ port.net->users.erase(std::remove_if(port.net->users.begin(), port.net->users.end(),
+ [cell, port_name](const PortRef &user) {
+ return user.cell == cell && user.port == port_name;
+ }),
+ port.net->users.end());
+ }
+}
+
+void connect_ports(Context *ctx, CellInfo *cell1, IdString port1_name, CellInfo *cell2, IdString port2_name)
+{
+ PortInfo &port1 = cell1->ports.at(port1_name);
+ if (port1.net == nullptr) {
+ // No net on port1; need to create one
+ std::unique_ptr<NetInfo> p1net(new NetInfo());
+ p1net->name = ctx->id(cell1->name.str(ctx) + "$conn$" + port1_name.str(ctx));
+ connect_port(ctx, p1net.get(), cell1, port1_name);
+ IdString p1name = p1net->name;
+ NPNR_ASSERT(!ctx->cells.count(p1name));
+ ctx->nets[p1name] = std::move(p1net);
+ }
+ connect_port(ctx, port1.net, cell2, port2_name);
+}
+
NEXTPNR_NAMESPACE_END
diff --git a/common/design_utils.h b/common/design_utils.h
index 95975179..8a42d21f 100644
--- a/common/design_utils.h
+++ b/common/design_utils.h
@@ -82,6 +82,15 @@ template <typename F1> CellInfo *net_driven_by(const Context *ctx, const NetInfo
}
}
+// Connect a net to a port
+void connect_port(const Context *ctx, NetInfo *net, CellInfo *cell, IdString port_name);
+
+// Disconnect a net from a port
+void disconnect_port(const Context *ctx, CellInfo *cell, IdString port_name);
+
+// Connect two ports together
+void connect_ports(Context *ctx, CellInfo *cell1, IdString port1_name, CellInfo *cell2, IdString port2_name);
+
void print_utilisation(const Context *ctx);
NEXTPNR_NAMESPACE_END
diff --git a/common/log.cc b/common/log.cc
index e30449ad..6b2d6065 100644
--- a/common/log.cc
+++ b/common/log.cc
@@ -177,7 +177,8 @@ void log_always(const char *format, ...)
void log(const char *format, ...)
{
- if (log_quiet_warnings) return;
+ if (log_quiet_warnings)
+ return;
va_list ap;
va_start(ap, format);
logv(format, ap);
@@ -186,7 +187,8 @@ void log(const char *format, ...)
void log_info(const char *format, ...)
{
- if (log_quiet_warnings) return;
+ if (log_quiet_warnings)
+ return;
va_list ap;
va_start(ap, format);
logv_info(format, ap);
@@ -195,7 +197,6 @@ void log_info(const char *format, ...)
void log_warning(const char *format, ...)
{
- if (log_quiet_warnings) return;
va_list ap;
va_start(ap, format);
logv_warning(format, ap);
@@ -204,7 +205,6 @@ void log_warning(const char *format, ...)
void log_warning_noprefix(const char *format, ...)
{
- if (log_quiet_warnings) return;
va_list ap;
va_start(ap, format);
logv_warning_noprefix(format, ap);
@@ -235,7 +235,8 @@ void log_cmd_error(const char *format, ...)
void log_break()
{
- if (log_quiet_warnings) return;
+ if (log_quiet_warnings)
+ return;
if (log_newline_count < 2)
log_always("\n");
if (log_newline_count < 2)
diff --git a/common/nextpnr.cc b/common/nextpnr.cc
index b04679ad..4e6407b2 100644
--- a/common/nextpnr.cc
+++ b/common/nextpnr.cc
@@ -89,6 +89,11 @@ WireId Context::getNetinfoSinkWire(const NetInfo *net_info, const PortRef &user_
delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &user_info) const
{
+#ifdef ARCH_ECP5
+ if (net_info->is_global)
+ return 0;
+#endif
+
WireId src_wire = getNetinfoSourceWire(net_info);
if (src_wire == WireId())
return 0;
@@ -99,8 +104,10 @@ delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &us
while (cursor != WireId() && cursor != src_wire) {
auto it = net_info->wires.find(cursor);
+
if (it == net_info->wires.end())
break;
+
PipId pip = it->second.pip;
delay += getPipDelay(pip).maxDelay();
delay += getWireDelay(cursor).maxDelay();
@@ -238,6 +245,11 @@ void Context::check() const
NPNR_ASSERT(ni == getBoundPipNet(w.second.pip));
}
}
+ if (ni->driver.cell != nullptr)
+ NPNR_ASSERT(ni->driver.cell->ports.at(ni->driver.port).net == ni);
+ for (auto user : ni->users) {
+ NPNR_ASSERT(user.cell->ports.at(user.port).net == ni);
+ }
}
for (auto w : getWires()) {
diff --git a/common/place_common.cc b/common/place_common.cc
index 5cdb96ef..120e5e00 100644
--- a/common/place_common.cc
+++ b/common/place_common.cc
@@ -329,7 +329,8 @@ class ConstraintLegaliseWorker
yRootSearch = IncreasingDiameterSearch(cell->constr_y);
if (cell->constr_z == cell->UNCONSTR)
- zRootSearch = IncreasingDiameterSearch(currentLoc.z, 0, ctx->getTileBelDimZ(currentLoc.x, currentLoc.y));
+ zRootSearch =
+ IncreasingDiameterSearch(currentLoc.z, 0, ctx->getTileBelDimZ(currentLoc.x, currentLoc.y));
else
zRootSearch = IncreasingDiameterSearch(cell->constr_z);
while (!xRootSearch.done()) {
diff --git a/common/placer1.cc b/common/placer1.cc
index 363b4d58..01f822a5 100644
--- a/common/placer1.cc
+++ b/common/placer1.cc
@@ -81,7 +81,8 @@ class SAPlacer
}
}
- ~SAPlacer() {
+ ~SAPlacer()
+ {
for (auto &net : ctx->nets)
net.second->udata = old_udata[net.second->udata];
}
@@ -351,7 +352,7 @@ class SAPlacer
// Attempt a SA position swap, return true on success or false on failure
bool try_swap_position(CellInfo *cell, BelId newBel)
{
- static std::vector<NetInfo*> updates;
+ static std::vector<NetInfo *> updates;
updates.clear();
BelId oldBel = cell->bel;
CellInfo *other_cell = ctx->getBoundBelCell(newBel);
@@ -371,7 +372,8 @@ class SAPlacer
for (const auto &port : cell->ports) {
if (port.second.net != nullptr) {
auto &cost = costs[port.second.net->udata];
- if (cost.new_cost == 0) continue;
+ if (cost.new_cost == 0)
+ continue;
cost.new_cost = 0;
updates.emplace_back(port.second.net);
}
@@ -381,7 +383,8 @@ class SAPlacer
for (const auto &port : other_cell->ports)
if (port.second.net != nullptr) {
auto &cost = costs[port.second.net->udata];
- if (cost.new_cost == 0) continue;
+ if (cost.new_cost == 0)
+ continue;
cost.new_cost = 0;
updates.emplace_back(port.second.net);
}
@@ -483,7 +486,8 @@ class SAPlacer
const float post_legalise_dia_scale = 1.5;
Placer1Cfg cfg;
- struct CostChange {
+ struct CostChange
+ {
wirelen_t curr_cost;
wirelen_t new_cost;
};
diff --git a/common/router1.cc b/common/router1.cc
index 5cd4414c..c4708de7 100644
--- a/common/router1.cc
+++ b/common/router1.cc
@@ -532,6 +532,12 @@ void addNetRouteJobs(Context *ctx, const Router1Cfg &cfg, IdString net_name,
{
NetInfo *net_info = ctx->nets.at(net_name).get();
+#ifdef ARCH_ECP5
+ // ECP5 global nets currently appear part-unrouted due to arch database limitations
+ // Don't touch them in the router
+ if (net_info->is_global)
+ return;
+#endif
if (net_info->driver.cell == nullptr)
return;
diff --git a/common/settings.h b/common/settings.h
index e1f1166a..0c4a67db 100644
--- a/common/settings.h
+++ b/common/settings.h
@@ -38,7 +38,7 @@ class Settings
if (!pair.second) {
return boost::lexical_cast<T>(pair.first->second);
}
-
+
} catch (boost::bad_lexical_cast &) {
log_error("Problem reading setting %s, using default value\n", name);
}
@@ -51,7 +51,7 @@ class Settings
auto pair = ctx->settings.emplace(id, std::to_string(value));
if (!pair.second) {
ctx->settings[pair.first->first] = value;
- }
+ }
}
private:
diff --git a/common/timing.cc b/common/timing.cc
index a0735b55..d1a85779 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -151,6 +151,22 @@ struct Timing
}
// Sanity check to ensure that all ports where fanins were recorded were indeed visited
+ if (!port_fanin.empty()) {
+ for (auto fanin : port_fanin) {
+ NetInfo *net = fanin.first->net;
+ if (net != nullptr) {
+ log_info(" remaining fanin includes %s (net %s)\n", fanin.first->name.c_str(ctx),
+ net->name.c_str(ctx));
+ if (net->driver.cell != nullptr)
+ log_info(" driver = %s.%s\n", net->driver.cell->name.c_str(ctx),
+ net->driver.port.c_str(ctx));
+ for (auto net_user : net->users)
+ log_info(" user: %s.%s\n", net_user.cell->name.c_str(ctx), net_user.port.c_str(ctx));
+ } else {
+ log_info(" remaining fanin includes %s (no net)\n", fanin.first->name.c_str(ctx));
+ }
+ }
+ }
NPNR_ASSERT(port_fanin.empty());
// Go forwards topographically to find the maximum arrival time and max path length for each net