nexus: Add packing framework
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
eb15463406
commit
2c49f812d9
@ -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()
|
bool Arch::place()
|
||||||
{
|
{
|
||||||
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
|
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
|
||||||
|
175
nexus/pack.cc
Normal file
175
nexus/pack.cc
Normal file
@ -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 ¶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<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
|
Loading…
Reference in New Issue
Block a user