// -*- C++ -*- //************************************************************************* // // Copyright 2003-2010 by Wilson Snyder. This program is free software; you can // redistribute it and/or modify it under the terms of either the GNU // Lesser General Public License Version 3 or the Perl Artistic License. // Version 2.0. // // Verilator is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //========================================================================= /// /// \file /// \brief Verilator: Linked against all applications using Verilated source. /// /// This file must be compiled and linked against all objects /// created from Verilator. /// /// Code available from: http://www.veripool.org/verilator /// //========================================================================= #define _VERILATED_CPP_ #include "verilated_imp.h" #include #include #define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING //=========================================================================== // Global variables // Slow path variables int Verilated::s_randReset = 0; VerilatedVoidCb Verilated::s_flushCb = NULL; // Keep below together in one cache line int Verilated::s_debug = 1; bool Verilated::s_calcUnusedSigs = false; bool Verilated::s_gotFinish = false; bool Verilated::s_assertOn = true; VL_THREAD const VerilatedScope* Verilated::t_dpiScopep = NULL; VL_THREAD const char* Verilated::t_dpiFilename = ""; VL_THREAD int Verilated::t_dpiLineno = 0; VerilatedImp VerilatedImp::s_s; //=========================================================================== // User definable functions #ifndef VL_USER_FINISH // Define this to override this function void vl_finish (const char* filename, int linenum, const char* hier) { if (0 && hier) {} VL_PRINTF("- %s:%d: Verilog $finish\n", filename, linenum); if (Verilated::gotFinish()) { VL_PRINTF("- %s:%d: Second verilog $finish, exiting\n", filename, linenum); Verilated::flushCall(); exit(0); } Verilated::gotFinish(true); } #endif #ifndef VL_USER_STOP // Define this to override this function void vl_stop (const char* filename, int linenum, const char* hier) { Verilated::gotFinish(true); Verilated::flushCall(); vl_fatal (filename,linenum,hier,"Verilog $stop"); } #endif #ifndef VL_USER_FATAL // Define this to override this function void vl_fatal (const char* filename, int linenum, const char* hier, const char* msg) { if (0 && hier) {} Verilated::gotFinish(true); VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg); Verilated::flushCall(); abort(); } #endif //=========================================================================== // Random reset -- Only called at init time, so don't inline. IData VL_RAND32() { #if defined(_WIN32) && !defined(__CYGWIN__) // Windows doesn't have lrand48(), although Cygwin does. return (rand()<<16) ^ rand(); #else return (lrand48()<<16) ^ lrand48(); #endif } IData VL_RANDOM_I(int obits) { return VL_RAND32() & VL_MASK_I(obits); } QData VL_RANDOM_Q(int obits) { QData data = ((QData)VL_RAND32()<=0; i--) { VL_PRINTF("%08x ",iwp[i]); } VL_PRINTF("\n"); } //=========================================================================== // Slow math WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus) { // See Knuth Algorithm D. Computes u/v = q.r // This isn't massively tuned, as wide division is rare // for debug see V3Number version // Requires clean input int words = VL_WORDS_I(lbits); for (int i=0; i= 0; j--) { vluint64_t unw64 = ((k<> 32 won't mask the value for (int i = vw-1; i>0; i--) { vn[i] = (rwp[i] << s) | (shift_mask & (rwp[i-1] >> (32-s))); } vn[0] = rwp[0] << s; // Copy and shift dividend by same amount; may set new upper word if (s) un[uw] = lwp[uw-1] >> (32-s); else un[uw] = 0; for (int i=uw-1; i>0; i--) { un[i] = (lwp[i] << s) | (shift_mask & (lwp[i-1] >> (32-s))); } un[0] = lwp[0] << s; // Main loop for (int j = uw - vw; j >= 0; j--) { // Estimate vluint64_t unw64 = ((vluint64_t)(un[j+vw])<= VL_ULL(0x100000000) || ((qhat*vn[vw-2]) > ((rhat<> VL_ULL(32)) - (t >> VL_ULL(32)); } t = un[j+vw] - k; un[j+vw] = t; owp[j] = qhat; // Save quotient digit if (t < 0) { // Over subtracted; correct by adding back owp[j]--; k = 0; for (int i=0; i> VL_ULL(32); } un[j+vw] = un[j+vw] + k; } } if (is_modulus) { // modulus // Need to reverse normalization on copy to output for (int i=0; i> s) | (shift_mask & (un[i+1] << (32-s))); } for (int i=vw; i=0; lsb--) { lsb = (lsb / 8) * 8; // Next digit IData charval = (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xff; output += (charval==0)?' ':charval; } break; case 'd': { // Signed decimal int digits=sprintf(tmp,"%" VL_PRI64 "d",(vlsint64_t)(VL_EXTENDS_QQ(lbits,lbits,ld))); int needmore = width-digits; if (needmore>0) output.append(needmore,' '); // Pre-pad spaces output += tmp; break; } case 'u': { // Unsigned decimal int digits=sprintf(tmp,"%" VL_PRI64 "u",ld); int needmore = width-digits; if (needmore>0) output.append(needmore,' '); // Pre-pad spaces output += tmp; break; } case 't': { // Time int digits; if (VL_TIME_MULTIPLIER==1) { digits=sprintf(tmp,"%" VL_PRI64 "u",ld); } else if (VL_TIME_MULTIPLIER==1000) { digits=sprintf(tmp,"%" VL_PRI64 "u.%03" VL_PRI64 "u", (QData)(ld/VL_TIME_MULTIPLIER), (QData)(ld%VL_TIME_MULTIPLIER)); } else { vl_fatal(__FILE__,__LINE__,"","Unsupported VL_TIME_MULTIPLIER"); } int needmore = width-digits; if (needmore>0) output.append(needmore,' '); // Pre-pad spaces output += tmp; break; } case 'b': for (; lsb>=0; lsb--) { output += ((lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 1) + '0'; } break; case 'o': for (; lsb>=0; lsb--) { lsb = (lsb / 3) * 3; // Next digit // Octal numbers may span more than one wide word, // so we need to grab each bit separately and check for overrun // Octal is rare, so we'll do it a slow simple way output += ('0' + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+0)) ? 1 : 0) + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+1)) ? 2 : 0) + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+2)) ? 4 : 0)); } break; case 'x': for (; lsb>=0; lsb--) { lsb = (lsb / 4) * 4; // Next digit IData charval = (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xf; output += "0123456789abcdef"[charval]; } break; default: string msg = string("Unknown _vl_vsformat code: ")+pos[0]; vl_fatal(__FILE__,__LINE__,"",msg.c_str()); break; } // switch } } // switch } } } static inline bool _vl_vsss_eof(FILE* fp, int& floc) { if (fp) return feof(fp) ? 1 : 0; // 1:0 to prevent MSVC++ warning else return (floc<0); } static inline void _vl_vsss_advance(FILE* fp, int& floc) { if (fp) fgetc(fp); else floc -= 8; } static inline int _vl_vsss_peek(FILE* fp, int& floc, WDataInP fromp) { // Get a character without advancing if (fp) { int data = fgetc(fp); if (data == EOF) return EOF; ungetc(data,fp); return data; } else { if (floc < 0) return EOF; floc = floc & ~7; // Align to closest character int data = (fromp[VL_BITWORD_I(floc)] >> VL_BITBIT_I(floc)) & 0xff; return data; } } static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp) { while (1) { int c = _vl_vsss_peek(fp, floc, fromp); if (c==EOF || !isspace(c)) return; _vl_vsss_advance(fp, floc); } } static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, char* tmpp, const char* acceptp) { // Read into tmp, consisting of characters from acceptp list char* cp = tmpp; while (1) { int c = _vl_vsss_peek(fp, floc, fromp); if (c==EOF || isspace(c)) break; if (acceptp!=NULL // String - allow anything && NULL==strchr(acceptp, c)) break; if (acceptp!=NULL) c = tolower(c); // Non-strings we'll simplify *cp++ = c; _vl_vsss_advance(fp, floc); } *cp++ = '\0'; //VL_PRINTF("\t_read got='%s'\n", tmpp); } static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits, IData ld) { for (; nbits && lsb>=1) { VL_ASSIGNBIT_WI(0, lsb, owp, ld & 1); } } static inline void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp, int posstart, int posend) { // Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits. int lsb = 0; for (int i=0, pos=posend-1; i=posstart; pos--) { switch (tolower (strp[pos])) { case 'x': case 'z': case '?': //FALLTHRU case '0': lsb += baseLog2; break; case '1': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 1); lsb+=baseLog2; break; case '2': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 2); lsb+=baseLog2; break; case '3': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 3); lsb+=baseLog2; break; case '4': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 4); lsb+=baseLog2; break; case '5': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 5); lsb+=baseLog2; break; case '6': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 6); lsb+=baseLog2; break; case '7': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 7); lsb+=baseLog2; break; case '8': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 8); lsb+=baseLog2; break; case '9': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 9); lsb+=baseLog2; break; case 'a': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 10); lsb+=baseLog2; break; case 'b': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 11); lsb+=baseLog2; break; case 'c': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 12); lsb+=baseLog2; break; case 'd': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 13); lsb+=baseLog2; break; case 'e': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 14); lsb+=baseLog2; break; case 'f': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 15); lsb+=baseLog2; break; case '_': break; } } } IData _vl_vsscanf(FILE* fp, // If a fscanf int fbits, WDataInP fromp, // Else if a sscanf const char* formatp, va_list ap) { // Read a Verilog $sscanf/$fscanf style format into the output list // The format must be pre-processed (and lower cased) by Verilator // Arguments are in "width, arg-value (or WDataIn* if wide)" form static VL_THREAD char tmp[VL_VALUE_STRING_MAX_WIDTH]; int floc = fbits - 1; IData got = 0; bool inPct = false; const char* pos = formatp; for (; *pos && !_vl_vsss_eof(fp,floc); ++pos) { //VL_PRINTF("_vlscan fmt='%c' floc=%d file='%c'\n", pos[0], floc, _vl_vsss_peek(fp,floc,fromp)); if (!inPct && pos[0]=='%') { inPct = true; } else if (!inPct && isspace(pos[0])) { // Format spaces while (isspace(pos[1])) pos++; _vl_vsss_skipspace(fp,floc,fromp); } else if (!inPct) { // Expected Format _vl_vsss_skipspace(fp,floc,fromp); int c = _vl_vsss_peek(fp,floc,fromp); if (c != pos[0]) goto done; else _vl_vsss_advance(fp,floc); } else { // Format character // Skip loading spaces inPct = false; char fmt = pos[0]; switch (fmt) { case '%': { int c = _vl_vsss_peek(fp,floc,fromp); if (c != '%') goto done; else _vl_vsss_advance(fp,floc); break; } default: { // Deal with all read-and-scan somethings // Note LSBs are preserved if there's an overflow const int obits = va_arg(ap, int); WData qowp[2]; WDataOutP owp = qowp; if (obits > VL_QUADSIZE) { owp = va_arg(ap,WDataOutP); } for (int i=0; i=0; pos--) { _vl_vsss_setbit(owp,obits,lsb, 8, tmp[pos]); lsb+=8; } break; } case 'd': { // Signed decimal _vl_vsss_skipspace(fp,floc,fromp); _vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xXzZ?_"); if (!tmp[0]) goto done; vlsint64_t ld; sscanf(tmp,"%" VL_PRI64 "d",&ld); VL_SET_WQ(owp,ld); break; } case 't': // FALLTHRU // Time case 'u': { // Unsigned decimal _vl_vsss_skipspace(fp,floc,fromp); _vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xXzZ?_"); if (!tmp[0]) goto done; QData ld; sscanf(tmp,"%" VL_PRI64 "u",&ld); VL_SET_WQ(owp,ld); break; } case 'b': { _vl_vsss_skipspace(fp,floc,fromp); _vl_vsss_read(fp,floc,fromp, tmp, "01xXzZ?_"); if (!tmp[0]) goto done; _vl_vsss_based(owp,obits, 1, tmp, 0, (int)strlen(tmp)); break; } case 'o': { _vl_vsss_skipspace(fp,floc,fromp); _vl_vsss_read(fp,floc,fromp, tmp, "01234567xXzZ?_"); if (!tmp[0]) goto done; _vl_vsss_based(owp,obits, 3, tmp, 0, (int)strlen(tmp)); break; } case 'x': { _vl_vsss_skipspace(fp,floc,fromp); _vl_vsss_read(fp,floc,fromp, tmp, "0123456789abcdefABCDEFxXzZ?_"); if (!tmp[0]) goto done; _vl_vsss_based(owp,obits, 4, tmp, 0, (int)strlen(tmp)); break; } default: string msg = string("Unknown _vl_vsscanf code: ")+pos[0]; vl_fatal(__FILE__,__LINE__,"",msg.c_str()); break; } // switch got++; // Reload data if non-wide (if wide, we put it in the right place directly) if (obits <= VL_BYTESIZE) { CData* p = va_arg(ap,CData*); *p = owp[0]; } else if (obits <= VL_SHORTSIZE) { SData* p = va_arg(ap,SData*); *p = owp[0]; } else if (obits <= VL_WORDSIZE) { IData* p = va_arg(ap,IData*); *p = owp[0]; } else if (obits <= VL_QUADSIZE) { QData* p = va_arg(ap,QData*); *p = VL_SET_QW(owp); } } } // switch } } done: return got; } //=========================================================================== // File I/O void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) { // See also VL_DATA_TO_STRING_NW int lsb=obits-1; bool start=true; char* destp = destoutp; for (; lsb>=0; lsb--) { lsb = (lsb / 8) * 8; // Next digit IData charval = (sourcep[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xff; if (!start || charval) { *destp++ = (charval==0)?' ':charval; start = false; // Drop leading 0s } } *destp++ = '\0'; // Terminate while (isspace(*(destp-1)) && destp>destoutp) *--destp = '\0'; // Drop trailing spaces } void _VL_STRING_TO_VINT(int obits, void* destp, int srclen, const char* srcp) { // Convert C string to Verilog format int bytes = VL_BYTES_I(obits); char* op = ((char*)(destp)); if (srclen > bytes) srclen = bytes; // Don't overflow destination int i; for (i=0; i VL_TO_STRING_MAX_WORDS*VL_WORDSIZE)) { vl_fatal(__FILE__,__LINE__,"","Internal: fgets buffer overrun"); } // We don't use fgets, as we must read \0s. IData got = 0; char* cp = buffer; while (got < bytes) { int c = getc(fp); if (c==EOF) break; *cp++ = c; got++; if (c=='\n') break; } _VL_STRING_TO_VINT(obits, destp, got, buffer); return got; } QData VL_FOPEN_QI(QData filename, IData mode) { IData fnw[2]; VL_SET_WQ(fnw, filename); return VL_FOPEN_WI(2, fnw, mode); } QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) { char filenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1]; _VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, filenamez, filenamep); char modez[5]; _VL_VINT_TO_STRING(VL_WORDSIZE, modez, &mode); return VL_CVT_FP_Q(fopen(filenamez,modez)); } void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) { va_list ap; va_start(ap,formatp); string output; _vl_vsformat(output, formatp, ap); va_end(ap); _VL_STRING_TO_VINT(obits, destp, (int)output.length(), output.c_str()); } string VL_SFORMATF_NX(const char* formatp, ...) { va_list ap; va_start(ap,formatp); string output; _vl_vsformat(output, formatp, ap); va_end(ap); return output; } void VL_WRITEF(const char* formatp, ...) { va_list ap; va_start(ap,formatp); string output; _vl_vsformat(output, formatp, ap); va_end(ap); // Users can redefine VL_PRINTF if they wish. VL_PRINTF("%s", output.c_str()); } void VL_FWRITEF(QData fpq, const char* formatp, ...) { FILE* fp = VL_CVT_Q_FP(fpq); if (VL_UNLIKELY(!fp)) return; va_list ap; va_start(ap,formatp); string output; _vl_vsformat(output, formatp, ap); va_end(ap); fputs(output.c_str(), fp); } IData VL_FSCANF_IX(QData fpq, const char* formatp, ...) { FILE* fp = VL_CVT_Q_FP(fpq); if (VL_UNLIKELY(!fp)) return 0; va_list ap; va_start(ap,formatp); IData got = _vl_vsscanf(fp, 0, NULL, formatp, ap); va_end(ap); return got; } IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) { IData fnw[2]; VL_SET_WI(fnw, ld); va_list ap; va_start(ap,formatp); IData got = _vl_vsscanf(NULL, lbits, fnw, formatp, ap); va_end(ap); return got; } IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) { IData fnw[2]; VL_SET_WQ(fnw, ld); va_list ap; va_start(ap,formatp); IData got = _vl_vsscanf(NULL, lbits, fnw, formatp, ap); va_end(ap); return got; } IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...) { va_list ap; va_start(ap,formatp); IData got = _vl_vsscanf(NULL, lbits, lwp, formatp, ap); va_end(ap); return got; } void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int, QData ofilename, void* memp, IData start, IData end) { IData fnw[2]; VL_SET_WQ(fnw, ofilename); return VL_READMEM_W(hex,width,depth,array_lsb,2, fnw,memp,start,end); } void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords, WDataInP ofilenamep, void* memp, IData start, IData end) { char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1]; _VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep); FILE* fp = fopen(ofilenamez, "r"); if (VL_UNLIKELY(!fp)) { // We don't report the Verilog source filename as it slow to have to pass it down vl_fatal (ofilenamez, 0, "", "$readmem file not found"); return; } // Prep for reading IData addr = start; int linenum = 1; bool innum = false; bool ignore_to_eol = false; bool ignore_to_cmt = false; bool needinc = false; bool reading_addr = false; int lastc = ' '; // Read the data // We process a character at a time, as then we don't need to deal // with changing buffer sizes dynamically, etc. while (1) { int c = fgetc(fp); if (VL_UNLIKELY(c==EOF)) break; //printf("%d: Got '%c' Addr%x IN%d IgE%d IgC%d ninc%d\n", linenum, c, addr, innum, ignore_to_eol, ignore_to_cmt, needinc); if (c=='\n') { linenum++; ignore_to_eol=false; if (innum) reading_addr=false; innum=false; } else if (c=='\t' || c==' ' || c=='\r' || c=='\f') { if (innum) reading_addr=false; innum=false; } // Skip // comments and detect /* comments else if (ignore_to_cmt && lastc=='*' && c=='/') { ignore_to_cmt = false; if (innum) reading_addr=false; innum=false; } else if (!ignore_to_eol && !ignore_to_cmt) { if (lastc=='/' && c=='*') { ignore_to_cmt = true; } else if (lastc=='/' && c=='/') { ignore_to_eol = true; } else if (c=='/') {} // Part of /* or // else if (c=='_') {} else if (c=='@') { reading_addr = true; innum=false; needinc=false; } // Check for hex or binary digits as file format requests else if (isxdigit(c)) { c = tolower(c); int value = (c >= 'a' ? (c-'a'+10) : (c-'0')); if (!innum) { // Prep for next number if (needinc) { addr++; needinc=false; } } if (reading_addr) { // Decode @ addresses if (!innum) addr=0; addr = (addr<<4) + value; } else { needinc = true; //printf(" Value width=%d @%x = %c\n", width, addr, c); if (addr >= (IData)(depth+array_lsb) || addr < (IData)(array_lsb)) { vl_fatal (ofilenamez, linenum, "", "$readmem file address beyond bounds of array"); } else { int entry = addr - array_lsb; QData shift = hex ? VL_ULL(4) : VL_ULL(1); // Shift value in if (width<=8) { CData* datap = &((CData*)(memp))[entry]; if (!innum) { *datap = 0; } *datap = ((*datap << shift) + value) & VL_MASK_I(width); } else if (width<=16) { SData* datap = &((SData*)(memp))[entry]; if (!innum) { *datap = 0; } *datap = ((*datap << shift) + value) & VL_MASK_I(width); } else if (width<=VL_WORDSIZE) { IData* datap = &((IData*)(memp))[entry]; if (!innum) { *datap = 0; } *datap = ((*datap << shift) + value) & VL_MASK_I(width); } else if (width<=VL_QUADSIZE) { QData* datap = &((QData*)(memp))[entry]; if (!innum) { *datap = 0; } *datap = ((*datap << (QData)(shift)) + (QData)(value)) & VL_MASK_Q(width); } else { WDataOutP datap = &((WDataOutP)(memp))[ entry*VL_WORDS_I(width) ]; if (!innum) { VL_ZERO_RESET_W(width, datap); } _VL_SHIFTL_INPLACE_W(width, datap, (IData)shift); datap[0] |= value; } if (value>=(1<=0; pos--) { _vl_vsss_setbit(rwp,rbits,lsb, 8, dp[pos]); lsb+=8; } break; default: // Compile time should have found all errors before this vl_fatal (__FILE__, __LINE__, "", "$value$plusargs format error"); break; } _VL_CLEAN_INPLACE_W(rbits,rwp); return 1; } const char* vl_mc_scan_plusargs(const char* prefixp) { string match = VerilatedImp::argPlusMatch(prefixp); static VL_THREAD char outstr[VL_VALUE_STRING_MAX_WIDTH]; if (match == "") return NULL; strncpy(outstr, match.c_str()+strlen(prefixp)+1, // +1 to skip the "+" VL_VALUE_STRING_MAX_WIDTH); outstr[VL_VALUE_STRING_MAX_WIDTH-1] = '\0'; return outstr; } //=========================================================================== // Heavy functions string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) { // See also _VL_VINT_TO_STRING char destout[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1]; int obits = lwords * VL_WORDSIZE; int lsb=obits-1; bool start=true; char* destp = destout; int len = 0; for (; lsb>=0; lsb--) { lsb = (lsb / 8) * 8; // Next digit IData charval = (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xff; if (!start || charval) { *destp++ = (charval==0)?' ':charval; len++; start = false; // Drop leading 0s } } return string(destout, len); } //=========================================================================== // Verilated:: Methods const char* Verilated::catName(const char* n1, const char* n2) { // Returns new'ed data // Used by symbol table creation to make module names static char* strp = NULL; static size_t len = 0; size_t newlen = strlen(n1)+strlen(n2)+2; if (newlen > len) { if (strp) delete [] strp; strp = new char[newlen]; len = newlen; } strcpy(strp,n1); if (*n1) strcat(strp,"."); strcat(strp,n2); return strp; } void Verilated::flushCb(VerilatedVoidCb cb) { if (s_flushCb == cb) {} // Ok - don't duplicate else if (!s_flushCb) { s_flushCb=cb; } else { // Someday we may allow multiple callbacks ala atexit(), but until then vl_fatal("unknown",0,"", "Verilated::flushCb called twice with different callbacks"); } } void Verilated::commandArgs(int argc, const char** argv) { VerilatedImp::commandArgs(argc,argv); } void Verilated::scopesDump() { VerilatedImp::scopesDump(); } int Verilated::exportFuncNum(const char* namep) { return VerilatedImp::exportFind(namep); } //=========================================================================== // VerilatedModule:: Methods VerilatedModule::VerilatedModule(const char* namep) : m_namep(strdup(namep)) { } VerilatedModule::~VerilatedModule() { if (m_namep) free((void*)m_namep); m_namep=NULL; } //====================================================================== // VerilatedScope:: Methods VerilatedScope::VerilatedScope() { m_callbacksp = NULL; m_namep = NULL; m_funcnumMax = 0; m_varsp = NULL; } VerilatedScope::~VerilatedScope() { VerilatedImp::scopeErase(this); if (m_namep) { delete [] m_namep; m_namep = NULL; } if (m_callbacksp) { delete [] m_callbacksp; m_callbacksp = NULL; } if (m_varsp) { delete m_varsp; m_varsp = NULL; } m_funcnumMax = 0; // Force callback table to empty } void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp) { // Slowpath - called once/scope at construction // We don't want the space and reference-count access overhead of strings. m_symsp = symsp; char* namep = new char[strlen(prefixp)+strlen(suffixp)+2]; strcpy(namep, prefixp); if (*prefixp && *suffixp) strcat(namep,"."); strcat(namep, suffixp); m_namep = namep; VerilatedImp::scopeInsert(this); } void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) { // Slowpath - called once/scope*export at construction // Insert a exported function into scope table int funcnum = VerilatedImp::exportInsert(namep); if (!finalize) { // Need two passes so we know array size to create // Alternative is to dynamically stretch the array, which is more code, and slower. if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum+1; } } else { if (funcnum >= m_funcnumMax) { vl_fatal(__FILE__,__LINE__,"","Internal: Bad funcnum vs. pre-finalize maximum"); } if (!m_callbacksp) { // First allocation m_callbacksp = new void* [m_funcnumMax]; memset(m_callbacksp, 0, m_funcnumMax*sizeof(void*)); } m_callbacksp[funcnum] = cb; } } void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype, int dims, ...) { // Grab dimensions // In the future we may just create a large table at emit time and statically construct from that. if (!finalize) return; if (!m_varsp) m_varsp = new VerilatedVarNameMap(); VerilatedVar var (namep, datap, vltype); va_list ap; va_start(ap,dims); for (int i=0; iinsert(make_pair(namep,var)); } VerilatedVar* VerilatedScope::varFind(const char* namep) const { if (VL_LIKELY(m_varsp)) { VerilatedVarNameMap::iterator it = m_varsp->find(namep); if (VL_LIKELY(it != m_varsp->end())) { return &(it->second); } } return NULL; } void* VerilatedScope::exportFindNullError(int funcnum) const { // Slowpath - Called only when find has failed string msg = (string("Testbench C called '") +VerilatedImp::exportName(funcnum) +"' but scope wasn't set, perhaps due to dpi import call without 'context'"); vl_fatal("unknown",0,"", msg.c_str()); return NULL; } void* VerilatedScope::exportFindError(int funcnum) const { // Slowpath - Called only when find has failed string msg = (string("Testbench C called '") +VerilatedImp::exportName(funcnum) +"' but this DPI export function exists only in other scopes, not scope '" +name()+"'"); vl_fatal("unknown",0,"", msg.c_str()); return NULL; } void VerilatedScope::scopeDump() const { VL_PRINTF(" SCOPE %p: %s\n", this, name()); for (int i=0; ibegin(); it != varsp()->end(); ++it) { VL_PRINTF(" VAR %p: %s\n", &(it->second), it->first); } } } //===========================================================================