From c8130265661517f7dc1a16269d004cf2ca72d04f Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Wed, 4 Sep 2019 06:15:41 -0400 Subject: [PATCH] Make Syms file honor --output-split-cfuncs, bug1499. --- Changes | 2 + src/V3EmitCSyms.cpp | 156 ++++++++++++++++++++++++-------- test_regress/t/t_flag_csplit.pl | 8 +- test_regress/t/t_flag_csplit.v | 6 +- 4 files changed, 134 insertions(+), 38 deletions(-) diff --git a/Changes b/Changes index 7b447ec18..c2b729799 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix make test with no VERILATOR_ROOT, bug1494. [Ahmed El-Mahmoudy] +**** Make Syms file honor --output-split-cfuncs, bug1499. [Todd Strader] + * Verilator 4.018 2019-08-29 diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 55975a69c..696bc3831 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -91,9 +91,16 @@ class EmitCSyms : EmitCBaseVisitor { int m_coverBins; // Coverage bin number int m_labelNum; // Next label number bool m_dpiHdrOnly; // Only emit the DPI header + int m_numStmts; // Number of statements output + int m_funcNum; // CFunc split function number + V3OutCFile* m_ofpBase; // Base (not split) C file + std::map m_usesVfinal; // Split method uses __Vfinal // METHODS void emitSymHdr(); + void checkSplit(bool usesVfinal); + void closeSplit(); + void emitSymImpPreamble(); void emitSymImp(); void emitDpiHdr(); void emitDpiImp(); @@ -183,8 +190,9 @@ class EmitCSyms : EmitCBaseVisitor { // Output if (!m_dpiHdrOnly) { - emitSymHdr(); + // Must emit implementation first to determine number of splits emitSymImp(); + emitSymHdr(); } if (v3Global.dpi()) { emitDpiHdr(); @@ -263,6 +271,8 @@ public: m_modp = NULL; m_coverBins = 0; m_labelNum = 0; + m_numStmts = 0; + m_funcNum = 0; iterate(nodep); } }; @@ -358,6 +368,17 @@ void EmitCSyms::emitSymHdr() { puts(symClassName()+"("+topClassName()+"* topp, const char* namep);\n"); puts(string("~")+symClassName()+"() {}\n"); + for (std::map::iterator it = m_usesVfinal.begin(); + it != m_usesVfinal.end(); ++it) { + puts("void "+symClassName()+"_"+cvtToStr(it->first)+"("); + if (it->second) { + puts("int __Vfinal"); + } else { + puts(topClassName()+"* topp"); + } + puts(");\n"); + } + puts("\n// METHODS\n"); puts("inline const char* name() { return __Vm_namep; }\n"); if (v3Global.opt.trace()) { @@ -373,13 +394,46 @@ void EmitCSyms::emitSymHdr() { puts("#endif // guard\n"); } -void EmitCSyms::emitSymImp() { - UINFO(6,__FUNCTION__<<": "<support(true); - V3OutCFile cf (filename); - m_ofp = &cf; + m_usesVfinal[m_funcNum] = usesVfinal; + closeSplit(); + + m_ofp = new V3OutCFile(filename); + + m_ofpBase->puts(symClassName()+"_"+cvtToStr(m_funcNum)+"("); + if (usesVfinal) { + m_ofpBase->puts("__Vfinal"); + } else { + m_ofpBase->puts("topp"); + } + m_ofpBase->puts(");\n"); + + emitSymImpPreamble(); + puts("void "+symClassName()+"::"+symClassName()+"_"+cvtToStr(m_funcNum)+"("); + if (usesVfinal) { + puts("int __Vfinal"); + } else { + puts(topClassName()+"* topp"); + } + puts(") {\n"); +} + +void EmitCSyms::emitSymImpPreamble() { ofp()->putsHeader(); puts("// DESCR" "IPTION: Verilator output: Symbol table implementation internals\n"); puts("\n"); @@ -390,9 +444,50 @@ void EmitCSyms::emitSymImp() { nodep; nodep=VN_CAST(nodep->nextp(), NodeModule)) { puts("#include \""+modClassName(nodep)+".h\"\n"); } +} + +void EmitCSyms::emitSymImp() { + UINFO(6,__FUNCTION__<<": "<support(true); + V3OutCFile cf (filename); + m_ofp = &cf; + m_ofpBase = m_ofp; + emitSymImpPreamble(); //puts("\n// GLOBALS\n"); + puts("\n"); + + if (v3Global.opt.savable() ) { + puts("\n"); + for (int de=0; de<2; ++de) { + string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize"; + string funcname = de ? "__Vdeserialize" : "__Vserialize"; + string op = de ? ">>" : "<<"; + // NOLINTNEXTLINE(performance-inefficient-string-concatenation) + puts("void "+symClassName()+"::"+funcname+"("+classname+"& os) {\n"); + puts( "// LOCAL STATE\n"); + // __Vm_namep presumably already correct + if (v3Global.opt.trace()) { + puts( "os"+op+"__Vm_activity;\n"); + } + puts( "os"+op+"__Vm_didInit;\n"); + puts( "// SUBCELL STATE\n"); + for (std::vector::iterator it = m_scopes.begin(); + it != m_scopes.end(); ++it) { + AstScope* scopep = it->first; AstNodeModule* modp = it->second; + if (!modp->isTop()) { + puts( scopep->nameDotless()+"."+funcname+"(os);\n"); + } + } + puts("}\n"); + } + } + + puts("\n"); + puts("\n// FUNCTIONS\n"); puts(symClassName()+"::"+symClassName()+"("+topClassName()+"* topp, const char* namep)\n"); puts("\t// Setup locals\n"); @@ -414,6 +509,7 @@ void EmitCSyms::emitSymImp() { putsQuoted(scopep->prettyName()); puts("))\n"); comma=','; + ++m_numStmts; } } puts("{\n"); @@ -424,6 +520,7 @@ void EmitCSyms::emitSymImp() { for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* modp = it->second; if (!modp->isTop()) { + checkSplit(false); string arrow = scopep->name(); string::size_type pos; while ((pos = arrow.find('.')) != string::npos) { @@ -433,6 +530,7 @@ void EmitCSyms::emitSymImp() { ofp()->printf("%-30s ", arrow.c_str()); puts(" = &"); puts(scopep->nameDotless()+";\n"); + ++m_numStmts; } } @@ -441,12 +539,14 @@ void EmitCSyms::emitSymImp() { for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* modp = it->second; if (!modp->isTop()) { + checkSplit(false); // first is used by AstCoverDecl's call to __vlCoverInsert bool first = !modp->user1(); modp->user1(true); puts(scopep->nameDotless()+".__Vconfigure(this, " +(first?"true":"false") +");\n"); + ++m_numStmts; } } @@ -457,20 +557,26 @@ void EmitCSyms::emitSymImp() { did = true; puts("// Setup scope names\n"); } + checkSplit(false); puts("__Vscope_"+it->second.m_symName+".configure(this,name(),"); putsQuoted(it->second.m_prettyName); puts(");\n"); + ++m_numStmts; } } + // Everything past here is in the __Vfinal loop, so start a new split file if needed + closeSplit(); + if (v3Global.dpi()) { - puts("// Setup export functions\n"); - puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n"); + m_ofpBase->puts("// Setup export functions\n"); + m_ofpBase->puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n"); for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) { AstScopeName* scopep = it->second.m_scopep; AstCFunc* funcp = it->second.m_funcp; AstNodeModule* modp = it->second.m_modp; if (funcp->dpiExport()) { + checkSplit(true); puts("__Vscope_"+scopep->scopeSymName()+".exportInsert(__Vfinal,"); putsQuoted(funcp->cname()); puts(", (void*)(&"); @@ -478,11 +584,13 @@ void EmitCSyms::emitSymImp() { puts("::"); puts(funcp->name()); puts("));\n"); + ++m_numStmts; } } // It would be less code if each module inserted its own variables. // Someday. For now public isn't common. for (ScopeVars::iterator it = m_scopeVars.begin(); it != m_scopeVars.end(); ++it) { + checkSplit(true); AstNodeModule* modp = it->second.m_modp; AstScope* scopep = it->second.m_scopep; AstVar* varp = it->second.m_varp; @@ -531,37 +639,13 @@ void EmitCSyms::emitSymImp() { puts(cvtToStr(pdim+udim)); puts(bounds); puts(");\n"); + ++m_numStmts; } - puts("}\n"); + m_ofpBase->puts("}\n"); } - puts("}\n"); - - if (v3Global.opt.savable() ) { - puts("\n"); - for (int de=0; de<2; ++de) { - string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize"; - string funcname = de ? "__Vdeserialize" : "__Vserialize"; - string op = de ? ">>" : "<<"; - // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - puts("void "+symClassName()+"::"+funcname+"("+classname+"& os) {\n"); - puts( "// LOCAL STATE\n"); - // __Vm_namep presumably already correct - if (v3Global.opt.trace()) { - puts( "os"+op+"__Vm_activity;\n"); - } - puts( "os"+op+"__Vm_didInit;\n"); - puts( "// SUBCELL STATE\n"); - for (std::vector::iterator it = m_scopes.begin(); - it != m_scopes.end(); ++it) { - AstScope* scopep = it->first; AstNodeModule* modp = it->second; - if (!modp->isTop()) { - puts( scopep->nameDotless()+"."+funcname+"(os);\n"); - } - } - puts("}\n"); - } - } + m_ofpBase->puts("}\n"); + closeSplit(); } //###################################################################### diff --git a/test_regress/t/t_flag_csplit.pl b/test_regress/t/t_flag_csplit.pl index 9126f460f..202efd959 100755 --- a/test_regress/t/t_flag_csplit.pl +++ b/test_regress/t/t_flag_csplit.pl @@ -64,11 +64,17 @@ sub make_version { sub check_splits { my $got1; + my $gotSyms1; foreach my $file (glob("$Self->{obj_dir}/*.cpp")) { - $got1 = 1 if $file =~ /__1/; + if ($file =~ /Syms__1/) { + $gotSyms1 = 1; + } elsif ($file =~ /__1/) { + $got1 = 1; + } check_cpp($file); } $got1 or error("No __1 split file found"); + $gotSyms1 or error("No Syms__1 split file found"); } sub check_cpp { diff --git a/test_regress/t/t_flag_csplit.v b/test_regress/t/t_flag_csplit.v index b90ab148d..e4ea0c2e3 100644 --- a/test_regress/t/t_flag_csplit.v +++ b/test_regress/t/t_flag_csplit.v @@ -46,6 +46,10 @@ module t (/*AUTOARG*/ endmodule module sub (input clk, input [31:0] i, output [31:0] z); + logic [31:0] z_tmp /* verilator public */; + always @(posedge clk) - z <= i+1+$c("0"); // $c so doesn't optimize away + z_tmp <= i+1+$c("0"); // $c so doesn't optimize away + + assign z = z_tmp; endmodule