Implemented read_verilog -defer
authorClifford Wolf <clifford@clifford.at>
Thu, 13 Feb 2014 12:59:13 +0000 (13:59 +0100)
committerClifford Wolf <clifford@clifford.at>
Thu, 13 Feb 2014 12:59:13 +0000 (13:59 +0100)
frontends/ast/ast.cc
frontends/ast/ast.h
frontends/verilog/verilog_frontend.cc
passes/hierarchy/hierarchy.cc

index 96608ae37d6c68a42abe4d34834266d6e9ae4ee2..ab2972b2c8e39ad07add52cf03bedca35a7e099b 100644 (file)
@@ -747,14 +747,18 @@ bool AstNode::asBool()
 }
 
 // create a new AstModule from an AST_MODULE AST node
-static AstModule* process_module(AstNode *ast)
+static AstModule* process_module(AstNode *ast, bool defer)
 {
        assert(ast->type == AST_MODULE);
-       log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
+
+       if (defer)
+               log("Storing AST representation for module `%s'.\n", ast->str.c_str());
+       else
+               log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
 
        current_module = new AstModule;
        current_module->ast = NULL;
-       current_module->name = ast->str;
+       current_module->name = defer ? "$abstract" + ast->str : ast->str;
        current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
 
        current_ast_mod = ast;
@@ -766,60 +770,63 @@ static AstModule* process_module(AstNode *ast)
                log("--- END OF AST DUMP ---\n");
        }
 
-       while (ast->simplify(!flag_noopt, false, false, 0, -1, false)) { }
+       if (!defer)
+       {
+               while (ast->simplify(!flag_noopt, false, false, 0, -1, false)) { }
 
-       if (flag_dump_ast2) {
-               log("Dumping verilog AST after simplification:\n");
-               ast->dumpAst(NULL, "    ");
-               log("--- END OF AST DUMP ---\n");
-       }
+               if (flag_dump_ast2) {
+                       log("Dumping verilog AST after simplification:\n");
+                       ast->dumpAst(NULL, "    ");
+                       log("--- END OF AST DUMP ---\n");
+               }
 
-       if (flag_dump_vlog) {
-               log("Dumping verilog AST (as requested by dump_vlog option):\n");
-               ast->dumpVlog(NULL, "    ");
-               log("--- END OF AST DUMP ---\n");
-       }
+               if (flag_dump_vlog) {
+                       log("Dumping verilog AST (as requested by dump_vlog option):\n");
+                       ast->dumpVlog(NULL, "    ");
+                       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;
+               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["\\blackbox"] = AstNode::mkconst_int(1, false);
                }
-               ast->children.swap(new_children);
-               ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
-       }
 
-       ignoreThisSignalsInInitial = RTLIL::SigSpec();
+               ignoreThisSignalsInInitial = RTLIL::SigSpec();
 
-       for (auto &attr : ast->attributes) {
-               if (attr.second->type != AST_CONSTANT)
-                       log_error("Attribute `%s' with non-constant value at %s:%d!\n",
-                                       attr.first.c_str(), ast->filename.c_str(), ast->linenum);
-               current_module->attributes[attr.first] = attr.second->asAttrConst();
-       }
-       for (size_t i = 0; i < ast->children.size(); i++) {
-               AstNode *node = ast->children[i];
-               if (node->type == AST_WIRE || node->type == AST_MEMORY)
-                       node->genRTLIL();
-       }
-       for (size_t i = 0; i < ast->children.size(); i++) {
-               AstNode *node = ast->children[i];
-               if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
-                       node->genRTLIL();
-       }
+               for (auto &attr : ast->attributes) {
+                       if (attr.second->type != AST_CONSTANT)
+                               log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+                                               attr.first.c_str(), ast->filename.c_str(), ast->linenum);
+                       current_module->attributes[attr.first] = attr.second->asAttrConst();
+               }
+               for (size_t i = 0; i < ast->children.size(); i++) {
+                       AstNode *node = ast->children[i];
+                       if (node->type == AST_WIRE || node->type == AST_MEMORY)
+                               node->genRTLIL();
+               }
+               for (size_t i = 0; i < ast->children.size(); i++) {
+                       AstNode *node = ast->children[i];
+                       if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
+                               node->genRTLIL();
+               }
 
-       ignoreThisSignalsInInitial.sort_and_unify();
+               ignoreThisSignalsInInitial.sort_and_unify();
 
