diff --git a/README b/README index cc451b2b9..2277ef129 100644 --- a/README +++ b/README @@ -262,6 +262,11 @@ Verilog Attributes and non-standard features initialized "FPGA-style" with 'reg foo = val'. It can be used during synthesis to add the necessary reset logic. +- The "top" attribute on a module marks this module as the top of the + design hierarchy. The "hierarchy" command sets this attribute when called + with "-top". Other commands, such as "flatten" and various backends + use this attribute to determine the top module. + - In addition to the (* ... *) attribute syntax, yosys supports the non-standard {* ... *} attribute syntax to set default attributes for everything that comes after the {* ... *} statement. (Reset diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc index 27f087746..f5a982760 100644 --- a/backends/blif/blif.cc +++ b/backends/blif/blif.cc @@ -293,6 +293,11 @@ struct BlifBackend : public Backend { } extra_args(f, filename, args, argidx); + if (top_module_name.empty()) + for (auto & mod_it:design->modules) + if (mod_it.second->get_bool_attribute("\\top")) + top_module_name = mod_it.first; + fprintf(f, "# Generated by %s\n", yosys_version_str); std::vector mod_list; diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc index c5977bb1d..8843b3946 100644 --- a/backends/edif/edif.cc +++ b/backends/edif/edif.cc @@ -118,6 +118,11 @@ struct EdifBackend : public Backend { } extra_args(f, filename, args, argidx); + if (top_module_name.empty()) + for (auto & mod_it:design->modules) + if (mod_it.second->get_bool_attribute("\\top")) + top_module_name = mod_it.first; + for (auto module_it : design->modules) { RTLIL::Module *module = module_it.second; diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc index 6c8a3ec98..e7926e90e 100644 --- a/backends/spice/spice.cc +++ b/backends/spice/spice.cc @@ -172,6 +172,11 @@ struct SpiceBackend : public Backend { } extra_args(f, filename, args, argidx); + if (top_module_name.empty()) + for (auto & mod_it:design->modules) + if (mod_it.second->get_bool_attribute("\\top")) + top_module_name = mod_it.first; + fprintf(f, "* SPICE netlist generated by %s\n", yosys_version_str); fprintf(f, "\n"); diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index b98afcc1c..d9b52c6d0 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -280,6 +280,10 @@ struct HierarchyPass : public Pass { log(" use the specified top module to built a design hierarchy. modules\n"); log(" outside this tree (unused modules) are removed.\n"); log("\n"); + log(" when the -top option is used, the 'top' attribute will be set on the\n"); + log(" specified top module. otherwise a module with the 'top' attribute set\n"); + log(" will implicitly be used as top module, if such a module exists.\n"); + log("\n"); log("In -generate mode this pass generates blackbox modules for the given cell\n"); log("types (wildcards supported). For this the design is searched for cells that\n"); log("match the given types and then the given port declarations are used to\n"); @@ -381,6 +385,11 @@ struct HierarchyPass : public Pass { log_push(); + if (top_mod == NULL) + for (auto &mod_it : design->modules) + if (mod_it.second->get_bool_attribute("\\top")) + top_mod = mod_it.second; + if (top_mod != NULL) hierarchy(design, top_mod); @@ -407,6 +416,14 @@ struct HierarchyPass : public Pass { hierarchy(design, top_mod); } + if (top_mod != NULL) { + for (auto &mod_it : design->modules) + if (mod_it.second == top_mod) + mod_it.second->attributes["\\top"] = RTLIL::Const(1); + else + mod_it.second->attributes.erase("\\top"); + } + if (!keep_positionals) { std::set pos_mods; diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index e273769d1..7e3ba23ec 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -500,19 +500,42 @@ struct FlattenPass : public Pass { for (auto &it : design->modules) celltypeMap[it.first].insert(it.first); + RTLIL::Module *top_mod = NULL; + for (auto &mod_it : design->modules) + if (mod_it.second->get_bool_attribute("\\top")) + top_mod = mod_it.second; + bool did_something = true; std::set handled_cells; while (did_something) { did_something = false; - for (auto &mod_it : design->modules) - if (techmap_module(design, mod_it.second, design, handled_cells, celltypeMap, true)) + if (top_mod != NULL) { + if (techmap_module(design, top_mod, design, handled_cells, celltypeMap, true)) did_something = true; + } else { + for (auto &mod_it : design->modules) + if (techmap_module(design, mod_it.second, design, handled_cells, celltypeMap, true)) + did_something = true; + } } log("No more expansions possible.\n"); + + if (top_mod != NULL) { + std::map new_modules; + for (auto &mod_it : design->modules) + if (mod_it.second == top_mod) { + new_modules[mod_it.first] = mod_it.second; + } else { + log("Deleting now unused module %s.\n", RTLIL::id2cstr(mod_it.first)); + delete mod_it.second; + } + design->modules.swap(new_modules); + } + techmap_cache.clear(); techmap_do_cache.clear(); log_pop(); } } FlattenPass; - +