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 + * + * + * 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 port_xform; + std::unordered_map> port_multixform; + std::unordered_map param_xform; + std::vector> set_attrs; + std::vector> set_params; + }; + + void xform_cell(const std::unordered_map &rules, CellInfo *ci) + { + auto &rule = rules.at(ci->type); + ci->type = rule.new_type; + std::vector 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 xform_params; + for (auto ¶m : 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 ¶m : rule.set_params) + ci->params[param.first] = param.second; + } + + void generic_xform(const std::unordered_map &rules, bool print_summary = false) + { + std::map cell_count; + std::map 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 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 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