Make Syms file honor --output-split-cfuncs, bug1499.

This commit is contained in:
Todd Strader 2019-09-04 06:15:41 -04:00
parent 314cd92129
commit c813026566
4 changed files with 134 additions and 38 deletions

View File

@ -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

View File

@ -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<int,bool> 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<int,bool>::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__<<": "<<endl);
string filename = v3Global.opt.makeDir()+"/"+symClassName()+".cpp";
void EmitCSyms::closeSplit() {
if (!m_ofp || m_ofp == m_ofpBase) return;
puts("}\n");
delete m_ofp;
m_ofp = NULL;
}
void EmitCSyms::checkSplit(bool usesVfinal) {
if (m_ofp && (!v3Global.opt.outputSplitCFuncs() ||
m_numStmts < v3Global.opt.outputSplitCFuncs())) return;
m_numStmts = 0;
string filename = v3Global.opt.makeDir()+"/"+symClassName()+"__"+cvtToStr(++m_funcNum)+".cpp";
AstCFile* cfilep = newCFile(filename, true/*slow*/, true/*source*/);
cfilep->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__<<": "<<endl);
string filename = v3Global.opt.makeDir()+"/"+symClassName()+".cpp";
AstCFile* cfilep = newCFile(filename, true/*slow*/, true/*source*/);
cfilep->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<ScopeModPair>::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<ScopeModPair>::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<ScopeModPair>::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<ScopeModPair>::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();
}
//######################################################################

View File

@ -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 {

View File

@ -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