Internals: Refactor to introduce VerilatedFdList. (#2363)

This commit is contained in:
Stephen Henry 2020-05-28 22:59:18 +01:00 committed by GitHub
parent e8f27be200
commit c4aab57c62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 34 deletions

View File

@ -1190,11 +1190,8 @@ done:
// File I/O
FILE* VL_CVT_I_FP(IData lhs) VL_MT_SAFE {
// Expected non-MCD case; returns ONLY the first file descriptor seen in lhs (which
// in the MCD case can result in descriptors being ignored).
FILE* fp[1] = {NULL};
VerilatedImp::fdToFp(lhs, fp, 1);
return fp[0];
// Expected non-MCD case; returns null on MCD descriptors.
return VerilatedImp::fdToFp(lhs);
}
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) VL_MT_SAFE {
@ -1378,12 +1375,7 @@ void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE {
_vl_vsformat(output, formatp, ap);
va_end(ap);
FILE* fp[30];
const std::size_t n = VerilatedImp::fdToFp(fpi, fp, 30);
for (std::size_t i = 0; i < n; ++i) {
if (VL_UNLIKELY(!fp[i])) continue;
fwrite(output.c_str(), 1, output.size(), fp[i]);
}
VerilatedImp::fdWrite(fpi, output);
}
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE {

View File

@ -169,6 +169,24 @@ public:
};
#endif // VL_THREADED
// FILE* list constructed from a file-descriptor
class VerilatedFpList {
FILE* m_fp[31];
std::size_t m_sz;
public:
typedef FILE* const* const_iterator;
explicit VerilatedFpList()
: m_sz(0) {}
const_iterator begin() const { return m_fp; }
const_iterator end() const { return m_fp + m_sz; }
std::size_t size() const { return m_sz; }
std::size_t capacity() const { return 31; }
void push_back(FILE* fd) {
if (VL_LIKELY(size() < capacity())) m_fp[m_sz++] = fd;
}
};
//======================================================================
// VerilatedImp
@ -484,24 +502,32 @@ public: // But only for verilated*.cpp
return (idx | (1UL << 31)); // bit 31 indicates not MCD
}
static void fdFlush(IData fdi) VL_MT_SAFE {
FILE* fp[30];
const int n = fdToFp(fdi, fp, 30);
VerilatedLockGuard lock(s_s.m_fdMutex);
for (int i = 0; i < n; i++) fflush(fp[i]);
const VerilatedFpList fdlist = fdToFpList(fdi);
for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
fflush(*it);
}
}
static IData fdSeek(IData fdi, IData offset, IData origin) VL_MT_SAFE {
FILE* fp;
const int n = fdToFp(fdi, &fp);
VerilatedLockGuard lock(s_s.m_fdMutex);
if (VL_UNLIKELY(!fp || (n != 1))) return 0;
return static_cast<IData>(fseek(fp, static_cast<long>(offset), static_cast<int>(origin)));
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
return static_cast<IData>(
fseek(*fdlist.begin(), static_cast<long>(offset), static_cast<int>(origin)));
}
static IData fdTell(IData fdi) VL_MT_SAFE {
FILE* fp;
const int n = fdToFp(fdi, &fp);
VerilatedLockGuard lock(s_s.m_fdMutex);
if (VL_UNLIKELY(!fp || (n != 1))) return 0;
return static_cast<IData>(ftell(fp));
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
return static_cast<IData>(ftell(*fdlist.begin()));
}
static void fdWrite(IData fdi, const std::string& output) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
if (VL_UNLIKELY(!*it)) continue;
fwrite(output.c_str(), 1, output.size(), *it);
}
}
static void fdClose(IData fdi) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_fdMutex);
@ -524,29 +550,34 @@ public: // But only for verilated*.cpp
}
}
}
static inline int fdToFp(IData fdi, FILE** fp, std::size_t max = 1) VL_MT_SAFE {
if (VL_UNLIKELY(!fp || (max == 0))) return 0;
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_fdMutex);
int out = 0;
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return NULL;
return *fdlist.begin();
}
private:
static inline VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(s_s.m_fdMutex) {
VerilatedFpList fp;
if ((fdi & (1 << 31)) != 0) {
// Non-MCD case
IData idx = fdi & VL_MASK_I(31);
const IData idx = fdi & VL_MASK_I(31);
switch (idx) {
case 0: fp[out++] = stdin; break;
case 1: fp[out++] = stdout; break;
case 2: fp[out++] = stderr; break;
case 0: fp.push_back(stdin); break;
case 1: fp.push_back(stdout); break;
case 2: fp.push_back(stderr); break;
default:
if (VL_LIKELY(idx < s_s.m_fdps.size())) fp[out++] = s_s.m_fdps[idx];
if (VL_LIKELY(idx < s_s.m_fdps.size())) fp.push_back(s_s.m_fdps[idx]);
break;
}
} else {
// MCD Case
for (int i = 0; (fdi != 0) && (out < static_cast<int>(max)) && (i < 31);
++i, fdi >>= 1) {
if (fdi & VL_MASK_I(1)) fp[out++] = s_s.m_fdps[i];
for (int i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) {
if (fdi & VL_MASK_I(1)) fp.push_back(s_s.m_fdps[i]);
}
}
return out;
return fp;
}
};