diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/chain_utils.h | 68 | ||||
-rw-r--r-- | common/design_utils.cc | 52 | ||||
-rw-r--r-- | common/design_utils.h | 9 | ||||
-rw-r--r-- | common/log.cc | 11 | ||||
-rw-r--r-- | common/nextpnr.cc | 12 | ||||
-rw-r--r-- | common/place_common.cc | 3 | ||||
-rw-r--r-- | common/placer1.cc | 14 | ||||
-rw-r--r-- | common/router1.cc | 6 | ||||
-rw-r--r-- | common/settings.h | 4 | ||||
-rw-r--r-- | common/timing.cc | 16 |
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 |