-       for (size_t i = 0; i < ast->children.size(); i++) {
-               AstNode *node = ast->children[i];
-               if (node->type == AST_INITIAL)
-                       node->genRTLIL();
-       }
+               for (size_t i = 0; i < ast->children.size(); i++) {
+                       AstNode *node = ast->children[i];
+                       if (node->type == AST_INITIAL)
+                               node->genRTLIL();
+               }
 
-       ignoreThisSignalsInInitial = RTLIL::SigSpec();
+               ignoreThisSignalsInInitial = RTLIL::SigSpec();
+       }
 
        current_module->ast = ast_before_simplify;
        current_module->nolatches = flag_nolatches;
@@ -832,7 +839,7 @@ static AstModule* process_module(AstNode *ast)
 }
 
 // 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_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef)
+void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer)
 {
        current_ast = ast;
        flag_dump_ast1 = dump_ast1;
@@ -847,7 +854,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
 
        assert(current_ast->type == AST_DESIGN);
        for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++) {
-               if (design->modules.count((*it)->str) != 0) {
+               if (design->modules.count((*it)->str) != 0 && design->modules.count("$abstract" + (*it)->str) != 0) {
                        if (!ignore_redef)
                                log_error("Re-definition of module `%s' at %s:%d!\n",
                                                (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
@@ -855,7 +862,10 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
                                        (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
                        continue;
                }
-               design->modules[(*it)->str] = process_module(*it);
+               if (defer)
+                       design->modules["$abstract" + (*it)->str] = process_module(*it, true);
+               else
+                       design->modules[(*it)->str] = process_module(*it, false);
        }
 }
 
@@ -869,7 +879,12 @@ AstModule::~AstModule()
 // create a new parametric module (when needed) and return the name of the generated module
 RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters)
 {
-       log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", name.c_str());
+       std::string stripped_name = name;
+
+       if (stripped_name.substr(0, 9) == "$abstract")
+               stripped_name = stripped_name.substr(9);
+
+       log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());
 
        current_ast = NULL;
        flag_dump_ast1 = false;
@@ -885,12 +900,13 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
 
        std::string para_info;
        std::vector<unsigned char> hash_data;
-       hash_data.insert(hash_data.end(), name.begin(), name.end());
+       hash_data.insert(hash_data.end(), stripped_name.begin(), stripped_name.end());
        hash_data.push_back(0);
 
        AstNode *new_ast = ast->clone();
 
        int para_counter = 0;
+       int orig_parameters_n = parameters.size();
        for (auto it = new_ast->children.begin(); it != new_ast->children.end(); it++) {
                AstNode *child = *it;
                if (child->type != AST_PARAMETER)
@@ -917,10 +933,15 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
                }
        }
        if (parameters.size() > 0)
-               log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), name.c_str());
+               log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), stripped_name.c_str());
 
        std::string modname;
 
+       if (orig_parameters_n == 0)
+       {
+               modname = stripped_name;
+       }
+       else
        if (para_info.size() > 60)
        {
                unsigned char hash[20];
@@ -933,16 +954,16 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
                char hexstring[41];
                sha1::toHexString(hash, hexstring);
 
-               modname = "$paramod$" + std::string(hexstring) + name;
+               modname = "$paramod$" + std::string(hexstring) + stripped_name;
        }
        else
        {
-               modname = "$paramod" + name + para_info;
+               modname = "$paramod" + stripped_name + para_info;
        }
 
        if (design->modules.count(modname) == 0) {
                new_ast->str = modname;
-               design->modules[modname] = process_module(new_ast);
+               design->modules[modname] = process_module(new_ast, false);
                design->modules[modname]->check();
        } else {
                log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
index 01702c3cfef970717a67126654542ca2537b054f..8335db09603da2c2c212f4eb6714b15bcfb77adb 100644 (file)
@@ -232,7 +232,7 @@ 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_ast1 = false, bool dump_ast2 = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false, bool mem2reg = false, bool lib = false, bool noopt = false, bool icells = false, bool ignore_redef = false);
+       void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1 = false, bool dump_ast2 = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false, bool mem2reg = false, bool lib = false, bool noopt = false, bool icells = false, bool ignore_redef = false, bool defer = true);
 
        // parametric modules are supported directly by the AST library
        // therfore we need our own derivate of RTLIL::Module with overloaded virtual functions
