From 7bfc7b61a812e10177674def2f640d82cee49791 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 28 Mar 2013 09:20:10 +0100 Subject: [PATCH] Implemented proper handling of stub placeholder modules --- README | 6 ++++++ backends/verilog/verilog_backend.cc | 24 ++++++++++++++++++------ frontends/ast/ast.cc | 20 ++++++++++++++++++-- frontends/ast/ast.h | 6 +++--- frontends/verilog/verilog_frontend.cc | 10 +++++++++- kernel/show.cc | 13 +++++++++++-- passes/hierarchy/hierarchy.cc | 7 +++++-- 7 files changed, 70 insertions(+), 16 deletions(-) diff --git a/README b/README index ab9fcd612..d87d6a2f2 100644 --- a/README +++ b/README @@ -205,6 +205,12 @@ Verilog Attributes and non-standard features temporary variable within an always block. This is mostly used internally by yosys to synthesize verilog functions and access arrays. +- The "placeholder" attribute on modules is used to mark empty stub modules + that have the same ports as the real thing but do not contain information + on the internal configuration. This modules are only used by the synthesis + passes to identify input and output ports of cells. The verilog backend + also does not output placeholder modules on default. + - 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/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index a4713cb0a..04a3c7643 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -923,6 +923,11 @@ struct VerilogBackend : public Backend { log(" without this option all internal cells are converted to verilog\n"); log(" expressions.\n"); log("\n"); + log(" -placeholders\n"); + log(" usually modules with the 'placeholder' attribute are ignored. with\n"); + log(" this option set only the modules with the 'placeholder' attribute\n"); + log(" are written to the output file.\n"); + log("\n"); } virtual void execute(FILE *&f, std::string filename, std::vector args, RTLIL::Design *design) { @@ -933,6 +938,8 @@ struct VerilogBackend : public Backend { attr2comment = false; noexpr = false; + bool placeholders = false; + reg_ct.clear(); reg_ct.setup_stdcells_mem(); reg_ct.cell_types.insert("$sr"); @@ -958,16 +965,21 @@ struct VerilogBackend : public Backend { noexpr = true; continue; } + if (arg == "-placeholders") { + placeholders = true; + continue; + } break; } extra_args(f, filename, args, argidx); - for (auto it = design->modules.begin(); it != design->modules.end(); it++) { - log("Dumping module `%s'.\n", it->first.c_str()); - if (it != design->modules.begin()) - fprintf(f, "\n"); - dump_module(f, "", it->second); - } + for (auto it = design->modules.begin(); it != design->modules.end(); it++) + if ((it->second->attributes.count("\\placeholder") > 0) == placeholders) { + if (it != design->modules.begin()) + fprintf(f, "\n"); + log("Dumping module `%s'.\n", it->first.c_str()); + dump_module(f, "", it->second); + } reg_ct.clear(); } diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index d35ea4171..091b196ef 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -46,7 +46,7 @@ namespace AST { // instanciate global variables (private API) namespace AST_INTERNAL { - bool flag_dump_ast, flag_dump_ast_diff, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg; + bool flag_dump_ast, flag_dump_ast_diff, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib; AstNode *current_ast, *current_ast_mod; std::map current_scope; RTLIL::SigSpec *genRTLIL_subst_from = NULL; @@ -679,6 +679,18 @@ static AstModule* process_module(AstNode *ast) log("--- END OF AST DUMP ---\n"); } + if (flag_lib) { + std::vector new_children; + for (auto child : ast->children) { + if (child->type == AST_WIRE && (child->is_input || child->is_output)) + new_children.push_back(child); + else + delete child; + } + ast->children.swap(new_children); + ast->attributes["\\placeholder"] = AstNode::mkconst_int(0, false, 0); + } + current_module = new AstModule; current_module->ast = NULL; current_module->name = ast->str; @@ -705,11 +717,12 @@ static AstModule* process_module(AstNode *ast) current_module->nolatches = flag_nolatches; current_module->nomem2reg = flag_nomem2reg; current_module->mem2reg = flag_mem2reg; + current_module->lib = flag_lib; return current_module; } // create AstModule instances for all modules in the AST tree and add them to 'design' -void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast, bool dump_ast_diff, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg) +void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast, bool dump_ast_diff, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib) { current_ast = ast; flag_dump_ast = dump_ast; @@ -718,6 +731,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast, bool dump_ flag_nolatches = nolatches; flag_nomem2reg = nomem2reg; flag_mem2reg = mem2reg; + flag_lib = lib; assert(current_ast->type == AST_DESIGN); for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++) { @@ -747,6 +761,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map hash_data; @@ -821,6 +836,7 @@ void AstModule::update_auto_wires(std::map auto_sizes) flag_nolatches = nolatches; flag_nomem2reg = nomem2reg; flag_mem2reg = mem2reg; + flag_lib = lib; use_internal_line_num(); for (auto it = auto_sizes.begin(); it != auto_sizes.end(); it++) { diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index d65851acd..05b9a95cf 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -189,13 +189,13 @@ namespace AST }; // process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code - void process(RTLIL::Design *design, AstNode *ast, bool dump_ast = false, bool dump_ast_diff = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false, bool mem2reg = false); + void process(RTLIL::Design *design, AstNode *ast, bool dump_ast = false, bool dump_ast_diff = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false, bool mem2reg = false, bool lib = false); // parametric modules are supported directly by the AST library // therfore we need our own derivate of RTLIL::Module with overloaded virtual functions struct AstModule : RTLIL::Module { AstNode *ast; - bool nolatches, nomem2reg, mem2reg; + bool nolatches, nomem2reg, mem2reg, lib; virtual ~AstModule(); virtual RTLIL::IdString derive(RTLIL::Design *design, std::map parameters); virtual void update_auto_wires(std::map auto_sizes); @@ -217,7 +217,7 @@ namespace AST namespace AST_INTERNAL { // internal state variables - extern bool flag_dump_ast, flag_dump_ast_diff, flag_nolatches, flag_nomem2reg, flag_mem2reg; + extern bool flag_dump_ast, flag_dump_ast_diff, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib; extern AST::AstNode *current_ast, *current_ast_mod; extern std::map current_scope; extern RTLIL::SigSpec *genRTLIL_subst_from, *genRTLIL_subst_to; diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index f4a8c79fa..f9731cbc2 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -89,6 +89,9 @@ struct VerilogFrontend : public Frontend { log(" -nopp\n"); log(" do not run the pre-processor\n"); log("\n"); + log(" -lib\n"); + log(" only create empty placeholder modules\n"); + log("\n"); } virtual void execute(FILE *&f, std::string filename, std::vector args, RTLIL::Design *design) { @@ -100,6 +103,7 @@ struct VerilogFrontend : public Frontend { bool flag_mem2reg = false; bool flag_ppdump = false; bool flag_nopp = false; + bool flag_lib = false; frontend_verilog_yydebug = false; log_header("Executing Verilog-2005 frontend.\n"); @@ -144,6 +148,10 @@ struct VerilogFrontend : public Frontend { flag_nopp = true; continue; } + if (arg == "-lib") { + flag_lib = true; + continue; + } break; } extra_args(f, filename, args, argidx); @@ -173,7 +181,7 @@ struct VerilogFrontend : public Frontend { frontend_verilog_yyparse(); frontend_verilog_yylex_destroy(); - AST::process(design, current_ast, flag_dump_ast, flag_dump_ast_diff, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg); + AST::process(design, current_ast, flag_dump_ast, flag_dump_ast_diff, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib); if (!flag_nopp) fclose(fp); diff --git a/kernel/show.cc b/kernel/show.cc index 244a4d08e..33589ca03 100644 --- a/kernel/show.cc +++ b/kernel/show.cc @@ -352,8 +352,12 @@ struct ShowWorker if (!design->selected_module(module->name)) continue; if (design->selected_whole_module(module->name)) { + if (module->attributes.count("\\placeholder") > 0) { + log("Skipping placeholder module %s.\n", id2cstr(module->name)); + continue; + } else if (module->cells.empty() && module->connections.empty()) { - log("Skipping skeletton module %s.\n", id2cstr(module->name)); + log("Skipping empty module %s.\n", id2cstr(module->name)); continue; } else log("Dumping module %s to page %d.\n", id2cstr(module->name), ++page_counter); @@ -461,9 +465,14 @@ struct ShowPass : public Pass { if (format != "ps") { int modcount = 0; - for (auto &mod_it : design->modules) + for (auto &mod_it : design->modules) { + if (mod_it.second->attributes.count("\\placeholder") > 0) + continue; + if (mod_it.second->cells.empty() && mod_it.second->connections.empty()) + continue; if (design->selected_module(mod_it.first)) modcount++; + } if (modcount > 1) log_cmd_error("For formats different than 'ps' only one module must be selected.\n"); } diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 8ef169ce9..b80f0d493 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -113,6 +113,7 @@ static void generate(RTLIL::Design *design, const std::vector &cell RTLIL::Module *mod = new RTLIL::Module; mod->name = celltype; + mod->attributes["\\placeholder"] = RTLIL::Const(0, 0); design->modules[mod->name] = mod; for (auto &decl : ports) { @@ -146,6 +147,8 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla } if (cell->parameters.size() == 0) continue; + if (design->modules.at(cell->type)->attributes.count("\\placeholder") > 0) + continue; RTLIL::Module *mod = design->modules[cell->type]; cell->type = mod->derive(design, cell->parameters); cell->parameters.clear(); @@ -207,7 +210,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla if (auto_sizes.size() > 0) { module->update_auto_wires(auto_sizes); - log_header("Continuing EXPAND pass.\n"); + log_header("Continuing HIERARCHY pass.\n"); did_something = true; } @@ -269,7 +272,7 @@ 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("In -generate mode this pass generates skeletton modules for the given cell\n"); + log("In -generate mode this pass generates placeholder 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"); log("determine the direction of the ports. The syntax for a port declaration is:\n"); -- 2.30.2