Mark Verilated functions with multithreaded status. No functional change.

This commit is contained in:
Wilson Snyder 2017-10-26 20:05:42 -04:00
parent 350932e9c0
commit ad693d67b2
13 changed files with 312 additions and 284 deletions

View File

@ -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<VL_WORDS_I(obits); ++i) outwp[i] = 0;
return outwp;
}
@ -215,7 +216,7 @@ WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) {
//===========================================================================
// Debug
void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp) {
void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp) VL_MT_SAFE {
VL_PRINTF_MT(" Data: w%d: ", lbits);
for (int i=VL_WORDS_I(lbits)-1; 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='"<<tmpp<<"'\n");
//VL_DBG_MSGF("\t_read got='"<<tmpp<<"'\n");
}
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits, IData ld) {
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits, IData ld) VL_MT_SAFE {
for (; nbits && lsb<obits; nbits--, lsb++, ld>>=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<int>(posend)-1; i<obits && pos>=static_cast<int>(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='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp,floc,fromp,fstr)<<"'"<<endl);
//VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp,floc,fromp,fstr)<<"'"<<endl);
if (!inPct && pos[0]=='%') {
inPct = true;
} else if (!inPct && isspace(pos[0])) { // Format spaces
@ -845,11 +847,11 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
//===========================================================================
// File I/O
FILE* VL_CVT_I_FP(IData lhs) {
FILE* VL_CVT_I_FP(IData lhs) VL_MT_SAFE {
return VerilatedImp::fdToFp(lhs);
}
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) VL_MT_SAFE {
// See also VL_DATA_TO_STRING_NW
int lsb=obits-1;
bool start=true;
@ -866,7 +868,7 @@ void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
if (!start) while (isspace(*(destp-1)) && destp>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<char*>(destp);
@ -876,7 +878,8 @@ void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp)
for (; i<bytes; ++i) { *op++ = 0; }
}
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) {
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return 0;
@ -894,7 +897,7 @@ IData VL_FGETS_IXI(int obits, void* destp, IData fpi) {
IData got = 0;
char* cp = buffer;
while (got < bytes) {
int c = getc(fp);
int c = getc(fp); // getc() is threadsafe
if (c==EOF) break;
*cp++ = c; got++;
if (c=='\n') break;
@ -904,34 +907,38 @@ IData VL_FGETS_IXI(int obits, void* destp, IData fpi) {
return got;
}
IData VL_FOPEN_NI(const std::string& filename, IData mode) {
IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
char modez[5];
_VL_VINT_TO_STRING(VL_WORDSIZE, modez, &mode);
return VL_FOPEN_S(filename.c_str(), modez);
}
IData VL_FOPEN_QI(QData filename, IData mode) {
IData VL_FOPEN_QI(QData filename, IData mode) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
WData fnw[2]; VL_SET_WQ(fnw, filename);
return VL_FOPEN_WI(2, fnw, mode);
}
IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
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_FOPEN_S(filenamez,modez);
}
IData VL_FOPEN_S(const char* filenamep, const char* modep) {
IData VL_FOPEN_S(const char* filenamep, const char* modep) VL_MT_SAFE {
return VerilatedImp::fdNew(fopen(filenamep,modep));
}
void VL_FCLOSE_I(IData fdi) {
void VL_FCLOSE_I(IData fdi) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
FILE* fp = VL_CVT_I_FP(fdi);
if (VL_UNLIKELY(!fp)) return;
fclose(fp);
VerilatedImp::fdDelete(fdi);
}
void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) {
void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
va_list ap;
@ -942,7 +949,7 @@ void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) {
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
}
void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) {
void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
va_list ap;
@ -953,7 +960,7 @@ void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) {
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
}
void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) {
void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
va_list ap;
@ -964,7 +971,7 @@ void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) {
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
}
void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) {
void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
va_list ap;
@ -975,7 +982,7 @@ void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) {
_VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str());
}
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
va_list ap;
@ -986,7 +993,7 @@ void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
_VL_STRING_TO_VINT(obits, destp, output.length(), output.c_str());
}
void VL_SFORMAT_X(int obits_ignored, std::string &output, const char* formatp, ...) {
void VL_SFORMAT_X(int obits_ignored, std::string &output, const char* formatp, ...) VL_MT_SAFE {
if (obits_ignored) {}
output = "";
va_list ap;
@ -995,7 +1002,7 @@ void VL_SFORMAT_X(int obits_ignored, std::string &output, const char* formatp, .
va_end(ap);
}
std::string VL_SFORMATF_NX(const char* formatp, ...) {
std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
va_list ap;
@ -1006,7 +1013,7 @@ std::string VL_SFORMATF_NX(const char* formatp, ...) {
return output;
}
void VL_WRITEF(const char* formatp, ...) {
void VL_WRITEF(const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
va_list ap;
@ -1017,7 +1024,8 @@ void VL_WRITEF(const char* formatp, ...) {
VL_PRINTF_MT("%s", output.c_str());
}
void VL_FWRITEF(IData fpi, const char* formatp, ...) {
void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
static VL_THREAD_LOCAL std::string output; // static only for speed
output = "";
FILE* fp = VL_CVT_I_FP(fpi);
@ -1031,7 +1039,8 @@ void VL_FWRITEF(IData fpi, const char* formatp, ...) {
fputs(output.c_str(), fp);
}
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) {
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return 0;
@ -1042,7 +1051,7 @@ IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) {
return got;
}
IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) {
IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) VL_MT_SAFE {
WData fnw[2]; VL_SET_WI(fnw, ld);
va_list ap;
@ -1051,7 +1060,7 @@ IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) {
va_end(ap);
return got;
}
IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) {
IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) VL_MT_SAFE {
WData fnw[2]; VL_SET_WQ(fnw, ld);
va_list ap;
@ -1060,14 +1069,14 @@ IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) {
va_end(ap);
return got;
}
IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...) {
IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...) VL_MT_SAFE {
va_list ap;
va_start(ap,formatp);
IData got = _vl_vsscanf(NULL, lbits, lwp, "", formatp, ap);
va_end(ap);
return got;
}
IData VL_SSCANF_INX(int, const std::string& ld, const char* formatp, ...) {
IData VL_SSCANF_INX(int, const std::string& ld, const char* formatp, ...) VL_MT_SAFE {
va_list ap;
va_start(ap,formatp);
IData got = _vl_vsscanf(NULL, ld.length()*8, NULL, ld, formatp, ap);
@ -1076,13 +1085,13 @@ IData VL_SSCANF_INX(int, const std::string& ld, const char* formatp, ...) {
}
void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int,
QData ofilename, void* memp, IData start, IData end) {
QData ofilename, void* memp, IData start, IData end) VL_MT_SAFE {
WData 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) {
WDataInP ofilenamep, void* memp, IData start, IData end) VL_MT_SAFE {
char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep);
std::string ofilenames(ofilenamez);
@ -1090,7 +1099,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
}
void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
const std::string& ofilenamep, void* memp, IData start, IData end) {
const std::string& ofilenamep, void* memp, IData start, IData end) VL_MT_SAFE {
if (fnwords) {}
FILE* fp = fopen(ofilenamep.c_str(), "r");
if (VL_UNLIKELY(!fp)) {
@ -1191,24 +1200,24 @@ void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
}
}
IData VL_SYSTEM_IQ(QData lhs) {
IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
WData lhsw[2]; VL_SET_WQ(lhsw, lhs);
return VL_SYSTEM_IW(2, lhsw);
}
IData VL_SYSTEM_IW(int lhswords, WDataInP filenamep) {
IData VL_SYSTEM_IW(int lhswords, WDataInP filenamep) VL_MT_SAFE {
char filenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
_VL_VINT_TO_STRING(lhswords*VL_WORDSIZE, filenamez, filenamep);
int code = system(filenamez);
int code = system(filenamez); // Yes, system() is threadsafe
return code >> 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)

File diff suppressed because it is too large Load Diff

View File

@ -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");

View File

@ -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<<t; return os.str();
}
@ -87,7 +87,7 @@ class VerilatedCov {
public:
// GLOBAL METHODS
/// Return default filename
static const char* defaultFilename() { return "coverage.dat"; }
static const char* defaultFilename() VL_PURE { return "coverage.dat"; }
/// Write all coverage data to a file
static void write (const char* filenamep = defaultFilename());
/// Insert a coverage item

View File

@ -63,12 +63,6 @@ VLCOVGEN_ITEM("name=>'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;

View File

@ -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<words-1; ++i) owp[i]=lwp[i];
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
}
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) {
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) VL_MT_SAFE {
int words = VL_WORDS_I(obits);
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
}
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, svLogicVecVal* lwp) {
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, svLogicVecVal* lwp) VL_MT_SAFE {
// Note we ignore X/Z in svLogicVecVal
int words = VL_WORDS_I(obits);
for (int i=0; i<words-1; ++i) owp[i]=lwp[i].aval;
owp[words-1] = lwp[words-1].aval & VL_MASK_I(obits);
}
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) {
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) VL_MT_SAFE {
// Note we don't create X/Z in svLogicVecVal
int words = VL_WORDS_I(obits);
for (int i=0; i<words; ++i) owp[i].bval=0;

View File

@ -36,49 +36,49 @@
//======================================================================
// Conversion functions
extern std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp);
inline std::string VL_CVT_PACK_STR_NQ(QData lhs) {
extern std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) VL_MT_SAFE;
inline std::string VL_CVT_PACK_STR_NQ(QData lhs) VL_PURE {
WData lw[2]; VL_SET_WQ(lw, lhs);
return VL_CVT_PACK_STR_NW(2, lw);
}
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) {
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) VL_PURE {
return lhs;
}
inline std::string VL_CVT_PACK_STR_NI(IData lhs) {
inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE {
WData lw[1]; lw[0] = lhs;
return VL_CVT_PACK_STR_NW(1, lw);
}
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) {
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) VL_PURE {
return lhs+rhs;
}
inline std::string VL_REPLICATEN_NNQ(int,int,int, const std::string& lhs, IData rep) {
inline std::string VL_REPLICATEN_NNQ(int,int,int, const std::string& lhs, IData rep) VL_PURE {
std::string out; out.reserve(lhs.length() * rep);
for (unsigned times=0; times<rep; ++times) out += lhs;
return out;
}
inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits, const std::string& lhs, IData rep) {
inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits, const std::string& lhs, IData rep) VL_PURE {
return VL_REPLICATEN_NNQ(obits,lbits,rbits,lhs,rep);
}
extern IData VL_FOPEN_NI(const std::string& filename, IData mode);
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
const std::string& ofilename, void* memp, IData start, IData end);
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits_ignored, std::string &output, const char* formatp, ...);
extern std::string VL_SFORMATF_NX(const char* formatp, ...);
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rdp);
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, IData& rdr) {
const std::string& ofilename, void* memp, IData start, IData end) VL_MT_SAFE;
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits_ignored, std::string &output, const char* formatp, ...) VL_MT_SAFE;
extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE;
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rdp) VL_MT_SAFE;
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, IData& rdr) VL_MT_SAFE {
WData rwp[2]; // WData must always be at least 2
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
if (got) rdr = rwp[0];
return got;
}
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, QData& rdr) {
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, QData& rdr) VL_MT_SAFE {
WData rwp[2];
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
if (got) rdr = VL_SET_QW(rwp);
return got;
}
extern IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr);
extern IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_SAFE;
#endif // Guard

