Added "read_verilog -nomeminit" and "nomeminit" attribute
authorClifford Wolf <clifford@clifford.at>
Sat, 14 Feb 2015 10:21:12 +0000 (11:21 +0100)
committerClifford Wolf <clifford@clifford.at>
Sat, 14 Feb 2015 10:21:12 +0000 (11:21 +0100)
README
frontends/ast/ast.cc
frontends/ast/ast.h
frontends/ast/simplify.cc
frontends/verilog/verilog_frontend.cc

diff --git a/README b/README
index 4ef43093867f829187d1df1d6b3b3dee34c16f7f..9fe43ec98ed54b672acea473bf698e14f94d28aa 100644 (file)
--- a/README
+++ b/README
@@ -257,6 +257,11 @@ Verilog Attributes and non-standard features
 - The "mem2reg" attribute on modules or arrays forces the early
   conversion of arrays to separate registers.
 
+- The "nomeminit" attribute on modules or arrays prohibits the
+  creation of initialized memories. This effectively puts "mem2reg"
+  on all memories that are written to in an "initial" block and
+  are not ROMs.
+
 - The "nolatches" attribute on modules or always-blocks
   prohibits the generation of logic-loops for latches. Instead
   all not explicitly assigned values default to x-bits. This does
index 589b08e1dcd33b52d66df00a6b7e6b7ca5605fe9..0de24013c6730fbd79698f0e7a7d67e50dcef916 100644 (file)
@@ -53,7 +53,7 @@ namespace AST {
 
 // instanciate global variables (private API)
 namespace AST_INTERNAL {
-       bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+       bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
        AstNode *current_ast, *current_ast_mod;
        std::map<std::string, AstNode*> current_scope;
        const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
@@ -958,6 +958,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
 
        current_module->ast = ast_before_simplify;
        current_module->nolatches = flag_nolatches;
+       current_module->nomeminit = flag_nomeminit;
        current_module->nomem2reg = flag_nomem2reg;
        current_module->mem2reg = flag_mem2reg;
        current_module->lib = flag_lib;
@@ -969,13 +970,14 @@ static AstModule* process_module(AstNode *ast, bool defer)
 }
 
 // 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, bool defer, bool autowire)
+void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
 {
        current_ast = ast;
        flag_dump_ast1 = dump_ast1;
        flag_dump_ast2 = dump_ast2;
        flag_dump_vlog = dump_vlog;
        flag_nolatches = nolatches;
+       flag_nomeminit = nomeminit;
        flag_nomem2reg = nomem2reg;
        flag_mem2reg = mem2reg;
        flag_lib = lib;
@@ -1037,6 +1039,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
        flag_dump_ast2 = false;
        flag_dump_vlog = false;
        flag_nolatches = nolatches;
+       flag_nomeminit = nomeminit;
        flag_nomem2reg = nomem2reg;
        flag_mem2reg = mem2reg;
        flag_lib = lib;
@@ -1103,6 +1106,7 @@ RTLIL::Module *AstModule::clone() const
 
        new_mod->ast = ast->clone();
        new_mod->nolatches = nolatches;
+       new_mod->nomeminit = nomeminit;
        new_mod->nomem2reg = nomem2reg;
        new_mod->mem2reg = mem2reg;
        new_mod->lib = lib;
index 3523d075448266c3153412297f02bf5cc6e55e84..0c1135620d611f5c137b08b9f49502975c723b0f 100644 (file)
@@ -265,13 +265,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_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
+       void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
 
        // 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, lib, noopt, icells, autowire;
+               bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
                virtual ~AstModule();
                virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
                virtual RTLIL::Module *clone() const;
@@ -295,7 +295,7 @@ namespace AST
 namespace AST_INTERNAL
 {
        // internal state variables
-       extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+       extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
        extern AST::AstNode *current_ast, *current_ast_mod;
        extern std::map<std::string, AST::AstNode*> current_scope;
        extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
index 6e56920116c842a915098db79209fa726b3453a0..10b65100015b2eef155420c78d541fc533f85475 100644 (file)
@@ -83,11 +83,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                        {
                                AstNode *mem = it.first;
                                uint32_t memflags = it.second;
+                               bool this_nomeminit = flag_nomeminit;
                                log_assert((memflags & ~0x00ffff00) == 0);
 
                                if (mem->get_bool_attribute("\\nomem2reg"))
                                        continue;
 
+                               if (mem->get_bool_attribute("\\nomeminit") || get_bool_attribute("\\nomeminit"))
+                                       this_nomeminit = true;
+
                                if (memflags & AstNode::MEM2REG_FL_FORCED)
                                        goto silent_activate;
 
@@ -97,7 +101,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                                if (memflags & AstNode::MEM2REG_FL_SET_ASYNC)
                                        goto verbose_activate;
 
-                               if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE))
+                               if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE) && this_nomeminit)
                                        goto verbose_activate;
 
                                if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
index 23d35f682803b08126f424017f1adba93cbea0fc..41561e80c60545b651f4af46e67b120f4f4b2f1b 100644 (file)
@@ -83,11 +83,20 @@ struct VerilogFrontend : public Frontend {
                log("        this can also be achieved by setting the 'nomem2reg'\n");
                log("        attribute on the respective module or register.\n");
                log("\n");
+               log("        This is potentially dangerous. Usually the front-end has good\n");
+               log("        reasons for converting an array to a list of registers.\n");
+               log("        Prohibiting this step will likely result in incorrect synthesis\n");
+               log("        results.\n");
+               log("\n");
                log("    -mem2reg\n");
                log("        always convert memories to registers. this can also be\n");
                log("        achieved by setting the 'mem2reg' attribute on the respective\n");
                log("        module or register.\n");
                log("\n");
+               log("    -nomeminit\n");
+               log("        do not infer $meminit cells and instead convert initialized\n");
+               log("        memories to registers directly in the front-end.\n");
+               log("\n");
                log("    -ppdump\n");
                log("        dump verilog code after pre-processor\n");
                log("\n");
@@ -139,6 +148,7 @@ struct VerilogFrontend : public Frontend {
                bool flag_dump_ast2 = false;
                bool flag_dump_vlog = false;
                bool flag_nolatches = false;
+               bool flag_nomeminit = false;
                bool flag_nomem2reg = false;
                bool flag_mem2reg = false;
                bool flag_ppdump = false;
@@ -186,6 +196,10 @@ struct VerilogFrontend : public Frontend {
                                flag_nolatches = true;
                                continue;
                        }
+                       if (arg == "-nomeminit") {
+                               flag_nomeminit = true;
+                               continue;
+                       }
                        if (arg == "-nomem2reg") {
                                flag_nomem2reg = true;
                                continue;
@@ -288,7 +302,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, flag_defer, default_nettype_wire);
+               AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
 
                if (!flag_nopp)
                        delete lexin;