From ad693d67b2e2e0b58b9d251bec74e82608230269 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 26 Oct 2017 20:05:42 -0400 Subject: [PATCH] Mark Verilated functions with multithreaded status. No functional change. --- include/verilated.cpp | 153 ++++++++-------- include/verilated.h | 349 ++++++++++++++++++------------------ include/verilated_cov.cpp | 10 +- include/verilated_cov.h | 4 +- include/verilated_cov_key.h | 13 +- include/verilated_dpi.h | 8 +- include/verilated_heavy.h | 32 ++-- include/verilated_save.h | 2 + include/verilated_syms.h | 5 + include/verilated_vcd_c.h | 2 +- include/verilated_vcd_sc.h | 2 + include/verilated_vpi.cpp | 10 +- include/verilatedos.h | 6 + 13 files changed, 312 insertions(+), 284 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 4c3b7afde..158edb808 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -48,11 +48,11 @@ 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) { +void vl_finish (const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { if (0 && hier) {} - VL_PRINTF("- %s:%d: Verilog $finish\n", filename, linenum); + VL_PRINTF("- %s:%d: Verilog $finish\n", filename, linenum); // Not VL_PRINTF_MT, already on main thread if (Verilated::gotFinish()) { - VL_PRINTF("- %s:%d: Second verilog $finish, exiting\n", filename, linenum); + VL_PRINTF("- %s:%d: Second verilog $finish, exiting\n", filename, linenum); // Not VL_PRINTF_MT, already on main thread Verilated::flushCall(); exit(0); } @@ -61,7 +61,7 @@ void vl_finish (const char* filename, int linenum, const char* hier) { #endif #ifndef VL_USER_STOP // Define this to override this function -void vl_stop (const char* filename, int linenum, const char* hier) { +void vl_stop (const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { Verilated::gotFinish(true); Verilated::flushCall(); vl_fatal (filename,linenum,hier,"Verilog $stop"); @@ -69,20 +69,20 @@ void vl_stop (const char* filename, int linenum, const char* hier) { #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) { +void vl_fatal (const char* filename, int linenum, const char* hier, const char* msg) VL_MT_UNSAFE { if (0 && hier) {} Verilated::gotFinish(true); - VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg); + VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg); // Not VL_PRINTF_MT, already on main thread Verilated::flushCall(); - VL_PRINTF("Aborting...\n"); + VL_PRINTF("Aborting...\n"); // Not VL_PRINTF_MT, already on main thread Verilated::flushCall(); // Second flush in case VL_PRINTF does something needing a flush abort(); } #endif //=========================================================================== -// Non-user overridable wrapper to call user-overridable functions +// Wrapper to call certain functions via messages when multithreaded void VL_FINISH_MT (const char* filename, int linenum, const char* hier) { vl_finish(filename, linenum, hier); @@ -100,7 +100,7 @@ void VL_FATAL_MT (const char* filename, int linenum, const char* hier, const cha // Debug prints /// sprintf but return as string (this isn't fast, for print messages only) -std::string _vl_string_vprintf(const char* formatp, va_list ap) { +std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE { va_list aq; va_copy(aq, ap); int len = VL_VSNPRINTF(NULL, 0, formatp, aq); @@ -122,13 +122,14 @@ vluint32_t VL_THREAD_ID() { return 0; } -void VL_DBG_MSGF(const char* formatp, ...) { +void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE { // We're still using c printf formats instead of operator<< so we can avoid the heavy // includes that otherwise would be required in every Verilated module va_list ap; va_start(ap, formatp); std::string out = _vl_string_vprintf(formatp, ap); va_end(ap); + // printf("-imm-V{t%d,%" VL_PRI64 "d}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str()); VL_PRINTF_MT("-V{t%d,%" VL_PRI64 "d}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str()); } @@ -207,7 +208,7 @@ WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) { return outwp; } -WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) { +WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE { for (int i=0; i=0; --i) { VL_PRINTF_MT("%08x ",iwp[i]); } VL_PRINTF_MT("\n"); @@ -224,7 +225,7 @@ void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp) { //=========================================================================== // Slow math -WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus) { +WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus) VL_MT_SAFE { // See Knuth Algorithm D. Computes u/v = q.r // This isn't massively tuned, as wide division is rare // for debug see V3Number version @@ -333,7 +334,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo } } -WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp) { +WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp) VL_MT_SAFE { // obits==lbits, rbits can be different owp[0] = 1; for (int i=1; i < VL_WORDS_I(obits); i++) owp[i] = 0; @@ -355,11 +356,11 @@ WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDa } return owp; } -WDataOutP VL_POW_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp, QData rhs) { +WDataOutP VL_POW_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp, QData rhs) VL_MT_SAFE { WData rhsw[2]; VL_SET_WQ(rhsw, rhs); return VL_POW_WWW(obits,lbits,rbits,owp,lwp,rhsw); } -QData VL_POW_QQW(int, int, int rbits, QData lhs, WDataInP rwp) { +QData VL_POW_QQW(int, int, int rbits, QData lhs, WDataInP rwp) VL_MT_SAFE { // Skip check for rhs == 0, as short-circuit doesn't save time if (VL_UNLIKELY(lhs==0)) return 0; QData power = lhs; @@ -371,7 +372,7 @@ QData VL_POW_QQW(int, int, int rbits, QData lhs, WDataInP rwp) { return out; } -WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool lsign, bool rsign) { +WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool lsign, bool rsign) VL_MT_SAFE { // obits==lbits, rbits can be different if (rsign && VL_SIGN_W(rbits, rwp)) { int words = VL_WORDS_I(obits); @@ -391,11 +392,11 @@ WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, W } return VL_POW_WWW(obits, rbits, rbits, owp, lwp, rwp); } -WDataOutP VL_POWSS_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp, QData rhs, bool lsign, bool rsign) { +WDataOutP VL_POWSS_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp, QData rhs, bool lsign, bool rsign) VL_MT_SAFE { WData rhsw[2]; VL_SET_WQ(rhsw, rhs); return VL_POWSS_WWW(obits,lbits,rbits,owp,lwp,rhsw,lsign,rsign); } -QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsign, bool rsign) { +QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsign, bool rsign) VL_MT_SAFE { // Skip check for rhs == 0, as short-circuit doesn't save time if (rsign && VL_SIGN_W(rbits, rwp)) { if (lhs==0) return 0; // "X" @@ -415,7 +416,7 @@ QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsig // Do a va_arg returning a quad, assuming input argument is anything less than wide #define _VL_VA_ARG_Q(ap, bits) (((bits) <= VL_WORDSIZE) ? va_arg(ap,IData) : va_arg(ap,QData)) -void _vl_vsformat(std::string& output, const char* formatp, va_list ap) { +void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SAFE { // Format a Verilog $write 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 @@ -621,15 +622,15 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) { } } -static inline bool _vl_vsss_eof(FILE* fp, int& floc) { +static inline bool _vl_vsss_eof(FILE* fp, int& floc) VL_MT_SAFE { 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) { +static inline void _vl_vsss_advance(FILE* fp, int& floc) VL_MT_SAFE { if (fp) fgetc(fp); else floc -= 8; } -static inline int _vl_vsss_peek(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr) { +static inline int _vl_vsss_peek(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr) VL_MT_SAFE { // Get a character without advancing if (fp) { int data = fgetc(fp); @@ -646,7 +647,7 @@ static inline int _vl_vsss_peek(FILE* fp, int& floc, WDataInP fromp, const std: } } } -static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr) { +static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr) VL_MT_SAFE { while (1) { int c = _vl_vsss_peek(fp, floc, fromp, fstr); if (c==EOF || !isspace(c)) return; @@ -654,7 +655,7 @@ static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp, const } } static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr, - char* tmpp, const char* acceptp) { + char* tmpp, const char* acceptp) VL_MT_SAFE { // Read into tmp, consisting of characters from acceptp list char* cp = tmpp; while (1) { @@ -667,14 +668,15 @@ static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std: _vl_vsss_advance(fp, floc); } *cp++ = '\0'; - //VL_DBG_MSG("\t_read got='"<>=1) { VL_ASSIGNBIT_WI(0, lsb, owp, ld & 1); } } -static inline void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp, size_t posstart, size_t posend) { +static inline void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, + const char* strp, size_t posstart, size_t posend) VL_MT_SAFE { // Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits. int lsb = 0; for (int i=0, pos=static_cast(posend)-1; i=static_cast(posstart); --pos) { @@ -704,7 +706,7 @@ static inline void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const IData _vl_vsscanf(FILE* fp, // If a fscanf int fbits, WDataInP fromp, // Else if a sscanf const std::string& fstr, // if a sscanf to string - const char* formatp, va_list ap) { + const char* formatp, va_list ap) VL_MT_SAFE { // 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 @@ -714,7 +716,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf bool inPct = false; const char* pos = formatp; for (; *pos && !_vl_vsss_eof(fp,floc); ++pos) { - //VL_DBG_MSG("_vlscan fmt='"<destoutp) *--destp = '\0'; // Drop trailing spaces } -void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp) { +void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp) VL_MT_SAFE { // Convert C string to Verilog format size_t bytes = VL_BYTES_I(obits); char* op = reinterpret_cast(destp); @@ -876,7 +878,8 @@ void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp) for (; i> 8; // Want exit status } -IData VL_TESTPLUSARGS_I(const char* formatp) { +IData VL_TESTPLUSARGS_I(const char* formatp) VL_MT_SAFE { const std::string& match = VerilatedImp::argPlusMatch(formatp); if (match == "") return 0; else return 1; } -IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) { +IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE { std::string prefix; bool inPct = false; bool done = false; @@ -1267,7 +1276,7 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) { _VL_CLEAN_INPLACE_W(rbits,rwp); return 1; } -IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) { +IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_SAFE { std::string prefix; bool inPct = false; bool done = false; @@ -1295,7 +1304,7 @@ IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) { return 1; } -const char* vl_mc_scan_plusargs(const char* prefixp) { +const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE { const std::string& match = VerilatedImp::argPlusMatch(prefixp); static VL_THREAD_LOCAL char outstr[VL_VALUE_STRING_MAX_WIDTH]; if (match == "") return NULL; @@ -1308,7 +1317,7 @@ const char* vl_mc_scan_plusargs(const char* prefixp) { //=========================================================================== // Heavy functions -std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) { +std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) VL_MT_SAFE { // See also _VL_VINT_TO_STRING char destout[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1]; int obits = lwords * VL_WORDSIZE; @@ -1342,7 +1351,7 @@ void Verilated::debug(int val) { } } -const char* Verilated::catName(const char* n1, const char* n2) { +const char* Verilated::catName(const char* n1, const char* n2) VL_MT_SAFE { // Returns new'ed data // Used by symbol table creation to make module names static char* strp = NULL; @@ -1411,6 +1420,7 @@ VerilatedModule::VerilatedModule(const char* namep) } VerilatedModule::~VerilatedModule() { + // Memory cleanup - not called during normal operation if (m_namep) { free((void*)m_namep); m_namep=NULL; } } @@ -1444,6 +1454,7 @@ VerilatedScope::VerilatedScope() { } VerilatedScope::~VerilatedScope() { + // Memory cleanup - not called during normal operation VerilatedImp::scopeErase(this); if (m_namep) { delete [] m_namep; m_namep = NULL; } if (m_callbacksp) { delete [] m_callbacksp; m_callbacksp = NULL; } @@ -1451,7 +1462,7 @@ VerilatedScope::~VerilatedScope() { m_funcnumMax = 0; // Force callback table to empty } -void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp) { +void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp) VL_MT_UNSAFE { // Slowpath - called once/scope at construction // We don't want the space and reference-count access overhead of strings. m_symsp = symsp; @@ -1463,7 +1474,7 @@ void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const VerilatedImp::scopeInsert(this); } -void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) { +void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE { // Slowpath - called once/scope*export at construction // Insert a exported function into scope table int funcnum = VerilatedImp::exportInsert(namep); @@ -1484,7 +1495,7 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) { } void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, - VerilatedVarType vltype, int vlflags, int dims, ...) { + VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE { // Grab dimensions // In the future we may just create a large table at emit time and statically construct from that. if (!finalize) return; @@ -1515,7 +1526,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, } // cppcheck-suppress unusedFunction // Used by applications -VerilatedVar* VerilatedScope::varFind(const char* namep) const { +VerilatedVar* VerilatedScope::varFind(const char* namep) const VL_MT_SAFE_POSTINIT { if (VL_LIKELY(m_varsp)) { VerilatedVarNameMap::iterator it = m_varsp->find(namep); if (VL_LIKELY(it != m_varsp->end())) { @@ -1525,7 +1536,7 @@ VerilatedVar* VerilatedScope::varFind(const char* namep) const { return NULL; } -void* VerilatedScope::exportFindNullError(int funcnum) { +void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE { // Slowpath - Called only when find has failed std::string msg = (std::string("Testbench C called '") +VerilatedImp::exportName(funcnum) diff --git a/include/verilated.h b/include/verilated.h index c08a4b63e..7ed1fa3bc 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -283,8 +283,8 @@ public: static const char* commandArgsPlusMatch(const char* prefixp); /// Produce name & version for (at least) VPI - static const char* productName() { return VERILATOR_PRODUCT; } - static const char* productVersion() { return VERILATOR_VERSION; } + static const char* productName() VL_PURE { return VERILATOR_PRODUCT; } + static const char* productVersion() VL_PURE { return VERILATOR_VERSION; } /// For debugging, print much of the Verilator internal state. /// The output of this function may change in future @@ -312,8 +312,8 @@ public: static const char* dpiFilenamep() { return t_dpiFilename; } static int dpiLineno() { return t_dpiLineno; } static int exportFuncNum(const char* namep); - static size_t serializedSize() { return sizeof(s_s); } - static void* serializedPtr() { return &s_s; } + static size_t serializedSize() VL_PURE { return sizeof(s_s); } + static void* serializedPtr() VL_MT_UNSAFE { return &s_s; } }; //========================================================================= @@ -328,16 +328,19 @@ public: /// Routine to call for $finish /// User code may wish to replace this function, to do so, define VL_USER_FINISH. +/// This code does not have to be thread safe. /// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this. extern void vl_finish (const char* filename, int linenum, const char* hier); /// Routine to call for $stop /// User code may wish to replace this function, to do so, define VL_USER_STOP. +/// This code does not have to be thread safe. /// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this. extern void vl_stop (const char* filename, int linenum, const char* hier); /// Routine to call for a couple of fatal messages /// User code may wish to replace this function, to do so, define VL_USER_FATAL. +/// This code does not have to be thread safe. /// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this. extern void vl_fatal (const char* filename, int linenum, const char* hier, const char* msg); @@ -355,7 +358,7 @@ extern void VL_FATAL_MT (const char* filename, int linenum, const char* hier, /// Print a string, multithread safe. Eventually VL_PRINTF will get called. #define VL_PRINTF_MT VL_PRINTF /// Print a debug message from internals with standard prefix, with printf style format -extern void VL_DBG_MSGF(const char* formatp, ...); +extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE; extern IData VL_RANDOM_I(int obits); ///< Randomize a signal extern QData VL_RANDOM_Q(int obits); ///< Randomize a signal @@ -376,7 +379,7 @@ extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi); extern IData VL_FOPEN_S(const char* filenamep, const char* mode); extern IData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode); extern IData VL_FOPEN_QI(QData ofilename, IData mode); -inline IData VL_FOPEN_II(IData ofilename, IData mode) { return VL_FOPEN_QI(ofilename,mode); } +inline IData VL_FOPEN_II(IData ofilename, IData mode) VL_MT_SAFE { return VL_FOPEN_QI(ofilename,mode); } extern void VL_FCLOSE_I(IData fdi); @@ -386,7 +389,7 @@ extern void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwo extern void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords, QData ofilename, void* memp, IData start, IData end); inline void VL_READMEM_I(bool hex, int width, int depth, int array_lsb, int fnwords, - IData ofilename, void* memp, IData start, IData end) { + IData ofilename, void* memp, IData start, IData end) VL_MT_SAFE { VL_READMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); } extern void VL_WRITEF(const char* formatp, ...); @@ -405,7 +408,7 @@ extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...); extern IData VL_SYSTEM_IW(int lhsnwords, WDataInP lhs); extern IData VL_SYSTEM_IQ(QData lhs); -inline IData VL_SYSTEM_II(IData lhs) { return VL_SYSTEM_IQ(lhs); } +inline IData VL_SYSTEM_II(IData lhs) VL_MT_SAFE { return VL_SYSTEM_IQ(lhs); } extern IData VL_TESTPLUSARGS_I(const char* formatp); extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish @@ -431,19 +434,19 @@ extern FILE* VL_CVT_I_FP(IData lhs); // Use a union to avoid cast-to-different-size warnings /// Return void* from QData -static inline void* VL_CVT_Q_VP(QData lhs) { union { void* fp; QData q; } u; u.q=lhs; return u.fp; } +static inline void* VL_CVT_Q_VP(QData lhs) VL_PURE { union { void* fp; QData q; } u; u.q=lhs; return u.fp; } /// Return QData from void* -static inline QData VL_CVT_VP_Q(void* fp) { union { void* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; } +static inline QData VL_CVT_VP_Q(void* fp) VL_PURE { union { void* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; } /// Return double from QData (bits, not numerically) -static inline double VL_CVT_D_Q(QData lhs) { union { double d; QData q; } u; u.q=lhs; return u.d; } +static inline double VL_CVT_D_Q(QData lhs) VL_PURE { union { double d; QData q; } u; u.q=lhs; return u.d; } /// Return QData from double (bits, not numerically) -static inline QData VL_CVT_Q_D(double lhs) { union { double d; QData q; } u; u.d=lhs; return u.q; } +static inline QData VL_CVT_Q_D(double lhs) VL_PURE { union { double d; QData q; } u; u.d=lhs; return u.q; } /// Return double from QData (numeric) -static inline double VL_ITOR_D_I(IData lhs) { return static_cast(static_cast(lhs)); } +static inline double VL_ITOR_D_I(IData lhs) VL_PURE { return static_cast(static_cast(lhs)); } /// Return QData from double (numeric) -static inline IData VL_RTOI_I_D(double lhs) { return static_cast(VL_TRUNC(lhs)); } +static inline IData VL_RTOI_I_D(double lhs) VL_PURE { return static_cast(VL_TRUNC(lhs)); } /// Return QData from double (numeric) -static inline IData VL_RTOIROUND_I_D(double lhs) { return static_cast(VL_ROUND(lhs)); } +static inline IData VL_RTOIROUND_I_D(double lhs) VL_PURE { return static_cast(VL_ROUND(lhs)); } // Sign extend such that if MSB set, we get ffff_ffff, else 0s // (Requires clean input) @@ -454,8 +457,8 @@ static inline IData VL_RTOIROUND_I_D(double lhs) { return static_cast(lhs)) #define VL_EXTEND_QQ(obits,lbits,lhs) ((lhs)) -static inline WDataOutP VL_EXTEND_WI(int obits, int, WDataOutP owp, IData ld) { +static inline WDataOutP VL_EXTEND_WI(int obits, int, WDataOutP owp, IData ld) VL_MT_SAFE { // Note for extracts that obits != lbits owp[0] = ld; for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0; return(owp); } -static inline WDataOutP VL_EXTEND_WQ(int obits, int, WDataOutP owp, QData ld) { +static inline WDataOutP VL_EXTEND_WQ(int obits, int, WDataOutP owp, QData ld) VL_MT_SAFE { VL_SET_WQ(owp,ld); for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0; return(owp); } -static inline WDataOutP VL_EXTEND_WW(int obits, int lbits, WDataOutP owp, WDataInP lwp) { +static inline WDataOutP VL_EXTEND_WW(int obits, int lbits, WDataOutP owp, WDataInP lwp) VL_MT_SAFE { for (int i=0; i < VL_WORDS_I(lbits); ++i) owp[i] = lwp[i]; for (int i=VL_WORDS_I(lbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0; return(owp); @@ -687,30 +690,30 @@ static inline WDataOutP VL_EXTEND_WW(int obits, int lbits, WDataOutP owp, WDataI // EMIT_RULE: VL_EXTENDS: oclean=*dirty*; obits=lbits; // Sign extension; output dirty -static inline IData VL_EXTENDS_II(int, int lbits, IData lhs) { +static inline IData VL_EXTENDS_II(int, int lbits, IData lhs) VL_PURE { return VL_EXTENDSIGN_I(lbits,lhs) | lhs; } -static inline QData VL_EXTENDS_QI(int, int lbits, QData lhs/*Q_as_need_extended*/) { +static inline QData VL_EXTENDS_QI(int, int lbits, QData lhs/*Q_as_need_extended*/) VL_PURE { return VL_EXTENDSIGN_Q(lbits,lhs) | lhs; } -static inline QData VL_EXTENDS_QQ(int, int lbits, QData lhs) { +static inline QData VL_EXTENDS_QQ(int, int lbits, QData lhs) VL_PURE { return VL_EXTENDSIGN_Q(lbits,lhs) | lhs; } -static inline WDataOutP VL_EXTENDS_WI(int obits, int lbits, WDataOutP owp, IData ld) { +static inline WDataOutP VL_EXTENDS_WI(int obits, int lbits, WDataOutP owp, IData ld) VL_MT_SAFE { IData sign = VL_SIGNONES_I(lbits,ld); owp[0] = ld | (sign & ~VL_MASK_I(lbits)); for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = sign; return(owp); } -static inline WDataOutP VL_EXTENDS_WQ(int obits, int lbits, WDataOutP owp, QData ld) { +static inline WDataOutP VL_EXTENDS_WQ(int obits, int lbits, WDataOutP owp, QData ld) VL_MT_SAFE { VL_SET_WQ(owp,ld); IData sign = VL_SIGNONES_I(lbits,owp[1]); owp[1] |= sign & ~VL_MASK_I(lbits); for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = sign; return(owp); } -static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp, WDataInP lwp) { +static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp, WDataInP lwp) VL_MT_SAFE { for (int i=0; i < VL_WORDS_I(lbits)-1; ++i) owp[i] = lwp[i]; int lmsw=VL_WORDS_I(lbits)-1; IData sign = VL_SIGNONES_I(lbits,lwp[lmsw]); @@ -725,7 +728,7 @@ static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp, WData // EMIT_RULE: VL_REDAND: oclean=clean; lclean==clean; obits=1; #define VL_REDAND_II(obits,lbits,lhs) (lhs == VL_MASK_I(lbits)) #define VL_REDAND_IQ(obits,lbits,lhs) (lhs == VL_MASK_Q(lbits)) -static inline IData VL_REDAND_IW(int, int lbits, WDataInP lwp) { +static inline IData VL_REDAND_IW(int, int lbits, WDataInP lwp) VL_MT_SAFE { int words = VL_WORDS_I(lbits); IData combine=lwp[0]; for (int i=1; i < words-1; ++i) combine &= lwp[i]; @@ -736,19 +739,19 @@ static inline IData VL_REDAND_IW(int, int lbits, WDataInP lwp) { // EMIT_RULE: VL_REDOR: oclean=clean; lclean==clean; obits=1; #define VL_REDOR_I(lhs) (lhs!=0) #define VL_REDOR_Q(lhs) (lhs!=0) -static inline IData VL_REDOR_W(int words, WDataInP lwp) { +static inline IData VL_REDOR_W(int words, WDataInP lwp) VL_MT_SAFE { IData equal=0; for (int i=0; i < words; ++i) equal |= lwp[i]; return(equal!=0); } // EMIT_RULE: VL_REDXOR: oclean=dirty; obits=1; -static inline IData VL_REDXOR_2(IData r) { +static inline IData VL_REDXOR_2(IData r) VL_PURE { // Experiments show VL_REDXOR_2 is faster than __builtin_parityl r=(r^(r>>1)); return r; } -static inline IData VL_REDXOR_4(IData r) { +static inline IData VL_REDXOR_4(IData r) VL_PURE { #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) return __builtin_parityl(r); #else @@ -756,7 +759,7 @@ static inline IData VL_REDXOR_4(IData r) { return r; #endif } -static inline IData VL_REDXOR_8(IData r) { +static inline IData VL_REDXOR_8(IData r) VL_PURE { #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) return __builtin_parityl(r); #else @@ -764,7 +767,7 @@ static inline IData VL_REDXOR_8(IData r) { return r; #endif } -static inline IData VL_REDXOR_16(IData r) { +static inline IData VL_REDXOR_16(IData r) VL_PURE { #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) return __builtin_parityl(r); #else @@ -772,7 +775,7 @@ static inline IData VL_REDXOR_16(IData r) { return r; #endif } -static inline IData VL_REDXOR_32(IData r) { +static inline IData VL_REDXOR_32(IData r) VL_PURE { #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) return __builtin_parityl(r); #else @@ -780,7 +783,7 @@ static inline IData VL_REDXOR_32(IData r) { return r; #endif } -static inline IData VL_REDXOR_64(QData r) { +static inline IData VL_REDXOR_64(QData r) VL_PURE { #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) return __builtin_parityll(r); #else @@ -788,14 +791,14 @@ static inline IData VL_REDXOR_64(QData r) { return static_cast(r); #endif } -static inline IData VL_REDXOR_W(int words, WDataInP lwp) { +static inline IData VL_REDXOR_W(int words, WDataInP lwp) VL_MT_SAFE { IData r = lwp[0]; for (int i=1; i < words; ++i) r ^= lwp[i]; return VL_REDXOR_32(r); } // EMIT_RULE: VL_COUNTONES_II: oclean = false; lhs clean -static inline IData VL_COUNTONES_I(IData lhs) { +static inline IData VL_COUNTONES_I(IData lhs) VL_PURE { // This is faster than __builtin_popcountl IData r = lhs - ((lhs >> 1) & 033333333333) - ((lhs >> 2) & 011111111111); r = (r + (r>>3)) & 030707070707; @@ -803,22 +806,22 @@ static inline IData VL_COUNTONES_I(IData lhs) { r = (r + (r>>12) + (r>>24)) & 077; return r; } -static inline IData VL_COUNTONES_Q(QData lhs) { +static inline IData VL_COUNTONES_Q(QData lhs) VL_PURE { return VL_COUNTONES_I(static_cast(lhs)) + VL_COUNTONES_I(static_cast(lhs>>32)); } -static inline IData VL_COUNTONES_W(int words, WDataInP lwp) { +static inline IData VL_COUNTONES_W(int words, WDataInP lwp) VL_MT_SAFE { IData r = 0; for (int i=0; (i < words); ++i) r+=VL_COUNTONES_I(lwp[i]); return r; } -static inline IData VL_ONEHOT_I(IData lhs) { +static inline IData VL_ONEHOT_I(IData lhs) VL_PURE { return (((lhs & (lhs-1))==0) & (lhs!=0)); } -static inline IData VL_ONEHOT_Q(QData lhs) { +static inline IData VL_ONEHOT_Q(QData lhs) VL_PURE { return (((lhs & (lhs-1))==0) & (lhs!=0)); } -static inline IData VL_ONEHOT_W(int words, WDataInP lwp) { +static inline IData VL_ONEHOT_W(int words, WDataInP lwp) VL_MT_SAFE { IData one=0; for (int i=0; (i < words); ++i) { if (lwp[i]) { @@ -830,13 +833,13 @@ static inline IData VL_ONEHOT_W(int words, WDataInP lwp) { return one; } -static inline IData VL_ONEHOT0_I(IData lhs) { +static inline IData VL_ONEHOT0_I(IData lhs) VL_PURE { return ((lhs & (lhs-1))==0); } -static inline IData VL_ONEHOT0_Q(QData lhs) { +static inline IData VL_ONEHOT0_Q(QData lhs) VL_PURE { return ((lhs & (lhs-1))==0); } -static inline IData VL_ONEHOT0_W(int words, WDataInP lwp) { +static inline IData VL_ONEHOT0_W(int words, WDataInP lwp) VL_MT_SAFE { bool one=false; for (int i=0; (i < words); ++i) { if (lwp[i]) { @@ -848,7 +851,7 @@ static inline IData VL_ONEHOT0_W(int words, WDataInP lwp) { return 1; } -static inline IData VL_CLOG2_I(IData lhs) { +static inline IData VL_CLOG2_I(IData lhs) VL_PURE { // There are faster algorithms, or fls GCC4 builtins, but rarely used if (VL_UNLIKELY(!lhs)) return 0; lhs--; @@ -856,14 +859,14 @@ static inline IData VL_CLOG2_I(IData lhs) { for (; lhs!=0; ++shifts) lhs = lhs >> 1; return shifts; } -static inline IData VL_CLOG2_Q(QData lhs) { +static inline IData VL_CLOG2_Q(QData lhs) VL_PURE { if (VL_UNLIKELY(!lhs)) return 0; lhs--; int shifts=0; for (; lhs!=0; ++shifts) lhs = lhs >> VL_ULL(1); return shifts; } -static inline IData VL_CLOG2_W(int words, WDataInP lwp) { +static inline IData VL_CLOG2_W(int words, WDataInP lwp) VL_MT_SAFE { IData adjust = (VL_COUNTONES_W(words,lwp)==1) ? 0 : 1; for (int i=words-1; i>=0; --i) { if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken @@ -878,7 +881,7 @@ static inline IData VL_CLOG2_W(int words, WDataInP lwp) { return 0; } -static inline IData VL_MOSTSETBITP1_W(int words, WDataInP lwp) { +static inline IData VL_MOSTSETBITP1_W(int words, WDataInP lwp) VL_MT_SAFE { // MSB set bit plus one; similar to FLS. 0=value is zero for (int i=words-1; i>=0; --i) { if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken @@ -897,33 +900,33 @@ static inline IData VL_MOSTSETBITP1_W(int words, WDataInP lwp) { // SIMPLE LOGICAL OPERATORS // EMIT_RULE: VL_AND: oclean=lclean||rclean; obits=lbits; lbits==rbits; -static inline WDataOutP VL_AND_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){ +static inline WDataOutP VL_AND_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp) VL_MT_SAFE { for (int i=0; (i < words); ++i) owp[i] = (lwp[i] & rwp[i]); return(owp); } // EMIT_RULE: VL_OR: oclean=lclean&&rclean; obits=lbits; lbits==rbits; -static inline WDataOutP VL_OR_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){ +static inline WDataOutP VL_OR_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp) VL_MT_SAFE { for (int i=0; (i < words); ++i) owp[i] = (lwp[i] | rwp[i]); return(owp); } // EMIT_RULE: VL_CHANGEXOR: oclean=1; obits=32; lbits==rbits; -static inline IData VL_CHANGEXOR_W(int words, WDataInP lwp,WDataInP rwp){ +static inline IData VL_CHANGEXOR_W(int words, WDataInP lwp,WDataInP rwp) VL_MT_SAFE { IData od = 0; for (int i=0; (i < words); ++i) od |= (lwp[i] ^ rwp[i]); return(od); } // EMIT_RULE: VL_XOR: oclean=lclean&&rclean; obits=lbits; lbits==rbits; -static inline WDataOutP VL_XOR_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){ +static inline WDataOutP VL_XOR_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp) VL_MT_SAFE { for (int i=0; (i < words); ++i) owp[i] = (lwp[i] ^ rwp[i]); return(owp); } // EMIT_RULE: VL_XNOR: oclean=dirty; obits=lbits; lbits==rbits; -static inline WDataOutP VL_XNOR_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){ +static inline WDataOutP VL_XNOR_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp) VL_MT_SAFE { for (int i=0; (i < words); ++i) owp[i] = (lwp[i] ^ ~rwp[i]); return(owp); } // EMIT_RULE: VL_NOT: oclean=dirty; obits=lbits; -static inline WDataOutP VL_NOT_W(int words, WDataOutP owp,WDataInP lwp) { +static inline WDataOutP VL_NOT_W(int words, WDataOutP owp,WDataInP lwp) VL_MT_SAFE { for (int i=0; i < words; ++i) owp[i] = ~(lwp[i]); return(owp); } @@ -944,14 +947,14 @@ static inline WDataOutP VL_NOT_W(int words, WDataOutP owp,WDataInP lwp) { #define VL_GTE_W(words,lwp,rwp) (_VL_CMP_W(words,lwp,rwp)>=0) // Output clean, AND MUST BE CLEAN -static inline IData VL_EQ_W(int words, WDataInP lwp, WDataInP rwp) { +static inline IData VL_EQ_W(int words, WDataInP lwp, WDataInP rwp) VL_MT_SAFE { int nequal=0; for (int i=0; (i < words); ++i) nequal |= (lwp[i] ^ rwp[i]); return(nequal==0); } // Internal usage -static inline int _VL_CMP_W(int words, WDataInP lwp, WDataInP rwp) { +static inline int _VL_CMP_W(int words, WDataInP lwp, WDataInP rwp) VL_MT_SAFE { for (int i=words-1; i>=0; --i) { if (lwp[i] > rwp[i]) return 1; if (lwp[i] < rwp[i]) return -1; @@ -964,53 +967,53 @@ static inline int _VL_CMP_W(int words, WDataInP lwp, WDataInP rwp) { #define VL_GTS_IWW(obits,lbits,rbits,lwp,rwp) (_VL_CMPS_W(lbits,lwp,rwp)>0) #define VL_GTES_IWW(obits,lbits,rbits,lwp,rwp) (_VL_CMPS_W(lbits,lwp,rwp)>=0) -static inline IData VL_GTS_III(int, int lbits, int, IData lhs, IData rhs) { +static inline IData VL_GTS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE { // For lbits==32, this becomes just a single instruction, otherwise ~5. // GCC 3.3.4 sign extension bugs on AMD64 architecture force us to use quad logic vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); //Q for gcc vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); //Q for gcc return lhs_signed > rhs_signed; } -static inline IData VL_GTS_IQQ(int, int lbits, int, QData lhs, QData rhs) { +static inline IData VL_GTS_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE { vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); return lhs_signed > rhs_signed; } -static inline IData VL_GTES_III(int, int lbits, int, IData lhs, IData rhs) { +static inline IData VL_GTES_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE { vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); //Q for gcc vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); //Q for gcc return lhs_signed >= rhs_signed; } -static inline IData VL_GTES_IQQ(int, int lbits, int, QData lhs, QData rhs) { +static inline IData VL_GTES_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE { vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); return lhs_signed >= rhs_signed; } -static inline IData VL_LTS_III(int, int lbits, int, IData lhs, IData rhs) { +static inline IData VL_LTS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE { vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); //Q for gcc vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); //Q for gcc return lhs_signed < rhs_signed; } -static inline IData VL_LTS_IQQ(int, int lbits, int, QData lhs, QData rhs) { +static inline IData VL_LTS_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE { vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); return lhs_signed < rhs_signed; } -static inline IData VL_LTES_III(int, int lbits, int, IData lhs, IData rhs) { +static inline IData VL_LTES_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE { vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); //Q for gcc vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); //Q for gcc return lhs_signed <= rhs_signed; } -static inline IData VL_LTES_IQQ(int, int lbits, int, QData lhs, QData rhs) { +static inline IData VL_LTES_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE { vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); return lhs_signed <= rhs_signed; } -static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) { +static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) VL_MT_SAFE { int words = VL_WORDS_I(lbits); int i=words-1; // We need to flip sense if negative comparison @@ -1038,7 +1041,7 @@ static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) { #define VL_MODDIV_QQQ(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)%(rhs)) #define VL_MODDIV_WWW(lbits,owp,lwp,rwp) (_vl_moddiv_w(lbits,owp,lwp,rwp,1)) -static inline WDataOutP VL_ADD_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){ +static inline WDataOutP VL_ADD_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp) VL_MT_SAFE { QData carry = 0; for (int i=0; i(lwp[i]) + static_cast(rwp[i]); @@ -1048,7 +1051,7 @@ static inline WDataOutP VL_ADD_W(int words, WDataOutP owp,WDataInP lwp,WDataInP return(owp); } -static inline WDataOutP VL_SUB_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){ +static inline WDataOutP VL_SUB_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp) VL_MT_SAFE { QData carry = 0; for (int i=0; i(lwp[i]) + static_cast(static_cast(~rwp[i])); @@ -1062,10 +1065,10 @@ static inline WDataOutP VL_SUB_W(int words, WDataOutP owp,WDataInP lwp,WDataInP // Optimization bug in GCC 2.96 and presumably all-pre GCC 3 versions need this workaround, // we can't just //# define VL_NEGATE_I(data) (-(data)) -static inline IData VL_NEGATE_I(IData data) { return -data; } -static inline QData VL_NEGATE_Q(QData data) { return -data; } +static inline IData VL_NEGATE_I(IData data) VL_PURE { return -data; } +static inline QData VL_NEGATE_Q(QData data) VL_PURE { return -data; } -static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp,WDataInP lwp){ +static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp,WDataInP lwp) VL_MT_SAFE { QData carry = 0; for (int i=0; i(static_cast(~lwp[i])); @@ -1076,7 +1079,7 @@ static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp,WDataInP lwp){ return(owp); } -static inline WDataOutP VL_MUL_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){ +static inline WDataOutP VL_MUL_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp) VL_MT_SAFE { for (int i=0; i(ld))) // Iff lbits==1 -static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) { +static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) VL_PURE { IData returndata = ld; for (unsigned i=1; i < rep; ++i){ returndata = returndata << lbits; @@ -1384,7 +1387,7 @@ static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) { } return (returndata); } -static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) { +static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) VL_PURE { QData returndata = ld; for (unsigned i=1; i < rep; ++i){ returndata = returndata << lbits; @@ -1392,21 +1395,21 @@ static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) { } return (returndata); } -static inline WDataOutP VL_REPLICATE_WII(int obits, int lbits, int, WDataOutP owp, IData ld, IData rep) { +static inline WDataOutP VL_REPLICATE_WII(int obits, int lbits, int, WDataOutP owp, IData ld, IData rep) VL_MT_SAFE { owp[0] = ld; for (unsigned i=1; i < rep; ++i){ _VL_INSERT_WI(obits,owp,ld,i*lbits+lbits-1,i*lbits); } return(owp); } -static inline WDataOutP VL_REPLICATE_WQI(int obits, int lbits, int, WDataOutP owp, QData ld, IData rep) { +static inline WDataOutP VL_REPLICATE_WQI(int obits, int lbits, int, WDataOutP owp, QData ld, IData rep) VL_MT_SAFE { VL_SET_WQ(owp,ld); for (unsigned i=1; i < rep; ++i){ _VL_INSERT_WQ(obits,owp,ld,i*lbits+lbits-1,i*lbits); } return(owp); } -static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP owp, WDataInP lwp, IData rep) { +static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP owp, WDataInP lwp, IData rep) VL_MT_SAFE { for (int i=0; i < VL_WORDS_I(lbits); ++i) owp[i] = lwp[i]; for (unsigned i=1; i < rep; ++i){ _VL_INSERT_WW(obits,owp,lwp,i*lbits+lbits-1,i*lbits); @@ -1418,7 +1421,7 @@ static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP ow // Special "fast" versions for slice sizes that are a power of 2. These use // shifts and masks to execute faster than the slower for-loop approach where a // subset of bits is copied in during each iteration. -static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_log2) { +static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_log2) VL_PURE { // Pre-shift bits in most-significant slice: // // If lbits is not a multiple of the slice size (i.e., lbits % rd != 0), @@ -1460,7 +1463,7 @@ static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_ return ret >> (VL_WORDSIZE - lbits); } -static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_log2) { +static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_log2) VL_PURE { // Pre-shift bits in most-significant slice (see comment in VL_STREAML_FAST_III) QData ret = ld; if (rd_log2) { @@ -1487,7 +1490,7 @@ static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_ } // Regular "slow" streaming operators -static inline IData VL_STREAML_III(int, int lbits, int, IData ld, IData rd) { +static inline IData VL_STREAML_III(int, int lbits, int, IData ld, IData rd) VL_PURE { IData ret = 0; // Slice size should never exceed the lhs width IData mask = VL_MASK_I(rd); @@ -1499,7 +1502,7 @@ static inline IData VL_STREAML_III(int, int lbits, int, IData ld, IData rd) { return ret; } -static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) { +static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) VL_PURE { QData ret = 0; // Slice size should never exceed the lhs width QData mask = VL_MASK_Q(rd); @@ -1511,7 +1514,7 @@ static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) { return ret; } -static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WDataInP lwp, IData rd) { +static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WDataInP lwp, IData rd) VL_MT_SAFE { VL_ZERO_W(lbits, owp); // Slice size should never exceed the lhs width int ssize = (rd < static_cast(lbits)) ? rd : (static_cast(lbits)); @@ -1538,55 +1541,55 @@ static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WData #define VL_CONCAT_QQI(obits,lbits,rbits,ld,rd) (static_cast(ld)<<(rbits) | static_cast(rd)) #define VL_CONCAT_QQQ(obits,lbits,rbits,ld,rd) (static_cast(ld)<<(rbits) | static_cast(rd)) -static inline WDataOutP VL_CONCAT_WII(int obits,int lbits,int rbits,WDataOutP owp,IData ld,IData rd) { +static inline WDataOutP VL_CONCAT_WII(int obits,int lbits,int rbits,WDataOutP owp,IData ld,IData rd) VL_MT_SAFE { owp[0] = rd; for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0; _VL_INSERT_WI(obits,owp,ld,rbits+lbits-1,rbits); return(owp); } -static inline WDataOutP VL_CONCAT_WWI(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, IData rd) { +static inline WDataOutP VL_CONCAT_WWI(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, IData rd) VL_MT_SAFE { owp[0] = rd; for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0; _VL_INSERT_WW(obits,owp,lwp,rbits+lbits-1,rbits); return(owp); } -static inline WDataOutP VL_CONCAT_WIW(int obits,int lbits,int rbits,WDataOutP owp,IData ld, WDataInP rwp) { +static inline WDataOutP VL_CONCAT_WIW(int obits,int lbits,int rbits,WDataOutP owp,IData ld, WDataInP rwp) VL_MT_SAFE { for (int i=0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i]; for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0; _VL_INSERT_WI(obits,owp,ld,rbits+lbits-1,rbits); return(owp); } -static inline WDataOutP VL_CONCAT_WIQ(int obits,int lbits,int rbits,WDataOutP owp,IData ld,QData rd) { +static inline WDataOutP VL_CONCAT_WIQ(int obits,int lbits,int rbits,WDataOutP owp,IData ld,QData rd) VL_MT_SAFE { VL_SET_WQ(owp,rd); for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0; _VL_INSERT_WI(obits,owp,ld,rbits+lbits-1,rbits); return(owp); } -static inline WDataOutP VL_CONCAT_WQI(int obits,int lbits,int rbits,WDataOutP owp,QData ld,IData rd) { +static inline WDataOutP VL_CONCAT_WQI(int obits,int lbits,int rbits,WDataOutP owp,QData ld,IData rd) VL_MT_SAFE { owp[0] = rd; for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0; _VL_INSERT_WQ(obits,owp,ld,rbits+lbits-1,rbits); return(owp); } -static inline WDataOutP VL_CONCAT_WQQ(int obits,int lbits,int rbits,WDataOutP owp,QData ld,QData rd) { +static inline WDataOutP VL_CONCAT_WQQ(int obits,int lbits,int rbits,WDataOutP owp,QData ld,QData rd) VL_MT_SAFE { VL_SET_WQ(owp,rd); for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0; _VL_INSERT_WQ(obits,owp,ld,rbits+lbits-1,rbits); return(owp); } -static inline WDataOutP VL_CONCAT_WWQ(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, QData rd) { +static inline WDataOutP VL_CONCAT_WWQ(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, QData rd) VL_MT_SAFE { VL_SET_WQ(owp,rd); for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0; _VL_INSERT_WW(obits,owp,lwp,rbits+lbits-1,rbits); return(owp); } -static inline WDataOutP VL_CONCAT_WQW(int obits,int lbits,int rbits,WDataOutP owp,QData ld, WDataInP rwp) { +static inline WDataOutP VL_CONCAT_WQW(int obits,int lbits,int rbits,WDataOutP owp,QData ld, WDataInP rwp) VL_MT_SAFE { for (int i=0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i]; for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0; _VL_INSERT_WQ(obits,owp,ld,rbits+lbits-1,rbits); return(owp); } -static inline WDataOutP VL_CONCAT_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) { +static inline WDataOutP VL_CONCAT_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) VL_MT_SAFE { for (int i=0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i]; for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0; _VL_INSERT_WW(obits,owp,lwp,rbits+lbits-1,rbits); @@ -1598,7 +1601,7 @@ static inline WDataOutP VL_CONCAT_WWW(int obits,int lbits,int rbits,WDataOutP ow // Static shift, used by internal functions // The output is the same as the input - it overlaps! -static inline void _VL_SHIFTL_INPLACE_W(int obits,WDataOutP iowp,IData rd/*1 or 4*/) { +static inline void _VL_SHIFTL_INPLACE_W(int obits,WDataOutP iowp,IData rd/*1 or 4*/) VL_MT_SAFE { int words = VL_WORDS_I(obits); IData linsmask = VL_MASK_I(rd); for (int i=words-1; i>=1; --i) { @@ -1611,7 +1614,7 @@ static inline void _VL_SHIFTL_INPLACE_W(int obits,WDataOutP iowp,IData rd/*1 or // EMIT_RULE: VL_SHIFTL: oclean=lclean; rclean==clean; // Important: Unlike most other funcs, the shift might well be a computed // expression. Thus consider this when optimizing. (And perhaps have 2 funcs?) -static inline WDataOutP VL_SHIFTL_WWI(int obits,int,int,WDataOutP owp,WDataInP lwp, IData rd) { +static inline WDataOutP VL_SHIFTL_WWI(int obits,int,int,WDataOutP owp,WDataInP lwp, IData rd) VL_MT_SAFE { int word_shift = VL_BITWORD_I(rd); int bit_shift = VL_BITBIT_I(rd); if (rd >= static_cast(obits)) { // rd may be huge with MSB set @@ -1625,7 +1628,7 @@ static inline WDataOutP VL_SHIFTL_WWI(int obits,int,int,WDataOutP owp,WDataInP l } return(owp); } -static inline WDataOutP VL_SHIFTL_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) { +static inline WDataOutP VL_SHIFTL_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) VL_MT_SAFE { for (int i=1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more return VL_ZERO_W(obits, owp); @@ -1633,7 +1636,7 @@ static inline WDataOutP VL_SHIFTL_WWW(int obits,int lbits,int rbits,WDataOutP ow } return VL_SHIFTL_WWI(obits,lbits,32,owp,lwp,rwp[0]); } -static inline IData VL_SHIFTL_IIW(int obits,int,int rbits,IData lhs, WDataInP rwp) { +static inline IData VL_SHIFTL_IIW(int obits,int,int rbits,IData lhs, WDataInP rwp) VL_MT_SAFE { for (int i=1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more return 0; @@ -1645,7 +1648,7 @@ static inline IData VL_SHIFTL_IIW(int obits,int,int rbits,IData lhs, WDataInP rw // EMIT_RULE: VL_SHIFTR: oclean=lclean; rclean==clean; // Important: Unlike most other funcs, the shift might well be a computed // expression. Thus consider this when optimizing. (And perhaps have 2 funcs?) -static inline WDataOutP VL_SHIFTR_WWI(int obits,int,int,WDataOutP owp,WDataInP lwp, IData rd) { +static inline WDataOutP VL_SHIFTR_WWI(int obits,int,int,WDataOutP owp,WDataInP lwp, IData rd) VL_MT_SAFE { int word_shift = VL_BITWORD_I(rd); // Maybe 0 int bit_shift = VL_BITBIT_I(rd); if (rd >= static_cast(obits)) { // rd may be huge with MSB set @@ -1670,7 +1673,7 @@ static inline WDataOutP VL_SHIFTR_WWI(int obits,int,int,WDataOutP owp,WDataInP l } return(owp); } -static inline WDataOutP VL_SHIFTR_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) { +static inline WDataOutP VL_SHIFTR_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) VL_MT_SAFE { for (int i=1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more return VL_ZERO_W(obits, owp); @@ -1678,7 +1681,7 @@ static inline WDataOutP VL_SHIFTR_WWW(int obits,int lbits,int rbits,WDataOutP ow } return VL_SHIFTR_WWI(obits,lbits,32,owp,lwp,rwp[0]); } -static inline IData VL_SHIFTR_IIW(int obits,int,int rbits,IData lhs, WDataInP rwp) { +static inline IData VL_SHIFTR_IIW(int obits,int,int rbits,IData lhs, WDataInP rwp) VL_MT_SAFE { for (int i=1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more return 0; @@ -1688,7 +1691,7 @@ static inline IData VL_SHIFTR_IIW(int obits,int,int rbits,IData lhs, WDataInP rw } // EMIT_RULE: VL_SHIFTRS: oclean=false; lclean=clean, rclean==clean; -static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData rhs) { +static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData rhs) VL_PURE { // Note the C standard does not specify the >> operator as a arithmetic shift! // IEEE says signed if output signed, but bit position from lbits; // must use lbits for sign; lbits might != obits, @@ -1697,15 +1700,15 @@ static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData r IData signext = ~(VL_MASK_I(lbits) >> rhs); // One with bits where we've shifted "past" return (lhs >> rhs) | (sign & VL_CLEAN_II(obits,obits,signext)); } -static inline QData VL_SHIFTRS_QQI(int obits, int lbits, int, QData lhs, IData rhs) { +static inline QData VL_SHIFTRS_QQI(int obits, int lbits, int, QData lhs, IData rhs) VL_PURE { QData sign = -(lhs >> (lbits-1)); QData signext = ~(VL_MASK_Q(lbits) >> rhs); return (lhs >> rhs) | (sign & VL_CLEAN_QQ(obits,obits,signext)); } -static inline IData VL_SHIFTRS_IQI(int obits, int lbits, int rbits, QData lhs, IData rhs) { +static inline IData VL_SHIFTRS_IQI(int obits, int lbits, int rbits, QData lhs, IData rhs) VL_PURE { return static_cast(VL_SHIFTRS_QQI(obits, lbits, rbits, lhs, rhs)); } -static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDataInP lwp, IData rd) { +static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDataInP lwp, IData rd) VL_MT_SAFE { int word_shift = VL_BITWORD_I(rd); int bit_shift = VL_BITBIT_I(rd); int lmsw = VL_WORDS_I(obits)-1; @@ -1737,7 +1740,7 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDa } return(owp); } -static inline WDataOutP VL_SHIFTRS_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) { +static inline WDataOutP VL_SHIFTRS_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) VL_MT_SAFE { for (int i=1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more int lmsw = VL_WORDS_I(obits)-1; @@ -1749,7 +1752,7 @@ static inline WDataOutP VL_SHIFTRS_WWW(int obits,int lbits,int rbits,WDataOutP o } return VL_SHIFTRS_WWI(obits,lbits,32,owp,lwp,rwp[0]); } -static inline IData VL_SHIFTRS_IIW(int obits,int lbits,int rbits,IData lhs, WDataInP rwp) { +static inline IData VL_SHIFTRS_IIW(int obits,int lbits,int rbits,IData lhs, WDataInP rwp) VL_MT_SAFE { for (int i=1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more IData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative @@ -1758,7 +1761,7 @@ static inline IData VL_SHIFTRS_IIW(int obits,int lbits,int rbits,IData lhs, WDat } return VL_SHIFTRS_III(obits,lbits,32,lhs,rwp[0]); } -static inline QData VL_SHIFTRS_QQW(int obits,int lbits,int rbits,QData lhs, WDataInP rwp) { +static inline QData VL_SHIFTRS_QQW(int obits,int lbits,int rbits,QData lhs, WDataInP rwp) VL_MT_SAFE { for (int i=1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more QData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative @@ -1767,11 +1770,11 @@ static inline QData VL_SHIFTRS_QQW(int obits,int lbits,int rbits,QData lhs, WDat } return VL_SHIFTRS_QQI(obits,lbits,32,lhs,rwp[0]); } -static inline IData VL_SHIFTRS_IIQ(int obits,int lbits,int rbits,IData lhs, QData rhs) { +static inline IData VL_SHIFTRS_IIQ(int obits,int lbits,int rbits,IData lhs, QData rhs) VL_PURE { WData rwp[2]; VL_SET_WQ(rwp,rhs); return VL_SHIFTRS_IIW(obits,lbits,rbits,lhs,rwp); } -static inline QData VL_SHIFTRS_QQQ(int obits,int lbits,int rbits,QData lhs, QData rhs) { +static inline QData VL_SHIFTRS_QQQ(int obits,int lbits,int rbits,QData lhs, QData rhs) VL_PURE { WData rwp[2]; VL_SET_WQ(rwp,rhs); return VL_SHIFTRS_QQW(obits,lbits,rbits,lhs,rwp); } @@ -1785,7 +1788,7 @@ static inline QData VL_SHIFTRS_QQQ(int obits,int lbits,int rbits,QData lhs, QDat #define VL_BITSEL_QQII(obits,lbits,rbits,zbits,lhs,rhs) ((lhs)>>(rhs)) #define VL_BITSEL_IQII(obits,lbits,rbits,zbits,lhs,rhs) (static_cast((lhs)>>(rhs))) -static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData rd) { +static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData rd) VL_MT_SAFE { int word = VL_BITWORD_I(rd); if (VL_UNLIKELY(rd > static_cast(lbits))) { return ~0; // Spec says you can go outside the range of a array. Don't coredump if so. @@ -1801,7 +1804,7 @@ static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData #define VL_SEL_QQII(obits,lbits,rbits,tbits,lhs,lsb,width) ((lhs)>>(lsb)) #define VL_SEL_IQII(obits,lbits,rbits,tbits,lhs,lsb,width) (static_cast((lhs)>>(lsb))) -static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP lwp, IData lsb, IData width) { +static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP lwp, IData lsb, IData width) VL_MT_SAFE { int msb = lsb+width-1; if (VL_UNLIKELY(msb>lbits)) { return ~0; // Spec says you can go outside the range of a array. Don't coredump if so. @@ -1815,7 +1818,7 @@ static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP lwp, IData ls } } -static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP lwp, IData lsb, IData width) { +static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP lwp, IData lsb, IData width) VL_MT_SAFE { int msb = lsb+width-1; if (VL_UNLIKELY(msb>lbits)) { return ~0; // Spec says you can go outside the range of a array. Don't coredump if so. @@ -1836,7 +1839,7 @@ static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP lwp, IData ls } } -static inline WDataOutP VL_SEL_WWII(int obits,int lbits,int,int,WDataOutP owp,WDataInP lwp, IData lsb, IData width) { +static inline WDataOutP VL_SEL_WWII(int obits,int lbits,int,int,WDataOutP owp,WDataInP lwp, IData lsb, IData width) VL_MT_SAFE { int msb = lsb+width-1; int word_shift = VL_BITWORD_I(lsb); if (VL_UNLIKELY(msb>lbits)) { // Outside bounds, @@ -1867,33 +1870,33 @@ static inline WDataOutP VL_SEL_WWII(int obits,int lbits,int,int,WDataOutP owp,WD // Range assignments // EMIT_RULE: VL_ASSIGNRANGE: rclean=dirty; -static inline void VL_ASSIGNSEL_IIII(int obits, int lsb, CData& lhsr, IData rhs) { +static inline void VL_ASSIGNSEL_IIII(int obits, int lsb, CData& lhsr, IData rhs) VL_PURE { _VL_INSERT_II(obits, lhsr, rhs, lsb+obits-1, lsb); } -static inline void VL_ASSIGNSEL_IIII(int obits, int lsb, SData& lhsr, IData rhs) { +static inline void VL_ASSIGNSEL_IIII(int obits, int lsb, SData& lhsr, IData rhs) VL_PURE { _VL_INSERT_II(obits, lhsr, rhs, lsb+obits-1, lsb); } -static inline void VL_ASSIGNSEL_IIII(int obits, int lsb, IData& lhsr, IData rhs) { +static inline void VL_ASSIGNSEL_IIII(int obits, int lsb, IData& lhsr, IData rhs) VL_PURE { _VL_INSERT_II(obits, lhsr, rhs, lsb+obits-1, lsb); } -static inline void VL_ASSIGNSEL_QIII(int obits, int lsb, QData& lhsr, IData rhs) { +static inline void VL_ASSIGNSEL_QIII(int obits, int lsb, QData& lhsr, IData rhs) VL_PURE { _VL_INSERT_QQ(obits, lhsr, rhs, lsb+obits-1, lsb); } -static inline void VL_ASSIGNSEL_QQII(int obits, int lsb, QData& lhsr, QData rhs) { +static inline void VL_ASSIGNSEL_QQII(int obits, int lsb, QData& lhsr, QData rhs) VL_PURE { _VL_INSERT_QQ(obits, lhsr, rhs, lsb+obits-1, lsb); } -static inline void VL_ASSIGNSEL_QIIQ(int obits, int lsb, QData& lhsr, QData rhs) { +static inline void VL_ASSIGNSEL_QIIQ(int obits, int lsb, QData& lhsr, QData rhs) VL_PURE { _VL_INSERT_QQ(obits, lhsr, rhs, lsb+obits-1, lsb); } -//static inline void VL_ASSIGNSEL_IIIW(int obits, int lsb, IData& lhsr,WDataInP rwp) { +//static inline void VL_ASSIGNSEL_IIIW(int obits, int lsb, IData& lhsr,WDataInP rwp) VL_MT_SAFE { // Illegal, as lhs width >= rhs width -static inline void VL_ASSIGNSEL_WIII(int obits, int lsb, WDataOutP owp, IData rhs) { +static inline void VL_ASSIGNSEL_WIII(int obits, int lsb, WDataOutP owp, IData rhs) VL_MT_SAFE { _VL_INSERT_WI(obits, owp, rhs, lsb+obits-1, lsb); } -static inline void VL_ASSIGNSEL_WIIQ(int obits, int lsb, WDataOutP owp, QData rhs) { +static inline void VL_ASSIGNSEL_WIIQ(int obits, int lsb, WDataOutP owp, QData rhs) VL_MT_SAFE { _VL_INSERT_WQ(obits, owp, rhs, lsb+obits-1, lsb); } -static inline void VL_ASSIGNSEL_WIIW(int obits, int lsb, WDataOutP owp, WDataInP rwp) { +static inline void VL_ASSIGNSEL_WIIW(int obits, int lsb, WDataOutP owp, WDataInP rwp) VL_MT_SAFE { _VL_INSERT_WW(obits, owp, rwp, lsb+obits-1, lsb); } @@ -1901,7 +1904,7 @@ static inline void VL_ASSIGNSEL_WIIW(int obits, int lsb, WDataOutP owp, WDataInP // Triops static inline WDataOutP VL_COND_WIWW(int obits, int, int, int, - WDataOutP owp, int cond, WDataInP w1p, WDataInP w2p) { + WDataOutP owp, int cond, WDataInP w1p, WDataInP w2p) VL_MT_SAFE { int words = VL_WORDS_I(obits); for (int i=0; i < words; ++i) owp[i] = cond ? w1p[i] : w2p[i]; return(owp); @@ -1921,75 +1924,75 @@ static inline WDataOutP VL_COND_WIWW(int obits, int, int, int, return o static inline WDataOutP VL_CONST_W_1X(int obits, WDataOutP o, - IData d0) { + IData d0) VL_MT_SAFE { o[0]=d0; _END(obits,1); } static inline WDataOutP VL_CONST_W_2X(int obits, WDataOutP o, - IData d1,IData d0) { + IData d1,IData d0) VL_MT_SAFE { o[0]=d0; o[1]=d1; _END(obits,2); } static inline WDataOutP VL_CONST_W_3X(int obits, WDataOutP o, - IData d2,IData d1,IData d0) { + IData d2,IData d1,IData d0) VL_MT_SAFE { o[0]=d0; o[1]=d1; o[2]=d2; _END(obits,3); } static inline WDataOutP VL_CONST_W_4X(int obits, WDataOutP o, - IData d3,IData d2,IData d1,IData d0) { + IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE { o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; _END(obits,4); } static inline WDataOutP VL_CONST_W_5X(int obits, WDataOutP o, - IData d4,IData d3,IData d2,IData d1,IData d0) { + IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE { o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; _END(obits,5); } static inline WDataOutP VL_CONST_W_6X(int obits, WDataOutP o, - IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) { + IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE { o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; _END(obits,6); } static inline WDataOutP VL_CONST_W_7X(int obits, WDataOutP o, - IData d6,IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) { + IData d6,IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE { o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; _END(obits,7); } static inline WDataOutP VL_CONST_W_8X(int obits, WDataOutP o, - IData d7,IData d6,IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) { + IData d7,IData d6,IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE { o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7; _END(obits,8); } // static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP obase, - IData d0) { + IData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0]=d0; _END(obits,1); } static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP obase, - IData d1,IData d0) { + IData d1,IData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0]=d0; o[1]=d1; _END(obits,2); } static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP obase, - IData d2,IData d1,IData d0) { + IData d2,IData d1,IData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0]=d0; o[1]=d1; o[2]=d2; _END(obits,3); } static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP obase, - IData d3,IData d2,IData d1,IData d0) { + IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; _END(obits,4); } static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase, - IData d4,IData d3,IData d2,IData d1,IData d0) { + IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; _END(obits,5); } static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase, - IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) { + IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; _END(obits,6); } static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase, - IData d6,IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) { + IData d6,IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; _END(obits,7); } static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase, - IData d7,IData d6,IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) { + IData d7,IData d6,IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7; _END(obits,8); } @@ -1998,7 +2001,7 @@ static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase, // Partial constant, lower words of vector wider than 8*32, starting at bit number lsb static inline void VL_CONSTLO_W_8X(int lsb, WDataOutP obase, - IData d7, IData d6, IData d5, IData d4, IData d3, IData d2, IData d1, IData d0) { + IData d7, IData d6, IData d5, IData d4, IData d3, IData d2, IData d1, IData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7; } diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp index 14da062b7..bbd12f0ab 100644 --- a/include/verilated_cov.cpp +++ b/include/verilated_cov.cpp @@ -128,7 +128,7 @@ private: m_indexValues.insert(std::make_pair(nextIndex, value)); return nextIndex; } - static std::string dequote(const std::string& text) { + static std::string dequote(const std::string& text) VL_PURE { // Quote any special characters std::string rtn; for (const char* pos = text.c_str(); *pos; ++pos) { @@ -141,7 +141,7 @@ private: } return rtn; } - static bool legalKey(const std::string& key) { + static bool legalKey(const std::string& key) VL_PURE { // Because we compress long keys to a single letter, and // don't want applications to either get confused if they use // a letter differently, nor want them to rely on our compression... @@ -150,7 +150,7 @@ private: if (key.length()==2 && isdigit(key[1])) return false; return true; } - static std::string keyValueFormatter (const std::string& key, const std::string& value) { + static std::string keyValueFormatter(const std::string& key, const std::string& value) VL_PURE { std::string name; if (key.length()==1 && isalpha(key[0])) { name += std::string("\001")+key; @@ -160,7 +160,7 @@ private: name += std::string("\002")+dequote(value); return name; } - static std::string combineHier (const std::string& old, const std::string& add) { + static std::string combineHier(const std::string& old, const std::string& add) VL_PURE { // (foo.a.x, foo.b.x) => foo.*.x // (foo.a.x, foo.b.y) => foo.* // (foo.a.x, foo.b) => foo.* @@ -206,7 +206,7 @@ private: } return false; } - static void selftest() { + static void selftest() VL_MT_SAFE { // Little selftest if (combineHier ("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n"); if (combineHier ("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n"); diff --git a/include/verilated_cov.h b/include/verilated_cov.h index 6be2731a8..96f8de7ee 100644 --- a/include/verilated_cov.h +++ b/include/verilated_cov.h @@ -73,7 +73,7 @@ //============================================================================= /// Convert VL_COVER_INSERT value arguments to strings -template< class T> std::string vlCovCvtToStr (const T& t) { +template< class T> std::string vlCovCvtToStr (const T& t) VL_PURE { std::ostringstream os; os<'row2', short=>'r2', group=>0, default=>undef, ") VLCOVGEN_ITEM("name=>'row3', short=>'r3', group=>0, default=>undef, ") VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr=>'For totaling items, weight of this item'") -//============================================================================= -// VerilatedCovKey -/// Verilator coverage global class -//// -/// Global class with methods affecting all coverage data. - // VLCOVGEN_CIK_AUTO_EDIT_BEGIN #define VL_CIK_COL0 "c0" #define VL_CIK_COL0_NAME "C0" @@ -102,9 +96,14 @@ VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr #define VL_CIK_WEIGHT "w" // VLCOVGEN_CIK_AUTO_EDIT_END +//============================================================================= +// VerilatedCovKey +/// Verilator coverage global class. +/// This class is thread safe. + class VerilatedCovKey { public: - static std::string shortKey(const std::string& key) { + static std::string shortKey(const std::string& key) VL_PURE { // VLCOVGEN_SHORT_AUTO_EDIT_BEGIN if (key == "col0") return VL_CIK_COL0; if (key == "col0_name") return VL_CIK_COL0_NAME; diff --git a/include/verilated_dpi.h b/include/verilated_dpi.h index 05eebe6ae..3b00443e4 100644 --- a/include/verilated_dpi.h +++ b/include/verilated_dpi.h @@ -35,23 +35,23 @@ // SETTING OPERATORS /// Return svBitVecVal from WData -static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, svBitVecVal* lwp) { +static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, svBitVecVal* lwp) VL_MT_SAFE { int words = VL_WORDS_I(obits); for (int i=0; i=(94)) *m_writep++ = static_cast((code/94)%94+33); *m_writep++ = static_cast((code)%94+33); } - static std::string stringCode (vluint32_t code) { + static std::string stringCode (vluint32_t code) VL_PURE { std::string out; if (code>=(94*94*94)) out += static_cast((code/94/94/94)%94+33); if (code>=(94*94)) out += static_cast((code/94/94)%94+33); diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h index e1c20d076..8f22f882f 100644 --- a/include/verilated_vcd_sc.h +++ b/include/verilated_vcd_sc.h @@ -17,6 +17,8 @@ /// \file /// \brief Verilator tracing in VCD format /// +/// This class is not threadsafe, as the SystemC kernel is not threadsafe. +/// //============================================================================= // SPDIFF_OFF diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index ff6ba59e6..4301b396a 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -517,7 +517,7 @@ VerilatedVpiError* VerilatedVpiImp::error_info() { //====================================================================== // VerilatedVpiError Methods -const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) { +const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE { static const char* const names[] = { "*undefined*", "vpiBinStrVal", @@ -542,7 +542,7 @@ const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) { if (vpiVal < 0) return names[0]; return names[(vpiVal<=vpiRawFourStateVal)?vpiVal:0]; } -const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) { +const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE { static const char* const names[] = { "*undefined*", "vpiAlways", @@ -684,7 +684,7 @@ const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) { if (vpiVal < 0) return names[0]; return names[(vpiVal<=vpiGenVar)?vpiVal:0]; } -const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) { +const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE { static const char* const names[] = { "vpiCondition", "vpiDelay", @@ -727,7 +727,7 @@ const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) { return names[vpiVal-vpiCondition]; } -const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) { +const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_SAFE { static const char* const names[] = { "*undefined*", "cbValueChange", @@ -766,7 +766,7 @@ const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) { return names[(vpiVal<=cbAtEndOfSimTime)?vpiVal:0]; } -const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) { +const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE { static const char* const names[] = { "*undefined or other*", "vpiType", diff --git a/include/verilatedos.h b/include/verilatedos.h index 5102e3821..401f12dc6 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -90,6 +90,12 @@ #define VL_THREAD ///< Deprecated #define VL_STATIC_OR_THREAD static ///< Deprecated +#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE) +#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED +#define VL_MT_SAFE_POSTINIT ///< Comment tag that function is threadsafe when VL_THREADED, only during normal operation (post-init) +#define VL_MT_UNSAFE ///< Comment tag that function is not threadsafe when VL_THREADED +#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED, protected to make sure single-caller + #ifdef _MSC_VER # define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant #else