mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-13 04:28:18 +00:00
flatten: topologically sort modules.
This commit is contained in:
parent
6268bdfe6f
commit
d731fe054b
|
@ -51,13 +51,9 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
|
||||||
|
|
||||||
struct FlattenWorker
|
struct FlattenWorker
|
||||||
{
|
{
|
||||||
pool<IdString> flatten_do_list;
|
|
||||||
pool<IdString> flatten_done_list;
|
|
||||||
pool<Cell*> flatten_keep_list;
|
|
||||||
|
|
||||||
bool ignore_wb = false;
|
bool ignore_wb = false;
|
||||||
|
|
||||||
void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl)
|
void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, std::vector<RTLIL::Cell*> &new_cells)
|
||||||
{
|
{
|
||||||
if (tpl->processes.size() != 0) {
|
if (tpl->processes.size() != 0) {
|
||||||
log("Flattening yielded processes:");
|
log("Flattening yielded processes:");
|
||||||
|
@ -197,6 +193,7 @@ struct FlattenWorker
|
||||||
apply_prefix(cell->name, c_name);
|
apply_prefix(cell->name, c_name);
|
||||||
|
|
||||||
RTLIL::Cell *c = module->addCell(c_name, tpl_cell);
|
RTLIL::Cell *c = module->addCell(c_name, tpl_cell);
|
||||||
|
new_cells.push_back(c);
|
||||||
design->select(module, c);
|
design->select(module, c);
|
||||||
|
|
||||||
for (auto &conn : c->connections())
|
for (auto &conn : c->connections())
|
||||||
|
@ -245,15 +242,17 @@ struct FlattenWorker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool flatten_module(RTLIL::Design *design, RTLIL::Module *module)
|
void flatten_module(RTLIL::Design *design, RTLIL::Module *module, pool<RTLIL::Module*> &used_modules)
|
||||||
{
|
{
|
||||||
if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb))
|
if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb))
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
bool did_something = false;
|
std::vector<RTLIL::Cell*> worklist = module->selected_cells();
|
||||||
|
while (!worklist.empty())
|
||||||
for (auto cell : module->selected_cells())
|
|
||||||
{
|
{
|
||||||
|
RTLIL::Cell *cell = worklist.back();
|
||||||
|
worklist.pop_back();
|
||||||
|
|
||||||
if (!design->has(cell->type))
|
if (!design->has(cell->type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -262,19 +261,17 @@ struct FlattenWorker
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (cell->get_bool_attribute(ID::keep_hierarchy) || tpl->get_bool_attribute(ID::keep_hierarchy)) {
|
if (cell->get_bool_attribute(ID::keep_hierarchy) || tpl->get_bool_attribute(ID::keep_hierarchy)) {
|
||||||
if (!flatten_keep_list[cell]) {
|
log("Keeping %s.%s (found keep_hierarchy property).\n", log_id(module), log_id(cell));
|
||||||
log("Keeping %s.%s (found keep_hierarchy property).\n", log_id(module), log_id(cell));
|
used_modules.insert(tpl);
|
||||||
flatten_keep_list.insert(cell);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("Flattening %s.%s (%s) using %s.\n", log_id(module), log_id(cell), log_id(cell->type), log_id(tpl));
|
log_debug("Flattening %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
|
||||||
flatten_cell(design, module, cell, tpl);
|
// If a design is fully selected and has a top module defined, topological sorting ensures that all cells
|
||||||
did_something = true;
|
// added during flattening are black boxes, and flattening is finished in one pass. However, when flattening
|
||||||
|
// individual modules, this isn't the case, and the newly added cells might have to be flattened further.
|
||||||
|
flatten_cell(design, module, cell, tpl, worklist);
|
||||||
}
|
}
|
||||||
|
|
||||||
return did_something;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -314,50 +311,45 @@ struct FlattenPass : public Pass {
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
RTLIL::Module *top_mod = nullptr;
|
RTLIL::Module *top = nullptr;
|
||||||
if (design->full_selection())
|
if (design->full_selection())
|
||||||
for (auto mod : design->modules())
|
for (auto module : design->modules())
|
||||||
if (mod->get_bool_attribute(ID::top))
|
if (module->get_bool_attribute(ID::top))
|
||||||
top_mod = mod;
|
top = module;
|
||||||
|
|
||||||
if (top_mod != nullptr) {
|
pool<RTLIL::Module*> used_modules;
|
||||||
worker.flatten_do_list.insert(top_mod->name);
|
if (top == nullptr)
|
||||||
while (!worker.flatten_do_list.empty()) {
|
used_modules = design->modules();
|
||||||
auto mod = design->module(*worker.flatten_do_list.begin());
|
else
|
||||||
while (worker.flatten_module(design, mod)) { }
|
used_modules.insert(top);
|
||||||
worker.flatten_done_list.insert(mod->name);
|
|
||||||
worker.flatten_do_list.erase(mod->name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (auto mod : design->modules().to_vector())
|
|
||||||
while (worker.flatten_module(design, mod)) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
log_suppressed();
|
TopoSort<RTLIL::Module*, IdString::compare_ptr_by_name<RTLIL::Module>> topo_modules;
|
||||||
log("No more expansions possible.\n");
|
pool<RTLIL::Module*> worklist = used_modules;
|
||||||
|
while (!worklist.empty()) {
|
||||||
if (top_mod != nullptr)
|
RTLIL::Module *module = worklist.pop();
|
||||||
{
|
for (auto cell : module->selected_cells()) {
|
||||||
pool<IdString> used_modules, new_used_modules;
|
RTLIL::Module *tpl = design->module(cell->type);
|
||||||
new_used_modules.insert(top_mod->name);
|
if (tpl != nullptr) {
|
||||||
while (!new_used_modules.empty()) {
|
if (topo_modules.database.count(tpl) == 0)
|
||||||
pool<IdString> queue;
|
worklist.insert(tpl);
|
||||||
queue.swap(new_used_modules);
|
topo_modules.edge(tpl, module);
|
||||||
for (auto modname : queue)
|
|
||||||
used_modules.insert(modname);
|
|
||||||
for (auto modname : queue)
|
|
||||||
for (auto cell : design->module(modname)->cells())
|
|
||||||
if (design->module(cell->type) && !used_modules[cell->type])
|
|
||||||
new_used_modules.insert(cell->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto mod : design->modules().to_vector())
|
|
||||||
if (!used_modules[mod->name] && !mod->get_blackbox_attribute(worker.ignore_wb)) {
|
|
||||||
log("Deleting now unused module %s.\n", log_id(mod));
|
|
||||||
design->remove(mod);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!topo_modules.sort())
|
||||||
|
log_error("Cannot flatten a design containing recursive instantiations.\n");
|
||||||
|
|
||||||
|
for (auto module : topo_modules.sorted)
|
||||||
|
worker.flatten_module(design, module, used_modules);
|
||||||
|
|
||||||
|
if (top != nullptr)
|
||||||
|
for (auto module : design->modules().to_vector())
|
||||||
|
if (!used_modules[module] && !module->get_blackbox_attribute(worker.ignore_wb)) {
|
||||||
|
log("Deleting now unused module %s.\n", log_id(module));
|
||||||
|
design->remove(module);
|
||||||
|
}
|
||||||
|
|
||||||
log_pop();
|
log_pop();
|
||||||
}
|
}
|
||||||
} FlattenPass;
|
} FlattenPass;
|
||||||
|
|
Loading…
Reference in a new issue