Preserve hierarchy through packing
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
b100087024
commit
fe40094216
@ -21,6 +21,7 @@
|
|||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include "design_utils.h"
|
#include "design_utils.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -723,4 +724,76 @@ void BaseCtx::copyBelPorts(IdString cell, BelId bel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct FixupHierarchyWorker
|
||||||
|
{
|
||||||
|
FixupHierarchyWorker(Context *ctx) : ctx(ctx){};
|
||||||
|
Context *ctx;
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
trim_hierarchy(ctx->top_module);
|
||||||
|
rebuild_hierarchy();
|
||||||
|
};
|
||||||
|
// Remove cells and nets that no longer exist in the netlist
|
||||||
|
std::vector<IdString> todelete_cells, todelete_nets;
|
||||||
|
void trim_hierarchy(IdString path)
|
||||||
|
{
|
||||||
|
auto &h = ctx->hierarchy.at(path);
|
||||||
|
todelete_cells.clear();
|
||||||
|
todelete_nets.clear();
|
||||||
|
for (auto &lc : h.leaf_cells) {
|
||||||
|
if (!ctx->cells.count(lc.second))
|
||||||
|
todelete_cells.push_back(lc.first);
|
||||||
|
}
|
||||||
|
for (auto &n : h.nets)
|
||||||
|
if (!ctx->nets.count(n.second))
|
||||||
|
todelete_nets.push_back(n.first);
|
||||||
|
for (auto tdc : todelete_cells) {
|
||||||
|
h.leaf_cells_by_gname.erase(h.leaf_cells.at(tdc));
|
||||||
|
h.leaf_cells.erase(tdc);
|
||||||
|
}
|
||||||
|
for (auto tdn : todelete_nets) {
|
||||||
|
h.nets_by_gname.erase(h.nets.at(tdn));
|
||||||
|
h.nets.erase(tdn);
|
||||||
|
}
|
||||||
|
for (auto &sc : h.hier_cells)
|
||||||
|
trim_hierarchy(sc.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
IdString construct_local_name(HierarchicalCell &hc, IdString global_name, bool is_cell)
|
||||||
|
{
|
||||||
|
std::string gn = global_name.str(ctx);
|
||||||
|
auto dp = gn.find_last_of('.');
|
||||||
|
if (dp != std::string::npos)
|
||||||
|
gn = gn.substr(dp + 1);
|
||||||
|
IdString name = ctx->id(gn);
|
||||||
|
// Make sure name is unique
|
||||||
|
int adder = 0;
|
||||||
|
while (is_cell ? hc.leaf_cells.count(name) : hc.nets.count(name)) {
|
||||||
|
++adder;
|
||||||
|
name = ctx->id(gn + "$" + std::to_string(adder));
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update hierarchy structure for nets and cells that have hiercell set
|
||||||
|
void rebuild_hierarchy()
|
||||||
|
{
|
||||||
|
for (auto cell : sorted(ctx->cells)) {
|
||||||
|
CellInfo *ci = cell.second;
|
||||||
|
if (ci->hierpath == IdString())
|
||||||
|
ci->hierpath = ctx->top_module;
|
||||||
|
auto &hc = ctx->hierarchy.at(ci->hierpath);
|
||||||
|
if (hc.leaf_cells_by_gname.count(ci->name))
|
||||||
|
continue; // already known
|
||||||
|
IdString local_name = construct_local_name(hc, ci->name, true);
|
||||||
|
hc.leaf_cells_by_gname[ci->name] = local_name;
|
||||||
|
hc.leaf_cells[local_name] = ci->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void Context::fixupHierarchy() { FixupHierarchyWorker(this).run(); }
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -544,6 +544,9 @@ struct HierarchicalCell
|
|||||||
IdString name, type, parent, fullpath;
|
IdString name, type, parent, fullpath;
|
||||||
// Name inside cell instance -> global name
|
// Name inside cell instance -> global name
|
||||||
std::unordered_map<IdString, IdString> leaf_cells, nets;
|
std::unordered_map<IdString, IdString> leaf_cells, nets;
|
||||||
|
// Global name -> name inside cell instance
|
||||||
|
std::unordered_map<IdString, IdString> leaf_cells_by_gname, nets_by_gname;
|
||||||
|
// Cell port to net
|
||||||
std::unordered_map<IdString, HierarchicalPort> ports;
|
std::unordered_map<IdString, HierarchicalPort> ports;
|
||||||
// Name inside cell instance -> global name
|
// Name inside cell instance -> global name
|
||||||
std::unordered_map<IdString, IdString> hier_cells;
|
std::unordered_map<IdString, IdString> hier_cells;
|
||||||
@ -835,6 +838,10 @@ struct Context : Arch, DeterministicRNG
|
|||||||
bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay = nullptr,
|
bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay = nullptr,
|
||||||
std::unordered_map<WireId, PipId> *route = nullptr, bool useEstimate = true);
|
std::unordered_map<WireId, PipId> *route = nullptr, bool useEstimate = true);
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// call after changing hierpath or adding/removing nets and cells
|
||||||
|
void fixupHierarchy();
|
||||||
|
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
// provided by sdf.cc
|
// provided by sdf.cc
|
||||||
|
@ -233,6 +233,8 @@ static void replace_port_safe(bool has_ff, CellInfo *ff, IdString ff_port, CellI
|
|||||||
|
|
||||||
void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool driven_by_lut)
|
void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool driven_by_lut)
|
||||||
{
|
{
|
||||||
|
if (lc->hierpath == IdString())
|
||||||
|
lc->hierpath = ff->hierpath;
|
||||||
bool has_ff = lc->ports.at(ctx->id("Q0")).net != nullptr || lc->ports.at(ctx->id("Q1")).net != nullptr;
|
bool has_ff = lc->ports.at(ctx->id("Q0")).net != nullptr || lc->ports.at(ctx->id("Q1")).net != nullptr;
|
||||||
std::string reg = "REG" + std::to_string(index);
|
std::string reg = "REG" + std::to_string(index);
|
||||||
set_param_safe(has_ff, lc, ctx->id("SRMODE"), str_or_default(ff->params, ctx->id("SRMODE"), "LSR_OVER_CE"));
|
set_param_safe(has_ff, lc, ctx->id("SRMODE"), str_or_default(ff->params, ctx->id("SRMODE"), "LSR_OVER_CE"));
|
||||||
@ -271,6 +273,8 @@ void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool drive
|
|||||||
|
|
||||||
void lut_to_slice(Context *ctx, CellInfo *lut, CellInfo *lc, int index)
|
void lut_to_slice(Context *ctx, CellInfo *lut, CellInfo *lc, int index)
|
||||||
{
|
{
|
||||||
|
if (lc->hierpath == IdString())
|
||||||
|
lc->hierpath = lut->hierpath;
|
||||||
lc->params[ctx->id("LUT" + std::to_string(index) + "_INITVAL")] =
|
lc->params[ctx->id("LUT" + std::to_string(index) + "_INITVAL")] =
|
||||||
get_or_default(lut->params, ctx->id("INIT"), Property(0, 16));
|
get_or_default(lut->params, ctx->id("INIT"), Property(0, 16));
|
||||||
replace_port(lut, ctx->id("A"), lc, ctx->id("A" + std::to_string(index)));
|
replace_port(lut, ctx->id("A"), lc, ctx->id("A" + std::to_string(index)));
|
||||||
@ -282,6 +286,8 @@ void lut_to_slice(Context *ctx, CellInfo *lut, CellInfo *lc, int index)
|
|||||||
|
|
||||||
void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc)
|
void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc)
|
||||||
{
|
{
|
||||||
|
if (lc->hierpath == IdString())
|
||||||
|
lc->hierpath = ccu->hierpath;
|
||||||
lc->params[ctx->id("MODE")] = std::string("CCU2");
|
lc->params[ctx->id("MODE")] = std::string("CCU2");
|
||||||
lc->params[ctx->id("LUT0_INITVAL")] = get_or_default(ccu->params, ctx->id("INIT0"), Property(0, 16));
|
lc->params[ctx->id("LUT0_INITVAL")] = get_or_default(ccu->params, ctx->id("INIT0"), Property(0, 16));
|
||||||
lc->params[ctx->id("LUT1_INITVAL")] = get_or_default(ccu->params, ctx->id("INIT1"), Property(0, 16));
|
lc->params[ctx->id("LUT1_INITVAL")] = get_or_default(ccu->params, ctx->id("INIT1"), Property(0, 16));
|
||||||
@ -309,6 +315,8 @@ void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc)
|
|||||||
|
|
||||||
void dram_to_ramw(Context *ctx, CellInfo *ram, CellInfo *lc)
|
void dram_to_ramw(Context *ctx, CellInfo *ram, CellInfo *lc)
|
||||||
{
|
{
|
||||||
|
if (lc->hierpath == IdString())
|
||||||
|
lc->hierpath = ram->hierpath;
|
||||||
lc->params[ctx->id("MODE")] = std::string("RAMW");
|
lc->params[ctx->id("MODE")] = std::string("RAMW");
|
||||||
replace_port(ram, ctx->id("WAD[0]"), lc, ctx->id("D0"));
|
replace_port(ram, ctx->id("WAD[0]"), lc, ctx->id("D0"));
|
||||||
replace_port(ram, ctx->id("WAD[1]"), lc, ctx->id("B0"));
|
replace_port(ram, ctx->id("WAD[1]"), lc, ctx->id("B0"));
|
||||||
@ -340,6 +348,8 @@ static unsigned get_dram_init(const Context *ctx, const CellInfo *ram, int bit)
|
|||||||
|
|
||||||
void dram_to_ram_slice(Context *ctx, CellInfo *ram, CellInfo *lc, CellInfo *ramw, int index)
|
void dram_to_ram_slice(Context *ctx, CellInfo *ram, CellInfo *lc, CellInfo *ramw, int index)
|
||||||
{
|
{
|
||||||
|
if (lc->hierpath == IdString())
|
||||||
|
lc->hierpath = ram->hierpath;
|
||||||
lc->params[ctx->id("MODE")] = std::string("DPRAM");
|
lc->params[ctx->id("MODE")] = std::string("DPRAM");
|
||||||
lc->params[ctx->id("WREMUX")] = str_or_default(ram->params, ctx->id("WREMUX"), "WRE");
|
lc->params[ctx->id("WREMUX")] = str_or_default(ram->params, ctx->id("WREMUX"), "WRE");
|
||||||
lc->params[ctx->id("WCKMUX")] = str_or_default(ram->params, ctx->id("WCKMUX"), "WCK");
|
lc->params[ctx->id("WCKMUX")] = str_or_default(ram->params, ctx->id("WCKMUX"), "WCK");
|
||||||
|
@ -423,8 +423,10 @@ template <typename FrontendType> struct GenericFrontend
|
|||||||
void import_leaf_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd)
|
void import_leaf_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd)
|
||||||
{
|
{
|
||||||
IdString inst_name = unique_name(m.prefix, name, false);
|
IdString inst_name = unique_name(m.prefix, name, false);
|
||||||
|
ctx->hierarchy[m.path].leaf_cells_by_gname[inst_name] = ctx->id(name);
|
||||||
ctx->hierarchy[m.path].leaf_cells[ctx->id(name)] = inst_name;
|
ctx->hierarchy[m.path].leaf_cells[ctx->id(name)] = inst_name;
|
||||||
CellInfo *ci = ctx->createCell(inst_name, ctx->id(impl.get_cell_type(cd)));
|
CellInfo *ci = ctx->createCell(inst_name, ctx->id(impl.get_cell_type(cd)));
|
||||||
|
ci->hierpath = m.path;
|
||||||
// Import port directions
|
// Import port directions
|
||||||
std::unordered_map<IdString, PortType> port_dirs;
|
std::unordered_map<IdString, PortType> port_dirs;
|
||||||
impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { port_dirs[ctx->id(port)] = dir; });
|
impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { port_dirs[ctx->id(port)] = dir; });
|
||||||
|
@ -346,6 +346,8 @@ std::unique_ptr<CellInfo> create_ice_cell(Context *ctx, IdString type, std::stri
|
|||||||
|
|
||||||
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff)
|
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff)
|
||||||
{
|
{
|
||||||
|
if (lc->hierpath == IdString())
|
||||||
|
lc->hierpath = lut->hierpath;
|
||||||
lc->params[ctx->id("LUT_INIT")] = lut->params[ctx->id("LUT_INIT")].extract(0, 16, Property::State::S0);
|
lc->params[ctx->id("LUT_INIT")] = lut->params[ctx->id("LUT_INIT")].extract(0, 16, Property::State::S0);
|
||||||
replace_port(lut, ctx->id("I0"), lc, ctx->id("I0"));
|
replace_port(lut, ctx->id("I0"), lc, ctx->id("I0"));
|
||||||
replace_port(lut, ctx->id("I1"), lc, ctx->id("I1"));
|
replace_port(lut, ctx->id("I1"), lc, ctx->id("I1"));
|
||||||
@ -359,6 +361,8 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff)
|
|||||||
|
|
||||||
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
|
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
|
||||||
{
|
{
|
||||||
|
if (lc->hierpath == IdString())
|
||||||
|
lc->hierpath = dff->hierpath;
|
||||||
lc->params[ctx->id("DFF_ENABLE")] = Property::State::S1;
|
lc->params[ctx->id("DFF_ENABLE")] = Property::State::S1;
|
||||||
std::string config = dff->type.str(ctx).substr(6);
|
std::string config = dff->type.str(ctx).substr(6);
|
||||||
auto citer = config.begin();
|
auto citer = config.begin();
|
||||||
|
@ -1487,6 +1487,7 @@ bool Arch::pack()
|
|||||||
promote_globals(ctx);
|
promote_globals(ctx);
|
||||||
ctx->assignArchInfo();
|
ctx->assignArchInfo();
|
||||||
constrain_chains(ctx);
|
constrain_chains(ctx);
|
||||||
|
ctx->fixupHierarchy();
|
||||||
ctx->assignArchInfo();
|
ctx->assignArchInfo();
|
||||||
ctx->settings[ctx->id("pack")] = 1;
|
ctx->settings[ctx->id("pack")] = 1;
|
||||||
archInfoToAttributes();
|
archInfoToAttributes();
|
||||||
|
Loading…
Reference in New Issue
Block a user