diff --git a/Changes b/Changes index b428d4f90..377938c58 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Added --inhibit-sim flag for environments using old __Vm_inhibitSim. +**** Declare tables static, to reduce D-Cache miss rate. + * Verilator 3.600 08/28/2006 ** Support dotted cross-hierarchy variable and task references. diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 93298a052..984511e6d 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -84,7 +84,7 @@ public: void displayArg(AstDisplay* dispp, AstNode** elistp, string fmt, char fmtLetter); void emitVarDecl(AstVar* nodep, const string& prefixIfImp); - typedef enum {EVL_IO, EVL_SIG, EVL_TEMP, EVL_ALL} EisWhich; + typedef enum {EVL_IO, EVL_SIG, EVL_TEMP, EVL_STATIC, EVL_ALL} EisWhich; void emitVarList(AstNode* firstp, EisWhich which, const string& prefixIfImp); void emitVarCtors(); bool emitSimpleOk(AstNodeMath* nodep); @@ -597,16 +597,16 @@ class EmitCImp : EmitCStmts { +"<initsp()) puts("// Variables\n"); - ofp()->putAlign(4); + ofp()->putAlign(V3OutFile::AL_AUTO, 4); for (AstNode* subnodep=nodep->argsp(); subnodep; subnodep = subnodep->nextp()) { if (AstVar* varp=subnodep->castVar()) { if (varp->isFuncReturn()) emitVarDecl(varp, ""); } } emitVarList(nodep->initsp(), EVL_ALL, ""); - ofp()->putAlign(4); + ofp()->putAlign(V3OutFile::AL_AUTO, 4); emitVarList(nodep->stmtsp(), EVL_ALL, ""); - ofp()->putAlign(4); + ofp()->putAlign(V3OutFile::AL_AUTO, 4); nodep->initsp()->iterateAndNext(*this); @@ -693,7 +693,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) { if (nodep->isIO()) { if (nodep->isSc()) { m_ctorVarsVec.push_back(nodep); - ofp()->putAlign(4); // sc stuff is a structure, so bigger alignment + ofp()->putAlign(nodep->isStatic(), 4); // sc stuff is a structure, so bigger alignment if (nodep->attrScClocked() && nodep->isInput()) { puts("sc_in_clk\t"); } else { @@ -708,7 +708,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) { puts(nodep->name()); puts(";\n"); } else { // C++ signals - ofp()->putAlign(nodep->widthAlignBytes()); + ofp()->putAlign(nodep->isStatic(), nodep->widthAlignBytes()); if (nodep->isTristate()) puts("VL_INOUT"); else if (nodep->isInput()) puts("VL_IN"); else if (nodep->isOutput()) puts("VL_OUT"); @@ -731,8 +731,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) { } else { // Arrays need a small alignment, but may need different padding after. // For example three VL_SIG8's needs alignment 1 but size 3. - ofp()->putAlign(nodep->widthAlignBytes(), nodep->arrayElements()*nodep->widthAlignBytes()); - // if (nodep->isStatic()) puts("static "); // Need implementation declaration too - prefixIfImp is start in this direction + ofp()->putAlign(nodep->isStatic(), nodep->widthAlignBytes(), nodep->arrayElements()*nodep->widthAlignBytes()); + if (nodep->isStatic() && prefixIfImp=="") puts("static "); if (nodep->widthMin() <= 8) { puts("VL_SIG8("); } else if (nodep->widthMin() <= 16) { @@ -1109,7 +1109,7 @@ void EmitCImp::emitCoverageDecl(AstModule* modp) { ofp()->putsPrivate(true); puts("// Coverage\n"); puts("SpZeroed\t__Vcoverage["); puts(cvtToStr(m_coverIds.size())); puts("];\n"); - ofp()->putAlign(sizeof(uint32_t)*m_coverIds.size()); + ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(uint32_t)*m_coverIds.size()); // Rather then putting out SP_COVER_INSERT calls directly, we do it via this function // This gets around gcc slowness constructing all of the template arguments puts("void _vlCoverInsert(SpZeroed* countp, const char* filename, int lineno, int column,\n"); @@ -1239,35 +1239,41 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref // Put out a list of signal declarations // in order of 0:clocks, 1:uint8, 2:uint16, 4:uint32, 5:uint64, 6:wide, 7:arrays // This aids cache packing and locality - for (int size=0; size<8; size++) { - if (size==3) continue; - for (AstNode* nodep=firstp; nodep; nodep = nodep->nextp()) { - if (AstVar* varp = nodep->castVar()) { - bool doit = true; - switch (which) { - case EVL_ALL: doit = true; break; - case EVL_IO: doit = varp->isIO(); break; - case EVL_SIG: doit = (varp->isSignal() && !varp->isIO()); break; - case EVL_TEMP: doit = varp->isTemp(); break; - default: v3fatalSrc("Bad Case"); - } - if (doit) { - int sigbytes = varp->widthAlignBytes(); - if (varp->isUsedClock() && varp->widthMin()==1) sigbytes = 0; - else if (varp->arraysp()) sigbytes=7; - else if (varp->isScWide()) sigbytes=6; - else if (sigbytes==8) sigbytes=5; - else if (sigbytes==4) sigbytes=4; - else if (sigbytes==2) sigbytes=2; - else if (sigbytes==1) sigbytes=1; - if (size==sigbytes) { - emitVarDecl(varp, prefixIfImp); + // Largest->smallest reduces the number of pad variables. + // But for now, Smallest->largest makes it more likely a small offset will allow access to the signal. + for (int isstatic=1; isstatic>=0; isstatic--) { + if (prefixIfImp!="" && !isstatic) continue; + for (int size=0; size<8; size++) { + if (size==3) continue; + for (AstNode* nodep=firstp; nodep; nodep = nodep->nextp()) { + if (AstVar* varp = nodep->castVar()) { + bool doit = true; + switch (which) { + case EVL_ALL: doit = true; break; + case EVL_IO: doit = varp->isIO(); break; + case EVL_SIG: doit = (varp->isSignal() && !varp->isIO()); break; + case EVL_TEMP: doit = varp->isTemp(); break; + default: v3fatalSrc("Bad Case"); + } + if (varp->isStatic() ? !isstatic : isstatic) doit=false; + if (doit) { + int sigbytes = varp->widthAlignBytes(); + if (varp->isUsedClock() && varp->widthMin()==1) sigbytes = 0; + else if (varp->arraysp()) sigbytes=7; + else if (varp->isScWide()) sigbytes=6; + else if (sigbytes==8) sigbytes=5; + else if (sigbytes==4) sigbytes=4; + else if (sigbytes==2) sigbytes=2; + else if (sigbytes==1) sigbytes=1; + if (size==sigbytes) { + emitVarDecl(varp, prefixIfImp); + } } } } } + ofp()->putAlign(isstatic, 4, 0, prefixIfImp.c_str()); } - ofp()->putAlign(4, 0, prefixIfImp.c_str()); } struct CmpName { @@ -1354,22 +1360,22 @@ void EmitCImp::emitInt(AstModule* modp) { puts("\n// INTERNAL VARIABLES\n"); ofp()->putsPrivate(!modp->isTop()); // private: unless top - ofp()->putAlign(8); + ofp()->putAlign(V3OutFile::AL_AUTO, 8); puts(symClassName()+"*\t__VlSymsp;\t\t// Symbol table\n"); ofp()->putsPrivate(false); // public: if (modp->isTop()) { if (v3Global.opt.inhibitSim()) { - ofp()->putAlign(sizeof(bool)); + ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); puts("bool\t__Vm_inhibitSim;\t///< Set true to disable evaluation of module\n"); } - ofp()->putAlign(sizeof(bool)); + ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); puts("bool\t__Vm_activity;\t\t///< Used by trace routines to determine change occurred\n"); - ofp()->putAlign(sizeof(bool)); + ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); puts("bool\t__Vm_didInit;\n"); } - ofp()->putAlign(8); + ofp()->putAlign(V3OutFile::AL_AUTO, 8); emitCoverageDecl(modp); // may flip public/private - ofp()->putAlign(8); + ofp()->putAlign(V3OutFile::AL_AUTO, 8); puts("\n// PARAMETERS\n"); ofp()->putsPrivate(false); // public: @@ -1482,6 +1488,13 @@ void EmitCImp::emitImp(AstModule* modp) { } emitTextSection(AstType::SCIMPHDR); + + if (m_slow && m_splitFilenum==0) { + puts("\n//--------------------\n"); + puts("// STATIC VARIABLES\n\n"); + emitVarList(modp->stmtsp(), EVL_ALL, modClassName(modp)); + } + if (m_fast && m_splitFilenum==0) { emitTextSection(AstType::SCIMP); emitStaticDecl(modp); @@ -1770,7 +1783,7 @@ class EmitCTrace : EmitCStmts { if (nodep->initsp()) puts("// Variables\n"); emitVarList(nodep->initsp(), EVL_ALL, ""); nodep->initsp()->iterateAndNext(*this); - ofp()->putAlign(4); + ofp()->putAlign(V3OutFile::AL_AUTO, 4); puts("// Body\n"); puts("{\n"); diff --git a/src/V3File.cpp b/src/V3File.cpp index a52ee3f9d..30a4ecc5c 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -225,7 +225,7 @@ bool V3File::checkTimes(const string& filename, const string& cmdline) { V3OutFile::V3OutFile(const string& filename) : m_lineno(1), m_column(0), m_nobreak(false), m_prependIndent(true), m_indentLevel(0) - , m_declAlign(0), m_declPadNum(0) { + , m_declSAlign(0), m_declNSAlign(0), m_declPadNum(0) { if ((m_fp = V3File::new_fopen_w(filename.c_str())) == NULL) { v3fatal("Cannot write "<8) alignSize=8; - int padsize = alignSize - (m_declAlign % alignSize); + int& alignr = isStatic ? m_declSAlign : m_declNSAlign; + int padsize = alignSize - (alignr % alignSize); if (padsize && padsize!=alignSize) { puts("char\t"); puts(prefix); - puts("__VpadToAlign"+cvtToStr(m_declPadNum) + puts("__VpadToAlign"+cvtToStr(alignr) +"["+cvtToStr(padsize)+"];\n"); - m_declAlign += padsize; + alignr += padsize; m_declPadNum++; } - m_declAlign += size; + alignr += size; } //---------------------------------------------------------------------- diff --git a/src/V3File.h b/src/V3File.h index 00465adf5..8e48e20b0 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -64,24 +64,32 @@ public: // V3OutFile: A class for printing to a file, with automatic indentation of C++ code. class V3OutFile { + // TYPES + enum MiscConsts { + INDBLK = 4, // Indentation per block level + WIDTH = 50, // Width after which to break at ,'s + MAXSPACE = 80}; // After this indent, stop indenting more +public: + enum AlignClass { + AL_AUTO = 0, + AL_STATIC = 1}; + +private: + // MEMBERS FILE* m_fp; int m_lineno; int m_column; int m_nobreak; // Basic operator or begin paren, don't break next bool m_prependIndent; int m_indentLevel; // Current {} indentation - int m_declAlign; // Byte alignment of next declaration + int m_declSAlign; // Byte alignment of next declaration, statics + int m_declNSAlign; // Byte alignment of next declaration, nonstatics int m_declPadNum; // Pad variable number stack m_parenVec; // Stack of columns where last ( was int endLevels(const char* strg); static const char* indentStr(int levels); - enum MiscConsts { - INDBLK = 4, // Indentation per block level - WIDTH = 50, // Width after which to break at ,'s - MAXSPACE = 80}; // After this indent, stop indenting more - public: V3OutFile(const string& filename); ~V3OutFile(); @@ -95,7 +103,7 @@ public: void putsNoTracking(const string& strg) { putsNoTracking(strg.c_str()); } void putBreak(); // Print linebreak if line is too wide void putBreakExpr(); // Print linebreak in expression if line is too wide - void putAlign(int align, int size=0/*=align*/, const char* prefix=""); // Declare a variable, with natural alignment + void putAlign(bool isstatic/*AlignClass*/, int align, int size=0/*=align*/, const char* prefix=""); // Declare a variable, with natural alignment void putbs(const char* strg) { putBreakExpr(); puts(strg); } void putbs(const string& strg) { putBreakExpr(); puts(strg); } bool exceededWidth() const { return m_column > WIDTH; }