Add --savable to support model save/restore.

This commit is contained in:
Wilson Snyder
2012-08-26 21:19:43 -04:00
parent 9309d0b00f
commit 9c00fd10de
23 changed files with 980 additions and 91 deletions
+94 -2
View File
@@ -29,6 +29,7 @@
#include <algorithm>
#include "V3Global.h"
#include "V3String.h"
#include "V3EmitC.h"
#include "V3EmitCBase.h"
@@ -842,6 +843,7 @@ class EmitCImp : EmitCStmts {
void emitCoverageDecl(AstNodeModule* modp);
void emitCoverageImp(AstNodeModule* modp);
void emitDestructorImp(AstNodeModule* modp);
void emitSavableImp(AstNodeModule* modp);
void emitTextSection(AstType type);
void emitIntFuncDecls(AstNodeModule* modp);
// High level
@@ -1436,7 +1438,7 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
// compatible, and have a common wrapper.
puts("void "+modClassName(m_modp)+"::__vlCoverInsert(uint32_t* countp, bool enable, const char* filenamep, int lineno, int column,\n");
puts( "const char* hierp, const char* pagep, const char* commentp) {\n");
puts( "static uint32_t fake_zero_count = 0;\n");
puts( "static uint32_t fake_zero_count = 0;\n"); // static doesn't need save-restore as constant
puts( "if (!enable) countp = &fake_zero_count;\n"); // Used for second++ instantiation of identical bin
puts( "*countp = 0;\n");
puts( "SP_COVER_INSERT(countp,");
@@ -1459,6 +1461,79 @@ void EmitCImp::emitDestructorImp(AstNodeModule* modp) {
puts("}\n");
}
void EmitCImp::emitSavableImp(AstNodeModule* modp) {
if (v3Global.opt.savable() ) {
puts("\n// Savable\n");
for (int de=0; de<2; ++de) {
string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize";
string funcname = de ? "__Vdeserialize" : "__Vserialize";
string writeread = de ? "read" : "write";
string op = de ? ">>" : "<<";
puts("void "+modClassName(modp)+"::"+funcname+"("+classname+"& os) {\n");
// Place a computed checksum to insure proper structure save/restore formatting
// OK if this hash includes some things we won't dump, since just looking for loading the wrong model
VHashFnv hash;
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstVar* varp = nodep->castVar()) {
hash.hash(varp->name());
hash.hash(varp->dtypep()->width());
}
}
ofp()->printf( "vluint64_t __Vcheckval = VL_ULL(0x%" VL_PRI64 "x);\n",
hash.value());
if (de) {
puts("os.readAssert(__Vcheckval);\n");
} else {
puts("os<<__Vcheckval;\n");
}
// Save all members
if (v3Global.opt.inhibitSim()) puts("os"+op+"__Vm_inhibitSim;\n");
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstVar* varp = nodep->castVar()) {
if (varp->isIO() && modp->isTop() && optSystemC()) {
// System C top I/O doesn't need loading, as the lower level subinst code does it.
}
else if (varp->isParam()) {}
else if (varp->isStatic() && varp->isConst()) {}
else {
int vects = 0;
// This isn't very robust and may need cleanup for other data types
for (AstArrayDType* arrayp=varp->dtypeSkipRefp()->castArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castArrayDType()) {
int vecnum = vects++;
if (arrayp->msb() < arrayp->lsb()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
string ivar = string("__Vi")+cvtToStr(vecnum);
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts("{ int __Vi"+cvtToStr(vecnum)+"="+cvtToStr(0)+";");
puts(" for (; "+ivar+"<"+cvtToStr(arrayp->elementsConst()));
puts("; ++"+ivar+") {\n");
}
if (varp->basicp() && (varp->basicp()->keyword() == AstBasicDTypeKwd::STRING
|| !varp->basicp()->isWide())) {
puts("os"+op+varp->name());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
puts(";\n");
} else {
puts("os."+writeread+"(&"+varp->name());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
puts(",sizeof("+varp->name());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
puts("));\n");
}
for (int v=0; v<vects; ++v) puts( "}}\n");
}
}
}
if (modp->isTop()) { // Save the children
puts( "__VlSymsp->"+funcname+"(os);\n");
}
puts("}\n");
}
}
}
void EmitCImp::emitStaticDecl(AstNodeModule* modp) {
// Need implementation here. Be careful of alignment code; needs to be uniquified
// with module name to avoid multiple symbols.
@@ -1675,8 +1750,12 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
} else {
puts("#include \"verilated.h\"\n");
}
if (v3Global.opt.savable()) {
puts("#include \"verilated_save.h\"\n");
}
if (v3Global.opt.coverage()) {
puts("#include \"SpCoverage.h\"\n");
if (v3Global.opt.savable()) v3error("--coverage and --savable not supported together");
}
if (v3Global.needHInlines()) { // Set by V3EmitCInlines; should have been called before us
puts("#include \""+topClassName()+"__Inlines.h\"\n");
@@ -1842,10 +1921,22 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("static void traceFull ("+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code);\n");
puts("static void traceChg ("+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code);\n");
}
if (v3Global.opt.savable()) {
puts("void __Vserialize(VerilatedSerialize& os);\n");
puts("void __Vdeserialize(VerilatedDeserialize& os);\n");
puts("\n");
}
puts("} VL_ATTR_ALIGNED(64);\n");
puts("} VL_ATTR_ALIGNED(128);\n");
puts("\n");
// Save/restore
if (v3Global.opt.savable() && modp->isTop()) {
puts("inline VerilatedSerialize& operator<<(VerilatedSerialize& os, "+modClassName(modp)+"& rhs) {rhs.__Vserialize(os); return os;}\n");
puts("inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, "+modClassName(modp)+"& rhs) {rhs.__Vdeserialize(os); return os;}\n");
puts("\n");
}
// finish up h-file
if (!optSystemPerl()) {
puts("#endif /*guard*/\n");
@@ -1893,6 +1984,7 @@ void EmitCImp::emitImp(AstNodeModule* modp) {
emitCtorImp(modp);
emitConfigureImp(modp);
emitDestructorImp(modp);
emitSavableImp(modp);
emitCoverageImp(modp);
}