View File

@ -28,6 +28,7 @@
//=============================================================================
// VerilatedSerialize - convert structures to a stream representation
// This class is not thread safe, it must be called by a single thread
class VerilatedSerialize {
protected:
@ -84,6 +85,7 @@ private:
//=============================================================================
// VerilatedDeserial - load structures from a stream representation
// This class is not thread safe, it must be called by a single thread
class VerilatedDeserialize {
protected:

View File

@ -20,6 +20,9 @@
/// the symbol table. It is not included in verilated.h
/// as it requires some heavyweight C++ classes.
///
/// These classes are thread safe on read only. It is constructed
/// only when a model is built (from the main thread).
///
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
@ -34,6 +37,7 @@
//===========================================================================
/// Verilator range
/// Thread safety: Assume is constructed only with model, then any number of readers
// See also V3Ast::VNumRange
class VerilatedRange {
@ -53,6 +57,7 @@ public:
//===========================================================================
/// Verilator variable
/// Thread safety: Assume is constructed only with model, then any number of readers
class VerilatedVar {
void* m_datap; // Location of data

View File

@ -135,7 +135,7 @@ private:
if (code>=(94)) *m_writep++ = static_cast<char>((code/94)%94+33);
*m_writep++ = static_cast<char>((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<char>((code/94/94/94)%94+33);
if (code>=(94*94)) out += static_cast<char>((code/94/94)%94+33);

View File

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

View File

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

View File

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