Implemented proper handling of stub placeholder modules
authorClifford Wolf <clifford@clifford.at>
Thu, 28 Mar 2013 08:20:10 +0000 (09:20 +0100)
committerClifford Wolf <clifford@clifford.at>
Thu, 28 Mar 2013 08:20:10 +0000 (09:20 +0100)
README
backends/verilog/verilog_backend.cc
frontends/ast/ast.cc
frontends/ast/ast.h
frontends/verilog/verilog_frontend.cc
kernel/show.cc
passes/hierarchy/hierarchy.cc

diff --git a/README b/README
index ab9fcd6127d5b0b17e60301cb6ff473b7566db1b..d87d6a2f2cca99d6571a0abfc902b3d705e53601 100644 (file)
--- 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
index a4713cb0a138da2095cb318795e2dd0d29e261f6..04a3c7643001efd6625e13daaf63e822a87fed86 100644 (file)
@@ -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<std::string> 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();
        }
index d35ea4171c4db9f32b9f71b8043442d30862b6d8..091b196efa4ffe09e2f5b49f1fa97d2d52215f02 100644 (file)
@@ -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<std::string, AstNode*> 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<AstNode*> 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<RTLIL::IdStrin
        flag_nolatches = nolatches;
        flag_nomem2reg = nomem2reg;
        flag_mem2reg = mem2reg;
+       flag_lib = lib;
        use_internal_line_num();
 
        std::vector<unsigned char> hash_data;
@@ -821,6 +836,7 @@ void AstModule::update_auto_wires(std::map<RTLIL::IdString, int> 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++) {
index d65851acd4a68920cad315e15f0f4e3b41a5db4a..05b9a95cf0a8a210aa520d4e742545b7117865bf 100644 (file)
@@ -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<RTLIL::IdString, RTLIL::Const> parameters);
                virtual void update_auto_wires(std::map<RTLIL::IdString, int> 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<std::string, AST::AstNode*> current_scope;
        extern RTLIL::SigSpec *genRTLIL_subst_from, *genRTLIL_subst_to;
index f4a8c79fac35fe6f13372edf5f449e46156a65bf..f9731cbc2390aa39cd68040d4e40d030cd4c1a7c 100644 (file)
@@ -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<std::string> 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);
index 244a4d08e022cd1f781a1f015f86aadf7684b90c..33589ca038e01075fc284cfcc05d2df924d48e7c 100644 (file)
@@ -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");
                }
index 8ef169ce919923abe471cdcf9265238700300a96..b80f0d493e4d29f3a4c20110205f94875fa819d5 100644 (file)
@@ -113,6 +113,7 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &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");