aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nexus/arch.cc8
-rw-r--r--nexus/pack.cc175
2 files changed, 175 insertions, 8 deletions
diff --git a/nexus/arch.cc b/nexus/arch.cc
index 4b924a86..b0a22894 100644
--- a/nexus/arch.cc
+++ b/nexus/arch.cc
@@ -376,14 +376,6 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
// -----------------------------------------------------------------------
-bool Arch::pack()
-{
- // FIXME
- getCtx()->attrs[getCtx()->id("step")] = std::string("pack");
- archInfoToAttributes();
- return true;
-}
-
bool Arch::place()
{
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
diff --git a/nexus/pack.cc b/nexus/pack.cc
new file mode 100644
index 00000000..5a18f6d4
--- /dev/null
+++ b/nexus/pack.cc
@@ -0,0 +1,175 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2020 David Shah <dave@ds0.me>
+ *
+ *
+ * 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.
+ *
+ */
+
+#include "design_utils.h"
+#include "log.h"
+#include "nextpnr.h"
+#include "util.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+struct NexusPacker
+{
+ Context *ctx;
+
+ // Generic cell transformation
+ // Given cell name map and port map
+ // If port name is not found in port map; it will be copied as-is but stripping []
+ struct XFormRule
+ {
+ IdString new_type;
+ std::unordered_map<IdString, IdString> port_xform;
+ std::unordered_map<IdString, std::vector<IdString>> port_multixform;
+ std::unordered_map<IdString, IdString> param_xform;
+ std::vector<std::pair<IdString, std::string>> set_attrs;
+ std::vector<std::pair<IdString, Property>> set_params;
+ };
+
+ void xform_cell(const std::unordered_map<IdString, XFormRule> &rules, CellInfo *ci)
+ {
+ auto &rule = rules.at(ci->type);
+ ci->type = rule.new_type;
+ std::vector<IdString> orig_port_names;
+ for (auto &port : ci->ports)
+ orig_port_names.push_back(port.first);
+
+ for (auto pname : orig_port_names) {
+ if (rule.port_multixform.count(pname)) {
+ auto old_port = ci->ports.at(pname);
+ disconnect_port(ctx, ci, pname);
+ ci->ports.erase(pname);
+ for (auto new_name : rule.port_multixform.at(pname)) {
+ ci->ports[new_name].name = new_name;
+ ci->ports[new_name].type = old_port.type;
+ connect_port(ctx, old_port.net, ci, new_name);
+ }
+ } else {
+ IdString new_name;
+ if (rule.port_xform.count(pname)) {
+ new_name = rule.port_xform.at(pname);
+ } else {
+ std::string stripped_name;
+ for (auto c : pname.str(ctx))
+ if (c != '[' && c != ']')
+ stripped_name += c;
+ new_name = ctx->id(stripped_name);
+ }
+ if (new_name != pname) {
+ rename_port(ctx, ci, pname, new_name);
+ }
+ }
+ }
+
+ std::vector<IdString> xform_params;
+ for (auto &param : ci->params)
+ if (rule.param_xform.count(param.first))
+ xform_params.push_back(param.first);
+ for (auto param : xform_params)
+ ci->params[rule.param_xform.at(param)] = ci->params[param];
+
+ for (auto &attr : rule.set_attrs)
+ ci->attrs[attr.first] = attr.second;
+
+ for (auto &param : rule.set_params)
+ ci->params[param.first] = param.second;
+ }
+
+ void generic_xform(const std::unordered_map<IdString, XFormRule> &rules, bool print_summary = false)
+ {
+ std::map<std::string, int> cell_count;
+ std::map<std::string, int> new_types;
+ for (auto cell : sorted(ctx->cells)) {
+ CellInfo *ci = cell.second;
+ if (rules.count(ci->type)) {
+ cell_count[ci->type.str(ctx)]++;
+ xform_cell(rules, ci);
+ new_types[ci->type.str(ctx)]++;
+ }
+ }
+ if (print_summary) {
+ for (auto &nt : new_types) {
+ log_info(" Created %d %s cells from:\n", nt.second, nt.first.c_str());
+ for (auto &cc : cell_count) {
+ if (rules.at(ctx->id(cc.first)).new_type != ctx->id(nt.first))
+ continue;
+ log_info(" %6dx %s\n", cc.second, cc.first.c_str());
+ }
+ }
+ }
+ }
+
+ void pack_luts()
+ {
+ log_info("Packing LUTs...\n");
+ std::unordered_map<IdString, XFormRule> lut_rules;
+ lut_rules[id_LUT4].new_type = id_OXIDE_COMB;
+ lut_rules[id_LUT4].port_xform[id_Z] = id_F;
+ generic_xform(lut_rules);
+ }
+
+ void pack_ffs()
+ {
+ log_info("Packing FFs...\n");
+ std::unordered_map<IdString, XFormRule> ff_rules;
+ for (auto type : {id_FD1P3BX, id_FD1P3DX, id_FD1P3IX, id_FD1P3JX}) {
+ ff_rules[type].new_type = id_OXIDE_FF;
+ ff_rules[type].port_xform[id_CK] = id_CLK;
+ ff_rules[type].port_xform[id_D] = id_M; // will be rerouted to DI later if applicable
+ ff_rules[type].port_xform[id_SP] = id_CE;
+ ff_rules[type].port_xform[id_Q] = id_Q;
+ }
+ // Async preload
+ ff_rules[id_FD1P3BX].set_params.emplace_back(id_SRMODE, std::string("ASYNC"));
+ ff_rules[id_FD1P3BX].set_params.emplace_back(id_REGSET, std::string("SET"));
+ ff_rules[id_FD1P3BX].port_xform[id_PD] = id_LSR;
+ // Async clear
+ ff_rules[id_FD1P3DX].set_params.emplace_back(id_SRMODE, std::string("ASYNC"));
+ ff_rules[id_FD1P3DX].set_params.emplace_back(id_REGSET, std::string("RESET"));
+ ff_rules[id_FD1P3DX].port_xform[id_CD] = id_LSR;
+ // Sync preload
+ ff_rules[id_FD1P3JX].set_params.emplace_back(id_SRMODE, std::string("LSR_OVER_CE"));
+ ff_rules[id_FD1P3JX].set_params.emplace_back(id_REGSET, std::string("SET"));
+ ff_rules[id_FD1P3JX].port_xform[id_PD] = id_LSR;
+ // Sync clear
+ ff_rules[id_FD1P3IX].set_params.emplace_back(id_SRMODE, std::string("LSR_OVER_CE"));
+ ff_rules[id_FD1P3IX].set_params.emplace_back(id_REGSET, std::string("RESET"));
+ ff_rules[id_FD1P3IX].port_xform[id_CD] = id_LSR;
+
+ generic_xform(ff_rules, true);
+ }
+
+ explicit NexusPacker(Context *ctx) : ctx(ctx) {}
+
+ void operator()()
+ {
+ pack_ffs();
+ pack_luts();
+ }
+};
+
+bool Arch::pack()
+{
+ (NexusPacker(getCtx()))();
+ attrs[id("step")] = std::string("pack");
+ archInfoToAttributes();
+ return true;
+}
+
+NEXTPNR_NAMESPACE_END \ No newline at end of file