index c70d6f305732c2b6650b9cc0eaa62c80a4fc11a3..d46dfa6e2e1329cc3290b919bbe5f576aebbcb38 100644 (file)
@@ -106,6 +106,11 @@ struct VerilogFrontend : public Frontend {
                log("        ignore re-definitions of modules. (the default behavior is to\n");
                log("        create an error message.)\n");
                log("\n");
+               log("    -defer\n");
+               log("        only read the abstract syntax tree and defer actual compilation\n");
+               log("        to a later 'hierarchy' command. Useful in cases where the default\n");
+               log("        parameters of modules yield invalid or not synthesizable code.\n");
+               log("\n");
                log("    -setattr <attribute_name>\n");
                log("        set the specified attribute (to the value 1) on all loaded modules\n");
                log("\n");
@@ -135,6 +140,7 @@ struct VerilogFrontend : public Frontend {
                bool flag_noopt = false;
                bool flag_icells = false;
                bool flag_ignore_redef = false;
+               bool flag_defer = false;
                std::map<std::string, std::string> defines_map;
                std::list<std::string> include_dirs;
                std::list<std::string> attributes;
@@ -199,6 +205,10 @@ struct VerilogFrontend : public Frontend {
                                flag_ignore_redef = true;
                                continue;
                        }
+                       if (arg == "-defer") {
+                               flag_defer = true;
+                               continue;
+                       }
                        if (arg == "-setattr" && argidx+1 < args.size()) {
                                attributes.push_back(RTLIL::escape_id(args[++argidx]));
                                continue;
@@ -264,7 +274,7 @@ struct VerilogFrontend : public Frontend {
                                        child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
                }
 
-               AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef);
+               AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer);
 
                if (!flag_nopp)
                        fclose(fp);
index 50d0e6e47db78ca8f1e8d374d3be703cb23ca1d5..526d17294c9e6685d678c7d2f7087e2a9dfeddcf 100644 (file)
@@ -145,6 +145,14 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
 
                if (design->modules.count(cell->type) == 0)
                {
+                       if (design->modules.count("$abstract" + cell->type))
+                       {
+                               cell->type = design->modules.at("$abstract" + cell->type)->derive(design, cell->parameters);
+                               cell->parameters.clear();
+                               did_something = true;
+                               continue;
+                       }
+
                        if (cell->type[0] == '$')
                                continue;
 
@@ -210,7 +218,7 @@ static void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &us
        }
 }
 
-static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
+static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib, bool first_pass)
 {
        std::set<RTLIL::Module*> used;
        hierarchy_worker(design, used, top, 0);
@@ -221,6 +229,8 @@ static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
                        del_modules.push_back(it.second);
 
        for (auto mod : del_modules) {
+               if (first_pass && mod->name.substr(0, 9) == "$abstract")
+                       continue;
                if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
                        continue;
                log("Removing unused module `%s'.\n", mod->name.c_str());
@@ -362,10 +372,12 @@ struct HierarchyPass : public Pass {
                        if (args[argidx] == "-top") {
                                if (++argidx >= args.size())
                                        log_cmd_error("Option -top requires an additional argument!\n");
-                               if (args[argidx][0] != '$' && args[argidx][0] != '\\')
-                                       top_mod = design->modules.count("\\" + args[argidx]) > 0 ? design->modules["\\" + args[argidx]] : NULL;
-                               else
-                                       top_mod = design->modules.count(args[argidx]) > 0 ? design->modules[args[argidx]] : NULL;
+                               top_mod = design->modules.count(RTLIL::escape_id(args[argidx])) ? design->modules.at(RTLIL::escape_id(args[argidx])) : NULL;
+                               if (top_mod == NULL && design->modules.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
+                                       std::map<RTLIL::IdString, RTLIL::Const> empty_parameters;
+                                       design->modules.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
+                                       top_mod = design->modules.count(RTLIL::escape_id(args[argidx])) ? design->modules.at(RTLIL::escape_id(args[argidx])) : NULL;
+                               }
                                if (top_mod == NULL)
                                        log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
                                continue;
@@ -387,7 +399,7 @@ struct HierarchyPass : public Pass {
                                        top_mod = mod_it.second;
 
                if (top_mod != NULL)
-                       hierarchy(design, top_mod, purge_lib);
+                       hierarchy(design, top_mod, purge_lib, true);
 
                bool did_something = true;
                bool did_something_once = false;
@@ -409,7 +421,7 @@ struct HierarchyPass : public Pass {
 
                if (top_mod != NULL && did_something_once) {
                        log_header("Re-running hierarchy analysis..\n");
-                       hierarchy(design, top_mod, purge_lib);
+                       hierarchy(design, top_mod, purge_lib, false);
                }
 
                if (top_mod != NULL) {