From b2228afd1aa4fa5fe2f31a048402be898251d7ff Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 4 Apr 2020 08:50:56 -0400 Subject: [PATCH 001/127] devel release --- Changes | 3 +++ configure.ac | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 719aa2d10..f9c18a064 100644 --- a/Changes +++ b/Changes @@ -3,6 +3,9 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! +* Verilator 4.033 devel + + * Verilator 4.032 2020-04-04 *** Add column numbers to errors and warnings. diff --git a/configure.ac b/configure.ac index 23ec1a6e1..0db24735d 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.032 2020-04-04], +AC_INIT([Verilator],[4.033 devel], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file From a13eab55f523ad7d540c7651043c3f634aff7d13 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 4 Apr 2020 13:06:31 -0400 Subject: [PATCH 002/127] Internals: Add missing VL_DO_CLEARs. No functional change. --- include/verilated.cpp | 11 ++++++----- include/verilated_save.h | 14 +++++++++----- include/verilated_vcd_c.cpp | 18 +++++++++--------- include/verilated_vpi.cpp | 2 +- src/VlcBucket.h | 2 +- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 373082276..ab27d2af7 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -245,7 +245,8 @@ Verilated::NonSerialized::NonSerialized() { } Verilated::NonSerialized::~NonSerialized() { if (s_profThreadsFilenamep) { - free(const_cast(s_profThreadsFilenamep)); s_profThreadsFilenamep=NULL; + VL_DO_CLEAR(free(const_cast(s_profThreadsFilenamep)), + s_profThreadsFilenamep = NULL); } } @@ -2265,7 +2266,7 @@ VerilatedModule::VerilatedModule(const char* namep) VerilatedModule::~VerilatedModule() { // Memory cleanup - not called during normal operation // NOLINTNEXTLINE(google-readability-casting) - if (m_namep) { free((void*)(m_namep)); m_namep=NULL; } + if (m_namep) VL_DO_CLEAR(free((void*)(m_namep)), m_namep = NULL); } //====================================================================== @@ -2322,9 +2323,9 @@ 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; } - if (m_varsp) { delete m_varsp; m_varsp = NULL; } + if (m_namep) VL_DO_CLEAR(delete [] m_namep, m_namep = NULL); + if (m_callbacksp) VL_DO_CLEAR(delete [] m_callbacksp, m_callbacksp = NULL); + if (m_varsp) VL_DO_CLEAR(delete m_varsp, m_varsp = NULL); m_funcnumMax = 0; // Force callback table to empty } diff --git a/include/verilated_save.h b/include/verilated_save.h index 94497fbde..d9f3b79e1 100644 --- a/include/verilated_save.h +++ b/include/verilated_save.h @@ -54,7 +54,7 @@ public: } virtual ~VerilatedSerialize() { close(); - if (m_bufp) { delete m_bufp; m_bufp=NULL; } + if (m_bufp) VL_DO_CLEAR(delete m_bufp, m_bufp = NULL); } // METHODS bool isOpen() const { return m_isOpen; } @@ -107,6 +107,7 @@ protected: // CONSTRUCTORS VL_UNCOPYABLE(VerilatedDeserialize); + public: VerilatedDeserialize() { m_isOpen = false; @@ -116,7 +117,7 @@ public: } virtual ~VerilatedDeserialize() { close(); - if (m_bufp) { delete m_bufp; m_bufp=NULL; } + if (m_bufp) VL_DO_CLEAR(delete m_bufp, m_bufp = NULL); } // METHODS bool isOpen() const { return m_isOpen; } @@ -160,10 +161,12 @@ private: public: // CONSTRUCTORS - VerilatedSave() { m_fd = -1; } + VerilatedSave() + : m_fd(-1) {} virtual ~VerilatedSave() VL_OVERRIDE { close(); } // METHODS - void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors + /// Open the file; call isOpen() to see if errors + void open(const char* filenamep) VL_MT_UNSAFE_ONE; void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); } virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE; virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE; @@ -179,7 +182,8 @@ private: public: // CONSTRUCTORS - VerilatedRestore() { m_fd = -1; } + VerilatedRestore() + : m_fd(-1) {} virtual ~VerilatedRestore() VL_OVERRIDE { close(); } // METHODS diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index bf344ecc9..f14f1445d 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -265,17 +265,17 @@ void VerilatedVcd::makeNameMap() { } void VerilatedVcd::deleteNameMap() { - if (m_namemapp) { delete m_namemapp; m_namemapp=NULL; } + if (m_namemapp) VL_DO_CLEAR(delete m_namemapp, m_namemapp = NULL); } VerilatedVcd::~VerilatedVcd() { close(); - if (m_wrBufp) { delete[] m_wrBufp; m_wrBufp=NULL; } - if (m_sigs_oldvalp) { delete[] m_sigs_oldvalp; m_sigs_oldvalp=NULL; } + if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = NULL); + if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL); deleteNameMap(); - if (m_filep && m_fileNewed) { delete m_filep; m_filep = NULL; } - for (CallbackVec::const_iterator it=m_callbacks.begin(); it!=m_callbacks.end(); ++it) { - delete (*it); + if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = NULL); + for (CallbackVec::const_iterator it = m_callbacks.begin(); it != m_callbacks.end(); ++it) { + delete *it; } m_callbacks.clear(); VerilatedVcdSingleton::removeVcd(this); @@ -347,12 +347,12 @@ void VerilatedVcd::bufferResize(vluint64_t minsize) { // writing when we are 3/4 full (with thus 2*minsize remaining free) if (VL_UNLIKELY(minsize > m_wrChunkSize)) { char* oldbufp = m_wrBufp; - m_wrChunkSize = minsize*2; - m_wrBufp = new char [m_wrChunkSize * 8]; + m_wrChunkSize = minsize * 2; + m_wrBufp = new char[m_wrChunkSize * 8]; memcpy(m_wrBufp, oldbufp, m_writep - oldbufp); m_writep = m_wrBufp + (m_writep - oldbufp); m_wrFlushp = m_wrBufp + m_wrChunkSize * 6; - delete [] oldbufp; oldbufp=NULL; + VL_DO_CLEAR(delete[] oldbufp, oldbufp = NULL); } } diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 2a6f727df..3d5cd6651 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -204,7 +204,7 @@ public: m_varDatap = varp->datap(); } virtual ~VerilatedVpioVar() { - if (m_prevDatap) { delete [] m_prevDatap; m_prevDatap = NULL; } + if (m_prevDatap) VL_DO_CLEAR(delete[] m_prevDatap, m_prevDatap = NULL); } static inline VerilatedVpioVar* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); diff --git a/src/VlcBucket.h b/src/VlcBucket.h index 31b922b27..24c23d1f1 100644 --- a/src/VlcBucket.h +++ b/src/VlcBucket.h @@ -61,7 +61,7 @@ public: } ~VlcBuckets() { m_dataSize = 0; - free(m_datap); m_datap = NULL; + VL_DO_CLEAR(free(m_datap), m_datap = NULL); } // ACCESSORS From e07e9390f6947a0fe44f333da9a058e33c581451 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 4 Apr 2020 13:45:24 -0400 Subject: [PATCH 003/127] Internals: clang-format cleanups. No functional change. --- docs/clang-format.txt | 8 -- include/verilated_fst_c.cpp | 23 ++-- include/verilated_fst_c.h | 34 +++--- include/verilated_save.cpp | 53 ++++---- include/verilated_save.h | 29 +++-- include/verilated_sym_props.h | 98 +++++++++------ include/verilated_threads.cpp | 65 ++++------ include/verilated_threads.h | 1 + include/verilated_vcd_c.cpp | 215 +++++++++++++++++--------------- include/verilated_vcd_c.h | 222 +++++++++++++++++++--------------- 10 files changed, 398 insertions(+), 350 deletions(-) diff --git a/docs/clang-format.txt b/docs/clang-format.txt index 3a1876b64..a4b6bcd1f 100644 --- a/docs/clang-format.txt +++ b/docs/clang-format.txt @@ -10,22 +10,14 @@ be made to a file. The following files are not yet clang-format clean: clang-format -i include/verilated.h clang-format -i include/verilated_dpi.h -clang-format -i include/verilated_fst_c.h clang-format -i include/verilated_heavy.h clang-format -i include/verilated_imp.h -clang-format -i include/verilated_save.h -clang-format -i include/verilated_sym_props.h clang-format -i include/verilated_unordered_set_map.h -clang-format -i include/verilated_vcd_c.h clang-format -i include/verilatedos.h clang-format -i include/verilated.cpp clang-format -i include/verilated_cov.cpp clang-format -i include/verilated_dpi.cpp -clang-format -i include/verilated_fst_c.cpp -clang-format -i include/verilated_save.cpp -clang-format -i include/verilated_threads.cpp -clang-format -i include/verilated_vcd_c.cpp clang-format -i include/verilated_vpi.cpp clang-format -i src/V3Ast.h diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 7b816fd75..b0776e468 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -91,7 +91,7 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { m_curScope.clear(); m_nextCode = 1; - for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) { + for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { VerilatedFstCallInfo* cip = m_callbacks[ent]; cip->m_code = m_nextCode; // Initialize; callbacks will call decl* which update m_nextCode @@ -106,18 +106,16 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { } } -void VerilatedFst::module(const std::string& name) { - m_module = name; -} +void VerilatedFst::module(const std::string& name) { m_module = name; } //============================================================================= // Decl void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elements, - unsigned int minValbits, - const char** itemNamesp, const char** itemValuesp) { - fstEnumHandle enumNum = fstWriterCreateEnumTable(m_fst, name, elements, - minValbits, itemNamesp, itemValuesp); + unsigned int minValbits, const char** itemNamesp, + const char** itemValuesp) { + fstEnumHandle enumNum + = fstWriterCreateEnumTable(m_fst, name, elements, minValbits, itemNamesp, itemValuesp); m_local2fstdtype[dtypenum] = enumNum; } @@ -127,7 +125,7 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f // Make sure deduplicate tracking increments for future declarations int codesNeeded = 1 + int(bits / 32); - //Not supported: if (tri) codesNeeded *= 2; // Space in change array for __en signals + // Not supported: if (tri) codesNeeded *= 2; // Space in change array for __en signals m_nextCode = std::max(m_nextCode, code + codesNeeded); std::pair p @@ -143,8 +141,7 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f std::list::iterator cur_it = m_curScope.begin(); std::list::iterator new_it = tokens.begin(); while (cur_it != m_curScope.end() && new_it != tokens.end()) { - if (*cur_it != *new_it) - break; + if (*cur_it != *new_it) break; ++cur_it; ++new_it; } @@ -201,14 +198,14 @@ void VerilatedFst::dump(vluint64_t timeui) { if (!isOpen()) return; if (VL_UNLIKELY(m_fullDump)) { m_fullDump = false; // No more need for next dump to be full - for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) { + for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { VerilatedFstCallInfo* cip = m_callbacks[ent]; (cip->m_fullcb)(this, cip->m_userthis, cip->m_code); } return; } fstWriterEmitTimeChange(m_fst, timeui); - for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) { + for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { VerilatedFstCallInfo* cip = m_callbacks[ent]; (cip->m_changecb)(this, cip->m_userthis, cip->m_code); } diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 1ce99df69..bd7e6a830 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -43,6 +43,7 @@ class VerilatedFst { typedef std::map Code2SymbolType; typedef std::map Local2FstDtype; typedef std::vector CallbackVec; + private: void* m_fst; VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread @@ -61,9 +62,12 @@ private: bool array, int arraynum, vluint32_t len, vluint32_t bits); // helpers std::vector m_valueStrBuffer; + public: - explicit VerilatedFst(void* fst=NULL); - ~VerilatedFst() { if (m_fst == NULL) { fstWriterClose(m_fst); } } + explicit VerilatedFst(void* fst = NULL); + ~VerilatedFst() { + if (m_fst == NULL) { fstWriterClose(m_fst); } + } void changeThread() { m_assertOne.changeThread(); } bool isOpen() const { return m_fst != NULL; } void open(const char* filename) VL_MT_UNSAFE; @@ -76,7 +80,7 @@ public: void set_time_unit(const char* unitp) { fstWriterSetTimescaleFromString(m_fst, unitp); } void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); } - void set_time_resolution(const char* unitp) { if (unitp) {} } + void set_time_resolution(const char*) {} void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); } // double timescaleToDouble(const char* unitp); @@ -156,18 +160,18 @@ public: fstWriterEmitValueChangeVec32(m_fst, m_code2symbol[code], bits, newval); } - void fullBit(vluint32_t code, const vluint32_t newval) { - chgBit(code, newval); } + void fullBit(vluint32_t code, const vluint32_t newval) { chgBit(code, newval); } void fullBus(vluint32_t code, const vluint32_t newval, int bits) { - chgBus(code, newval, bits); } - void fullDouble(vluint32_t code, const double newval) { - chgDouble(code, newval); } - void fullFloat(vluint32_t code, const float newval) { - chgFloat(code, newval); } + chgBus(code, newval, bits); + } + void fullDouble(vluint32_t code, const double newval) { chgDouble(code, newval); } + void fullFloat(vluint32_t code, const float newval) { chgFloat(code, newval); } void fullQuad(vluint32_t code, const vluint64_t newval, int bits) { - chgQuad(code, newval, bits); } + chgQuad(code, newval, bits); + } void fullArray(vluint32_t code, const vluint32_t* newval, int bits) { - chgArray(code, newval, bits); } + chgArray(code, newval, bits); + } void declTriBit(vluint32_t code, const char* name, int arraynum); void declTriBus(vluint32_t code, const char* name, int arraynum, int msb, int lsb); @@ -198,12 +202,14 @@ class VerilatedFstC { // CONSTRUCTORS VL_UNCOPYABLE(VerilatedFstC); + public: - explicit VerilatedFstC(void* filep=NULL) : m_sptrace(filep) {} + explicit VerilatedFstC(void* filep = NULL) + : m_sptrace(filep) {} ~VerilatedFstC() { close(); } /// Routines can only be called from one thread; allow next call from different thread void changeThread() { spTrace()->changeThread(); } -public: + // ACCESSORS /// Is file open? bool isOpen() const { return m_sptrace.isOpen(); } diff --git a/include/verilated_save.cpp b/include/verilated_save.cpp index 18b668e98..fde2a5190 100644 --- a/include/verilated_save.cpp +++ b/include/verilated_save.cpp @@ -40,7 +40,8 @@ #endif // CONSTANTS -static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n"; ///< Value of first bytes of each file +static const char* const VLTSAVE_HEADER_STR + = "verilatorsave01\n"; ///< Value of first bytes of each file static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file //============================================================================= @@ -48,22 +49,23 @@ static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last b //============================================================================= // Searalization -bool VerilatedDeserialize::readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE { +bool VerilatedDeserialize::readDiffers(const void* __restrict datap, + size_t size) VL_MT_UNSAFE_ONE { bufferCheck(); const vluint8_t* __restrict dp = static_cast(datap); vluint8_t miss = 0; while (size--) { miss |= (*dp++ ^ *m_cp++); } - return (miss!=0); + return (miss != 0); } VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE { if (VL_UNLIKELY(readDiffers(datap, size))) { std::string fn = filename(); - std::string msg = "Can't deserialize save-restore file as was made from different model:" - +filename(); + std::string msg + = "Can't deserialize save-restore file as was made from different model:" + filename(); VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str()); close(); } @@ -84,8 +86,8 @@ void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE { VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) { std::string fn = filename(); - std::string msg = std::string("Can't deserialize; file has wrong header signature: ") - +filename(); + std::string msg + = std::string("Can't deserialize; file has wrong header signature: ") + filename(); VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str()); close(); } @@ -103,7 +105,7 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE { if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) { std::string fn = filename(); std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature: ") - +filename(); + + filename(); VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str()); close(); } @@ -119,13 +121,13 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE { if (isOpen()) return; VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep);); - if (filenamep[0]=='|') { + if (filenamep[0] == '|') { assert(0); // Not supported yet. } else { // cppcheck-suppress duplicateExpression - m_fd = ::open(filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC - , 0666); - if (m_fd<0) { + m_fd = ::open(filenamep, + O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666); + if (m_fd < 0) { // User code can check isOpen() m_isOpen = false; return; @@ -142,13 +144,12 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE { if (isOpen()) return; VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep);); - if (filenamep[0]=='|') { + if (filenamep[0] == '|') { assert(0); // Not supported yet. } else { // cppcheck-suppress duplicateExpression - m_fd = ::open(filenamep, O_CREAT|O_RDONLY|O_LARGEFILE|O_CLOEXEC - , 0666); - if (m_fd<0) { + m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666); + if (m_fd < 0) { // User code can check isOpen() m_isOpen = false; return; @@ -186,15 +187,15 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE { vluint8_t* wp = m_bufp; while (true) { ssize_t remaining = (m_cp - wp); - if (remaining==0) break; + if (remaining == 0) break; errno = 0; ssize_t got = ::write(m_fd, wp, remaining); - if (got>0) { + if (got > 0) { wp += got; } else if (got < 0) { if (errno != EAGAIN && errno != EINTR) { // write failed, presume error (perhaps out of disk space) - std::string msg = std::string(__FUNCTION__)+": "+strerror(errno); + std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno); VL_FATAL_MT("", 0, "", msg.c_str()); close(); break; @@ -209,21 +210,21 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE { if (VL_UNLIKELY(!isOpen())) return; // Move remaining characters down to start of buffer. (No memcpy, overlaps allowed) vluint8_t* rp = m_bufp; - for (vluint8_t* sp=m_cp; sp < m_endp;) *rp++ = *sp++; // Overlaps + for (vluint8_t* sp = m_cp; sp < m_endp; *rp++ = *sp++) {} // Overlaps m_endp = m_bufp + (m_endp - m_cp); m_cp = m_bufp; // Reset buffer // Read into buffer starting at m_endp while (true) { - ssize_t remaining = (m_bufp+bufferSize() - m_endp); - if (remaining==0) break; + ssize_t remaining = (m_bufp + bufferSize() - m_endp); + if (remaining == 0) break; errno = 0; ssize_t got = ::read(m_fd, m_endp, remaining); - if (got>0) { + if (got > 0) { m_endp += got; } else if (got < 0) { if (errno != EAGAIN && errno != EINTR) { // write failed, presume error (perhaps out of disk space) - std::string msg = std::string(__FUNCTION__)+": "+strerror(errno); + std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno); VL_FATAL_MT("", 0, "", msg.c_str()); close(); break; @@ -231,7 +232,9 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE { } else { // got==0, EOF // Fill buffer from here to end with NULLs so reader's don't // need to check eof each character. - while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0'; + while (m_endp < m_bufp + bufferSize()) { + *m_endp++ = '\0'; + } break; } } diff --git a/include/verilated_save.h b/include/verilated_save.h index d9f3b79e1..7652e0750 100644 --- a/include/verilated_save.h +++ b/include/verilated_save.h @@ -46,6 +46,7 @@ protected: // CONSTRUCTORS VL_UNCOPYABLE(VerilatedSerialize); + public: VerilatedSerialize() { m_isOpen = false; @@ -65,20 +66,20 @@ public: const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap; while (size) { bufferCheck(); - size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize(); + size_t blk = size; + if (blk > bufferInsertSize()) blk = bufferInsertSize(); const vluint8_t* __restrict maxp = dp + blk; - while (dp < maxp) *m_cp++ = *dp++; + for (; dp < maxp; *m_cp++ = *dp++) {} size -= blk; } return *this; // For function chaining } + private: VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE { // Flush the write buffer if there's not enough space left for new information // We only call this once per vector, so we need enough slop for a very wide "b###" line - if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) { - flush(); - } + if (VL_UNLIKELY(m_cp > (m_bufp + (bufferSize() - bufferInsertSize())))) flush(); return *this; // For function chaining } }; @@ -125,12 +126,13 @@ public: virtual void close() VL_MT_UNSAFE_ONE { flush(); } virtual void flush() VL_MT_UNSAFE_ONE {} inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE { - vluint8_t* __restrict dp = (vluint8_t* __restrict)datap; + vluint8_t* __restrict dp = static_cast(datap); while (size) { bufferCheck(); - size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize(); + size_t blk = size; + if (blk > bufferInsertSize()) blk = bufferInsertSize(); const vluint8_t* __restrict maxp = dp + blk; - while (dp < maxp) *dp++ = *m_cp++; + for (; dp < maxp; *dp++ = *m_cp++); size -= blk; } return *this; // For function chaining @@ -138,15 +140,15 @@ public: // Read a datum and compare with expected value VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE; VerilatedDeserialize& readAssert(vluint64_t data) VL_MT_UNSAFE_ONE { - return readAssert(&data, sizeof(data)); } + return readAssert(&data, sizeof(data)); + } + private: bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE; VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE { // Flush the write buffer if there's not enough space left for new information // We only call this once per vector, so we need enough slop for a very wide "b###" line - if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) { - fill(); - } + if (VL_UNLIKELY((m_cp + bufferInsertSize()) > m_endp)) fill(); return *this; // For function chaining } }; @@ -187,7 +189,8 @@ public: virtual ~VerilatedRestore() VL_OVERRIDE { close(); } // METHODS - void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors + /// Open the file; call isOpen() to see if errors + void open(const char* filenamep) VL_MT_UNSAFE_ONE; void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); } virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE; virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE {} diff --git a/include/verilated_sym_props.h b/include/verilated_sym_props.h index 845e40f1b..47846c8ec 100644 --- a/include/verilated_sym_props.h +++ b/include/verilated_sym_props.h @@ -35,14 +35,19 @@ // See also V3Ast::VNumRange class VerilatedRange { - int m_left; - int m_right; + int m_left; + int m_right; + protected: friend class VerilatedVarProps; friend class VerilatedScope; VerilatedRange() : m_left(0), m_right(0) {} VerilatedRange(int left, int right) : m_left(left), m_right(right) {} - void init(int left, int right) { m_left=left; m_right=right; } + void init(int left, int right) { + m_left = left; + m_right = right; + } + public: ~VerilatedRange() {} int left() const { return m_left; } @@ -50,7 +55,8 @@ public: int low() const { return (m_left < m_right) ? m_left : m_right; } int high() const { return (m_left > m_right) ? m_left : m_right; } int elements() const { - return (VL_LIKELY(m_left>=m_right) ? (m_left-m_right+1) : (m_right-m_left+1)); } + return (VL_LIKELY(m_left >= m_right) ? (m_left - m_right + 1) : (m_right - m_left + 1)); + } int increment() const { return (m_left >= m_right) ? 1 : -1; } }; @@ -62,71 +68,86 @@ class VerilatedVarProps { // TYPES enum { MAGIC = 0xddc4f829 }; // MEMBERS - const vluint32_t m_magic; // Magic number - const VerilatedVarType m_vltype; // Data type - const VerilatedVarFlags m_vlflags; // Direction - const int m_pdims; // Packed dimensions - const int m_udims; // Unpacked dimensions - VerilatedRange m_packed; // Packed array range - VerilatedRange m_unpacked[3]; // Unpacked array range + const vluint32_t m_magic; // Magic number + const VerilatedVarType m_vltype; // Data type + const VerilatedVarFlags m_vlflags; // Direction + const int m_pdims; // Packed dimensions + const int m_udims; // Unpacked dimensions + VerilatedRange m_packed; // Packed array range + VerilatedRange m_unpacked[3]; // Unpacked array range // CONSTRUCTORS protected: friend class VerilatedScope; VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int pdims, int udims) : m_magic(MAGIC), m_vltype(vltype), m_vlflags(vlflags), m_pdims(pdims), m_udims(udims) {} + public: class Unpacked {}; // Without packed VerilatedVarProps(VerilatedVarType vltype, int vlflags) : m_magic(MAGIC), m_vltype(vltype), - m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(0) { } + m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(0) {} VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r) : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(1) { - m_unpacked[0].init(u0l, u0r); } + m_unpacked[0].init(u0l, u0r); + } VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l, int u1r) : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(2) { - m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); } + m_unpacked[0].init(u0l, u0r); + m_unpacked[1].init(u1l, u1r); + } VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l, int u1r, int u2l, int u2r) : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(3) { - m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); m_unpacked[2].init(u2l, u2r); } + m_unpacked[0].init(u0l, u0r); + m_unpacked[1].init(u1l, u1r); + m_unpacked[2].init(u2l, u2r); + } // With packed class Packed {}; VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr) : m_magic(MAGIC), m_vltype(vltype), - m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(0), m_packed(pl,pr) { } + m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(0), m_packed(pl,pr) {} VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked, int u0l, int u0r) : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(1), m_packed(pl,pr) { - m_unpacked[0].init(u0l, u0r); } + m_unpacked[0].init(u0l, u0r); + } VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked, int u0l, int u0r, int u1l, int u1r) : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(2), m_packed(pl,pr) { - m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); } + m_unpacked[0].init(u0l, u0r); + m_unpacked[1].init(u1l, u1r); + } VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked, int u0l, int u0r, int u1l, int u1r, int u2l, int u2r) : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(3), m_packed(pl,pr) { - m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); m_unpacked[2].init(u2l, u2r); } + m_unpacked[0].init(u0l, u0r); + m_unpacked[1].init(u1l, u1r); + m_unpacked[2].init(u2l, u2r); + } + public: ~VerilatedVarProps() {} // METHODS bool magicOk() const { return m_magic == MAGIC; } VerilatedVarType vltype() const { return m_vltype; } VerilatedVarFlags vldir() const { - return static_cast(static_cast(m_vlflags) & VLVF_MASK_DIR); } + return static_cast(static_cast(m_vlflags) & VLVF_MASK_DIR); + } vluint32_t entSize() const; bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); } /// DPI compatible C standard layout @@ -137,28 +158,28 @@ public: const VerilatedRange& unpacked() const { return m_unpacked[0]; } // DPI accessors int left(int dim) const { - return dim==0 ? m_packed.left() - : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].left() : 0; + return dim == 0 ? m_packed.left() + : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].left() : 0; } int right(int dim) const { - return dim==0 ? m_packed.right() - : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].right() : 0; + return dim == 0 ? m_packed.right() + : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].right() : 0; } int low(int dim) const { - return dim==0 ? m_packed.low() - : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].low() : 0; + return dim == 0 ? m_packed.low() + : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].low() : 0; } int high(int dim) const { - return dim==0 ? m_packed.high() - : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].high() : 0; + return dim == 0 ? m_packed.high() + : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].high() : 0; } int increment(int dim) const { - return dim==0 ? m_packed.increment() - : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].increment() : 0; + return dim == 0 ? m_packed.increment() + : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].increment() : 0; } int elements(int dim) const { - return dim==0 ? m_packed.elements() - : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].elements() : 0; + return dim == 0 ? m_packed.elements() + : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].elements() : 0; } /// Total size in bytes (note DPI limited to 4GB) size_t totalSize() const; @@ -199,7 +220,8 @@ public: int elements(int dim) const { return m_propsp->elements(dim); } size_t totalSize() const { return m_propsp->totalSize(); } void* datapAdjustIndex(void* datap, int dim, int indx) const { - return m_propsp->datapAdjustIndex(datap, dim, indx); } + return m_propsp->datapAdjustIndex(datap, dim, indx); + } }; //=========================================================================== @@ -213,10 +235,12 @@ class VerilatedVar : public VerilatedVarProps { protected: friend class VerilatedScope; // CONSTRUCTORS - VerilatedVar(const char* namep, void* datap, - VerilatedVarType vltype, VerilatedVarFlags vlflags, int dims) - : VerilatedVarProps(vltype, vlflags, (dims>0?1:0), ((dims>1)?dims-1:0)) - , m_datap(datap), m_namep(namep) {} + VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype, + VerilatedVarFlags vlflags, int dims) + : VerilatedVarProps(vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0)) + , m_datap(datap) + , m_namep(namep) {} + public: ~VerilatedVar() {} // ACCESSORS diff --git a/include/verilated_threads.cpp b/include/verilated_threads.cpp index 7568e1585..77d19b700 100644 --- a/include/verilated_threads.cpp +++ b/include/verilated_threads.cpp @@ -27,8 +27,8 @@ VL_THREAD_LOCAL VlThreadPool::ProfileTrace* VlThreadPool::t_profilep = NULL; // VlMTaskVertex VlMTaskVertex::VlMTaskVertex(vluint32_t upstreamDepCount) - : m_upstreamDepsDone(0), - m_upstreamDepCount(upstreamDepCount) { + : m_upstreamDepsDone(0) + , m_upstreamDepCount(upstreamDepCount) { assert(atomic_is_lock_free(&m_upstreamDepsDone)); } @@ -41,7 +41,7 @@ VlWorkerThread::VlWorkerThread(VlThreadPool* poolp, bool profiling) , m_poolp(poolp) , m_profiling(profiling) , m_exiting(false) - // Must init this last -- after setting up fields that it might read: + // Must init this last -- after setting up fields that it might read: , m_cthread(startWorker, this) {} VlWorkerThread::~VlWorkerThread() { @@ -52,17 +52,13 @@ VlWorkerThread::~VlWorkerThread() { } void VlWorkerThread::workerLoop() { - if (VL_UNLIKELY(m_profiling)) { - m_poolp->setupProfilingClientThread(); - } + if (VL_UNLIKELY(m_profiling)) m_poolp->setupProfilingClientThread(); ExecRec work; work.m_fnp = NULL; while (true) { - if (VL_LIKELY(!work.m_fnp)) { - dequeWork(&work); - } + if (VL_LIKELY(!work.m_fnp)) dequeWork(&work); // Do this here, not above, to avoid a race with the destructor. if (VL_UNLIKELY(m_exiting.load(std::memory_order_acquire))) @@ -74,14 +70,10 @@ void VlWorkerThread::workerLoop() { } } - if (VL_UNLIKELY(m_profiling)) { - m_poolp->tearDownProfilingClientThread(); - } + if (VL_UNLIKELY(m_profiling)) m_poolp->tearDownProfilingClientThread(); } -void VlWorkerThread::startWorker(VlWorkerThread* workerp) { - workerp->workerLoop(); -} +void VlWorkerThread::startWorker(VlWorkerThread* workerp) { workerp->workerLoop(); } //============================================================================= // VlThreadPool @@ -90,23 +82,22 @@ VlThreadPool::VlThreadPool(int nThreads, bool profiling) : m_profiling(profiling) { // --threads N passes nThreads=N-1, as the "main" threads counts as 1 unsigned cpus = std::thread::hardware_concurrency(); - if (cpus < nThreads+1) { + if (cpus < nThreads + 1) { static int warnedOnce = 0; if (!warnedOnce++) { VL_PRINTF_MT("%%Warning: System has %u CPUs but model Verilated with" - " --threads %d; may run slow.\n", cpus, nThreads+1); + " --threads %d; may run slow.\n", + cpus, nThreads + 1); } } // Create'em - for (int i=0; ibegin(); - eit != (*pit)->end(); ++eit) { + for (ProfileTrace::const_iterator eit = (*pit)->begin(); eit != (*pit)->end(); ++eit) { switch (eit->m_type) { case VlProfileRec::TYPE_BARRIER: printing = true; break; case VlProfileRec::TYPE_MTASK_RUN: if (!printing) break; - fprintf(fp, "VLPROF mtask %d" - " start %" VL_PRI64"u end %" VL_PRI64"u elapsed %" VL_PRI64 "u" + fprintf(fp, + "VLPROF mtask %d" + " start %" VL_PRI64 "u end %" VL_PRI64 "u elapsed %" VL_PRI64 "u" " predict_time %u cpu %u on thread %u\n", - eit->m_mtaskId, - eit->m_startTime, - eit->m_endTime, - (eit->m_endTime - eit->m_startTime), - eit->m_predictTime, - eit->m_cpu, + eit->m_mtaskId, eit->m_startTime, eit->m_endTime, + (eit->m_endTime - eit->m_startTime), eit->m_predictTime, eit->m_cpu, thread_id); break; default: assert(false); break; // LCOV_EXCL_LINE } } } - fprintf(fp, "VLPROF stat ticks %" VL_PRI64 "u\n", - ticksElapsed); + fprintf(fp, "VLPROF stat ticks %" VL_PRI64 "u\n", ticksElapsed); fclose(fp); } diff --git a/include/verilated_threads.h b/include/verilated_threads.h index 39cab0a11..19d7af2c2 100644 --- a/include/verilated_threads.h +++ b/include/verilated_threads.h @@ -284,6 +284,7 @@ public: // this once to setup profiling state: void setupProfilingClientThread(); void tearDownProfilingClientThread(); + private: VL_UNCOPYABLE(VlThreadPool); }; diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index f14f1445d..821f5311b 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -58,6 +58,7 @@ private: VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces }; static Singleton& singleton() { static Singleton s; return s; } + public: static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) { VerilatedLockGuard lock(singleton().s_vcdMutex); @@ -65,8 +66,8 @@ public: } static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) { VerilatedLockGuard lock(singleton().s_vcdMutex); - VcdVec::iterator pos = find(singleton().s_vcdVecp.begin(), - singleton().s_vcdVecp.end(), vcdp); + VcdVec::iterator pos + = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp); if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); } } static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE { @@ -115,13 +116,12 @@ protected: // VerilatedVcdFile bool VerilatedVcdFile::open(const std::string& name) VL_MT_UNSAFE { - m_fd = ::open(name.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC, 0666); + m_fd = ::open(name.c_str(), + O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666); return m_fd >= 0; } -void VerilatedVcdFile::close() VL_MT_UNSAFE { - ::close(m_fd); -} +void VerilatedVcdFile::close() VL_MT_UNSAFE { ::close(m_fd); } ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) VL_MT_UNSAFE { return ::write(m_fd, bufp, len); @@ -147,8 +147,8 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) m_evcd = false; m_scopeEscape = '.'; // Backward compatibility m_fullDump = true; - m_wrChunkSize = 8*1024; - m_wrBufp = new char [m_wrChunkSize*8]; + m_wrChunkSize = 8 * 1024; + m_wrBufp = new char[m_wrChunkSize * 8]; m_wrFlushp = m_wrBufp + m_wrChunkSize * 6; m_writep = m_wrBufp; m_wroteBytes = 0; @@ -167,15 +167,13 @@ void VerilatedVcd::open(const char* filename) { Verilated::flushCb(&flush_all); // SPDIFF_ON - openNext(m_rolloverMB!=0); + openNext(m_rolloverMB != 0); if (!isOpen()) return; dumpHeader(); // Allocate space now we know the number of codes - if (!m_sigs_oldvalp) { - m_sigs_oldvalp = new vluint32_t [m_nextCode+10]; - } + if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[m_nextCode + 10]; if (m_rolloverMB) { openNext(true); @@ -192,28 +190,29 @@ void VerilatedVcd::openNext(bool incFilename) { // Find _0000.{ext} in filename std::string name = m_filename; size_t pos = name.rfind('.'); - if (pos>8 && 0==strncmp("_cat",name.c_str()+pos-8,4) - && isdigit(name.c_str()[pos-4]) - && isdigit(name.c_str()[pos-3]) - && isdigit(name.c_str()[pos-2]) - && isdigit(name.c_str()[pos-1])) { + if (pos > 8 && 0 == strncmp("_cat", name.c_str() + pos - 8, 4) + && isdigit(name.c_str()[pos - 4]) + && isdigit(name.c_str()[pos - 3]) + && isdigit(name.c_str()[pos - 2]) + && isdigit(name.c_str()[pos - 1])) { // Increment code. - if ((++(name[pos-1])) > '9') { - name[pos-1] = '0'; - if ((++(name[pos-2])) > '9') { - name[pos-2] = '0'; - if ((++(name[pos-3])) > '9') { - name[pos-3] = '0'; - if ((++(name[pos-4])) > '9') { - name[pos-4] = '0'; - }}}} + if ((++(name[pos - 1])) > '9') { + name[pos - 1] = '0'; + if ((++(name[pos - 2])) > '9') { + name[pos - 2] = '0'; + if ((++(name[pos - 3])) > '9') { + name[pos - 3] = '0'; + if ((++(name[pos - 4])) > '9') { name[pos - 4] = '0'; } + } + } + } } else { // Append _cat0000 - name.insert(pos,"_cat0000"); + name.insert(pos, "_cat0000"); } m_filename = name; } - if (m_filename[0]=='|') { + if (m_filename[0] == '|') { assert(0); // Not supported yet. } else { // cppcheck-suppress duplicateExpression @@ -245,19 +244,19 @@ void VerilatedVcd::makeNameMap() { // If no scope was specified, prefix everything with a "top" // This comes from user instantiations with no name - IE Vtop(""). bool nullScope = false; - for (NameMap::const_iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) { + for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) { const std::string& hiername = it->first; - if (!hiername.empty() && hiername[0] == '\t') nullScope=true; + if (!hiername.empty() && hiername[0] == '\t') nullScope = true; } if (nullScope) { NameMap* newmapp = new NameMap; - for (NameMap::const_iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) { + for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) { const std::string& hiername = it->first; - const std::string& decl = it->second; + const std::string& decl = it->second; std::string newname = std::string("top"); if (hiername[0] != '\t') newname += ' '; newname += hiername; - newmapp->insert(std::make_pair(newname,decl)); + newmapp->insert(std::make_pair(newname, decl)); } deleteNameMap(); m_namemapp = newmapp; @@ -322,8 +321,8 @@ void VerilatedVcd::printStr(const char* str) { } void VerilatedVcd::printQuad(vluint64_t n) { - char buf [100]; - sprintf(buf,"%" VL_PRI64 "u", n); + char buf[100]; + sprintf(buf, "%" VL_PRI64 "u", n); printStr(buf); } @@ -366,17 +365,17 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE { char* wp = m_wrBufp; while (true) { ssize_t remaining = (m_writep - wp); - if (remaining==0) break; + if (remaining == 0) break; errno = 0; ssize_t got = m_filep->write(wp, remaining); - if (got>0) { + if (got > 0) { wp += got; m_wroteBytes += got; } else if (got < 0) { if (errno != EAGAIN && errno != EINTR) { // write failed, presume error (perhaps out of disk space) - std::string msg = std::string("VerilatedVcd::bufferFlush: ")+strerror(errno); - VL_FATAL_MT("",0,"",msg.c_str()); + std::string msg = std::string("VerilatedVcd::bufferFlush: ") + strerror(errno); + VL_FATAL_MT("", 0, "", msg.c_str()); closeErr(); break; } @@ -391,13 +390,13 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE { // Simple methods void VerilatedVcd::set_time_unit(const char* unitp) { - //cout<<" set_time_unit("<=1e-12) { suffixp="ps"; value *= 1e12; } else if (value>=1e-15) { suffixp="fs"; value *= 1e15; } else if (value>=1e-18) { suffixp="as"; value *= 1e18; } - char valuestr[100]; sprintf(valuestr,"%3.0f%s", value, suffixp); + char valuestr[100]; + sprintf(valuestr, "%3.0f%s", value, suffixp); return valuestr; // Gets converted to string, so no ref to stack } @@ -437,16 +437,20 @@ std::string VerilatedVcd::doubleToTimescale(double value) { // Definitions void VerilatedVcd::printIndent(int level_change) { - if (level_change<0) m_modDepth += level_change; - assert(m_modDepth>=0); - for (int i=0; i0) m_modDepth += level_change; + if (level_change < 0) m_modDepth += level_change; + assert(m_modDepth >= 0); + for (int i = 0; i < m_modDepth; i++) { + printStr(" "); + } + if (level_change > 0) m_modDepth += level_change; } void VerilatedVcd::dumpHeader() { printStr("$version Generated by VerilatedVcd $end\n"); time_t time_str = time(NULL); - printStr("$date "); printStr(ctime(&time_str)); printStr(" $end\n"); + printStr("$date "); + printStr(ctime(&time_str)); + printStr(" $end\n"); printStr("$timescale "); const std::string& timeResStr = doubleToTimescale(m_timeRes); @@ -456,7 +460,7 @@ void VerilatedVcd::dumpHeader() { makeNameMap(); // Signal header - assert(m_modDepth==0); + assert(m_modDepth == 0); printIndent(1); printStr("\n"); @@ -467,7 +471,7 @@ void VerilatedVcd::dumpHeader() { // Print the signal names const char* lastName = ""; - for (NameMap::const_iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) { + for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) { const std::string& hiernamestr = it->first; const std::string& decl = it->second; @@ -479,13 +483,16 @@ void VerilatedVcd::dumpHeader() { // Skip common prefix, it must break at a space or tab for (; *np && (*np == *lp); np++, lp++) {} - while (np!=hiername && *np && *np!=' ' && *np!='\t') { np--; lp--; } - //printf("hier %s\n lp=%s\n np=%s\n",hiername,lp,np); + while (np != hiername && *np && *np != ' ' && *np != '\t') { + np--; + lp--; + } + // printf("hier %s\n lp=%s\n np=%s\n",hiername,lp,np); // Any extra spaces in last name are scope ups we need to do bool first = true; for (; *lp; lp++) { - if (*lp==' ' || (first && *lp!='\t')) { + if (*lp == ' ' || (first && *lp != '\t')) { printIndent(-1); printStr("$upscope $end\n"); } @@ -494,14 +501,18 @@ void VerilatedVcd::dumpHeader() { // Any new spaces are scope downs we need to do while (*np) { - if (*np==' ') np++; - if (*np=='\t') break; // tab means signal name starts + if (*np == ' ') np++; + if (*np == '\t') break; // tab means signal name starts printIndent(1); printStr("$scope module "); - for (; *np && *np!=' ' && *np!='\t'; np++) { - if (*np=='[') printStr("("); - else if (*np==']') printStr(")"); - else *m_writep++=*np; + for (; *np && *np != ' ' && *np != '\t'; np++) { + if (*np == '[') { + printStr("("); + } else if (*np == ']') { + printStr(")"); + } else { + *m_writep++ = *np; + } } printStr(" $end\n"); } @@ -510,7 +521,7 @@ void VerilatedVcd::dumpHeader() { printStr(decl.c_str()); } - while (m_modDepth>1) { + while (m_modDepth > 1) { printIndent(-1); printStr("$upscope $end\n"); } @@ -530,8 +541,9 @@ void VerilatedVcd::module(const std::string& name) { void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, bool array, int arraynum, bool tri, bool bussed, int msb, int lsb) { - if (!code) { VL_FATAL_MT(__FILE__, __LINE__, "", - "Internal: internal trace problem, code 0 is illegal"); } + if (!code) { + VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal"); + } int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1; int codesNeeded = 1 + int(bits / 32); @@ -540,11 +552,11 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, // Make sure array is large enough m_nextCode = std::max(m_nextCode, code + codesNeeded); if (m_sigs.capacity() <= m_nextCode) { - m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up + m_sigs.reserve(m_nextCode * 2); // Power-of-2 allocation speeds things up } // Make sure write buffer is large enough (one character per bit), plus header - bufferResize(bits+1024); + bufferResize(bits + 1024); // Save declaration info VerilatedVcdSig sig = VerilatedVcdSig(code, bits); @@ -558,11 +570,11 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, // Note the hiername may be nothing, if so we'll add "\t{name}" std::string nameasstr = name; if (!m_modName.empty()) { - nameasstr = m_modName+m_scopeEscape+nameasstr; // Optional ->module prefix + nameasstr = m_modName + m_scopeEscape + nameasstr; // Optional ->module prefix } std::string hiername; std::string basename; - for (const char* cp=nameasstr.c_str(); *cp; cp++) { + for (const char* cp = nameasstr.c_str(); *cp; cp++) { if (isScopeEscape(*cp)) { // Ahh, we've just read a scope, not a basename if (!hiername.empty()) hiername += " "; @@ -572,12 +584,17 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, basename += *cp; } } - hiername += "\t"+basename; + hiername += "\t" + basename; // Print reference std::string decl = "$var "; - if (m_evcd) decl += "port"; else decl += wirep; // usually "wire" - char buf [1000]; + if (m_evcd) { + decl += "port"; + } else { + decl += wirep; // usually "wire" + } + + char buf[1000]; sprintf(buf, " %2d ", bits); decl += buf; if (m_evcd) { @@ -598,7 +615,7 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, decl += buf; } decl += " $end\n"; - m_namemapp->insert(std::make_pair(hiername,decl)); + m_namemapp->insert(std::make_pair(hiername, decl)); } void VerilatedVcd::declBit(vluint32_t code, const char* name, bool array, int arraynum) { @@ -646,7 +663,9 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) { // Buffer can't overflow before sprintf; we sized during declaration sprintf(m_writep, "r%.16g", newval); m_writep += strlen(m_writep); - *m_writep++=' '; printCode(code); *m_writep++='\n'; + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } void VerilatedVcd::fullFloat(vluint32_t code, const float newval) { @@ -655,7 +674,9 @@ void VerilatedVcd::fullFloat(vluint32_t code, const float newval) { // Buffer can't overflow before sprintf; we sized during declaration sprintf(m_writep, "r%.16g", static_cast(newval)); m_writep += strlen(m_writep); - *m_writep++=' '; printCode(code); *m_writep++='\n'; + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } @@ -716,9 +737,7 @@ void VerilatedVcd::dumpPrep(vluint64_t timeui) { //====================================================================== // Static members -void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { - VerilatedVcdSingleton::flush_all(); -} +void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_all(); } //====================================================================== //====================================================================== @@ -748,39 +767,39 @@ void vcdInit(VerilatedVcd* vcdp, void* userthis, vluint32_t code) { // Note need to add 3 for next code. vcdp->module("top2"); vcdp->declBus(0x2, "t2v1",-1,4,1); - vcdp->declTriBit (0x10, "io1", -1); - vcdp->declTriBus (0x12, "io5", -1,4,0); + vcdp->declTriBit(0x10, "io1",-1); + vcdp->declTriBus(0x12, "io5",-1,4,0); vcdp->declTriArray(0x16, "io96",-1,95,0); // Note need to add 6 for next code. - vcdp->declDouble (0x1c, "doub",-1); + vcdp->declDouble(0x1c, "doub",-1); // Note need to add 2 for next code. - vcdp->declArray(0x1e, "q2",-1, 95, 0); + vcdp->declArray(0x1e, "q2",-1,95,0); // Note need to add 4 for next code. } void vcdFull(VerilatedVcd* vcdp, void* userthis, vluint32_t code) { - vcdp->fullBus (0x2, v1,5); - vcdp->fullBus (0x3, v2,7); - vcdp->fullBit (0x4, s1); - vcdp->fullBus (0x5, ch,2); + vcdp->fullBus(0x2, v1, 5); + vcdp->fullBus(0x3, v2, 7); + vcdp->fullBit(0x4, s1); + vcdp->fullBus(0x5, ch, 2); vcdp->fullArray(0x6, &s2[0], 38); - vcdp->fullTriBit (0x10, tri96[0]&1, tri96__tri[0]&1); - vcdp->fullTriBus (0x12, tri96[0]&0x1f, tri96__tri[0]&0x1f, 5); - vcdp->fullTriArray(0x16, tri96, tri96__tri, 96); + vcdp->fullTriBit(0x10, tri96[0] & 1, tri96__tri[0] & 1); + vcdp->fullTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5); + vcdp->fullTriArray(0x16, tri96, tri96__tri, 96); vcdp->fullDouble(0x1c, doub); vcdp->fullArray(0x1e, &quad96[0], 96); } void vcdChange(VerilatedVcd* vcdp, void* userthis, vluint32_t code) { - vcdp->chgBus (0x2, v1,5); - vcdp->chgBus (0x3, v2,7); - vcdp->chgBit (0x4, s1); - vcdp->chgBus (0x5, ch,2); + vcdp->chgBus(0x2, v1, 5); + vcdp->chgBus(0x3, v2, 7); + vcdp->chgBit(0x4, s1); + vcdp->chgBus(0x5, ch, 2); vcdp->chgArray(0x6, &s2[0], 38); - vcdp->chgTriBit (0x10, tri96[0]&1, tri96__tri[0]&1); - vcdp->chgTriBus (0x12, tri96[0]&0x1f, tri96__tri[0]&0x1f, 5); - vcdp->chgTriArray (0x16, tri96, tri96__tri, 96); - vcdp->chgDouble (0x1c, doub); + vcdp->chgTriBit(0x10, tri96[0] & 1, tri96__tri[0] & 1); + vcdp->chgTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5); + vcdp->chgTriArray(0x16, tri96, tri96__tri, 96); + vcdp->chgDouble(0x1c, doub); vcdp->chgArray(0x1e, &quad96[0], 96); } @@ -803,13 +822,13 @@ main() { v1 = 0xfff; tri96[2] = 4; tri96[1] = 2; tri96[0] = 1; tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri - quad96[1] = 0xffffffff ; quad96[0] = 0; + quad96[1] = 0xffffffff; quad96[0] = 0; doub = 1.5; vcdp->dump(timestamp++); v2 = 0x1; s2[1] = 2; tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change - quad96[1] = 0 ; quad96[0] = ~0; + quad96[1] = 0; quad96[0] = ~0; doub = -1.66e13; vcdp->dump(timestamp++); ch = 2; diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 7051b07d1..359131a37 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -60,6 +60,7 @@ protected: VerilatedVcdSig(vluint32_t code, int bits) : m_code(code) , m_bits(bits) {} + public: ~VerilatedVcdSig() {} }; @@ -75,33 +76,33 @@ typedef void (*VerilatedVcdCallback_t)(VerilatedVcd* vcdp, void* userthis, vluin class VerilatedVcd { private: - VerilatedVcdFile* m_filep; ///< File we're writing to - bool m_fileNewed; ///< m_filep needs destruction - bool m_isOpen; ///< True indicates open file - bool m_evcd; ///< True for evcd format - std::string m_filename; ///< Filename we're writing to (if open) - vluint64_t m_rolloverMB; ///< MB of file size to rollover at - char m_scopeEscape; ///< Character to separate scope components - int m_modDepth; ///< Depth of module hierarchy - bool m_fullDump; ///< True indicates dump ignoring if changed - vluint32_t m_nextCode; ///< Next code number to assign - std::string m_modName; ///< Module name being traced now - double m_timeRes; ///< Time resolution (ns/ms etc) - double m_timeUnit; ///< Time units (ns/ms etc) - vluint64_t m_timeLastDump; ///< Last time we did a dump + VerilatedVcdFile* m_filep; ///< File we're writing to + bool m_fileNewed; ///< m_filep needs destruction + bool m_isOpen; ///< True indicates open file + bool m_evcd; ///< True for evcd format + std::string m_filename; ///< Filename we're writing to (if open) + vluint64_t m_rolloverMB; ///< MB of file size to rollover at + char m_scopeEscape; ///< Character to separate scope components + int m_modDepth; ///< Depth of module hierarchy + bool m_fullDump; ///< True indicates dump ignoring if changed + vluint32_t m_nextCode; ///< Next code number to assign + std::string m_modName; ///< Module name being traced now + double m_timeRes; ///< Time resolution (ns/ms etc) + double m_timeUnit; ///< Time units (ns/ms etc) + vluint64_t m_timeLastDump; ///< Last time we did a dump - char* m_wrBufp; ///< Output buffer - char* m_wrFlushp; ///< Output buffer flush trigger location - char* m_writep; ///< Write pointer into output buffer - vluint64_t m_wrChunkSize; ///< Output buffer size - vluint64_t m_wroteBytes; ///< Number of bytes written to this file + char* m_wrBufp; ///< Output buffer + char* m_wrFlushp; ///< Output buffer flush trigger location + char* m_writep; ///< Write pointer into output buffer + vluint64_t m_wrChunkSize; ///< Output buffer size + vluint64_t m_wroteBytes; ///< Number of bytes written to this file - vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values - typedef std::vector SigVec; - SigVec m_sigs; ///< Pointer to signal information - typedef std::vector CallbackVec; + vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values + typedef std::vector SigVec; + SigVec m_sigs; ///< Pointer to signal information + typedef std::vector CallbackVec; CallbackVec m_callbacks; ///< Routines to perform dumping - typedef std::map NameMap; + typedef std::map NameMap; NameMap* m_namemapp; ///< List of names for the header VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread @@ -153,6 +154,7 @@ private: // CONSTRUCTORS VL_UNCOPYABLE(VerilatedVcd); + public: explicit VerilatedVcd(VerilatedVcdFile* filep = NULL); ~VerilatedVcd(); @@ -170,7 +172,8 @@ public: inline bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; } // METHODS - void open(const char* filename) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors + /// Open the file; call isOpen() to see if errors + void open(const char* filename) VL_MT_UNSAFE_ONE; void openNext(bool incFilename); ///< Open next data-only file void close() VL_MT_UNSAFE_ONE; ///< Close the file /// Flush any remaining data to this file @@ -194,47 +197,54 @@ public: /// Inside dumping routines, declare callbacks for tracings void addCallback(VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, - VerilatedVcdCallback_t changecb, - void* userthis) VL_MT_UNSAFE_ONE; + VerilatedVcdCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE; /// Inside dumping routines, declare a module void module(const std::string& name); /// Inside dumping routines, declare a signal - void declBit( vluint32_t code, const char* name, bool array, int arraynum); - void declBus( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declQuad( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declArray( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declTriBit( vluint32_t code, const char* name, bool array, int arraynum); - void declTriBus( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declTriQuad( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declDouble( vluint32_t code, const char* name, bool array, int arraynum); - void declFloat( vluint32_t code, const char* name, bool array, int arraynum); + void declBit(vluint32_t code, const char* name, bool array, int arraynum); + void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); + void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); + void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); + void declTriBit(vluint32_t code, const char* name, bool array, int arraynum); + void declTriBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); + void declTriQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, + int lsb); + void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, + int lsb); + void declDouble(vluint32_t code, const char* name, bool array, int arraynum); + void declFloat(vluint32_t code, const char* name, bool array, int arraynum); // ... other module_start for submodules (based on cell name) /// Inside dumping routines, dump one signal void fullBit(vluint32_t code, const vluint32_t newval) { // Note the &1, so we don't require clean input -- makes more common no change case faster m_sigs_oldvalp[code] = newval; - *m_writep++=('0'+static_cast(newval&1)); printCode(code); *m_writep++='\n'; + *m_writep++ = ('0' + static_cast(newval & 1)); + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } void fullBus(vluint32_t code, const vluint32_t newval, int bits) { m_sigs_oldvalp[code] = newval; - *m_writep++='b'; - for (int bit=bits-1; bit>=0; --bit) { - *m_writep++=((newval&(1L<= 0; --bit) { + *m_writep++ = ((newval & (1L << bit)) ? '1' : '0'); } - *m_writep++=' '; printCode(code); *m_writep++='\n'; + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } void fullQuad(vluint32_t code, const vluint64_t newval, int bits) { (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; - *m_writep++='b'; - for (int bit=bits-1; bit>=0; --bit) { + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { *m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0'); } - *m_writep++=' '; printCode(code); *m_writep++='\n'; + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } void fullArray(vluint32_t code, const vluint32_t* newval, int bits) { @@ -245,64 +255,72 @@ public: for (int bit = bits - 1; bit >= 0; --bit) { *m_writep++ = ((newval[(bit / 32)] & (1L << (bit & 0x1f))) ? '1' : '0'); } - *m_writep ++= ' '; printCode(code); *m_writep ++= '\n'; + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } void fullArray(vluint32_t code, const vluint64_t* newval, int bits) { for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { m_sigs_oldvalp[code + word] = newval[word]; } - *m_writep ++= 'b'; + *m_writep++ = 'b'; for (int bit = bits - 1; bit >= 0; --bit) { *m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0'); } - *m_writep ++= ' '; printCode(code); *m_writep ++= '\n'; + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) { - m_sigs_oldvalp[code] = newval; - m_sigs_oldvalp[code+1] = newtri; - *m_writep++ = "01zz"[m_sigs_oldvalp[code] - | (m_sigs_oldvalp[code+1]<<1)]; - printCode(code); *m_writep++='\n'; + m_sigs_oldvalp[code] = newval; + m_sigs_oldvalp[code + 1] = newtri; + *m_writep++ = "01zz"[m_sigs_oldvalp[code] | (m_sigs_oldvalp[code + 1] << 1)]; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) { m_sigs_oldvalp[code] = newval; - m_sigs_oldvalp[code+1] = newtri; - *m_writep++='b'; - for (int bit=bits-1; bit>=0; --bit) { - *m_writep++ = "01zz"[((newval >> bit)&1) - | (((newtri >> bit)&1)<<1)]; + m_sigs_oldvalp[code + 1] = newtri; + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + *m_writep++ = "01zz"[((newval >> bit) & 1) | (((newtri >> bit) & 1) << 1)]; } - *m_writep++=' '; printCode(code); *m_writep++='\n'; + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } - void fullTriQuad(vluint32_t code, const vluint64_t newval, - const vluint32_t newtri, int bits) { + void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) { (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; - (*(reinterpret_cast(&m_sigs_oldvalp[code+1]))) = newtri; - *m_writep++='b'; - for (int bit=bits-1; bit>=0; --bit) { + (*(reinterpret_cast(&m_sigs_oldvalp[code + 1]))) = newtri; + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { *m_writep++ = "01zz"[((newval >> bit) & VL_ULL(1)) | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))]; } - *m_writep++=' '; printCode(code); *m_writep++='\n'; + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } - void fullTriArray(vluint32_t code, const vluint32_t* newvalp, - const vluint32_t* newtrip, int bits) { - for (int word=0; word<(((bits-1)/32)+1); ++word) { - m_sigs_oldvalp[code+word*2] = newvalp[word]; - m_sigs_oldvalp[code+word*2+1] = newtrip[word]; + void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, + int bits) { + for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { + m_sigs_oldvalp[code + word * 2] = newvalp[word]; + m_sigs_oldvalp[code + word * 2 + 1] = newtrip[word]; } - *m_writep++='b'; - for (int bit=bits-1; bit>=0; --bit) { - vluint32_t valbit = (newvalp[(bit/32)]>>(bit&0x1f)) & 1; - vluint32_t tribit = (newtrip[(bit/32)]>>(bit&0x1f)) & 1; - *m_writep++ = "01zz"[valbit | (tribit<<1)]; + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + vluint32_t valbit = (newvalp[(bit / 32)] >> (bit & 0x1f)) & 1; + vluint32_t tribit = (newtrip[(bit / 32)] >> (bit & 0x1f)) & 1; + *m_writep++ = "01zz"[valbit | (tribit << 1)]; } - *m_writep++=' '; printCode(code); *m_writep++='\n'; + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } void fullDouble(vluint32_t code, const double newval); @@ -313,15 +331,19 @@ public: /// Thus this is for special standalone applications that after calling /// fullBitX, must when then value goes non-X call fullBit. inline void fullBitX(vluint32_t code) { - *m_writep++='x'; printCode(code); *m_writep++='\n'; + *m_writep++ = 'x'; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } inline void fullBusX(vluint32_t code, int bits) { - *m_writep++='b'; - for (int bit=bits-1; bit>=0; --bit) { - *m_writep++='x'; + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + *m_writep++ = 'x'; } - *m_writep++=' '; printCode(code); *m_writep++='\n'; + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; bufferCheck(); } inline void fullQuadX(vluint32_t code, int bits) { fullBusX(code, bits); } @@ -370,10 +392,8 @@ public: } } } - inline void chgTriBit(vluint32_t code, const vluint32_t newval, - const vluint32_t newtri) { - vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval) - | (m_sigs_oldvalp[code+1] ^ newtri)); + inline void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) { + vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval) | (m_sigs_oldvalp[code + 1] ^ newtri)); if (VL_UNLIKELY(diff)) { // Verilator 3.510 and newer provide clean input, so the below // is only for back compatibility @@ -382,32 +402,32 @@ public: } } } - inline void chgTriBus(vluint32_t code, const vluint32_t newval, - const vluint32_t newtri, int bits) { - vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval) - | (m_sigs_oldvalp[code+1] ^ newtri)); + inline void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, + int bits) { + vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval) | (m_sigs_oldvalp[code + 1] ^ newtri)); if (VL_UNLIKELY(diff)) { - if (VL_UNLIKELY(bits==32 || (diff & ((1U<(&m_sigs_oldvalp[code]))) ^ newval) - | ((*(reinterpret_cast(&m_sigs_oldvalp[code+1]))) ^ newtri)); + inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, + int bits) { + vluint64_t diff + = (((*(reinterpret_cast(&m_sigs_oldvalp[code]))) ^ newval) + | ((*(reinterpret_cast(&m_sigs_oldvalp[code + 1]))) ^ newtri)); if (VL_UNLIKELY(diff)) { if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) { fullTriQuad(code, newval, newtri, bits); } } } - inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp, - const vluint32_t* newtrip, int bits) { - for (int word=0; word<(((bits-1)/32)+1); ++word) { - if (VL_UNLIKELY((m_sigs_oldvalp[code+word*2] ^ newvalp[word]) - | (m_sigs_oldvalp[code+word*2+1] ^ newtrip[word]))) { - fullTriArray(code,newvalp,newtrip,bits); + inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, + int bits) { + for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { + if (VL_UNLIKELY((m_sigs_oldvalp[code + word * 2] ^ newvalp[word]) + | (m_sigs_oldvalp[code + word * 2 + 1] ^ newtrip[word]))) { + fullTriArray(code, newvalp, newtrip, bits); return; } } @@ -441,12 +461,14 @@ class VerilatedVcdC { // CONSTRUCTORS VL_UNCOPYABLE(VerilatedVcdC); + public: explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL) : m_sptrace(filep) {} ~VerilatedVcdC() { close(); } /// Routines can only be called from one thread; allow next call from different thread void changeThread() { spTrace()->changeThread(); } + public: // ACCESSORS /// Is file open? From 5302a9d0e6648f9878f9cb16c75f6e01e103bf92 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 4 Apr 2020 17:55:37 -0400 Subject: [PATCH 004/127] Internals: clang-format cleanups. No functional change. --- docs/clang-format.txt | 1 - include/verilated_dpi.h | 40 ++++++++++++++------- include/verilated_heavy.h | 73 +++++++++++++++++++++++---------------- include/verilatedos.h | 5 ++- 4 files changed, 73 insertions(+), 46 deletions(-) diff --git a/docs/clang-format.txt b/docs/clang-format.txt index a4b6bcd1f..d21358c90 100644 --- a/docs/clang-format.txt +++ b/docs/clang-format.txt @@ -10,7 +10,6 @@ be made to a file. The following files are not yet clang-format clean: clang-format -i include/verilated.h clang-format -i include/verilated_dpi.h -clang-format -i include/verilated_heavy.h clang-format -i include/verilated_imp.h clang-format -i include/verilated_unordered_set_map.h clang-format -i include/verilatedos.h diff --git a/include/verilated_dpi.h b/include/verilated_dpi.h index 26ff6f02b..bad33e130 100644 --- a/include/verilated_dpi.h +++ b/include/verilated_dpi.h @@ -35,22 +35,28 @@ /// Return WData from svBitVecVal static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, const svBitVecVal* lwp) VL_MT_SAFE { int words = VL_WORDS_I(obits); - for (int i=0; i class VlWide { WData m_storage[T_Words]; + public: // Default constructor/destructor/copy are fine const WData& at(size_t index) const { return m_storage[index]; } @@ -95,13 +96,11 @@ public: // Convert a C array to std::array reference by pointer magic, without copy. // Data type (second argument) is so the function template can automatically generate. -template -VlWide& VL_CVT_W_A(WDataInP inp, const VlWide&) { +template VlWide& VL_CVT_W_A(WDataInP inp, const VlWide&) { return *((VlWide*)inp); } -template -std::string VL_TO_STRING(const VlWide& obj) { +template std::string VL_TO_STRING(const VlWide& obj) { return VL_TO_STRING_W(T_Words, obj.data()); } @@ -114,6 +113,7 @@ template class VlAssocArray { private: // TYPES typedef std::map Map; + public: typedef typename Map::const_iterator const_iterator; @@ -187,8 +187,11 @@ public: // Accessing. Verilog: v = assoc[index] const T_Value& at(const T_Key& index) const { typename Map::iterator it = m_map.find(index); - if (it == m_map.end()) return m_defaultValue; - else return it->second; + if (it == m_map.end()) { + return m_defaultValue; + } else { + return it->second; + } } // For save/restore const_iterator begin() const { return m_map.begin(); } @@ -251,6 +254,7 @@ template class VlQueue { private: // TYPES typedef std::deque Deque; + public: typedef typename Deque::const_iterator const_iterator; @@ -274,7 +278,9 @@ public: int size() const { return m_deque.size(); } // Clear array. Verilog: function void delete([input index]) void clear() { m_deque.clear(); } - void erase(size_t index) { if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index); } + void erase(size_t index) { + if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index); + } // Dynamic array new[] becomes a renew() void renew(size_t size) { @@ -282,7 +288,7 @@ public: m_deque.resize(size, atDefault()); } // Dynamic array new[]() becomes a renew_copy() - void renew_copy(size_t size, const VlQueue& rhs) { + void renew_copy(size_t size, const VlQueue& rhs) { if (size == 0) { clear(); } else { @@ -303,12 +309,16 @@ public: // function value_t q.pop_front(); T_Value pop_front() { if (m_deque.empty()) return m_defaultValue; - T_Value v = m_deque.front(); m_deque.pop_front(); return v; + T_Value v = m_deque.front(); + m_deque.pop_front(); + return v; } // function value_t q.pop_back(); T_Value pop_back() { if (m_deque.empty()) return m_defaultValue; - T_Value v = m_deque.back(); m_deque.pop_back(); return v; + T_Value v = m_deque.back(); + m_deque.pop_back(); + return v; } // Setting. Verilog: assoc[index] = v @@ -320,15 +330,19 @@ public: if (VL_UNLIKELY(index >= m_deque.size())) { s_throwAway = atDefault(); return s_throwAway; + } else { + return m_deque[index]; } - else return m_deque[index]; } // Accessing. Verilog: v = assoc[index] const T_Value& at(size_t index) const { static T_Value s_throwAway; // Needs to work for dynamic arrays, so does not use T_MaxSize - if (VL_UNLIKELY(index >= m_deque.size())) return atDefault(); - else return m_deque[index]; + if (VL_UNLIKELY(index >= m_deque.size())) { + return atDefault(); + } else { + return m_deque[index]; + } } // function void q.insert(index, value); void insert(size_t index, const T_Value& value) { @@ -352,8 +366,7 @@ public: } }; -template -std::string VL_TO_STRING(const VlQueue& obj) { +template std::string VL_TO_STRING(const VlQueue& obj) { return obj.to_string(); } @@ -362,26 +375,29 @@ std::string VL_TO_STRING(const VlQueue& obj) { 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[VL_WQ_WORDS_E]; VL_SET_WQ(lw, lhs); + WData lw[VL_WQ_WORDS_E]; + VL_SET_WQ(lw, lhs); return VL_CVT_PACK_STR_NW(VL_WQ_WORDS_E, lw); } -inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) VL_PURE { - return 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) VL_PURE { - WData lw[VL_WQ_WORDS_E]; VL_SET_WI(lw, lhs); + WData lw[VL_WQ_WORDS_E]; + VL_SET_WI(lw, lhs); return VL_CVT_PACK_STR_NW(1, lw); } 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) VL_PURE { - std::string out; out.reserve(lhs.length() * rep); - for (unsigned times=0; times Date: Sat, 4 Apr 2020 18:02:23 -0400 Subject: [PATCH 005/127] Update contributors for codacity --- docs/CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 0060aa607..4e1565764 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -39,6 +39,7 @@ Stefan Wallentowitz Tobias Rosenkranz Tobias Wölfel Todd Strader +Veripool API Bot Wilson Snyder Yutetsu TAKATSUKASA Yves Mathieu From bf17bb4648c195aad2884fffc7519982fa1b1656 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 4 Apr 2020 20:08:58 -0400 Subject: [PATCH 006/127] Fix codacity warnings --- src/V3AstNodes.cpp | 12 ++++++------ src/V3EmitCInlines.cpp | 4 ++-- src/V3EmitCSyms.cpp | 4 ++-- src/V3LinkDot.cpp | 2 +- src/V3ProtectLib.cpp | 4 ++-- test_regress/t/t_trace_two_cc.cpp | 1 - 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 64df9f9df..314cae720 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -335,9 +335,9 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT } else if (const AstBasicDType* bdtypep = dtypep->basicp()) { string otype; string oarray; - bool strtype = bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::STRING; + bool strtype = bdtypep->keyword() == AstBasicDTypeKwd::STRING; string bitvec; - if (bdtypep && !bdtypep->isOpaque() && !v3Global.opt.protectIds()) { + if (!bdtypep->isOpaque() && !v3Global.opt.protectIds()) { // We don't print msb()/lsb() as multidim packed would require recursion, // and may confuse users as C++ data is stored always with bit 0 used bitvec += "/*"+cvtToStr(dtypep->width()-1)+":0*/"; @@ -345,13 +345,13 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT if ((forFunc && isReadOnly()) || bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR || bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) otype += "const "; - if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) { + if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) { otype += "char*"; - } else if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) { + } else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) { otype += "VerilatedScope*"; - } else if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) { + } else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) { otype += "double"; - } else if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) { + } else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) { otype += "float"; } else if (strtype) { otype += "std::string"; diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index d3fa0084c..ef36bc395 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -132,6 +132,6 @@ void EmitCInlines::emitInt() { // EmitC class functions void V3EmitC::emitcInlines() { - UINFO(2,__FUNCTION__<<": "<nodep()<parentp())<parentp() == m_curSymp // Only when on same level + if (foundp->parentp() == m_curSymp // Only when on same level && !foundp->imported()) { // and not from package bool nansiBad = ((findvarp->isDeclTyped() && nodep->isDeclTyped()) || (findvarp->isIO() && nodep->isIO())); // e.g. !(output && output) diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index ecb49ff4b..b9be66a9b 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -452,6 +452,6 @@ class ProtectVisitor : public AstNVisitor { // ProtectLib class functions void V3ProtectLib::protect() { - UINFO(2,__FUNCTION__<<": "<clk = false; ap->clk = false; main_time += 10; } From 9fdb026e959949424c8448be2f7dcae9d91a6c7e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 4 Apr 2020 20:48:03 -0400 Subject: [PATCH 007/127] Add VM_C11 for future need of C++11 --- .travis.yml | 1 + include/verilated.mk.in | 17 +++++++++++++++-- src/V3EmitMk.cpp | 2 ++ src/V3Global.h | 12 ++++++++---- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index b0623c38c..e99bbd848 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ cache: before_install: # Perl modules needed for testing # Not listing Bit::Vector as slow to install, and only skips one test + - touch temp.cpp ; g++ -E -dM -c temp.cpp | sort ; rm -rf temp.cpp - yes yes | sudo cpan -fi Unix::Processors Parallel::Forker - sudo apt-get install gdb gtkwave - sudo apt-get install libgoogle-perftools-dev diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 0a5254610..47e3f61a9 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -114,9 +114,16 @@ endif ####################################################################### ##### Threaded builds +ifneq ($(VM_C11),0) + ifneq ($(VM_C11),) + VK_C11=1 + endif +endif + ifneq ($(VM_THREADS),0) ifneq ($(VM_THREADS),) CPPFLAGS += -DVL_THREADED + VK_C11=1 VK_LIBS_THREADED=1 endif endif @@ -124,14 +131,20 @@ endif ifneq ($(VM_TRACE_THREADED),0) ifneq ($(VM_TRACE_THREADED),) CPPFLAGS += -DVL_TRACE_THREADED + VK_C11=1 VK_LIBS_THREADED=1 endif endif +ifneq ($(VK_C11),0) + ifneq ($(VK_C11),) + # Need C++11 at least, so always default to newest + CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST) + endif +endif + ifneq ($(VK_LIBS_THREADED),0) ifneq ($(VK_LIBS_THREADED),) - # Need C++11 at least, so always default to newest - CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST) LDLIBS += $(CFG_LDLIBS_THREADS) endif endif diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 9efdad47f..e6147acf4 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -45,6 +45,8 @@ public: of.puts("# See "+v3Global.opt.prefix()+".mk"+" for the caller.\n"); of.puts("\n### Switches...\n"); + of.puts("# C11 constructs required? 0/1 (from --threads or use of classes)\n"); + of.puts("VM_C11 = " + cvtToStr(v3Global.needC11() || v3Global.opt.threads()) + "\n"); of.puts("# Coverage output mode? 0/1 (from --coverage)\n"); of.puts("VM_COVERAGE = "); of.puts(v3Global.opt.coverage()?"1":"0"); of.puts("\n"); of.puts("# Parallel builds? 0/1 (from --output-split)\n"); diff --git a/src/V3Global.h b/src/V3Global.h index d97c20274..5c9503032 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -73,9 +73,10 @@ class V3Global { int m_debugFileNumber; // Number to append to debug files created bool m_assertDTypesResolved; // Tree should have dtypep()'s bool m_constRemoveXs; // Const needs to strip any Xs - bool m_needTraceDumper; // Need __Vm_dumperp in symbols + bool m_needC11; // Need C++11 bool m_needHInlines; // Need __Inlines file bool m_needHeavy; // Need verilated_heavy.h include + bool m_needTraceDumper; // Need __Vm_dumperp in symbols bool m_dpi; // Need __Dpi include files public: @@ -89,9 +90,10 @@ public: m_widthMinUsage = VWidthMinUsage::LINT_WIDTH; m_assertDTypesResolved = false; m_constRemoveXs = false; - m_needTraceDumper = false; + m_needC11 = false; m_needHInlines = false; m_needHeavy = false; + m_needTraceDumper = false; m_dpi = false; m_rootp = NULL; // created by makeInitNetlist() so static constructors run first } @@ -117,12 +119,14 @@ public: char digits[100]; sprintf(digits, "%03d", m_debugFileNumber); return opt.makeDir()+"/"+opt.prefix()+"_"+digits+"_"+nameComment; } - bool needTraceDumper() const { return m_needTraceDumper; } - void needTraceDumper(bool flag) { m_needTraceDumper = flag; } + bool needC11() const { return m_needC11; } + void needC11(bool flag) { m_needC11 = flag; } bool needHInlines() const { return m_needHInlines; } void needHInlines(bool flag) { m_needHInlines = flag; } bool needHeavy() const { return m_needHeavy; } void needHeavy(bool flag) { m_needHeavy = flag; } + bool needTraceDumper() const { return m_needTraceDumper; } + void needTraceDumper(bool flag) { m_needTraceDumper = flag; } bool dpi() const { return m_dpi; } void dpi(bool flag) { m_dpi = flag; } }; From f6048cc9c13fa7203c5f957c953b032f39542e1b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 08:22:51 -0400 Subject: [PATCH 008/127] Fix clang warning. No functional change. --- src/V3Combine.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index 1ab5714cd..c9f2303f2 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -75,7 +75,6 @@ class CombCallVisitor : CombBaseVisitor { // Find all CCALLS of each CFUNC, so that we can later rename them private: // NODE STATE - bool m_find; // Find mode vs. delete mode typedef std::multimap CallMmap; CallMmap m_callMmap; // Associative array of {function}{call} // METHODS @@ -137,8 +136,7 @@ private: public: // CONSTRUCTORS - CombCallVisitor() - : m_find(false) {} + CombCallVisitor() {} virtual ~CombCallVisitor() {} void main(AstNetlist* nodep) { iterate(nodep); } }; From 6eadb8e7714c23d4a3470857df761fcbd4c6504f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 09:30:23 -0400 Subject: [PATCH 009/127] Add simplistic class support with many restrictions, see manual, #377. --- Changes | 2 + bin/verilator | 7 + include/verilated.cpp | 7 + include/verilated.h | 3 +- include/verilated_heavy.h | 19 +++ src/Makefile_obj.in | 1 + src/V3Ast.h | 12 +- src/V3AstNodes.cpp | 43 ++++++ src/V3AstNodes.h | 101 +++++++++++-- src/V3CCtors.cpp | 22 ++- src/V3CUse.cpp | 110 ++++++++++++++ src/V3Cast.cpp | 23 +++ src/V3Class.cpp | 143 +++++++++++++++++++ src/V3Class.h | 33 +++++ src/V3Const.cpp | 1 + src/V3Dead.cpp | 42 +++++- src/V3Descope.cpp | 3 + src/V3EmitC.cpp | 57 +++++++- src/V3EmitCInlines.cpp | 5 + src/V3EmitCSyms.cpp | 4 + src/V3Inline.cpp | 13 +- src/V3LinkDot.cpp | 87 ++++++++++- src/V3LinkParse.cpp | 16 ++- src/V3LinkResolve.cpp | 13 +- src/V3Name.cpp | 12 +- src/V3Order.cpp | 1 + src/V3Scope.cpp | 46 +++++- src/V3SymTable.h | 6 +- src/V3Task.cpp | 19 ++- src/V3TraceDecl.cpp | 1 + src/V3Tristate.cpp | 3 + src/V3Undriven.cpp | 1 + src/V3Width.cpp | 110 +++++++++++++- src/Verilator.cpp | 4 + src/verilog.y | 17 ++- test_regress/t/t_class1.out | 4 + test_regress/t/t_class1.pl | 22 +++ test_regress/t/t_class1.v | 29 ++++ test_regress/t/t_class2.out | 10 ++ test_regress/t/t_class2.pl | 25 ++++ test_regress/t/t_class2.v | 40 ++++++ test_regress/t/t_class_class.out | 4 + test_regress/t/t_class_class.pl | 19 +++ test_regress/t/t_class_class.v | 34 +++++ test_regress/t/t_class_copy.pl | 21 +++ test_regress/t/t_class_copy.v | 37 +++++ test_regress/t/t_class_copy_bad.out | 5 + test_regress/t/t_class_copy_bad.pl | 19 +++ test_regress/t/t_class_copy_bad.v | 21 +++ test_regress/t/t_class_dead.pl | 25 ++++ test_regress/t/t_class_dead.v | 30 ++++ test_regress/t/t_class_enum.pl | 21 +++ test_regress/t/t_class_enum.v | 19 +++ test_regress/t/t_class_extends.out | 10 ++ test_regress/t/t_class_extends.pl | 23 +++ test_regress/t/t_class_extends.v | 42 ++++++ test_regress/t/t_class_extends_bad.out | 4 + test_regress/t/t_class_extends_bad.pl | 19 +++ test_regress/t/t_class_extends_bad.v | 17 +++ test_regress/t/t_class_forward.pl | 21 +++ test_regress/t/t_class_forward.v | 40 ++++++ test_regress/t/t_class_local.out | 7 + test_regress/t/t_class_local.pl | 23 +++ test_regress/t/t_class_local.v | 27 ++++ test_regress/t/t_class_member_bad.out | 4 + test_regress/t/t_class_member_bad.pl | 19 +++ test_regress/t/t_class_member_bad.v | 20 +++ test_regress/t/t_class_method.pl | 21 +++ test_regress/t/t_class_method.v | 30 ++++ test_regress/t/t_class_method_bad.out | 4 + test_regress/t/t_class_method_bad.pl | 19 +++ test_regress/t/t_class_method_bad.v | 20 +++ test_regress/t/t_class_module.pl | 21 +++ test_regress/t/t_class_module.v | 28 ++++ test_regress/t/t_class_name.out | 4 + test_regress/t/t_class_name.pl | 23 +++ test_regress/t/t_class_name.v | 34 +++++ test_regress/t/t_class_new.out | 13 ++ test_regress/t/t_class_new.pl | 23 +++ test_regress/t/t_class_new.v | 33 +++++ test_regress/t/t_class_new_bad.out | 13 ++ test_regress/t/t_class_new_bad.pl | 19 +++ test_regress/t/t_class_new_bad.v | 30 ++++ test_regress/t/t_class_null_bad.out | 2 + test_regress/t/t_class_null_bad.pl | 22 +++ test_regress/t/t_class_null_bad.v | 19 +++ test_regress/t/t_class_package.pl | 21 +++ test_regress/t/t_class_package.v | 47 ++++++ test_regress/t/t_class_param.out | 4 + test_regress/t/t_class_param.pl | 23 +++ test_regress/t/t_class_param.v | 40 ++++++ test_regress/t/t_class_static_order.out | 10 ++ test_regress/t/t_class_static_order.pl | 23 +++ test_regress/t/t_class_static_order.v | 60 ++++++++ test_regress/t/t_class_unsup_bad.out | 20 +-- test_regress/t/t_class_unsup_bad.pl | 2 +- test_regress/t/t_class_unsup_bad.v | 2 +- test_regress/t/t_interface_param_acc_bits.pl | 2 +- test_regress/t/t_savable_class_bad.out | 2 + test_regress/t/t_savable_class_bad.pl | 21 +++ test_regress/t/t_savable_class_bad.v | 21 +++ 101 files changed, 2258 insertions(+), 66 deletions(-) create mode 100644 src/V3Class.cpp create mode 100644 src/V3Class.h create mode 100644 test_regress/t/t_class1.out create mode 100755 test_regress/t/t_class1.pl create mode 100644 test_regress/t/t_class1.v create mode 100644 test_regress/t/t_class2.out create mode 100755 test_regress/t/t_class2.pl create mode 100644 test_regress/t/t_class2.v create mode 100644 test_regress/t/t_class_class.out create mode 100755 test_regress/t/t_class_class.pl create mode 100644 test_regress/t/t_class_class.v create mode 100755 test_regress/t/t_class_copy.pl create mode 100644 test_regress/t/t_class_copy.v create mode 100644 test_regress/t/t_class_copy_bad.out create mode 100755 test_regress/t/t_class_copy_bad.pl create mode 100644 test_regress/t/t_class_copy_bad.v create mode 100755 test_regress/t/t_class_dead.pl create mode 100644 test_regress/t/t_class_dead.v create mode 100755 test_regress/t/t_class_enum.pl create mode 100644 test_regress/t/t_class_enum.v create mode 100644 test_regress/t/t_class_extends.out create mode 100755 test_regress/t/t_class_extends.pl create mode 100644 test_regress/t/t_class_extends.v create mode 100644 test_regress/t/t_class_extends_bad.out create mode 100755 test_regress/t/t_class_extends_bad.pl create mode 100644 test_regress/t/t_class_extends_bad.v create mode 100755 test_regress/t/t_class_forward.pl create mode 100644 test_regress/t/t_class_forward.v create mode 100644 test_regress/t/t_class_local.out create mode 100755 test_regress/t/t_class_local.pl create mode 100644 test_regress/t/t_class_local.v create mode 100644 test_regress/t/t_class_member_bad.out create mode 100755 test_regress/t/t_class_member_bad.pl create mode 100644 test_regress/t/t_class_member_bad.v create mode 100755 test_regress/t/t_class_method.pl create mode 100644 test_regress/t/t_class_method.v create mode 100644 test_regress/t/t_class_method_bad.out create mode 100755 test_regress/t/t_class_method_bad.pl create mode 100644 test_regress/t/t_class_method_bad.v create mode 100755 test_regress/t/t_class_module.pl create mode 100644 test_regress/t/t_class_module.v create mode 100644 test_regress/t/t_class_name.out create mode 100755 test_regress/t/t_class_name.pl create mode 100644 test_regress/t/t_class_name.v create mode 100644 test_regress/t/t_class_new.out create mode 100755 test_regress/t/t_class_new.pl create mode 100644 test_regress/t/t_class_new.v create mode 100644 test_regress/t/t_class_new_bad.out create mode 100755 test_regress/t/t_class_new_bad.pl create mode 100644 test_regress/t/t_class_new_bad.v create mode 100644 test_regress/t/t_class_null_bad.out create mode 100755 test_regress/t/t_class_null_bad.pl create mode 100644 test_regress/t/t_class_null_bad.v create mode 100755 test_regress/t/t_class_package.pl create mode 100644 test_regress/t/t_class_package.v create mode 100644 test_regress/t/t_class_param.out create mode 100755 test_regress/t/t_class_param.pl create mode 100644 test_regress/t/t_class_param.v create mode 100644 test_regress/t/t_class_static_order.out create mode 100755 test_regress/t/t_class_static_order.pl create mode 100644 test_regress/t/t_class_static_order.v create mode 100644 test_regress/t/t_savable_class_bad.out create mode 100755 test_regress/t/t_savable_class_bad.pl create mode 100644 test_regress/t/t_savable_class_bad.v diff --git a/Changes b/Changes index f9c18a064..938de3927 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.033 devel +** Add simplistic class support with many restrictions, see manual, #377. + * Verilator 4.032 2020-04-04 diff --git a/bin/verilator b/bin/verilator index 68c42e97e..5cbf582ae 100755 --- a/bin/verilator +++ b/bin/verilator @@ -3558,6 +3558,13 @@ ___05F (5F is the hex code of an underscore.) Verilator only supports "bind" to a target module name, not an instance path. +=head2 Class + +Verilator class support is very limited and in active development. +Verilator supports members, and methods. Verilator doe not support initial +values on class members, class static members, class new methods, class +extend, or class parameters. + =head2 Dotted cross-hierarchy references Verilator supports dotted references to variables, functions and tasks in diff --git a/include/verilated.cpp b/include/verilated.cpp index ab27d2af7..efdb84aff 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2088,12 +2088,19 @@ const char* Verilated::commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE { return outstr; } +void Verilated::nullPointerError(const char* filename, int linenum) VL_MT_SAFE { + // Slowpath - Called only on error + VL_FATAL_MT(filename, linenum, "", "Null pointer dereferenced"); + VL_UNREACHABLE +} + void Verilated::overWidthError(const char* signame) VL_MT_SAFE { // Slowpath - Called only when signal sets too high of a bit std::string msg = (std::string("Testbench C set input '") + signame + "' to value that overflows what the signal's width can fit"); VL_FATAL_MT("unknown", 0, "", msg.c_str()); + VL_UNREACHABLE } void Verilated::mkdir(const char* dirname) VL_MT_UNSAFE { diff --git a/include/verilated.h b/include/verilated.h index 2aed894a1..037f74121 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -510,7 +510,8 @@ public: const char* delimiter = "."); // Returns static data // Internal: Throw signal assertion - static void overWidthError(const char* signame) VL_MT_SAFE; + static void nullPointerError(const char* filename, int linenum) VL_ATTR_NORETURN VL_MT_SAFE; + static void overWidthError(const char* signame) VL_ATTR_NORETURN VL_MT_SAFE; // Internal: Find scope static const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE; diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index e1e7aa111..596d21292 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -28,6 +28,7 @@ #include #include +#include #include //=================================================================== @@ -370,6 +371,24 @@ template std::string VL_TO_STRING(const VlQueue& obj) { return obj.to_string(); } +//=================================================================== +// Verilog class reference container +// There are no multithreaded locks on this; the base variable must +// be protected by other means +// + +#if (defined(_MSC_VER) && _MSC_VER >= 1900) || (__cplusplus >= 201103L) +# define VlClassRef std::shared_ptr +#else +# define VlClassRef VlClassRef__SystemVerilog_class_support_requires_a_C11_or_newer_compiler +#endif + +template // T typically of type VlClassRef +inline T VL_NULL_CHECK(T t, const char* filename, int linenum) { + if (VL_UNLIKELY(!t)) Verilated::nullPointerError(filename, linenum); + return t; +} + //====================================================================== // Conversion functions diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index af74d9e8d..4b0d83dd2 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -167,6 +167,7 @@ RAW_OBJS = \ V3Cast.o \ V3Cdc.o \ V3Changed.o \ + V3Class.o \ V3Clean.o \ V3Clock.o \ V3Combine.o \ diff --git a/src/V3Ast.h b/src/V3Ast.h index edc5ca021..952377350 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2289,21 +2289,23 @@ private: uint64_t m_dpiOpenParent; // DPI import open array, if !=0, how many callees bool m_taskPublic:1; // Public task bool m_attrIsolateAssign:1;// User isolate_assignments attribute + bool m_classMethod:1; // Class method bool m_prototype:1; // Just a prototype bool m_dpiExport:1; // DPI exported bool m_dpiImport:1; // DPI imported bool m_dpiContext:1; // DPI import context bool m_dpiOpenChild:1; // DPI import open array child wrapper bool m_dpiTask:1; // DPI import task (vs. void function) - bool m_pure:1; // DPI import pure + bool m_isConstructor:1; // Class constructor + bool m_pure:1; // DPI import pure (vs. virtual pure) public: AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) : AstNode(t, fl) , m_name(name) , m_dpiOpenParent(0), m_taskPublic(false) - , m_attrIsolateAssign(false), m_prototype(false) + , m_attrIsolateAssign(false), m_classMethod(false), m_prototype(false) , m_dpiExport(false), m_dpiImport(false), m_dpiContext(false) - , m_dpiOpenChild(false), m_dpiTask(false), m_pure(false) { + , m_dpiOpenChild(false), m_dpiTask(false), m_isConstructor(false), m_pure(false) { addNOp3p(stmtsp); cname(name); // Might be overridden by dpi import/export } @@ -2334,6 +2336,8 @@ public: bool taskPublic() const { return m_taskPublic; } void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } bool attrIsolateAssign() const { return m_attrIsolateAssign; } + void classMethod(bool flag) { m_classMethod = flag; } + bool classMethod() const { return m_classMethod; } void prototype(bool flag) { m_prototype = flag; } bool prototype() const { return m_prototype; } void dpiExport(bool flag) { m_dpiExport = flag; } @@ -2346,6 +2350,8 @@ public: bool dpiOpenChild() const { return m_dpiOpenChild; } void dpiTask(bool flag) { m_dpiTask = flag; } bool dpiTask() const { return m_dpiTask; } + void isConstructor(bool flag) { m_isConstructor = flag; } + bool isConstructor() const { return m_isConstructor; } void pure(bool flag) { m_pure = flag; } bool pure() const { return m_pure; } }; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 314cae720..fef301062 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -328,6 +328,10 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT out += "> "; info.m_oprefix = out; return info; + } else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) { + VlArgTypeRecursed info; + info.m_oprefix = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">"; + return info; } else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) { VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), arrayed); info.m_osuffix = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + info.m_osuffix; @@ -999,6 +1003,43 @@ void AstCellInline::dump(std::ostream& str) const { this->AstNode::dump(str); str<<" -> "<brokeExists()); + return NULL; +} +void AstClass::insertCache(AstNode* nodep) { + if (VN_IS(nodep, Var) || VN_IS(nodep, NodeFTask) || VN_IS(nodep, EnumItemRef)) { + if (m_members.find(nodep->name()) != m_members.end()) { + nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ()); + } else { + m_members.insert(make_pair(nodep->name(), nodep)); + } + } +} +void AstClass::repairCache() { + clearCache(); + for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { + insertCache(itemp); + } +} +void AstClass::dump(std::ostream& str) const { + this->AstNode::dump(str); +} +AstClass* AstClassExtends::classp() const { + AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType); + UASSERT_OBJ(refp, this, "class extends non-ref"); + return refp->classp(); +} +void AstClassRefDType::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (classp()) { str<<" -> "; classp()->dump(str); } + else { str<<" -> UNLINKED"; } +} +void AstClassRefDType::dumpSmall(std::ostream& str) const { + this->AstNodeDType::dumpSmall(str); + str<<"class:"<AstNode::dump(str); if (immediate()) str<<" [IMMEDIATE]"; @@ -1276,6 +1317,7 @@ void AstVar::dump(std::ostream& str) const { if (attrClockEn()) str<<" [aCLKEN]"; if (attrIsolateAssign()) str<<" [aISO]"; if (attrFileDescr()) str<<" [aFD]"; + if (isClassMember()) str<<" [MEMBER]"; if (isFuncReturn()) str<<" [FUNCRTN]"; else if (isFuncLocal()) str<<" [FUNC]"; if (isDpiOpenArray()) str<<" [DPIOPENA]"; @@ -1320,6 +1362,7 @@ void AstNodeFTaskRef::dump(std::ostream& str) const { } void AstNodeFTask::dump(std::ostream& str) const { this->AstNode::dump(str); + if (classMethod()) str<<" [METHOD]"; if (taskPublic()) str<<" [PUBLIC]"; if (prototype()) str<<" [PROTOTYPE]"; if (dpiImport()) str<<" [DPII]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 6a23d8435..df358b486 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -247,20 +247,75 @@ public: AstRange* rangep() const { return VN_CAST(op2p(), Range); } // op2 = Range of pin }; -class AstClass : public AstNode { +//###################################################################### +// Classes + +class AstClassPackage : public AstNodeModule { + // The static information portion of a class (treated similarly to a package) + AstClass* m_classp; // Class package this is under (weak pointer, hard link is other way) +public: + AstClassPackage(FileLine* fl, const string& name) + : ASTGEN_SUPER(fl, name) {} + ASTNODE_NODE_FUNCS(ClassPackage) + virtual string verilogKwd() const { return "/*class*/package"; } + virtual const char* broken() const; + AstClass* classp() const { return m_classp; } + void classp(AstClass* classp) { m_classp = classp; } +}; + +class AstClass : public AstNodeModule { + // TYPES + typedef std::map MemberNameMap; // MEMBERS - string m_name; // Name + MemberNameMap m_members; // Members or method children + AstClassPackage* m_packagep; // Class package this is under + void insertCache(AstNode* nodep); public: AstClass(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl) - , m_name(name) {} + : ASTGEN_SUPER(fl, name) + , m_packagep(NULL) {} ASTNODE_NODE_FUNCS(Class) - virtual string name() const { return m_name; } // * = Var name - virtual void name(const string& name) { m_name = name; } virtual string verilogKwd() const { return "class"; } virtual bool maybePointedTo() const { return true; } - AstNode* membersp() const { return op1p(); } // op1 = List of statements - void addMembersp(AstNode* nodep) { addNOp1p(nodep); } + virtual void dump(std::ostream& str) const; + virtual const char* broken() const { + BROKEN_BASE_RTN(AstNodeModule::broken()); + BROKEN_RTN(m_packagep && !m_packagep->brokeExists()); + return NULL; + } + // op1/op2/op3 in AstNodeModule + AstClassPackage* packagep() const { return m_packagep; } + void packagep(AstClassPackage* classpackagep) { m_packagep = classpackagep; } + AstNode* membersp() const { return stmtsp(); } // op2 = List of statements + void addMembersp(AstNode* nodep) { + insertCache(nodep); + addStmtp(nodep); + } + AstClassExtends* extendsp() const { return VN_CAST(op4p(), ClassExtends); } + void extendsp(AstNode* nodep) { addNOp2p(nodep); } + void clearCache() { m_members.clear(); } + void repairCache(); + AstNode* findMember(const string& name) const { + MemberNameMap::const_iterator it = m_members.find(name); + return (it == m_members.end()) ? NULL : it->second; + } +}; + +class AstClassExtends : public AstNode { + // Children: AstClassRefDType during early parse, then moves to dtype +public: + AstClassExtends(FileLine* fl, AstNodeDType* dtp) + : ASTGEN_SUPER(fl) { + childDTypep(dtp); // Only for parser + } + ASTNODE_NODE_FUNCS(ClassExtends) + virtual string verilogKwd() const { return "extends"; } + virtual bool hasDType() const { return true; } + AstNodeDType* getChildDTypep() const { return childDTypep(); } + // op1 = Type assigning to + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + AstClass* classp() const; // Class being extended (after link) }; //###################################################################### @@ -778,8 +833,11 @@ public: const AstClassRefDType* asamep = static_cast(samep); return (m_classp == asamep->m_classp && m_packagep == asamep->m_packagep); } - virtual bool similarDType(AstNodeDType* samep) const { return this == samep; } + virtual bool similarDType(AstNodeDType* samep) const { + return this == samep || same(samep); } virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_classp), V3Hash(m_packagep)); } + virtual void dump(std::ostream& str=std::cout) const; + virtual void dumpSmall(std::ostream& str) const; virtual string name() const { return classp() ? classp()->name() : ""; } virtual AstBasicDType* basicp() const { return NULL; } virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } @@ -1498,6 +1556,7 @@ private: bool m_usedClock:1; // Signal used as a clock bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup) bool m_usedLoopIdx:1; // Variable subject of for unrolling + bool m_classMember:1; // Member variable for a class bool m_funcLocal:1; // Local variable for a function bool m_funcReturn:1; // Return variable for a function bool m_attrClockEn:1;// User clock enable attribute @@ -1525,6 +1584,7 @@ private: m_usedClock = false; m_usedParam = false; m_usedLoopIdx = false; m_sigPublic = false; m_sigModPublic = false; m_sigUserRdPublic = false; m_sigUserRWPublic = false; + m_classMember = false; m_funcLocal = false; m_funcReturn = false; m_attrClockEn = false; m_attrScBv = false; m_attrIsolateAssign = false; m_attrSFormat = false; m_attrSplitVar = false; @@ -1645,6 +1705,7 @@ public: void isConst(bool flag) { m_isConst = flag; } void isStatic(bool flag) { m_isStatic = flag; } void isIfaceParent(bool flag) { m_isIfaceParent = flag; } + void classMember(bool flag) { m_classMember = flag; } void funcLocal(bool flag) { m_funcLocal = flag; } void funcReturn(bool flag) { m_funcReturn = flag; } void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; } @@ -1699,6 +1760,7 @@ public: bool isTrace() const { return m_trace; } bool isConst() const { return m_isConst; } bool isStatic() const { return m_isStatic; } + bool isClassMember() const { return m_classMember; } bool isFuncLocal() const { return m_funcLocal; } bool isFuncReturn() const { return m_funcReturn; } bool isPullup() const { return m_isPullup; } @@ -4099,6 +4161,27 @@ public: return fileline() == samep->fileline(); } }; +class AstNullCheck : public AstNodeUniop { + // Return LHS after checking that LHS is non-null + // Children: VarRef or something returning pointer +public: + AstNullCheck(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER(fl, lhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(NullCheck) + virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } + virtual int instrCount() const { return 1; } // Rarely executes + virtual string emitVerilog() { return "%l"; } + virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitSimpleOperator() { V3ERROR_NA; return "";} + virtual bool cleanOut() const { return true; } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + virtual V3Hash sameHash() const { return V3Hash(fileline()->lineno()); } + virtual bool same(const AstNode* samep) const { return fileline() == samep->fileline(); } +}; + class AstTraceDecl : public AstNodeStmt { // Trace point declaration // Separate from AstTraceInc; as a declaration can't be deleted diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 3fb8e6073..b02e0ffb0 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -49,6 +49,7 @@ private: int m_funcNum; // Function number being built public: + AstCFunc* builtFuncp() const { return m_tlFuncp; } void add(AstNode* nodep) { if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) { @@ -59,7 +60,7 @@ public: m_basename+"_"+cvtToStr(++m_funcNum), NULL, "void"); m_funcp->isStatic(false); m_funcp->declPrivate(true); - m_funcp->slow(true); + m_funcp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path m_funcp->argTypes(m_argsp); m_modp->addStmtp(m_funcp); @@ -86,7 +87,7 @@ public: m_tlFuncp = new AstCFunc(nodep->fileline(), basename, NULL, "void"); m_tlFuncp->declPrivate(true); m_tlFuncp->isStatic(false); - m_tlFuncp->slow(true); + m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path m_tlFuncp->argTypes(m_argsp); if (stmt != "") { m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); @@ -146,8 +147,10 @@ void V3CCtors::cctorsAll() { for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp = VN_CAST(modp->nextp(), NodeModule)) { // Process each module in turn + AstCFunc* varResetFuncp; { V3CCtorsVisitor var_reset (modp, "_ctor_var_reset"); + varResetFuncp = var_reset.builtFuncp(); for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { if (AstVar* varp = VN_CAST(np, Var)) { if (!varp->isIfaceParent() && !varp->isIfaceRef() @@ -172,5 +175,20 @@ void V3CCtors::cctorsAll() { } } } + if (VN_IS(modp, Class)) { + AstCFunc* funcp = new AstCFunc(modp->fileline(), "new", NULL, ""); + funcp->isConstructor(true); + funcp->isStatic(false); + funcp->slow(false); + modp->addStmtp(funcp); + funcp->addStmtsp(new AstCCall(varResetFuncp->fileline(), varResetFuncp)); + } + if (VN_IS(modp, Class)) { + AstCFunc* funcp = new AstCFunc(modp->fileline(), "~", NULL, ""); + funcp->isDestructor(true); + funcp->isStatic(false); + funcp->slow(false); + modp->addStmtp(funcp); + } } } diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index d16959782..e0539d773 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -18,6 +18,9 @@ // Each module: // Each cell: // Create CUse for cell forward declaration +// Each class: +// Create string access functions +// Search for dtypes referencing class, and create CUse for forward declaraion // //************************************************************************* @@ -44,6 +47,8 @@ private: // Entire netlist: // AstClass::user1() -> bool. True if class needs to_string dumper AstUser1InUse m_inuser1; + // AstClass::user2() -> bool. True if iterated + AstUser2InUse m_inuser2; // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -67,6 +72,49 @@ public: VL_UNCOPYABLE(CUseState); }; +// Visit within a module all nodes and data types they reference, finding +// any classes so we can make sure they are defined when Verilated code +// compiles +class CUseDTypeVisitor : public AstNVisitor { + // MEMBERS + CUseState& m_stater; // State for inserter + bool m_impOnly; // In details needed only for implementation + // METHODS + virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE { + if (nodep->user2SetOnce()) return; // Process once + if (!m_impOnly) m_stater.newUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name()); + // No class.h, it's inside the class package's h file + m_stater.newUse(nodep, VUseType::IMP_INCLUDE, nodep->classp()->packagep()->name()); + // Need to include extends() when we implement, but no need for pointers to know + bool oldImpOnly = m_impOnly; + { + m_impOnly = true; + iterateChildren(nodep->classp()); // This also gets all extend classes + } + m_impOnly = oldImpOnly; + } + virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { + if (nodep->user2SetOnce()) return; // Process once + if (nodep->virtRefDTypep()) iterate(nodep->virtRefDTypep()); + if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p()); + } + virtual void visit(AstNode* nodep) VL_OVERRIDE { + if (nodep->user2SetOnce()) return; // Process once + if (nodep->dtypep() && !nodep->dtypep()->user2()) iterate(nodep->dtypep()); + iterateChildren(nodep); + } + +public: + // CONSTRUCTORS + explicit CUseDTypeVisitor(AstNodeModule* nodep, CUseState& stater) + : m_stater(stater) + , m_impOnly(false) { + iterate(nodep); + } + virtual ~CUseDTypeVisitor() {} + VL_UNCOPYABLE(CUseDTypeVisitor); +}; + class CUseVisitor : public AstNVisitor { // MEMBERS CUseState m_state; // Inserter state @@ -83,6 +131,62 @@ class CUseVisitor : public AstNVisitor { } } } + void makeVlToString(AstClass* nodep) { + AstCFunc* funcp = new AstCFunc(nodep->fileline(), "VL_TO_STRING", NULL, "std::string"); + funcp->argTypes("const VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(nodep) + + ">& obj"); + funcp->isMethod(false); + funcp->isConst(false); + funcp->isStatic(false); + funcp->protect(false); + AstNode* exprp = new AstCMath(nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0); + exprp->dtypeSetString(); + funcp->addStmtsp(new AstCReturn(nodep->fileline(), exprp)); + nodep->addStmtp(funcp); + } + void makeToString(AstClass* nodep) { + AstCFunc* funcp = new AstCFunc(nodep->fileline(), "to_string", NULL, "std::string"); + funcp->isConst(true); + funcp->isStatic(false); + funcp->protect(false); + AstNode* exprp = new AstCMath(nodep->fileline(), + "std::string(\"`{\") + to_string_middle() + \"}\"", 0); + exprp->dtypeSetString(); + funcp->addStmtsp(new AstCReturn(nodep->fileline(), exprp)); + nodep->addStmtp(funcp); + } + void makeToStringMiddle(AstClass* nodep) { + AstCFunc* funcp = new AstCFunc(nodep->fileline(), "to_string_middle", NULL, "std::string"); + funcp->isConst(true); + funcp->isStatic(false); + funcp->protect(false); + funcp->addStmtsp(new AstCStmt(nodep->fileline(), "std::string out;\n")); + std::string comma; + for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) { + if (VN_IS(itemp, Var)) { + string stmt = "out += \""; + stmt += comma; + comma = ", "; + stmt += itemp->origNameProtect(); + stmt += ":\" + VL_TO_STRING("; + stmt += itemp->nameProtect(); + stmt += ");\n"; + nodep->user1(true); // So what we extend dumps this + funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); + } + } + if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) { + string stmt = "out += \""; + if (!comma.empty()) stmt += "\", \"+ "; + comma = ", "; + stmt += nodep->extendsp()->dtypep()->nameProtect(); + stmt += "::to_string_middle();\n"; + nodep->user1(true); // So what we extend dumps this + funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); + } + funcp->addStmtsp(new AstCStmt(nodep->fileline(), "return out;\n")); + nodep->addStmtp(funcp); + } // VISITORS virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { @@ -92,6 +196,12 @@ class CUseVisitor : public AstNVisitor { usep->protect(false); } makeUseCells(nodep); + { CUseDTypeVisitor dtypeVisitor(nodep, m_state); } + if (AstClass* classp = VN_CAST(nodep, Class)) { + makeVlToString(classp); + makeToString(classp); + makeToStringMiddle(classp); + } } virtual void visit(AstNode*) VL_OVERRIDE {} // All in AstNodeModule diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index 4d7ee95f8..232f5ce58 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -96,6 +96,15 @@ private: insertCast(nodep->lhsp(), VL_IDATASIZE); } } + void ensureNullChecked(AstNode* nodep) { + // TODO optimize to track null checked values and avoid where possible + if (!VN_IS(nodep->backp(), NullCheck)) { + AstNRelinker relinkHandle; + nodep->unlinkFrBack(&relinkHandle); + AstNode* newp = new AstNullCheck(nodep->fileline(), nodep); + relinkHandle.relink(newp); + } + } // VISITORS virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE { @@ -156,6 +165,20 @@ private: nodep->user1(nodep->isQuad() || nodep->isWide()); } + // Null dereference protection + virtual void visit(AstNullCheck* nodep) VL_OVERRIDE { + iterateChildren(nodep); + nodep->user1(nodep->lhsp()->user1()); + } + virtual void visit(AstCMethodCall* nodep) VL_OVERRIDE { + iterateChildren(nodep); + ensureNullChecked(nodep->fromp()); + } + virtual void visit(AstMemberSel* nodep) VL_OVERRIDE { + iterateChildren(nodep); + ensureNullChecked(nodep->fromp()); + } + // NOPs virtual void visit(AstVar*) VL_OVERRIDE {} diff --git a/src/V3Class.cpp b/src/V3Class.cpp new file mode 100644 index 000000000..81afdd1ce --- /dev/null +++ b/src/V3Class.cpp @@ -0,0 +1,143 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Handle SV classes +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2020 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* +// V3Class's Transformations: +// +// Each class: +// Move to be modules under AstNetlist +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Global.h" +#include "V3Class.h" +#include "V3Ast.h" + +//###################################################################### + +class ClassVisitor : public AstNVisitor { +private: + // MEMBERS + AstUser1InUse m_inuser1; + string m_prefix; // String prefix to add to name based on hier + AstScope* m_classScopep; // Package moving scopes into + typedef std::vector > MoveVector; + MoveVector m_moves; + + // NODE STATE + // AstClass::user1() -> bool. True if iterated already + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + + virtual void visit(AstClass* nodep) VL_OVERRIDE { + if (nodep->user1SetOnce()) return; + // Move this class + nodep->name(m_prefix + nodep->name()); + nodep->unlinkFrBack(); + v3Global.rootp()->addModulep(nodep); + // Make containing package + // Note origName is the same as the class origName so errors look correct + AstClassPackage* packagep = new AstClassPackage(nodep->fileline(), nodep->origName()); + packagep->name(nodep->name() + "__Vclpkg"); + nodep->packagep(packagep); + packagep->classp(nodep); + v3Global.rootp()->addModulep(packagep); + // Add package to hierarchy + AstCell* cellp = new AstCell(packagep->fileline(), + packagep->fileline(), + packagep->name(), + packagep->name(), + NULL, NULL, NULL); + cellp->modp(packagep); + v3Global.rootp()->topModulep()->addStmtp(cellp); + // Find class's scope + // Alternative would be to move this and related to V3Scope + AstScope* classScopep = NULL; + for (AstNode* itp = nodep->stmtsp(); itp; itp = itp->nextp()) { + if ((classScopep = VN_CAST(itp, Scope))) { + break; + } + } + UASSERT_OBJ(classScopep, nodep, "No scope under class"); + + // Add scope + AstScope* scopep = new AstScope(nodep->fileline(), + packagep, classScopep->name(), classScopep->aboveScopep(), + classScopep->aboveCellp()); + packagep->addStmtp(scopep); + // Iterate + string prevPrefix = m_prefix; + { + m_classScopep = classScopep; + m_prefix = nodep->name() + "__02e"; // . + iterateChildren(nodep); + } + m_prefix = prevPrefix; + m_classScopep = NULL; + } + virtual void visit(AstPackage* nodep) VL_OVERRIDE { + string prevPrefix = m_prefix; + { + m_prefix = nodep->name() + "__03a__03a"; // :: + iterateChildren(nodep); + } + m_prefix = prevPrefix; + } + + virtual void visit(AstVar* nodep) VL_OVERRIDE { + iterateChildren(nodep); + // Don't move now, or wouldn't keep interating the class + // TODO move class statics only + //if (m_classScopep) { + // m_moves.push_back(make_pair(nodep, m_classScopep)); + //} + } + virtual void visit(AstCFunc* nodep) VL_OVERRIDE { + iterateChildren(nodep); + // Don't move now, or wouldn't keep interating the class + // TODO move function statics only + //if (m_classScopep) { + // m_moves.push_back(make_pair(nodep, m_classScopep)); + //} + } + + virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Short circuit + virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {} // Short circuit + virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } + +public: + // CONSTRUCTORS + explicit ClassVisitor(AstNetlist* nodep) + : m_classScopep(NULL) { + iterate(nodep); + } + virtual ~ClassVisitor() { + for (MoveVector::iterator it = m_moves.begin(); it != m_moves.end(); ++it) { + it->second->addVarp(it->first->unlinkFrBack()); + } + } +}; + +//###################################################################### +// Class class functions + +void V3Class::classAll(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + { ClassVisitor visitor(nodep); } // Destruct before checking + V3Global::dumpCheckGlobalTree("class", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); +} diff --git a/src/V3Class.h b/src/V3Class.h new file mode 100644 index 000000000..f93be9a71 --- /dev/null +++ b/src/V3Class.h @@ -0,0 +1,33 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Pre C-Emit stage changes +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2020 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#ifndef _V3CLASS_H_ +#define _V3CLASS_H_ 1 + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Error.h" +#include "V3Ast.h" + +//============================================================================ + +class V3Class { +public: + static void classAll(AstNetlist* nodep); +}; + +#endif // Guard diff --git a/src/V3Const.cpp b/src/V3Const.cpp index aa460d117..c99d1950b 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1608,6 +1608,7 @@ private: && m_doNConst && v3Global.opt.oConst() // Default value, not a "known" constant for this usage + && !nodep->varp()->isClassMember() && !(nodep->varp()->isFuncLocal() && nodep->varp()->isNonOutput()) && !nodep->varp()->noSubst() diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 2f9fcf83c..6b8e4de49 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -92,6 +92,7 @@ private: std::vector m_vscsp; // List of all encountered to avoid another loop through tree std::vector m_scopesp; // List of all encountered to avoid another loop through tree std::vector m_cellsp; // List of all encountered to avoid another loop through tree + std::vector m_classesp; // List of all encountered to avoid another loop through tree AssignMap m_assignMap; // List of all simple assignments for each variable bool m_elimUserVars; // Allow removal of user's vars bool m_elimDTypes; // Allow removal of DTypes @@ -135,6 +136,13 @@ private: if (!nodep->dead()) { iterateChildren(nodep); checkAll(nodep); + if (AstClass* classp = VN_CAST(nodep, Class)) { + if (classp->extendsp()) classp->extendsp()->user1Inc(); + if (classp->packagep()) classp->packagep()->user1Inc(); + m_classesp.push_back(classp); + // TODO we don't reclaim dead classes yet - graph implementation instead? + classp->user1Inc(); + } } } m_modp = origModp; @@ -148,7 +156,9 @@ private: iterateChildren(nodep); checkAll(nodep); if (nodep->aboveScopep()) nodep->aboveScopep()->user1Inc(); - + // Class packages might have no children, but need to remain as + // long as the class they refer to is needed + if (VN_IS(m_modp, Class) || VN_IS(m_modp, ClassPackage)) nodep->user1Inc(); if (!nodep->isTop() && !nodep->varsp() && !nodep->blocksp() && !nodep->finalClksp()) { m_scopesp.push_back(nodep); } @@ -196,6 +206,18 @@ private: else nodep->packagep()->user1Inc(); } } + virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE { + iterateChildren(nodep); + checkDType(nodep); + checkAll(nodep); + if (nodep->packagep()) { + if (m_elimCells) nodep->packagep(NULL); + else nodep->packagep()->user1Inc(); + } + if (nodep->classp()) { + nodep->classp()->user1Inc(); + } + } virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { iterateChildren(nodep); checkDType(nodep); @@ -342,6 +364,23 @@ private: } } } + void deadCheckClasses() { + for (bool retry = true; retry;) { + retry = false; + for (std::vector::iterator it = m_classesp.begin(); it != m_classesp.end(); + ++it) { + if (AstClass* nodep = *it) { // NULL if deleted earlier + if (nodep->user1() == 0) { + if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1); + if (nodep->packagep()) nodep->packagep()->user1Inc(-1); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + *it = NULL; + retry = true; + } + } + } + } + } void deadCheckVar() { // Delete any unused varscopes @@ -422,6 +461,7 @@ public: // Otherwise we have no easy way to know if a scope is used if (elimScopes) deadCheckScope(); if (elimCells) deadCheckCells(); + deadCheckClasses(); // Modules after vars, because might be vars we delete inside a mod we delete deadCheckMod(); diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 393254244..3a20eefdc 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -109,6 +109,9 @@ private: // The risk that this prevents combining identical logic from differently- // named but identical modules seems low. if (m_modSingleton) relativeRefOk = false; + // + // Class methods need relative + if (m_modp && VN_IS(m_modp, Class)) relativeRefOk = true; if (varp && varp->isFuncLocal()) { hierThisr = true; diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 71c70f214..8d0a85f66 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -829,9 +829,29 @@ public: iterateAndNextNull(nodep->expr2p()); puts(")"); } } + virtual void visit(AstMemberSel* nodep) VL_OVERRIDE { + iterateAndNextNull(nodep->fromp()); + putbs("->"); + puts(nodep->varp()->nameProtect()); + } + virtual void visit(AstNullCheck* nodep) VL_OVERRIDE { + puts("VL_NULL_CHECK("); + iterateAndNextNull(nodep->lhsp()); + puts(", "); + putsQuoted(protect(nodep->fileline()->filename())); + puts(", "); + puts(cvtToStr(nodep->fileline()->lineno())); + puts(")"); + } virtual void visit(AstNew* nodep) VL_OVERRIDE { - puts("std::make_shared<" + nodep->dtypep()->nameProtect() + ">("); - iterateChildren(nodep); + puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">("); + iterateAndNextNull(nodep->argsp()); + puts(")"); + } + virtual void visit(AstNewCopy* nodep) VL_OVERRIDE { + puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">("); + puts("*"); // i.e. make into a reference + iterateAndNextNull(nodep->rhsp()); puts(")"); } virtual void visit(AstSel* nodep) VL_OVERRIDE { @@ -1505,6 +1525,9 @@ class EmitCImp : EmitCStmts { return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()" + cvtarray); } + else if (AstClassRefDType* adtypep = VN_CAST(dtypep, ClassRefDType)) { + return ""; // Constructor does it + } else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) { return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()"); } @@ -2723,7 +2746,11 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("\n//----------\n\n"); emitTextSection(AstType::atScHdr); - if (optSystemC() && modp->isTop()) { + if (AstClass* classp = VN_CAST(modp, Class)) { + puts("class " + prefixNameProtect(modp)); + if (classp->extendsp()) puts(" : public " + classp->extendsp()->classp()->nameProtect()); + puts(" {\n"); + } else if (optSystemC() && modp->isTop()) { puts("SC_MODULE(" + prefixNameProtect(modp) + ") {\n"); } else { puts("VL_MODULE(" + prefixNameProtect(modp) + ") {\n"); @@ -2832,7 +2859,12 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("/// The special name "" may be used to make a wrapper with a\n"); puts("/// single model invisible with respect to DPI scope names.\n"); } - puts(prefixNameProtect(modp) + "(const char* name = \"TOP\");\n"); + if (VN_IS(modp, Class)) { + // TODO move all constructor definition to e.g. V3CUse + puts(prefixNameProtect(modp) + "();\n"); + } else { + puts(prefixNameProtect(modp) + "(const char* name = \"TOP\");\n"); + } if (modp->isTop()) { puts("/// Destroy the model; called (often implicitly) by application code\n"); } @@ -2889,6 +2921,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("void " + protect("__Vconfigure") + "(" + symClassName() + "* symsp, bool first);\n"); } + ofp()->putsPrivate(false); // public: emitIntFuncDecls(modp, true); if (v3Global.opt.trace() && !VN_IS(modp, Class)) { @@ -2996,6 +3029,12 @@ void EmitCImp::mainInt(AstNodeModule* modp) { m_ofp = newOutCFile(fileModp, false/*slow*/, false/*source*/); emitIntTop(modp); emitInt(modp); + if (AstClassPackage* packagep = VN_CAST(modp, ClassPackage)) { + // Put the non-static class implementation in same h file for speed + m_modp = packagep->classp(); + emitInt(packagep->classp()); + m_modp = modp; + } ofp()->putsEndGuard(); VL_DO_CLEAR(delete m_ofp, m_ofp = NULL); } @@ -3013,6 +3052,15 @@ void EmitCImp::mainImp(AstNodeModule* modp, bool slow, bool fast) { emitImpTop(fileModp); emitImp(modp); + if (AstClassPackage* packagep = VN_CAST(modp, ClassPackage)) { + // Put the non-static class implementation in same C++ files as + // often optimizations are possible when both are seen by the + // compiler together + m_modp = packagep->classp(); + emitImp(packagep->classp()); + m_modp = modp; + } + if (fast && modp->isTop() && v3Global.opt.mtasks()) { // Make a final pass and emit function definitions for the mtasks // in the ExecGraph @@ -3489,6 +3537,7 @@ void V3EmitC::emitc() { // Process each module in turn for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_CAST(nodep->nextp(), NodeModule)) { + if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage { EmitCImp cint; cint.mainInt(nodep); } if (v3Global.opt.outputSplit()) { { EmitCImp fast; fast.mainImp(nodep, false, true); } diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index ef36bc395..f8d108f9f 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -46,6 +46,11 @@ class EmitCInlines : EmitCBaseVisitor { v3Global.needHeavy(true); iterateChildren(nodep); } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + v3Global.needC11(true); + v3Global.needHeavy(true); + iterateChildren(nodep); + } virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE { v3Global.needHeavy(true); iterateChildren(nodep); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index abccab053..51616453e 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -283,6 +283,7 @@ class EmitCSyms : EmitCBaseVisitor { } } virtual void visit(AstScope* nodep) VL_OVERRIDE { + if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible nameCheck(nodep); m_scopes.push_back(make_pair(nodep, m_modp)); @@ -381,6 +382,7 @@ void EmitCSyms::emitSymHdr() { puts("\n// INCLUDE MODULE CLASSES\n"); for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_CAST(nodep->nextp(), NodeModule)) { + if (VN_IS(nodep, Class)) continue; // Class included earlier puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n"); } @@ -422,6 +424,7 @@ void EmitCSyms::emitSymHdr() { for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* modp = it->second; + if (VN_IS(modp, Class)) continue; if (modp->isTop()) { ofp()->printf("%-30s ", (prefixNameProtect(modp) + "*").c_str()); puts(protectIf(scopep->nameDotless() + "p", scopep->protect()) + ";\n"); @@ -528,6 +531,7 @@ void EmitCSyms::emitSymImpPreamble() { puts("#include \""+symClassName()+".h\"\n"); for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_CAST(nodep->nextp(), NodeModule)) { + if (VN_IS(nodep, Class)) continue; // Class included earlier puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n"); } } diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 382d75263..4525ee045 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -114,6 +114,12 @@ private: iterateChildren(nodep); m_modp = NULL; } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + // TODO allow inlining of modules that have classes + // (Probably wait for new inliner scheme) + cantInline("class", true); + iterateChildren(nodep); + } virtual void visit(AstCell* nodep) VL_OVERRIDE { nodep->modp()->user3Inc(); // Inc refs m_instances[m_modp][nodep->modp()]++; @@ -294,6 +300,11 @@ private: nodep->name(name); iterateChildren(nodep); } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + string name = m_cellp->name() + "__DOT__" + nodep->name(); + nodep->name(name); + iterateChildren(nodep); + } virtual void visit(AstModule* nodep) VL_OVERRIDE { m_renamedInterfaces.clear(); iterateChildren(nodep); @@ -376,7 +387,7 @@ private: // Variable under the inline cell, need to rename to avoid conflicts // Also clear I/O bits, as it is now local. string name = m_cellp->name() + "__DOT__" + nodep->name(); - if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name); + if (!nodep->isFuncLocal() && !nodep->isClassMember()) nodep->inlineAttrReset(name); if (!m_cellp->isTrace()) nodep->trace(false); if (debug() >= 9) { nodep->dumpTree(cout, "varchanged:"); } if (debug() >= 9 && nodep->valuep()) { nodep->valuep()->dumpTree(cout, "varchangei:"); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 82075bc11..3044eca87 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -325,6 +325,10 @@ public: if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp)); return symp; } + void insertMap(VSymEnt* symp, const string& scopename) { + if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp)); + } + VSymEnt* insertInline(VSymEnt* abovep, VSymEnt* modSymp, AstCellInline* nodep, const string& basename) { // A fake point in the hierarchy, corresponding to an inlined module @@ -816,6 +820,39 @@ class LinkDotFindVisitor : public AstNVisitor { // Prep for next m_packagep = NULL; } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit"); + UINFO(8," "<name(); + m_curSymp = m_modSymp + = m_statep->insertBlock(upperSymp, nodep->name(), nodep, m_packagep); + m_statep->insertMap(m_curSymp, m_scope); + UINFO(9, "New module scope "<user4(true); + } + m_scope = oldscope; + m_modSymp = oldModSymp; + m_curSymp = oldCurSymp; + m_paramNum = oldParamNum; + m_beginNum = oldBeginNum; + m_modBeginNum = oldModBeginNum; + } virtual void visit(AstScope* nodep) VL_OVERRIDE { UASSERT_OBJ(m_statep->forScopeCreation(), nodep, "Scopes should only exist right after V3Scope"); @@ -1400,7 +1437,7 @@ class LinkDotScopeVisitor : public AstNVisitor { m_scopep = NULL; } virtual void visit(AstVarScope* nodep) VL_OVERRIDE { - if (!nodep->varp()->isFuncLocal()) { + if (!nodep->varp()->isFuncLocal() && !nodep->varp()->isClassMember()) { VSymEnt* varSymp = m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL); if (nodep->varp()->isIfaceRef() && nodep->varp()->isIfaceParent()) { @@ -2484,6 +2521,44 @@ private: m_ds.m_dotSymp = m_curSymp = oldCurSymp; m_ftaskp = NULL; } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + UINFO(5, " " << nodep << endl); + checkNoDot(nodep); + for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) { + if (AstClassExtends* eitemp = VN_CAST(itemp, ClassExtends)) { + // Replace abstract reference with hard pointer + // Will need later resolution when deal with parameters + eitemp->v3error("Unsupported: class extends"); + } + } + VSymEnt* oldCurSymp = m_curSymp; + VSymEnt* oldModSymp = m_modSymp; + { + m_ds.init(m_curSymp); + // Until overridden by a SCOPE + m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); + m_modp = nodep; + iterateChildren(nodep); + } + // V3Width when determines types needs to find enum values and such + // so add members pointing to appropriate enum values + { + nodep->repairCache(); + for (VSymEnt::const_iterator it = m_curSymp->begin(); it != m_curSymp->end(); ++it) { + AstNode* itemp = it->second->nodep(); + if (!nodep->findMember(it->first)) { + if (AstEnumItem* aitemp = VN_CAST(itemp, EnumItem)) { + AstEnumItemRef* newp = new AstEnumItemRef(aitemp->fileline(), aitemp, + it->second->packagep()); + UINFO(8, "Class import noderef '" << it->first << "' " << newp << endl); + nodep->addMembersp(newp); + } + } + } + } + m_curSymp = oldCurSymp; + m_modSymp = oldModSymp; + } virtual void visit(AstRefDType* nodep) VL_OVERRIDE { // Resolve its reference if (nodep->user3SetOnce()) return; @@ -2515,8 +2590,16 @@ private: nodep->refDTypep(defp); nodep->packagep(foundp->packagep()); } + else if (AstClass* defp = foundp ? VN_CAST(foundp->nodep(), Class) : NULL) { + AstClassRefDType* newp = new AstClassRefDType(nodep->fileline(), defp); + newp->packagep(foundp->packagep()); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + return; + } else { - nodep->v3error("Can't find typedef: "<prettyNameQ()); + if (foundp) UINFO(1, "Found sym node: " << foundp->nodep() << endl); + nodep->v3error("Can't find typedef: " << nodep->prettyNameQ()); } } iterateChildren(nodep); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index ce6b45d52..d0e852695 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -219,12 +219,18 @@ private: if (nodep->valuep()) { // A variable with an = value can be three things: FileLine* fl = nodep->valuep()->fileline(); - // 1. Parameters and function inputs: It's a default to use if not overridden if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) { - } - else if (!m_ftaskp && nodep->isNonOutput()) { - nodep->v3error("Unsupported: Default value on module input: " - <prettyNameQ()); + // 1. Parameters and function inputs: It's a default to use if not overridden + } else if (VN_IS(m_modp, Class)) { + // We make a AstVar initial value, but then do not set it in the constructor + // V3Emit::emitVarRecurse only does non-value inits. + // Perhaps these should still become a new form of + // AstInitial, and we propagate the initial to the class + // constructor + nodep->valuep()->v3error("Unsupported: initial value on member"); + } else if (!m_ftaskp && nodep->isNonOutput()) { + nodep->v3error( + "Unsupported: Default value on module input: " << nodep->prettyNameQ()); nodep->valuep()->unlinkFrBack()->deleteTree(); } // 2. Under modules, it's an initial value to be loaded at time 0 via an AstInitial else if (m_valueModp) { diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 44fa612d3..9a24283bc 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -50,6 +50,7 @@ private: // STATE // Below state needs to be preserved between each module call. AstNodeModule* m_modp; // Current module + AstClass* m_classp; // Class we're inside AstNodeFTask* m_ftaskp; // Function or task we're inside AstNodeCoverOrAssert* m_assertp; // Current assertion int m_senitemCvtNum; // Temporary signal counter @@ -89,9 +90,17 @@ private: iterateChildren(nodep); m_assertp = NULL; } - + virtual void visit(AstClass* nodep) VL_OVERRIDE { + AstClass* origClassp = m_classp; + { + m_classp = nodep; + iterateChildren(nodep); + } + m_classp = origClassp; + } virtual void visit(AstVar* nodep) VL_OVERRIDE { iterateChildren(nodep); + if (m_classp) nodep->classMember(true); if (m_ftaskp) nodep->funcLocal(true); if (nodep->isSigModPublic()) { nodep->sigModPublic(false); // We're done with this attribute @@ -110,6 +119,7 @@ private: virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { // NodeTask: Remember its name for later resolution // Remember the existing symbol table scope + if (m_classp) nodep->classMethod(true); m_ftaskp = nodep; iterateChildren(nodep); m_ftaskp = NULL; @@ -458,6 +468,7 @@ private: public: // CONSTRUCTORS explicit LinkResolveVisitor(AstNetlist* rootp) { + m_classp = NULL; m_ftaskp = NULL; m_modp = NULL; m_assertp = NULL; diff --git a/src/V3Name.cpp b/src/V3Name.cpp index c995fbfb9..95ba18acc 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -82,7 +82,7 @@ private: // Add __PVT__ to names of local signals virtual void visit(AstVar* nodep) VL_OVERRIDE { // Don't iterate... Don't need temps for RANGES under the Var. - rename(nodep, (!m_modp->isTop() + rename(nodep, ((!m_modp || !m_modp->isTop()) && !nodep->isSigPublic() && !nodep->isFuncLocal() // Isn't exposed, and would mess up dpi import wrappers && !nodep->isTemp())); // Don't bother to rename internal signals @@ -101,7 +101,8 @@ private: } virtual void visit(AstCell* nodep) VL_OVERRIDE { if (!nodep->user1()) { - rename(nodep, !nodep->modp()->modPublic()); + rename(nodep, (!nodep->modp()->modPublic() + && !VN_IS(nodep->modp(), ClassPackage))); iterateChildren(nodep); } } @@ -121,10 +122,13 @@ private: if (!nodep->user1SetOnce()) { if (nodep->aboveScopep()) iterate(nodep->aboveScopep()); if (nodep->aboveCellp()) iterate(nodep->aboveCellp()); - // Always recompute name (as many level above scope may have changed) + // Always recompute name (as many levels above scope may have changed) // Same formula as V3Scope nodep->name(nodep->isTop() ? "TOP" - : (nodep->aboveScopep()->name()+"."+nodep->aboveCellp()->name())); + : VN_IS(m_modp, Class) ? ("TOP." + m_modp->name()) + : VN_IS(m_modp, ClassPackage) ? ("TOP." + m_modp->name()) + : (nodep->aboveScopep()->name() + "." + nodep->aboveCellp()->name())); + nodep->editCountInc(); iterateChildren(nodep); } } diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 65f859012..2844f094a 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -1018,6 +1018,7 @@ private: } m_modp = origModp; } + virtual void visit(AstClass*) VL_OVERRIDE {} virtual void visit(AstScope* nodep) VL_OVERRIDE { UINFO(4," SCOPE "<first; AstScope* scopep = it->second; - if (nodep->packagep()) { + if (nodep->packagep() + && !nodep->varp()->isClassMember()) { PackageScopeMap::iterator it2 = m_packageScopes.find(nodep->packagep()); UASSERT_OBJ(it2 != m_packageScopes.end(), nodep, "Can't locate package scope"); scopep = it2->second; @@ -147,6 +148,39 @@ private: // ***Note m_scopep is passed back to the caller of the routine (above) } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + // Create required blocks and add to module + AstScope* oldScopep = m_scopep; + AstCell* oldAbCellp = m_aboveCellp; + AstScope* oldAbScopep = m_aboveScopep; + { + m_aboveScopep = m_scopep; + + string scopename; + if (!m_aboveScopep) { + scopename = "TOP"; + } else { + scopename = m_aboveScopep->name() + "." + nodep->name(); + } + + UINFO(4, " CLASS AT " << scopename << " " << nodep << endl); + AstNode::user1ClearTree(); + + AstNode* abovep = (m_aboveCellp ? static_cast(m_aboveCellp) + : static_cast(nodep)); + m_scopep = new AstScope(abovep->fileline(), + m_modp, scopename, m_aboveScopep, m_aboveCellp); + // Create scope for the current usage of this cell + AstNode::user1ClearTree(); + nodep->addMembersp(m_scopep); + + iterateChildren(nodep); + } + // Done, restore vars + m_scopep = oldScopep; + m_aboveCellp = oldAbCellp; + m_aboveScopep = oldAbScopep; + } virtual void visit(AstCellInline* nodep) VL_OVERRIDE { nodep->scopep(m_scopep); } @@ -230,7 +264,14 @@ private: virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { // Add to list of blocks under this scope UINFO(4," FTASK "<cloneTree(false); + AstNodeFTask* clonep; + if (nodep->classMethod()) { + // Only one scope will be created, so avoid pointless cloning + nodep->unlinkFrBack(); + clonep = nodep; + } else { + clonep = nodep->cloneTree(false); + } nodep->user2p(clonep); m_scopep->addActivep(clonep); // We iterate under the *clone* @@ -238,7 +279,6 @@ private: } virtual void visit(AstVar* nodep) VL_OVERRIDE { // Make new scope variable - // This is called cross-module by AstVar, so we cannot trust any m_ variables if (!nodep->user1p()) { AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep); UINFO(6," New scope "< VSymConstMap; class VSymEnt { // Symbol table that can have a "superior" table for resolving upper references -private: // MEMBERS typedef std::multimap IdNameMap; IdNameMap m_idNameMap; // Hash of variables by name @@ -62,6 +61,11 @@ private: static inline int debug() { return 0; } // NOT runtime, too hot of a function #endif public: + + typedef IdNameMap::const_iterator const_iterator; + const_iterator begin() const { return m_idNameMap.begin(); } + const_iterator end() const { return m_idNameMap.end(); } + void dumpIterate(std::ostream& os, VSymConstMap& doneSymsr, const string& indent, int numLevels, const string& searchName) const { os<dpiImport()) m_curVxp->noInline(true); + if (nodep->classMethod()) m_curVxp->noInline(true); // Until V3Task supports it iterateChildren(nodep); m_curVxp = lastVxp; } @@ -993,7 +994,7 @@ private: cfuncp->funcPublic(nodep->taskPublic()); cfuncp->dpiExport(nodep->dpiExport()); cfuncp->dpiImportWrapper(nodep->dpiImport()); - cfuncp->isStatic(!(nodep->dpiImport()||nodep->taskPublic())); + cfuncp->isStatic(!(nodep->dpiImport() || nodep->taskPublic() || nodep->classMethod())); cfuncp->pure(nodep->pure()); //cfuncp->dpiImport // Not set in the wrapper - the called function has it set if (cfuncp->dpiExport()) cfuncp->cname(nodep->cname()); @@ -1206,19 +1207,25 @@ private: if (nodep->dpiImport()) modes++; if (nodep->dpiExport()) modes++; if (nodep->taskPublic()) modes++; + if (nodep->classMethod()) modes++; if (v3Global.opt.protectIds() && nodep->taskPublic()) { // We always call protect() on names, we don't check if public or not // Hence any external references wouldn't be able to find the refed public object. nodep->v3error("Unsupported: Using --protect-ids with public function"); } - if (modes > 1) nodep->v3error("Cannot mix DPI import, DPI export and/or public on same function: " - <prettyNameQ()); + if (modes > 1) { + nodep->v3error("Cannot mix DPI import, DPI export, class methods, and/or public " + "on same function: " + << nodep->prettyNameQ()); + } - if (nodep->dpiImport() || nodep->dpiExport() - || nodep->taskPublic() || m_statep->ftaskNoInline(nodep)) { + if (nodep->dpiImport() || nodep->dpiExport() || nodep->taskPublic() + || m_statep->ftaskNoInline(nodep)) { // Clone it first, because we may have later FTaskRef's that still need // the original version. - if (m_statep->ftaskNoInline(nodep)) m_statep->checkPurity(nodep); + if (m_statep->ftaskNoInline(nodep) && !nodep->classMethod()) { + m_statep->checkPurity(nodep); + } AstNodeFTask* clonedFuncp = nodep->cloneTree(false); AstCFunc* cfuncp = makeUserFunc(clonedFuncp, m_statep->ftaskNoInline(nodep)); if (cfuncp) { diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index c1286d404..4d203704b 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -195,6 +195,7 @@ private: // Generally this equation doesn't need updating, instead use // varp->isTrace() and/or vscIgnoreTrace. if ((!nodep->varp()->isTemp() || nodep->varp()->isTrace()) + && !nodep->varp()->isClassMember() && !nodep->varp()->isFuncLocal()) { UINFO(5, " vsc "<varp(); diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 42fe48ee2..362104e12 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -1338,6 +1338,9 @@ class TristateVisitor : public TristateBaseVisitor { m_tgraph.clear(); // Recursion not supported } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + // don't deal with classes + } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { // don't deal with functions } diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 50c7311d9..8178d6742 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -336,6 +336,7 @@ private: && !VN_IS(nodep, VarXRef)) { // Ignore interface variables and similar ugly items if (m_inProcAssign && !nodep->varp()->varType().isProcAssignable() && !nodep->varp()->isDeclTyped() + && !nodep->varp()->isClassMember() && !nodep->varp()->isFuncLocal()) { nodep->v3warn(PROCASSWIRE, "Procedural assignment to wire, perhaps intended var" << " (IEEE 1800-2017 6.5): " << nodep->prettyNameQ()); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 4173a79eb..f962f46ab 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1769,6 +1769,19 @@ private: nodep->widthForce(width, width); // Signing stays as-is, as parsed from declaration //if (debug()>=9) nodep->dumpTree("-class-out-"); } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + if (nodep->didWidthAndSet()) return; + userIterateChildren(nodep, NULL); // First size all members + nodep->repairCache(); + } + virtual void visit(AstClassExtends* nodep) VL_OVERRIDE { + if (nodep->didWidthAndSet()) return; + if (nodep->childDTypep()) { + nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern } + } + nodep->v3error("Unsupported: class extends"); // Member/meth access breaks + userIterateChildren(nodep, NULL); + } virtual void visit(AstMemberDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); @@ -1788,6 +1801,23 @@ private: UINFO(9," from dt "<dtypep(foundp->dtypep()); + nodep->varp(varp); + return; + } + if (AstEnumItemRef* adfoundp = VN_CAST(foundp, EnumItemRef)) { + nodep->replaceWith(adfoundp->cloneTree(false)); + return; + } + UINFO(1, "found object " << foundp << endl); + nodep->v3fatalSrc("MemberSel of non-variable\n" + << nodep->warnContextPrimary() << endl + << foundp->warnOther() << "... Location of found object\n" + << foundp->warnContextSecondary()); + } } else if (VN_IS(fromDtp, EnumDType) || VN_IS(fromDtp, AssocArrayDType) || VN_IS(fromDtp, DynArrayDType) @@ -1810,6 +1840,30 @@ private: nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::LogicFalse())); VL_DO_DANGLING(pushDeletep(nodep), nodep); } + AstNode* memberSelClass(AstMemberSel* nodep, AstClassRefDType* adtypep) { + // Returns node if ok + // No need to width-resolve the class, as it was done when we did the child + AstClass* first_classp = adtypep->classp(); + UASSERT_OBJ(first_classp, nodep, "Unlinked"); + for (AstClass* classp = first_classp; classp;) { + if (AstNode* foundp = classp->findMember(nodep->name())) return foundp; + classp = classp->extendsp() ? classp->extendsp()->classp() : NULL; + } + VSpellCheck speller; + for (AstClass* classp = first_classp; classp;) { + for (AstNode* itemp = classp->membersp(); itemp; itemp = itemp->nextp()) { + if (VN_IS(itemp, Var) || VN_IS(itemp, EnumItemRef)) { + speller.pushCandidate(itemp->prettyName()); + } + } + classp = classp->extendsp() ? classp->extendsp()->classp() : NULL; + } + string suggest = speller.bestCandidateMsg(nodep->prettyName()); + nodep->v3error("Member "<prettyNameQ()<<" not found in class " + <prettyNameQ()<<"\n" + <<(suggest.empty() ? "" : nodep->fileline()->warnMore()+suggest)); + return NULL; // Caller handles error + } bool memberSelStruct(AstMemberSel* nodep, AstNodeUOrStructDType* adtypep) { // Returns true if ok if (AstMemberDType* memberp = adtypep->findMember(nodep->name())) { @@ -1868,6 +1922,9 @@ private: else if (AstQueueDType* adtypep = VN_CAST(fromDtp, QueueDType)) { methodCallQueue(nodep, adtypep); } + else if (AstClassRefDType* adtypep = VN_CAST(fromDtp, ClassRefDType)) { + methodCallClass(nodep, adtypep); + } else if (AstUnpackArrayDType* adtypep = VN_CAST(fromDtp, UnpackArrayDType)) { methodCallUnpack(nodep, adtypep); } @@ -2218,6 +2275,35 @@ private: VL_DANGLING(index_exprp); // May have been edited return VN_CAST(nodep->pinsp(), Arg)->exprp(); } + void methodCallClass(AstMethodCall* nodep, AstClassRefDType* adtypep) { + // No need to width-resolve the class, as it was done when we did the child + AstClass* first_classp = adtypep->classp(); + UASSERT_OBJ(first_classp, nodep, "Unlinked"); + for (AstClass* classp = first_classp; classp;) { + if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) { + nodep->taskp(ftaskp); + nodep->dtypeFrom(ftaskp); + if (VN_IS(ftaskp, Task)) nodep->makeStatement(); + return; + } + classp = classp->extendsp() ? classp->extendsp()->classp() : NULL; + } + { + VSpellCheck speller; + for (AstClass* classp = first_classp; classp;) { + for (AstNode* itemp = classp->membersp(); itemp; itemp = itemp->nextp()) { + if (VN_IS(itemp, NodeFTask)) speller.pushCandidate(itemp->prettyName()); + } + classp = classp->extendsp() ? classp->extendsp()->classp() : NULL; + } + string suggest = speller.bestCandidateMsg(nodep->prettyName()); + nodep->v3error("Class method " + << nodep->prettyNameQ() << " not found in class " + << first_classp->prettyNameQ() << "\n" + << (suggest.empty() ? "" : nodep->fileline()->warnMore() + suggest)); + } + nodep->dtypeSetSigned32(); // Guess on error + } void methodCallUnpack(AstMethodCall* nodep, AstUnpackArrayDType* adtypep) { enum { UNKNOWN = 0, ARRAY_OR, ARRAY_AND, ARRAY_XOR } methodId; @@ -2347,12 +2433,25 @@ private: nodep->dtypep(refp); if (nodep->argsp()) { nodep->v3error("Unsupported: new with arguments"); - userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); + pushDeletep(nodep->argsp()->unlinkFrBackWithNext()); + //TODO code similar to AstNodeFTaskRef + //userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); } } virtual void visit(AstNewCopy* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; - nodep->v3error("Unsupported: new-as-copy"); + AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullp(), ClassRefDType); + if (!refp) { // e.g. int a = new; + nodep->v3error("new() not expected in this context"); + return; + } + nodep->dtypep(refp); + userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); + if (!similarDTypeRecurse(nodep->dtypep(), nodep->rhsp()->dtypep())) { + nodep->rhsp()->v3error("New-as-copier passed different data type '" + << nodep->dtypep()->prettyTypeName() << "' then expected '" + << nodep->rhsp()->dtypep()->prettyTypeName() << "'"); + } } virtual void visit(AstNewDynamic* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; @@ -2866,6 +2965,7 @@ private: added = true; newFormat += "%g"; } else if (VN_IS(dtypep, AssocArrayDType) + || VN_IS(dtypep, ClassRefDType) || VN_IS(dtypep, DynArrayDType) || VN_IS(dtypep, QueueDType)) { added = true; @@ -3297,7 +3397,11 @@ private: nodep->doingWidth(true); // Would use user1 etc, but V3Width called from too many places to spend a user m_ftaskp = nodep; userIterateChildren(nodep, NULL); - if (nodep->fvarp()) { + if (nodep->isConstructor()) { + // Pretend it's void so less special casing needed when look at dtypes + nodep->v3error("Unsupported: new constructor"); + nodep->dtypeSetVoid(); + } else if (nodep->fvarp()) { m_funcp = VN_CAST(nodep, Func); UASSERT_OBJ(m_funcp, nodep, "FTask with function variable, but isn't a function"); nodep->dtypeFrom(nodep->fvarp()); // Which will get it from fvarp()->dtypep() diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 7b773f820..72d32d051 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -26,6 +26,7 @@ #include "V3Case.h" #include "V3Cast.h" #include "V3Changed.h" +#include "V3Class.h" #include "V3Clean.h" #include "V3Clock.h" #include "V3Combine.h" @@ -228,6 +229,9 @@ static void process() { // Flatten hierarchy, creating a SCOPE for each module's usage as a cell V3Scope::scopeAll(v3Global.rootp()); V3LinkDot::linkDotScope(v3Global.rootp()); + + // Relocate classes (after linkDot) + V3Class::classAll(v3Global.rootp()); } //--SCOPE BASED OPTIMIZATIONS-------------- diff --git a/src/verilog.y b/src/verilog.y index 75a34552b..7fbc7200b 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3532,15 +3532,16 @@ funcId: // IEEE: function_data_type_or_implicit + part of function_bod funcIdNew: // IEEE: from class_constructor_declaration yNEW__ETC { $$ = new AstFunc($1, "new", NULL, NULL); - BBUNSUP($1, "Unsupported: new constructor"); + $$->isConstructor(true); SYMP->pushNewUnder($$, NULL); } | yNEW__PAREN { $$ = new AstFunc($1, "new", NULL, NULL); - BBUNSUP($1, "Unsupported: new constructor"); + $$->isConstructor(true); SYMP->pushNewUnder($$, NULL); } | class_scopeWithoutId yNEW__PAREN { $$ = new AstFunc($2, "new", NULL, NULL); BBUNSUP($2, "Unsupported: scoped new constructor"); + $$->isConstructor(true); SYMP->pushNewUnder($$, NULL); } ; @@ -5435,7 +5436,9 @@ class_declaration: // ==IEEE: part of class_declaration classFront parameter_port_listE classExtendsE classImplementsE ';' class_itemListE yENDCLASS endLabelE { $$ = $1; $1->addMembersp($2); - $1->addMembersp($4); $1->addMembersp($6); + $1->extendsp($3); + $1->addMembersp($4); + $1->addMembersp($6); SYMP->popScope($$); GRAMMARP->endLabel($7, $1, $8); } ; @@ -5443,8 +5446,7 @@ class_declaration: // ==IEEE: part of class_declaration classFront: // IEEE: part of class_declaration classVirtualE yCLASS lifetimeE idAny/*class_identifier*/ { $$ = new AstClass($2, *$4); - SYMP->pushNew($$); - BBUNSUP($2, "Unsupported: classes"); } + SYMP->pushNew($$); } // // IEEE: part of interface_class_declaration | yINTERFACE yCLASS lifetimeE idAny/*class_identifier*/ { $$ = new AstClass($2, *$4); @@ -5473,10 +5475,11 @@ classExtendsList: // IEEE: part of class_declaration classExtendsOne: // IEEE: part of class_declaration class_typeWithoutId - { $$ = NULL; BBUNSUP($1, "Unsupported: extends"); } + { $$ = new AstClassExtends($1->fileline(), $1); } // // IEEE: Might not be legal to have more than one set of parameters in an extends | class_typeWithoutId '(' list_of_argumentsE ')' - { $$ = NULL; BBUNSUP($1, "Unsupported: extends"); } + { $$ = new AstClassExtends($1->fileline(), $1); + if ($3) BBUNSUP($3, "Unsupported: extends with parameters"); } ; classImplementsE: // IEEE: part of class_declaration diff --git a/test_regress/t/t_class1.out b/test_regress/t/t_class1.out new file mode 100644 index 000000000..d88b62e63 --- /dev/null +++ b/test_regress/t/t_class1.out @@ -0,0 +1,4 @@ +Display: null = "null" +Display: newed = "`{imembera:'h0, imemberb:'h0}" +Display: set = "`{imembera:'ha, imemberb:'h14}" +*-* All Finished *-* diff --git a/test_regress/t/t_class1.pl b/test_regress/t/t_class1.pl new file mode 100755 index 000000000..2ba855492 --- /dev/null +++ b/test_regress/t/t_class1.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class1.v b/test_regress/t/t_class1.v new file mode 100644 index 000000000..6d9a663f1 --- /dev/null +++ b/test_regress/t/t_class1.v @@ -0,0 +1,29 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +typedef class Cls; + +class Cls; + int imembera; + int imemberb; +endclass : Cls + +module t (/*AUTOARG*/); + initial begin + Cls c; + if (c != null) $stop; + $display("Display: null = \"%p\"", c); // null + c = new; + $display("Display: newed = \"%p\"", c); // '{imembera:0, imemberb:0} + c.imembera = 10; + c.imemberb = 20; + $display("Display: set = \"%p\"", c); // '{imembera:10, imemberb:20} + if (c.imembera != 10) $stop; + if (c.imemberb != 20) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class2.out b/test_regress/t/t_class2.out new file mode 100644 index 000000000..7787ca18d --- /dev/null +++ b/test_regress/t/t_class2.out @@ -0,0 +1,10 @@ +%Error: t/t_class2.v:35:14: Unsupported: Hierarchical class references + 35 | if (Cls::ENUM_VAL != 22) $stop; + | ^~ +%Error: t/t_class2.v:35:16: Unsupported: scoped class reference + 35 | if (Cls::ENUM_VAL != 22) $stop; + | ^~~~~~~~ +%Error: t/t_class2.v:34:11: Unsupported: scoped class reference + 34 | if (Pkg::ENUMP_VAL != 33) $stop; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class2.pl b/test_regress/t/t_class2.pl new file mode 100755 index 000000000..fc2b215fb --- /dev/null +++ b/test_regress/t/t_class2.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); +# +#file_grep_not("$Self->{obj_dir}/V$Self->{name}__Syms.h", qr/Dead/x); + +ok(1); +1; diff --git a/test_regress/t/t_class2.v b/test_regress/t/t_class2.v new file mode 100644 index 000000000..774e95344 --- /dev/null +++ b/test_regress/t/t_class2.v @@ -0,0 +1,40 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +package Pkg; + typedef enum { ENUMP_VAL = 33 } enump_t; +endpackage + +module t (/*AUTOARG*/); +class Cls; + int imembera; + int imemberb; + typedef enum { ENUM_VAL = 22 } enum_t; +endclass : Cls + + Cls c; + Cls d; + + initial begin + // Alternate between two versions to make sure we don't + // constant propagate between them. + c = new; + d = new; + c.imembera = 10; + d.imembera = 11; + c.imemberb = 20; + d.imemberb = 21; + if (c.imembera != 10) $stop; + if (d.imembera != 11) $stop; + if (c.imemberb != 20) $stop; + if (d.imemberb != 21) $stop; + if (Pkg::ENUMP_VAL != 33) $stop; + if (Cls::ENUM_VAL != 22) $stop; + if (c.ENUM_VAL != 22) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_class.out b/test_regress/t/t_class_class.out new file mode 100644 index 000000000..65f4f5ce1 --- /dev/null +++ b/test_regress/t/t_class_class.out @@ -0,0 +1,4 @@ +%Error: t/t_class_class.v:12:4: Unsupported: class within class + 12 | class SubCls; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_class.pl b/test_regress/t/t_class_class.pl new file mode 100755 index 000000000..c08fc990a --- /dev/null +++ b/test_regress/t/t_class_class.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_class.v b/test_regress/t/t_class_class.v new file mode 100644 index 000000000..ef8596298 --- /dev/null +++ b/test_regress/t/t_class_class.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Note UVM internals do not require classes-in-classes +package P; +class Cls; + int imembera; + int imemberb; + class SubCls; + int smembera; + int smemberb; + endclass : SubCls + SubCls sc; +endclass : Cls +endpackage : P + +module t (/*AUTOARG*/); + P::Cls c; + initial begin + c = new; + c.imembera = 10; + c.imemberb = 20; + c.sc = new; + c.sc.smembera = 30; + c.sc.smemberb = 40; + if (c.imembera != 10) $stop; + if (c.imemberb != 20) $stop; + if (c.sc.smembera != 30) $stop; + if (c.sc.smemberb != 40) $stop; + end +endmodule diff --git a/test_regress/t/t_class_copy.pl b/test_regress/t/t_class_copy.pl new file mode 100755 index 000000000..27b3049d2 --- /dev/null +++ b/test_regress/t/t_class_copy.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_copy.v b/test_regress/t/t_class_copy.v new file mode 100644 index 000000000..9fba2e7dd --- /dev/null +++ b/test_regress/t/t_class_copy.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + int imembera; + function int inc_methoda; imembera += 1; return imembera; endfunction +endclass + +module t (/*AUTOARG*/); + initial begin + Cls c1; + Cls c2; + Cls c3; + c1 = new; + c1.imembera = 10; + if (c1.inc_methoda() != 11) $stop; + + // Assignment + c2 = c1; + if (c1.inc_methoda() != 12) $stop; + if (c2.inc_methoda() != 13) $stop; + if (c1.inc_methoda() != 14) $stop; + + // Shallow copy + c3 = new c1; + + if (c1.inc_methoda() != 15) $stop; + if (c3.inc_methoda() != 15) $stop; + if (c1.inc_methoda() != 16) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_copy_bad.out b/test_regress/t/t_class_copy_bad.out new file mode 100644 index 000000000..5b1c726b6 --- /dev/null +++ b/test_regress/t/t_class_copy_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_class_copy_bad.v:19:16: New-as-copier passed different data type 'CLASSREFDTYPE 'Cls'' then expected 'CLASSREFDTYPE 'Other'' + : ... In instance t + 19 | c1 = new co; + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_copy_bad.pl b/test_regress/t/t_class_copy_bad.pl new file mode 100755 index 000000000..43e2f6762 --- /dev/null +++ b/test_regress/t/t_class_copy_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_copy_bad.v b/test_regress/t/t_class_copy_bad.v new file mode 100644 index 000000000..d94615f08 --- /dev/null +++ b/test_regress/t/t_class_copy_bad.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Other; +endclass + +class Cls; + int imembera; + function int inc_methoda; imembera += 1; return imembera; endfunction +endclass + +module t (/*AUTOARG*/); + initial begin + Cls c1; + Other co; + c1 = new co; // Bad, incompatible types + end +endmodule diff --git a/test_regress/t/t_class_dead.pl b/test_regress/t/t_class_dead.pl new file mode 100755 index 000000000..d720a09b2 --- /dev/null +++ b/test_regress/t/t_class_dead.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +$Self->{vlt_all} and unsupported("Verilator unsupported, class dead"); + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +file_grep_not("$Self->{obj_dir}/V$Self->{name}__Syms.h", qr/dead/ix); + +ok(1); +1; diff --git a/test_regress/t/t_class_dead.v b/test_regress/t/t_class_dead.v new file mode 100644 index 000000000..28e75d3ad --- /dev/null +++ b/test_regress/t/t_class_dead.v @@ -0,0 +1,30 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class EmptyClass_Dead; +endclass + +module Mod_Dead; +class ModClass_Dead; + int memberb_dead; +endclass +endmodule + +//TODO dead check with class extends + +module t (/*AUTOARG*/); + + generate + if (0) begin + Mod_Dead cell_dead(); + end + endgenerate + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_enum.pl b/test_regress/t/t_class_enum.pl new file mode 100755 index 000000000..27b3049d2 --- /dev/null +++ b/test_regress/t/t_class_enum.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_enum.v b/test_regress/t/t_class_enum.v new file mode 100644 index 000000000..c87a0adb1 --- /dev/null +++ b/test_regress/t/t_class_enum.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + +class Cls; + typedef enum {A = 10, B = 20, C = 30} en_t; +endclass + + initial begin + Cls c; + if (c.A != 10) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_extends.out b/test_regress/t/t_class_extends.out new file mode 100644 index 000000000..9d4b05199 --- /dev/null +++ b/test_regress/t/t_class_extends.out @@ -0,0 +1,10 @@ +%Error: t/t_class_extends.v:13:21: Unsupported: class extends + 13 | class Base1 extends Base0; + | ^~~~~ +%Error: t/t_class_extends.v:17:21: Unsupported: class extends + 17 | class Base2 extends Base1; + | ^~~~~ +%Error: t/t_class_extends.v:21:19: Unsupported: class extends + 21 | class Cls extends Base2; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends.pl b/test_regress/t/t_class_extends.pl new file mode 100755 index 000000000..64b3d2dde --- /dev/null +++ b/test_regress/t/t_class_extends.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends.v b/test_regress/t/t_class_extends.v new file mode 100644 index 000000000..66120b89c --- /dev/null +++ b/test_regress/t/t_class_extends.v @@ -0,0 +1,42 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +typedef class Cls; + +class Base0; + // No members to check that to_string handles this +endclass + +class Base1 extends Base0; + int b1member; +endclass + +class Base2 extends Base1; + int b2member; +endclass + +class Cls extends Base2; + int imembera; + int imemberb; +endclass : Cls + +module t (/*AUTOARG*/); + initial begin + Cls c; + c = new; + c.b1member = 10; + c.b2member = 30; + c.imembera = 100; + c.imemberb = 110; + $display("Display: set = \"%p\"", c); // '{all 4 members} + if (c.b1member != 10) $stop; + if (c.b2member != 30) $stop; + if (c.imembera != 100) $stop; + if (c.imemberb != 110) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_extends_bad.out b/test_regress/t/t_class_extends_bad.out new file mode 100644 index 000000000..41a715c41 --- /dev/null +++ b/test_regress/t/t_class_extends_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_class_extends_bad.v:13:26: Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13), and unsupported for interface classes. + 13 | class Cls extends Base1, Base2; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_bad.pl b/test_regress/t/t_class_extends_bad.pl new file mode 100755 index 000000000..43e2f6762 --- /dev/null +++ b/test_regress/t/t_class_extends_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_bad.v b/test_regress/t/t_class_extends_bad.v new file mode 100644 index 000000000..8e16f2484 --- /dev/null +++ b/test_regress/t/t_class_extends_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Base1; +endclass + +class Base2; +endclass + +class Cls extends Base1, Base2; +endclass + +module t (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_class_forward.pl b/test_regress/t/t_class_forward.pl new file mode 100755 index 000000000..27b3049d2 --- /dev/null +++ b/test_regress/t/t_class_forward.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_forward.v b/test_regress/t/t_class_forward.v new file mode 100644 index 000000000..04e95d5b6 --- /dev/null +++ b/test_regress/t/t_class_forward.v @@ -0,0 +1,40 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +package P; + typedef class ClsB; +class ClsA; + int imembera; + ClsB b; +endclass +class ClsB; + int imemberb; + ClsA a; +endclass +endpackage + +module t (/*AUTOARG*/); + P::ClsA ca; + P::ClsB cb; + initial begin + // Alternate between two versions to make sure we don't + // constant propagate between them. + ca = new; + cb = new; + ca.b = new; + cb.a = new; + ca.imembera = 100; + ca.b.imemberb = 111; + cb.imemberb = 200; + cb.a.imembera = 202; + if (ca.imembera != 100) $stop; + if (ca.b.imemberb != 111) $stop; + if (cb.imemberb != 200) $stop; + if (cb.a.imembera != 202) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_local.out b/test_regress/t/t_class_local.out new file mode 100644 index 000000000..397a3ef37 --- /dev/null +++ b/test_regress/t/t_class_local.out @@ -0,0 +1,7 @@ +%Error: t/t_class_local.v:12:22: Unsupported: initial value on member + 12 | local int m_loc = 2; + | ^ +%Error: t/t_class_local.v:13:27: Unsupported: initial value on member + 13 | protected int m_prot = B; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_class_local.pl b/test_regress/t/t_class_local.pl new file mode 100755 index 000000000..64b3d2dde --- /dev/null +++ b/test_regress/t/t_class_local.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_local.v b/test_regress/t/t_class_local.v new file mode 100644 index 000000000..0df89e7a7 --- /dev/null +++ b/test_regress/t/t_class_local.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + +class Cls; + typedef enum {A = 10, B = 20, C = 30} en_t; + + local int m_loc = 2; + protected int m_prot = B; +endclass + + initial begin + Cls c; + if (c.A != 10) $stop; + c = new; + if (c.m_loc != 2) $stop; + c.m_loc = 10; + if (c.m_loc != 10) $stop; + if (c.m_prot != 20) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_member_bad.out b/test_regress/t/t_class_member_bad.out new file mode 100644 index 000000000..5e0cb3ddd --- /dev/null +++ b/test_regress/t/t_class_member_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_class_member_bad.v:11:20: Unsupported: class extends + 11 | class Cls2 extends Base1; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_member_bad.pl b/test_regress/t/t_class_member_bad.pl new file mode 100755 index 000000000..43e2f6762 --- /dev/null +++ b/test_regress/t/t_class_member_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_member_bad.v b/test_regress/t/t_class_member_bad.v new file mode 100644 index 000000000..6a9b8c682 --- /dev/null +++ b/test_regress/t/t_class_member_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Base1; + int memb1; +endclass + +class Cls2 extends Base1; + int memb2; +endclass + +module t (/*AUTOARG*/); + initial begin + Cls2 c; + c.memb3 = 3; // Not found + end +endmodule diff --git a/test_regress/t/t_class_method.pl b/test_regress/t/t_class_method.pl new file mode 100755 index 000000000..27b3049d2 --- /dev/null +++ b/test_regress/t/t_class_method.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_method.v b/test_regress/t/t_class_method.v new file mode 100644 index 000000000..feda390fd --- /dev/null +++ b/test_regress/t/t_class_method.v @@ -0,0 +1,30 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +typedef class Cls; + +class Cls; + int imembera; + function int get_methoda; return imembera; endfunction + task set_methoda(input int val); imembera = val; endtask + function void setv_methoda(input int val); imembera = val; endfunction +endclass : Cls + +module t (/*AUTOARG*/); + initial begin + Cls c; + if (c != null) $stop; + c = new; + c.imembera = 10; + if (c.get_methoda() != 10) $stop; + c.set_methoda(20); + if (c.get_methoda() != 20) $stop; + c.setv_methoda(30); + if (c.get_methoda() != 30) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_method_bad.out b/test_regress/t/t_class_method_bad.out new file mode 100644 index 000000000..3417f3ebb --- /dev/null +++ b/test_regress/t/t_class_method_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_class_method_bad.v:11:20: Unsupported: class extends + 11 | class Cls2 extends Base1; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_method_bad.pl b/test_regress/t/t_class_method_bad.pl new file mode 100755 index 000000000..43e2f6762 --- /dev/null +++ b/test_regress/t/t_class_method_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_method_bad.v b/test_regress/t/t_class_method_bad.v new file mode 100644 index 000000000..1d649080d --- /dev/null +++ b/test_regress/t/t_class_method_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Base1; + task meth1; endtask +endclass + +class Cls2 extends Base1; + task meth2; endtask +endclass + +module t (/*AUTOARG*/); + initial begin + Cls2 c; + c.meth3(); // Not found + end +endmodule diff --git a/test_regress/t/t_class_module.pl b/test_regress/t/t_class_module.pl new file mode 100755 index 000000000..27b3049d2 --- /dev/null +++ b/test_regress/t/t_class_module.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_module.v b/test_regress/t/t_class_module.v new file mode 100644 index 000000000..60f043d9c --- /dev/null +++ b/test_regress/t/t_class_module.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + +class Cls; + int imembera; + int imemberb; +endclass : Cls + +class Dead; +endclass + + initial begin + Cls c; + if (c != null) $stop; + c = new; + c.imembera = 10; + c.imemberb = 20; + if (c.imembera != 10) $stop; + if (c.imemberb != 20) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_name.out b/test_regress/t/t_class_name.out new file mode 100644 index 000000000..3543b0eaf --- /dev/null +++ b/test_regress/t/t_class_name.out @@ -0,0 +1,4 @@ +%Error: t/t_class_name.v:12:4: Unsupported: 'static' class item + 12 | static task static_name; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_name.pl b/test_regress/t/t_class_name.pl new file mode 100755 index 000000000..64b3d2dde --- /dev/null +++ b/test_regress/t/t_class_name.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_name.v b/test_regress/t/t_class_name.v new file mode 100644 index 000000000..8aa884a73 --- /dev/null +++ b/test_regress/t/t_class_name.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +task unit_name; + $write("unit_name = '%m'\n"); +endtask + +class Cls; + static task static_name; + $write("static_name = '%m'\n"); + endtask + task nonstatic_name; + $write("nonstatic_name = '%m'\n"); + endtask +endclass : Cls + +module t (/*AUTOARG*/); + initial begin + Cls c; + c = new; + $write("t = '%m'\n"); + unit_name(); + $write("Below results vary with simulator.\n"); + // E.g. '$unit.\Cls::static_name ' + // E.g. '$unit_x.Cls.static_name' + c.static_name(); + c.nonstatic_name(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_new.out b/test_regress/t/t_class_new.out new file mode 100644 index 000000000..6ddfd5636 --- /dev/null +++ b/test_regress/t/t_class_new.out @@ -0,0 +1,13 @@ +%Error: t/t_class_new.v:9:13: Unsupported: new constructor + : ... In instance t + 9 | function new(); + | ^~~ +%Error: t/t_class_new.v:16:13: Unsupported: new constructor + : ... In instance t + 16 | function new(int i); + | ^~~ +%Error: t/t_class_new.v:27:12: Unsupported: new with arguments + : ... In instance t + 27 | c2 = new(2); + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_new.pl b/test_regress/t/t_class_new.pl new file mode 100755 index 000000000..64b3d2dde --- /dev/null +++ b/test_regress/t/t_class_new.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_new.v b/test_regress/t/t_class_new.v new file mode 100644 index 000000000..27a806465 --- /dev/null +++ b/test_regress/t/t_class_new.v @@ -0,0 +1,33 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class ClsNoArg; + int imembera; + function new(); + imembera = 5; + endfunction +endclass + +class ClsArg; + int imembera; + function new(int i); + imembera = i + 1; + endfunction +endclass + +module t (/*AUTOARG*/); + initial begin + ClsNoArg c1; + ClsArg c2; + c1 = new; + if (c1.imembera != 5) $stop; + c2 = new(2); + if (c2.imembera != 3) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_new_bad.out b/test_regress/t/t_class_new_bad.out new file mode 100644 index 000000000..293a4cd3f --- /dev/null +++ b/test_regress/t/t_class_new_bad.out @@ -0,0 +1,13 @@ +%Error: t/t_class_new_bad.v:10:13: Unsupported: new constructor + : ... In instance t + 10 | function new(); + | ^~~ +%Error: t/t_class_new_bad.v:17:13: Unsupported: new constructor + : ... In instance t + 17 | function new(int i); + | ^~~ +%Error: t/t_class_new_bad.v:26:12: Unsupported: new with arguments + : ... In instance t + 26 | c1 = new(3); + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_new_bad.pl b/test_regress/t/t_class_new_bad.pl new file mode 100755 index 000000000..43e2f6762 --- /dev/null +++ b/test_regress/t/t_class_new_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_new_bad.v b/test_regress/t/t_class_new_bad.v new file mode 100644 index 000000000..4e721bd61 --- /dev/null +++ b/test_regress/t/t_class_new_bad.v @@ -0,0 +1,30 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + + +class ClsNoArg; + int imembera; + function new(); + imembera = 5; + endfunction +endclass + +class ClsArg; + int imembera; + function new(int i); + imembera = i + 1; + endfunction +endclass + +module t (/*AUTOARG*/); + initial begin + ClsNoArg c1; + ClsArg c2; + c1 = new(3); // Bad, called with arg + c2 = new(); // Bad, called without arg + $stop; + end +endmodule diff --git a/test_regress/t/t_class_null_bad.out b/test_regress/t/t_class_null_bad.out new file mode 100644 index 000000000..c2c9e00be --- /dev/null +++ b/test_regress/t/t_class_null_bad.out @@ -0,0 +1,2 @@ +%Error: t/t_class_null_bad.v:15: Null pointer dereferenced +Aborting... diff --git a/test_regress/t/t_class_null_bad.pl b/test_regress/t/t_class_null_bad.pl new file mode 100755 index 000000000..758049687 --- /dev/null +++ b/test_regress/t/t_class_null_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_null_bad.v b/test_regress/t/t_class_null_bad.v new file mode 100644 index 000000000..e45c24c10 --- /dev/null +++ b/test_regress/t/t_class_null_bad.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + int imembera; +endclass : Cls + +module t (/*AUTOARG*/); + Cls c; + initial begin + c = null; // Not really required as null is default + c.imembera = 10; // BAD IEEE 8.4 + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_package.pl b/test_regress/t/t_class_package.pl new file mode 100755 index 000000000..27b3049d2 --- /dev/null +++ b/test_regress/t/t_class_package.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_package.v b/test_regress/t/t_class_package.v new file mode 100644 index 000000000..5cae60a8c --- /dev/null +++ b/test_regress/t/t_class_package.v @@ -0,0 +1,47 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +package pkga; + int pvar; + class MyClass; + int member; + function int getpvar(); return pvar; endfunction + endclass +endpackage + +package pkgb; + int pvar; + class MyClass; + int member; + function int getpvar(); return pvar; endfunction + function int getavar(); return pkga::pvar; endfunction + endclass +endpackage + +module t (/*AUTOARG*/); + initial begin + pkga::MyClass a; + pkgb::MyClass b; + + pkga::pvar = 100; + pkgb::pvar = 200; + if (pkga::pvar != 100) $stop; + if (pkgb::pvar != 200) $stop; + + a = new; + b = new; + a.member = 10; + b.member = 20; + if (a.member != 10) $stop; + if (b.member != 20) $stop; + + if (a.getpvar() != 100) $stop; + if (b.getpvar() != 200) $stop; + if (b.getavar() != 100) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_param.out b/test_regress/t/t_class_param.out new file mode 100644 index 000000000..caccfa6de --- /dev/null +++ b/test_regress/t/t_class_param.out @@ -0,0 +1,4 @@ +%Error: t/t_class_param.v:20:11: Unsupported: Parameter classes + 20 | Cls #(.P(4)) c4; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_class_param.pl b/test_regress/t/t_class_param.pl new file mode 100755 index 000000000..64b3d2dde --- /dev/null +++ b/test_regress/t/t_class_param.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param.v b/test_regress/t/t_class_param.v new file mode 100644 index 000000000..6313faf57 --- /dev/null +++ b/test_regress/t/t_class_param.v @@ -0,0 +1,40 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + +class Cls #(parameter P = 12); + bit [P-1:0] member; + function bit [P-1:0] get_member; + return member; + endfunction + function int get_p; + return P; + endfunction +endclass + + Cls c12; + Cls #(.P(4)) c4; + + initial begin + c12 = new; + c4 = new; + if (c12.P != 12) $stop; + if (c4.P != 4) $stop; + if (c12.get_p() != 12) $stop; + if (c4.get_p() != 4) $stop; + // verilator lint_off WIDTH + c12.member = 32'haaaaaaaa; + c4.member = 32'haaaaaaaa; + // verilator lint_on WIDTH + if (c12.member != 12'haaa) $stop; + if (c4.member != 4'ha) $stop; + if (c12.get_member() != 12'haaa) $stop; + if (c4.get_member() != 4'ha) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_static_order.out b/test_regress/t/t_class_static_order.out new file mode 100644 index 000000000..e1f427b0a --- /dev/null +++ b/test_regress/t/t_class_static_order.out @@ -0,0 +1,10 @@ +%Error: t/t_class_static_order.v:23:4: Unsupported: 'static' class item + 23 | static ClsZ z = new; + | ^~~~~~ +%Error: t/t_class_static_order.v:34:4: Unsupported: 'static' class item + 34 | static ClsA a = new; + | ^~~~~~ +%Error: t/t_class_static_order.v:35:4: Unsupported: 'static' class item + 35 | static ClsB b = new; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_static_order.pl b/test_regress/t/t_class_static_order.pl new file mode 100755 index 000000000..64b3d2dde --- /dev/null +++ b/test_regress/t/t_class_static_order.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_static_order.v b/test_regress/t/t_class_static_order.v new file mode 100644 index 000000000..d9fda4eca --- /dev/null +++ b/test_regress/t/t_class_static_order.v @@ -0,0 +1,60 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class ClsZ; + function new(); + $display("ClsZ::new"); + endfunction +endclass + +class ClsA; + function new(); + $display("ClsA::new"); + endfunction + function void access; + $display("ClsA::access"); + endfunction +endclass + +class ClsB; + static ClsZ z = new; + function new(); + $display("ClsB::new"); + endfunction + function void access; + $display("ClsB::access"); + endfunction +endclass + +class ClsC; + // Elaboration will call these + static ClsA a = new; + static ClsB b = new; + function new(); + $display("ClsC::new"); + endfunction + function void access; + $display("ClsC::access"); + a = new; + a.access; + endfunction +endclass + +module t (/*AUTOARG*/); + function void makec; + ClsC c; + $display("c = new;"); + c = new; + $display("c.access;"); + c.access; + endfunction + initial begin + $display("makec;"); + makec; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_unsup_bad.out b/test_regress/t/t_class_unsup_bad.out index 1bc20487b..42116d10f 100644 --- a/test_regress/t/t_class_unsup_bad.out +++ b/test_regress/t/t_class_unsup_bad.out @@ -4,9 +4,6 @@ %Error: t/t_class_unsup_bad.v:8:1: Unsupported: virtual data type 8 | virtual vi_t vi2; | ^~~~~~~ -%Error: t/t_class_unsup_bad.v:13:1: Unsupported: classes - 13 | class C #(parameter P=1); - | ^~~~~ %Error: t/t_class_unsup_bad.v:14:26: Unsupported: class parameters 14 | localparam LOCPAR = 10; | ^ @@ -14,15 +11,18 @@ 25 | virtual function void func_virtual; endfunction | ^~~~~~~ %Error: t/t_class_unsup_bad.v:26:4: Unsupported: pure virtual class method - 26 | pure virtual function void func_pure_virtual; endfunction + 26 | pure virtual function void func_pure_virtual; | ^~~~ -%Error: t/t_class_unsup_bad.v:26:50: syntax error, unexpected endfunction - 26 | pure virtual function void func_pure_virtual; endfunction - | ^~~~~~~~~~~ +%Error: t/t_class_unsup_bad.v:27:4: Unsupported: automatic class member qualifier + 27 | automatic function void func_automatic; endfunction + | ^~~~~~~~~ +%Error: t/t_class_unsup_bad.v:28:4: Unsupported: const class member qualifier + 28 | const function void func_const; endfunction + | ^~~~~ +%Error: t/t_class_unsup_bad.v:29:4: Unsupported: extern class method prototype + 29 | extern task exttask; + | ^~~~~~ %Error: t/t_class_unsup_bad.v:32:1: Unsupported: virtual classes 32 | virtual class VC; | ^~~~~~~ -%Error: t/t_class_unsup_bad.v:32:9: Unsupported: classes - 32 | virtual class VC; - | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_unsup_bad.pl b/test_regress/t/t_class_unsup_bad.pl index 2365c113e..be57f782a 100755 --- a/test_regress/t/t_class_unsup_bad.pl +++ b/test_regress/t/t_class_unsup_bad.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2019 by Wilson Snyder. This program is free software; you +# Copyright 2020 by Wilson Snyder. This program is free software; you # can redistribute it and/or modify it under the terms of either the GNU # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. diff --git a/test_regress/t/t_class_unsup_bad.v b/test_regress/t/t_class_unsup_bad.v index 79546e2a7..7d4e032ce 100644 --- a/test_regress/t/t_class_unsup_bad.v +++ b/test_regress/t/t_class_unsup_bad.v @@ -23,7 +23,7 @@ class C #(parameter P=1); task classtask; endtask function int classfunc; endfunction virtual function void func_virtual; endfunction - pure virtual function void func_pure_virtual; endfunction + pure virtual function void func_pure_virtual; automatic function void func_automatic; endfunction const function void func_const; endfunction extern task exttask; diff --git a/test_regress/t/t_interface_param_acc_bits.pl b/test_regress/t/t_interface_param_acc_bits.pl index 4c3cbf1ae..40b4c78de 100755 --- a/test_regress/t/t_interface_param_acc_bits.pl +++ b/test_regress/t/t_interface_param_acc_bits.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => ($Self->{vlt} || $Self->{vltmt}), # Unsupported bug1523 + fails => $Self->{vlt_all}, # Unsupported bug1523 expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_savable_class_bad.out b/test_regress/t/t_savable_class_bad.out new file mode 100644 index 000000000..8128ec348 --- /dev/null +++ b/test_regress/t/t_savable_class_bad.out @@ -0,0 +1,2 @@ +%Error: Unsupported: --savable with dynamic new +%Error: Exiting due to diff --git a/test_regress/t/t_savable_class_bad.pl b/test_regress/t/t_savable_class_bad.pl new file mode 100755 index 000000000..fdcacb7d3 --- /dev/null +++ b/test_regress/t/t_savable_class_bad.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + v_flags2 => ["--savable"], + save_time => 500, + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_savable_class_bad.v b/test_regress/t/t_savable_class_bad.v new file mode 100644 index 000000000..08efffcfd --- /dev/null +++ b/test_regress/t/t_savable_class_bad.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + int imembera; +endclass : Cls + +module t (/*AUTOARG*/); + initial begin + Cls c; + if (c != null) $stop; + c = new; + c.imembera = 10; + if (c.imembera != 10) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From e55338f9277192d2ec9bad13571d7758e2854f91 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 10:11:28 -0400 Subject: [PATCH 010/127] Support $fflush without arguments, #1638. --- Changes | 2 ++ include/verilated.cpp | 4 ++++ src/V3EmitC.cpp | 2 +- src/verilog.y | 2 +- test_regress/t/t_sys_file_basic.v | 2 ++ 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 938de3927..0c5e94bfc 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Add simplistic class support with many restrictions, see manual, #377. +**** Support $fflush without arguments, #1638. + * Verilator 4.032 2020-04-04 diff --git a/include/verilated.cpp b/include/verilated.cpp index efdb84aff..adc6abacb 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1181,6 +1181,10 @@ void VL_FCLOSE_I(IData fdi) VL_MT_SAFE { VerilatedImp::fdDelete(fdi); } +void VL_FFLUSH_ALL() VL_MT_SAFE { + fflush(stdout); +} + 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 = ""; diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 8d0a85f66..6502f8bb4 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -557,7 +557,7 @@ public: } virtual void visit(AstFFlush* nodep) VL_OVERRIDE { if (!nodep->filep()) { - puts("fflush(stdout);\n"); + puts("Verilated::flushCall();\n"); } else { puts("if ("); iterateAndNextNull(nodep->filep()); diff --git a/src/verilog.y b/src/verilog.y index 7fbc7200b..6013f2248 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3232,7 +3232,7 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_SYSTEM '(' expr ')' { $$ = new AstSystemT($1, $3); } // | yD_FCLOSE '(' idClassSel ')' { $$ = new AstFClose($1, $3); } - | yD_FFLUSH parenE { $$ = NULL; BBUNSUP($1, "Unsupported: $fflush of all handles does not map to C++."); } + | yD_FFLUSH parenE { $$ = new AstFFlush($1, NULL); } | yD_FFLUSH '(' expr ')' { $$ = new AstFFlush($1, $3); } | yD_FINISH parenE { $$ = new AstFinish($1); } | yD_FINISH '(' expr ')' { $$ = new AstFinish($1); DEL($3); } diff --git a/test_regress/t/t_sys_file_basic.v b/test_regress/t/t_sys_file_basic.v index bd431eb33..43cbf3c31 100644 --- a/test_regress/t/t_sys_file_basic.v +++ b/test_regress/t/t_sys_file_basic.v @@ -61,6 +61,8 @@ module t; $fwriteb(file, "b: "); $fwriteb(file, i); $fwriteb(file, " "); $fdisplayb(file, i); $fflush(file); + $fflush(); + $fflush; $fclose(file); `ifdef verilator From b617cd5549b17e7aaa6e4286a8a8630fab85b52b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 10:26:53 -0400 Subject: [PATCH 011/127] Internals: Add V3ERROR_NA_RETURN. No functional change. --- src/V3AstNodes.h | 202 +++++++++++++++++++++++------------------------ src/V3Error.h | 6 ++ 2 files changed, 107 insertions(+), 101 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index df358b486..2b44aa7a9 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -139,8 +139,8 @@ public: uint32_t toUInt() const { return num().toUInt(); } vlsint32_t toSInt() const { return num().toSInt(); } vluint64_t toUQuad() const { return num().toUQuad(); } - virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } virtual V3Hash sameHash() const { return V3Hash(num().toHash()); } virtual bool same(const AstNode* samep) const { @@ -186,7 +186,7 @@ public: bool littleEndian() const { return m_littleEndian; } void littleEndian(bool flag) { m_littleEndian = flag; } virtual void dump(std::ostream& str) const; - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { return true; } }; @@ -200,8 +200,8 @@ public: setOp1p(dtp); } ASTNODE_NODE_FUNCS(AssocRange) - virtual string emitC() { V3ERROR_NA; return ""; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { return true; } AstNodeDType* keyDTypep() const { return VN_CAST(op1p(), NodeDType); } @@ -214,8 +214,8 @@ public: explicit AstQueueRange(FileLine* fl) : ASTGEN_SUPER(fl) {} ASTNODE_NODE_FUNCS(QueueRange) - virtual string emitC() { V3ERROR_NA; return ""; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { return true; } }; @@ -226,7 +226,7 @@ public: explicit AstUnsizedRange(FileLine* fl) : ASTGEN_SUPER(fl) {} ASTNODE_NODE_FUNCS(UnsizedRange) - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitVerilog() { return "[]"; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { return true; } @@ -241,7 +241,7 @@ public: } ASTNODE_NODE_FUNCS(GatePin) virtual string emitVerilog() { return "%l"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } AstNode* exprp() const { return op1p(); } // op1 = Pin expression AstRange* rangep() const { return VN_CAST(op2p(), Range); } // op2 = Range of pin @@ -1157,8 +1157,8 @@ public: const AstEnumItemRef* sp = static_cast(samep); return itemp() == sp->itemp(); } AstEnumItem* itemp() const { return m_itemp; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep = nodep; } @@ -1399,7 +1399,7 @@ public: virtual void dump(std::ostream& str) const; virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, const V3Number& width) { out.opSel(from, bit.toUInt()+width.toUInt()-1, bit.toUInt()); } - virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual string emitC() { return this->widthp()->isOne() ? "VL_BITSEL_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri)" @@ -1443,8 +1443,8 @@ public: virtual void dump(std::ostream& str) const; virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo, const V3Number& width) { V3ERROR_NA; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially - virtual string emitC() { V3ERROR_NA; return ""; } // Removed before EmitC + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } // Removed before EmitC virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return false; } virtual bool cleanRhs() const { return true; } @@ -1970,8 +1970,8 @@ public: else return (hiername()==samep->hiername() && varp()->name()==samep->varp()->name()); } virtual int instrCount() const { return widthInstrs()*(lvalue()?1:instrCountLd()); } - virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } }; @@ -1997,8 +1997,8 @@ public: string prettyDotted() const { return prettyName(dotted()); } string inlinedDots() const { return m_inlinedDots; } void inlinedDots(const string& flag) { m_inlinedDots = flag; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } virtual int instrCount() const { return widthInstrs(); } virtual V3Hash sameHash() const { return V3Hash(V3Hash(varp()), V3Hash(dotted())); } @@ -2203,8 +2203,8 @@ public: virtual V3Hash sameHash() const { return V3Hash(m_name); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; /* How can from be a const? */ } - virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return false; } virtual bool same(const AstNode* samep) const { return true; } // dtype comparison does it virtual int instrCount() const { return widthInstrs(); } @@ -2466,8 +2466,8 @@ public: const AstParseRef* asamep = static_cast(samep); return (expect() == asamep->expect() && m_name == asamep->m_name); } - virtual string emitVerilog() { V3ERROR_NA; return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual void name(const string& name) { m_name = name; } VParseRefExp expect() const { return m_expect; } void expect(VParseRefExp exp) { m_expect = exp; } @@ -2509,8 +2509,8 @@ public: return new AstDot(fl, new AstPackageRef(fl, packagep), rhsp); } virtual void dump(std::ostream& str) const; - virtual string emitVerilog() { V3ERROR_NA; return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } AstNode* lhsp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } }; @@ -2522,7 +2522,7 @@ public: : ASTGEN_SUPER(fl) {} ASTNODE_NODE_FUNCS(Unbounded) virtual string emitVerilog() { return "$"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } }; //###################################################################### @@ -2760,7 +2760,7 @@ public: AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignAlias) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { V3ERROR_NA; return NULL; } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { V3ERROR_NA_RETURN(NULL); } virtual bool brokeLhsMustBeLvalue() const { return false; } }; @@ -3162,7 +3162,7 @@ public: ASTNODE_NODE_FUNCS(DumpCtl) virtual string verilogKwd() const { return ctlType().ascii(); } virtual string emitVerilog() { return "%f" + verilogKwd() + "(%l)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isOutputter() const { return true; } @@ -3217,8 +3217,8 @@ public: ASTNODE_NODE_FUNCS(SFormat) virtual const char* broken() const { BROKEN_RTN(!fmtp()); return NULL; } virtual string verilogKwd() const { return "$sformat"; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return true; } virtual bool isPure() const { return true; } @@ -3352,8 +3352,8 @@ public: } ASTNODE_NODE_FUNCS(FRead) virtual string verilogKwd() const { return "$fread"; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: has 'visual' ordering @@ -3381,8 +3381,8 @@ public: } ASTNODE_NODE_FUNCS(FRewind) virtual string verilogKwd() const { return "$frewind"; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } @@ -3405,8 +3405,8 @@ public: } ASTNODE_NODE_FUNCS(FTell) virtual string verilogKwd() const { return "$ftell"; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } @@ -3434,8 +3434,8 @@ public: } ASTNODE_NODE_FUNCS(FSeek) virtual string verilogKwd() const { return "$fseek"; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: has 'visual' ordering @@ -3466,8 +3466,8 @@ public: ASTNODE_NODE_FUNCS(FScanF) virtual string name() const { return m_text; } virtual string verilogKwd() const { return "$fscanf"; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: has 'visual' ordering @@ -3499,8 +3499,8 @@ public: ASTNODE_NODE_FUNCS(SScanF) virtual string name() const { return m_text; } virtual string verilogKwd() const { return "$sscanf"; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: has 'visual' ordering @@ -3616,7 +3616,7 @@ public: ASTNODE_NODE_FUNCS(ValuePlusArgs) virtual string verilogKwd() const { return "$value$plusargs"; } virtual string emitVerilog() { return "%f$value$plusargs(%l, %k%r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool cleanOut() const { return true; } @@ -3944,7 +3944,7 @@ public: AstNode* exprp() const { return op1p(); } // op1 = LHS expression to compare with AstNode* itemsp() const { return op2p(); } // op2 = RHS, possibly a list of expr or AstInsideRange virtual string emitVerilog() { return "%l inside { %r }"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return false; } // NA }; @@ -3958,7 +3958,7 @@ public: AstNode* lhsp() const { return op1p(); } // op1 = LHS AstNode* rhsp() const { return op2p(); } // op2 = RHS virtual string emitVerilog() { return "[%l:%r]"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return false; } // NA // Create AstAnd(AstGte(...), AstLte(...)) AstNode* newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp); @@ -4062,7 +4062,7 @@ public: ASTNODE_NODE_FUNCS(New) virtual V3Hash sameHash() const { return V3Hash(); } virtual string emitVerilog() { return "new"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } virtual bool same(const AstNode* samep) const { return true; } virtual int instrCount() const { return widthInstrs(); } @@ -4082,7 +4082,7 @@ public: ASTNODE_NODE_FUNCS(NewCopy) virtual V3Hash sameHash() const { return V3Hash(); } virtual string emitVerilog() { return "new"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } virtual bool same(const AstNode* samep) const { return true; } virtual int instrCount() const { return widthInstrs(); } @@ -4103,7 +4103,7 @@ public: ASTNODE_NODE_FUNCS(NewDynamic) virtual V3Hash sameHash() const { return V3Hash(); } virtual string emitVerilog() { return "new"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } virtual bool same(const AstNode* samep) const { return true; } virtual int instrCount() const { return widthInstrs(); } @@ -4173,8 +4173,8 @@ public: virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } virtual int instrCount() const { return 1; } // Rarely executes virtual string emitVerilog() { return "%l"; } - virtual string emitC() { V3ERROR_NA; return ""; } - virtual string emitSimpleOperator() { V3ERROR_NA; return "";} + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } @@ -4344,7 +4344,7 @@ public: virtual bool same(const AstNode* samep) const { return m_dpiExport == static_cast(samep)->m_dpiExport; } virtual string emitVerilog() { return ""; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } AstText* scopeAttrp() const { return VN_CAST(op1p(), Text); } void scopeAttrp(AstNode* nodep) { addOp1p(nodep); } @@ -4450,8 +4450,8 @@ public: } ASTNODE_NODE_FUNCS(UCFunc) virtual bool cleanOut() const { return false; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } AstNode* bodysp() const { return op1p(); } // op1 = expressions to print virtual bool isPure() const { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const { return true; } @@ -4485,7 +4485,7 @@ public: ASTNODE_NODE_FUNCS(NegateD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegateD(lhs); } virtual string emitVerilog() { return "%f(- %l)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "-"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -4631,7 +4631,7 @@ public: ASTNODE_NODE_FUNCS(Signed) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); out.isSigned(false); } virtual string emitVerilog() { return "%f$signed(%l)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return false; } // Eliminated before matters virtual bool sizeMattersLhs() const { return true; } // Eliminated before matters @@ -4647,7 +4647,7 @@ public: ASTNODE_NODE_FUNCS(Unsigned) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); out.isSigned(false); } virtual string emitVerilog() { return "%f$unsigned(%l)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return false; } // Eliminated before matters virtual bool sizeMattersLhs() const { return true; } // Eliminated before matters @@ -4758,7 +4758,7 @@ public: ASTNODE_NODE_FUNCS(IsUnknown) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIsUnknown(lhs); } virtual string emitVerilog() { return "%f$isunknown(%l)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return false; } virtual bool sizeMattersLhs() const { return false; } @@ -4803,8 +4803,8 @@ public: ASTNODE_NODE_FUNCS(Cast) virtual bool hasDType() const { return true; } virtual string emitVerilog() { return "((%d)'(%l))"; } - virtual string emitC() { V3ERROR_NA; return ""; } - virtual bool cleanOut() const { V3ERROR_NA; return true;} + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } AstNode* lhsp() const { return op1p(); } @@ -4821,8 +4821,8 @@ public: } ASTNODE_NODE_FUNCS(CastParse) virtual string emitVerilog() { return "((%d)'(%l))"; } - virtual string emitC() { V3ERROR_NA; return ""; } - virtual bool cleanOut() const { V3ERROR_NA; return true;} + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } AstNode* lhsp() const { return op1p(); } @@ -4839,8 +4839,8 @@ public: ASTNODE_NODE_FUNCS(CastSize) // No hasDType because widthing removes this node before the hasDType check virtual string emitVerilog() { return "((%r)'(%l))"; } - virtual string emitC() { V3ERROR_NA; return ""; } - virtual bool cleanOut() const { V3ERROR_NA; return true;} + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } AstNode* lhsp() const { return op1p(); } @@ -5294,7 +5294,7 @@ public: virtual string emitVerilog() { return "%k(%l %f| %r)"; } virtual string emitC() { return "VL_OR_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "|"; } - virtual bool cleanOut() const {V3ERROR_NA; return false;} // Lclean && Rclean + virtual bool cleanOut() const { V3ERROR_NA_RETURN(false); } virtual bool cleanLhs() const { return false; } virtual bool cleanRhs() const { return false; } virtual bool sizeMattersLhs() const { return false; } @@ -5310,7 +5310,7 @@ public: virtual string emitVerilog() { return "%k(%l %f& %r)"; } virtual string emitC() { return "VL_AND_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "&"; } - virtual bool cleanOut() const {V3ERROR_NA; return false;} // Lclean || Rclean + virtual bool cleanOut() const { V3ERROR_NA_RETURN(false); } virtual bool cleanLhs() const { return false; } virtual bool cleanRhs() const { return false; } virtual bool sizeMattersLhs() const { return false; } @@ -5373,7 +5373,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEqD(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEqD(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f== %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "=="; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5391,7 +5391,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEqN(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEqN(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f== %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "=="; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5425,7 +5425,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstNeqD(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeqD(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f!= %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "!="; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5443,7 +5443,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstNeqN(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeqN(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f!= %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "!="; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5477,7 +5477,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLtD(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtD(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f< %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "<"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5512,7 +5512,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLtN(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtN(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f< %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "<"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5546,7 +5546,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGtD(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtD(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f> %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return ">"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5581,7 +5581,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGtN(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtN(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f> %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return ">"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5616,7 +5616,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGteD(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteD(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f>= %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return ">="; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5651,7 +5651,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGteN(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteN(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f>= %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return ">="; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5686,7 +5686,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLteD(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteD(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f<= %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "<="; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5721,7 +5721,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLteN(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteN(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f<= %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "<="; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5815,7 +5815,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAddD(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAddD(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f+ %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "+"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5849,7 +5849,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstSubD(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opSubD(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f- %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "-"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5884,7 +5884,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstMulD(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opMulD(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f* %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "*"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5936,7 +5936,7 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstDivD(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDivD(lhs, rhs); } virtual string emitVerilog() { return "%k(%l %f/ %r)"; } - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "/"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -6282,9 +6282,9 @@ public: virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstBufIf1(this->fileline(), lhsp, rhsp); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opBufIf1(lhs, rhs); } virtual string emitVerilog() { return "bufif(%r,%l)"; } - virtual string emitC() { V3ERROR_NA; return "";} // Lclean || Rclean - virtual string emitSimpleOperator() { V3ERROR_NA; return "";} // Lclean || Rclean - virtual bool cleanOut() const {V3ERROR_NA; return "";} // Lclean || Rclean + virtual string emitC() { V3ERROR_NA_RETURN(""); } // Lclean || Rclean + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } // Lclean || Rclean + virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } // Lclean || Rclean virtual bool cleanLhs() const { return false; } virtual bool cleanRhs() const { return false; } virtual bool sizeMattersLhs() const { return false; } @@ -6478,11 +6478,11 @@ public: AstPast(FileLine* fl, AstNode* exprp, AstNode* ticksp) : ASTGEN_SUPER(fl) { addOp1p(exprp); addNOp2p(ticksp); } ASTNODE_NODE_FUNCS(Past) - virtual string emitVerilog() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } - virtual string emitC() { V3ERROR_NA; return "";} - virtual string emitSimpleOperator() { V3ERROR_NA; return "";} - virtual bool cleanOut() const { V3ERROR_NA; return "";} + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } virtual int instrCount() const { return widthInstrs(); } AstNode* exprp() const { return op1p(); } // op1 = expression AstNode* ticksp() const { return op2p(); } // op2 = ticks or NULL means 1 @@ -6501,9 +6501,9 @@ public: : ASTGEN_SUPER(fl) { addOp1p(exprp); } ASTNODE_NODE_FUNCS(Sampled) virtual string emitVerilog() { return "$sampled(%l)"; } - virtual string emitC() { V3ERROR_NA; return "";} - virtual string emitSimpleOperator() { V3ERROR_NA; return ""; } - virtual bool cleanOut() const { V3ERROR_NA; return ""; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } virtual int instrCount() const { return 0; } AstNode* exprp() const { return op1p(); } // op1 = expression virtual V3Hash sameHash() const { return V3Hash(); } @@ -6518,11 +6518,11 @@ public: AstPattern(FileLine* fl, AstNode* itemsp) : ASTGEN_SUPER(fl) { addNOp2p(itemsp); } ASTNODE_NODE_FUNCS(Pattern) - virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } - virtual string emitC() { V3ERROR_NA; return "";} - virtual string emitSimpleOperator() { V3ERROR_NA; return "";} - virtual bool cleanOut() const {V3ERROR_NA; return "";} + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } virtual int instrCount() const { return widthInstrs(); } AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Type assigning to @@ -6541,11 +6541,11 @@ public: : ASTGEN_SUPER(fl) { addOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); m_default = false; } ASTNODE_NODE_FUNCS(PatMember) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } - virtual string emitVerilog() { return lhssp()?"%f{%r{%k%l}}":"%l"; } - virtual string emitC() { V3ERROR_NA; return "";} - virtual string emitSimpleOperator() { V3ERROR_NA; return "";} - virtual bool cleanOut() const {V3ERROR_NA; return "";} - virtual int instrCount() const { return widthInstrs()*2; } + virtual string emitVerilog() { return lhssp() ? "%f{%r{%k%l}}" : "%l"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const { return widthInstrs() * 2; } AstNode* lhssp() const { return op1p(); } // op1 = expression to assign or another AstPattern (list if replicated) AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text) AstNode* repp() const { return op3p(); } // op3 = replication count, or NULL for count 1 @@ -7036,8 +7036,8 @@ public: virtual bool isGateOptimizable() const { return m_pure; } virtual bool isPredictOptimizable() const { return m_pure; } virtual bool cleanOut() const { return m_cleanOut; } - virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially - virtual string emitC() { V3ERROR_NA; return ""; } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { return true; } void addBodysp(AstNode* nodep) { addNOp1p(nodep); } diff --git a/src/V3Error.h b/src/V3Error.h index b6d17b768..8e347544c 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -351,6 +351,12 @@ inline void v3errorEndFatal(std::ostringstream& sstr) { v3fatalSrc("Unexpected Call"); \ } while (false) +/// Throw fatal and return a value. The return value will never really be +/// needed, but required to avoid compiler error. +#define V3ERROR_NA_RETURN(value) \ + V3ERROR_NA; \ + return value + /// Declare a convenience debug() routine that may be added to any class in /// Verilator so that --debugi- will work to control UINFOs in /// that class: From a494ad5ec7a0c728a2d87b982771d724831855e8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 11:22:05 -0400 Subject: [PATCH 012/127] Support $ferror, #1638. --- Changes | 2 +- bin/verilator | 3 ++- include/verilated.cpp | 7 +++++++ include/verilated_heavy.h | 1 + src/V3AstNodes.h | 24 ++++++++++++++++++++++++ src/V3EmitC.cpp | 7 +++++++ src/V3LinkLValue.cpp | 10 ++++++++++ src/V3LinkResolve.cpp | 4 ++++ src/V3Width.cpp | 8 ++++++++ src/verilog.l | 1 + src/verilog.y | 2 ++ test_regress/t/t_sys_file_basic.v | 7 +++++++ 12 files changed, 74 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 0c5e94bfc..9ab756798 100644 --- a/Changes +++ b/Changes @@ -7,7 +7,7 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Add simplistic class support with many restrictions, see manual, #377. -**** Support $fflush without arguments, #1638. +**** Support $ferror, and $fflush without arguments, #1638. * Verilator 4.032 2020-04-04 diff --git a/bin/verilator b/bin/verilator index 5cbf582ae..e1545e98b 100755 --- a/bin/verilator +++ b/bin/verilator @@ -3867,7 +3867,8 @@ $dumplimit/$dumpportlimit are currently ignored. The rarely used optional parameter to $finish and $stop is ignored. -=item $fopen, $fclose, $fdisplay, $feof, $fflush, $fgetc, $fgets, $fscanf, $fwrite +=item $fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets, +$fscanf, $fwrite File descriptors passed to the file PLI calls must be file descriptors, not MCDs, which includes the mode parameter to $fopen being mandatory. diff --git a/include/verilated.cpp b/include/verilated.cpp index adc6abacb..7620d76a6 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1148,6 +1148,13 @@ IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE { return got; } +IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE { + // We ignore lhs/fpi - IEEE says "most recent error" so probably good enough + IData ret = errno; + outputr = std::string(::strerror(ret)); + return ret; +} + 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]; diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 596d21292..8f8d9d383 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -424,6 +424,7 @@ inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); } extern std::string VL_TOLOWER_NN(const std::string& ld); extern std::string VL_TOUPPER_NN(const std::string& ld); +extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE; extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE; extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb, const std::string& filename, void* memp, QData start, diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 2b44aa7a9..9741eba32 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -4912,6 +4912,30 @@ public: AstNode* filep() const { return lhsp(); } }; +class AstFError : public AstNodeMath { +public: + AstFError(FileLine* fl, AstNode* filep, AstNode* strp) + : ASTGEN_SUPER(fl) { + setOp1p(filep); + setOp2p(strp); + } + ASTNODE_NODE_FUNCS(FError) + virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } + virtual string emitVerilog() { return "%f$ferror(%l, %r)"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { return true; } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + virtual int instrCount() const { return widthInstrs() * 64; } + virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering + void filep(AstNode* nodep) { setOp1p(nodep); } + AstNode* filep() const { return op1p(); } + void strp(AstNode* nodep) { setOp2p(nodep); } + AstNode* strp() const { return op2p(); } + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { return true; } +}; + class AstFGetC : public AstNodeUniop { public: AstFGetC(FileLine* fl, AstNode* lhsp) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 6502f8bb4..9c8b0ba97 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -482,6 +482,13 @@ public: putsQuoted(nodep->text()); puts(")"); } + virtual void visit(AstFError* nodep) VL_OVERRIDE { + puts("VL_FERROR_IN("); + iterateAndNextNull(nodep->filep()); + putbs(", "); + iterateAndNextNull(nodep->strp()); + puts(")"); + } virtual void visit(AstFGetS* nodep) VL_OVERRIDE { checkMaxWords(nodep); emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), NULL); diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index c4318b8cb..6788e1d9b 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -102,6 +102,16 @@ private: } m_setRefLvalue = last_setRefLvalue; } + virtual void visit(AstFError* nodep) VL_OVERRIDE { + bool last_setRefLvalue = m_setRefLvalue; + { + m_setRefLvalue = true; + iterateAndNextNull(nodep->filep()); + iterateAndNextNull(nodep->strp()); + m_setRefLvalue = false; + } + m_setRefLvalue = last_setRefLvalue; + } virtual void visit(AstFFlush* nodep) VL_OVERRIDE { bool last_setRefLvalue = m_setRefLvalue; { diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 9a24283bc..3f5765881 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -378,6 +378,10 @@ private: iterateChildren(nodep); expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); } + virtual void visit(AstFError* nodep) VL_OVERRIDE { + iterateChildren(nodep); + expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); + } virtual void visit(AstFEof* nodep) VL_OVERRIDE { iterateChildren(nodep); expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f962f46ab..c71102b12 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3088,6 +3088,14 @@ private: assertAtStatement(nodep); iterateCheckFileDesc(nodep, nodep->filep(), BOTH); } + virtual void visit(AstFError* nodep) VL_OVERRIDE { + if (m_vup->prelim()) { + iterateCheckFileDesc(nodep, nodep->filep(), BOTH); + // We only support string types, not packed array + iterateCheckString(nodep, "$ferror string result", nodep->strp(), BOTH); + nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::SIGNED); // Spec says integer return + } + } virtual void visit(AstFEof* nodep) VL_OVERRIDE { if (m_vup->prelim()) { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); diff --git a/src/verilog.l b/src/verilog.l index 2674ff260..13a3229ef 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -217,6 +217,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$fdisplayh" { FL; return yD_FDISPLAYH; } "$fdisplayo" { FL; return yD_FDISPLAYO; } "$feof" { FL; return yD_FEOF; } + "$ferror" { FL; return yD_FERROR; } "$fflush" { FL; return yD_FFLUSH; } "$fgetc" { FL; return yD_FGETC; } "$fgets" { FL; return yD_FGETS; } diff --git a/src/verilog.y b/src/verilog.y index 6013f2248..a830caba0 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -570,6 +570,7 @@ class AstSenTree; %token yD_FDISPLAYH "$fdisplayh" %token yD_FDISPLAYO "$fdisplayo" %token yD_FEOF "$feof" +%token yD_FERROR "$ferror" %token yD_FFLUSH "$fflush" %token yD_FGETC "$fgetc" %token yD_FGETS "$fgets" @@ -3331,6 +3332,7 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_DIMENSIONS,$3); } | yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); } | yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); } + | yD_FERROR '(' idClassSel ',' idClassSel ')' { $$ = new AstFError($1, $3, $5); } | yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); } | yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); } | yD_FREAD '(' idClassSel ',' expr ')' { $$ = new AstFRead($1,$3,$5,NULL,NULL); } diff --git a/test_regress/t/t_sys_file_basic.v b/test_regress/t/t_sys_file_basic.v index 43cbf3c31..fe075a6be 100644 --- a/test_regress/t/t_sys_file_basic.v +++ b/test_regress/t/t_sys_file_basic.v @@ -9,6 +9,8 @@ `define STRINGIFY(x) `"x`" `define ratio_error(a,b) (((a)>(b) ? ((a)-(b)) : ((b)-(a))) /(a)) `define checkr(gotv,expv) do if (`ratio_error((gotv),(expv))>0.0001) begin $write("%%Error: %s:%0d: got=%g exp=%g\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); module t; integer file; @@ -75,6 +77,11 @@ module t; // The "r" is required so we get a FD not a MFD file = $fopen("DOES_NOT_EXIST","r"); if (|file) $stop; // Should not exist, IE must return 0 + // Check error function + s = ""; + i = $ferror(file, s); + `checkh(i, 2); + `checks(s, "No such file or directory"); end begin From a331397954b6b49784daf46466dc19de63df956a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 11:56:15 -0400 Subject: [PATCH 013/127] Fix real conversion from constant with X/Z. --- src/V3Number.cpp | 12 ++++++++---- src/V3Number.h | 1 + test_regress/t/t_math_real.v | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/V3Number.cpp b/src/V3Number.cpp index ca092ef53..4a4a757ac 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -1907,7 +1907,8 @@ V3Number& V3Number::opBufIf1(const V3Number& ens, const V3Number& if1s) { return *this; } -V3Number& V3Number::opAssign(const V3Number& lhs) { +V3Number& V3Number::opAssign(const V3Number& lhs) { return opAssignNonXZ(lhs, false); } +V3Number& V3Number::opAssignNonXZ(const V3Number& lhs, bool ignoreXZ) { // Note may be a width change during the assign. // Special case: opAssign unlike other ops, allows this an assignment // to itself; V3Simulate does this when hits "foo=foo;" @@ -1918,8 +1919,8 @@ V3Number& V3Number::opAssign(const V3Number& lhs) { m_stringVal = lhs.m_stringVal; } else { // Also handles double as is just bits - for (int bit=0; bitwidth(); bit++) { - setBit(bit, lhs.bitIs(bit)); + for (int bit = 0; bit < this->width(); bit++) { + setBit(bit, ignoreXZ ? lhs.bitIs1(bit) : lhs.bitIs(bit)); } } } @@ -2042,7 +2043,10 @@ V3Number& V3Number::opCond(const V3Number& lhs, const V3Number& if1s, const V3Nu V3Number& V3Number::opIToRD(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); - return setDouble(lhs.toSInt()); + // IEEE says we ignore x/z in real conversions + V3Number noxz(lhs); + noxz.opAssignNonXZ(lhs); + return setDouble(noxz.toSInt()); } V3Number& V3Number::opRToIS(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); diff --git a/src/V3Number.h b/src/V3Number.h index 5c1645842..541d92360 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -273,6 +273,7 @@ public: V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1 // V3Number& opAssign (const V3Number& lhs); + V3Number& opAssignNonXZ(const V3Number& lhs, bool ignoreXZ = true); V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension V3Number& opExtendXZ(const V3Number& lhs, uint32_t lbits); // X/Z extension V3Number& opRedOr (const V3Number& lhs); diff --git a/test_regress/t/t_math_real.v b/test_regress/t/t_math_real.v index 2bcf884e7..17bc0221c 100644 --- a/test_regress/t/t_math_real.v +++ b/test_regress/t/t_math_real.v @@ -82,6 +82,9 @@ module t (/*AUTOARG*/ // bug r = $bitstoreal($realtobits(1.414)); if (r != 1.414) $stop; + // bug + r = 32'bxz000_111; // 7 accoding to IEEE + if (r != 7) $stop; end // Test loop From 5932eae32aa423bab8796ca95d18987b3c20eb73 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 16:09:18 -0400 Subject: [PATCH 014/127] Commentary --- README.adoc | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.adoc b/README.adoc index 3e2eb528b..b20317532 100644 --- a/README.adoc +++ b/README.adoc @@ -22,7 +22,7 @@ endif::[] [cols="a,a",indent=0,frame="none"] |=== -^.^| *Welcome to Verilator, the fastest free Verilog HDL simulator.* +^.^| *Welcome to Verilator, the fastest Verilog HDL simulator.* +++
+++ • Accepts synthesizable Verilog or SystemVerilog +++
+++ • Performs lint code-quality checks +++
+++ • Compiles into multithreaded {cpp}, or SystemC @@ -56,7 +56,7 @@ endif::[] == What Verilator Does Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It -"Verilates" the specified synthesizable Verilog or SystemVerilog code by +"Verilates" the specified Verilog or SystemVerilog code by reading it, performing lint checks, and optionally inserting assertion checks and coverage-analysis points. It outputs single- or multi-threaded .cpp and .h files, the "Verilated" code. @@ -72,30 +72,30 @@ Verilator may not be the best choice if you are expecting a full featured replacement for NC-Verilog, VCS or another commercial Verilog simulator, or if you are looking for a behavioral Verilog simulator e.g. for a quick class project (we recommend http://iverilog.icarus.com[Icarus Verilog] for -this.) However, if you are looking for a path to migrate synthesizable -Verilog to {cpp} or SystemC, and your team is comfortable writing just a +this.) However, if you are looking for a path to migrate SystemVerilog to +{cpp} or SystemC, and your team is comfortable writing just a touch of {cpp} code, Verilator is the tool for you. == Performance -Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather -than only translate, Verilator compiles your code into a much faster -optimized and optionally thread-partitioned model, which is in turn wrapped -inside a {cpp}/SystemC/{cpp}-under-Python module. The results are a compiled Verilog -model that executes even on a single-thread over 10x faster than standalone -SystemC, and on a single thread is about 100 times faster than interpreted -Verilog simulators such as http://iverilog.icarus.com[Icarus +Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather, +Verilator compiles your code into a much faster optimized and optionally +thread-partitioned model, which is in turn wrapped inside a +{cpp}/SystemC/{cpp}-under-Python module. The results are a compiled +Verilog model that executes even on a single-thread over 10x faster than +standalone SystemC, and on a single thread is about 100 times faster than +interpreted Verilog simulators such as http://iverilog.icarus.com[Icarus Verilog]. Another 2-10x speedup might be gained from multithreading (yielding 200-1000x total over interpreted simulators). Verilator has typically similar or better performance versus the commercial Verilog simulators (Carbon Design Systems Carbonator, Modelsim, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic CVer/CVC). But, -Verilator is free, so you can spend on computes rather than licenses. Thus -Verilator gives you more cycles/dollar than anything else available. +Verilator is open-sourced, so you can spend on computes rather than +licenses. Thus Verilator gives you the best cycles/dollar. For more information on how Verilator stacks up to some of the other -commercial and free Verilog simulators, see the +closed-sourced and open-sourced Verilog simulators, see the https://www.veripool.org/verilog_sim_benchmarks.html[Verilog Simulator Benchmarks]. (If you benchmark Verilator, please see the notes in the https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)], and also From efaf37588715f37dc1544e55e4c1bc82c79077e4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 16:10:33 -0400 Subject: [PATCH 015/127] Configuring with ccache present now defaults to using it; see OBJCACHE in the manual. --- .travis.yml | 1 - Changes | 2 ++ bin/verilator | 16 +++++++++------- configure.ac | 6 ++++++ include/verilated.mk.in | 3 ++- src/Makefile_obj.in | 1 + 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index e99bbd848..e9cbc4c3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,6 @@ env: - VERILATOR_NUM_JOBS=$(echo `nproc` + 1 | bc) - VERILATOR_CONFIG_FLAGS="--enable-maintainer-mode --enable-longtests" - VERILATOR_AUTHOR_SITE=1 - - OBJCACHE=ccache cache: directories: diff --git a/Changes b/Changes index 9ab756798..14321ad0e 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Add simplistic class support with many restrictions, see manual, #377. +** Configuring with ccache present now defaults to using it; see OBJCACHE. + **** Support $ferror, and $fflush without arguments, #1638. diff --git a/bin/verilator b/bin/verilator index e1545e98b..2c544eeb0 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1080,7 +1080,8 @@ design --output-split 20000 resulted in splitting into approximately one-minute-compile chunks. Typically when using this, make with VM_PARALLEL_BUILDS=1 (set for you if -using the default makefiles), and use I. +using the default makefiles), and use I (set for you if present at +configure time). =item --output-split-cfuncs I @@ -2125,9 +2126,10 @@ needed at simulation runtime. =item OBJCACHE Optionally specifies a caching or distribution program to place in front of -all runs of the C++ Compiler. For example, "objcache --read --write", or -"ccache". If using distcc or icecc/icecream, they would generally be run -under either objcache or ccache; see the documentation for those programs. +all runs of the C++ compiler. For example, "ccache". If using distcc or +icecc/icecream, they would generally be run under cache; see the +documentation for those programs. If OBJCACHE is not set, and at configure +time ccache was present, ccache will be used as a default. =item SYSTEMC @@ -5136,9 +5138,9 @@ now relatively old GCC 3.0 to 3.3 being horrible. Compile in parallel on many machines and use caching; see the web for the ccache, distcc and icecream packages. ccache will skip GCC runs between -identical source builds, even across different users. You can use the -OBJCACHE environment variable to use these CC wrappers. Also see the ---output-split option. +identical source builds, even across different users. If ccache was +installed when Verilator was built it is used, or see OBJCACHE environment +variable to override this. Also see the --output-split option. To reduce the compile time of classes that use a Verilated module (e.g. a top CPP file) you may wish to add /*verilator no_inline_module*/ to your diff --git a/configure.ac b/configure.ac index 0db24735d..fd93c6580 100644 --- a/configure.ac +++ b/configure.ac @@ -159,6 +159,12 @@ if test "x$YACC" = "x" ; then AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it]) fi +AC_CHECK_PROG(OBJCACHE,ccache,ccache) +if test "x$OBJCACHE" != "x" ; then + objcache_version=$($OBJCACHE --version | head -1) + AC_MSG_RESULT([objcache is $OBJCACHE --version = $objcache_version]) +fi + # Checks for libraries. # Checks for typedefs, structures diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 47e3f61a9..f1fee71dc 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -12,8 +12,9 @@ PERL = @PERL@ CXX = @CXX@ LINK = @CXX@ -AR = ar +AR = ar RANLIB = ranlib +OBJCACHE ?= @OBJCACHE@ CFG_WITH_CCWARN = @CFG_WITH_CCWARN@ CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@ diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 4b0d83dd2..f35bb2103 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -42,6 +42,7 @@ LEX = @LEX@ LFLAGS = -d PERL = @PERL@ YACC = @YACC@ +OBJCACHE ?= @OBJCACHE@ prefix = @prefix@ From d922cae0a2399318e59659abd105d61c0439baa8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 16:13:41 -0400 Subject: [PATCH 016/127] Commentary --- docs/install.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/install.adoc b/docs/install.adoc index 8add7f3c1..3d8c9fd5e 100644 --- a/docs/install.adoc +++ b/docs/install.adoc @@ -84,8 +84,9 @@ To build Verilator you will need to install some standard packages: sudo apt-get install autoconf sudo apt-get install flex bison -The following are optional, but improve compilation speed: +The following are optional, but should be installed to improve compilation speed: + sudo apt-get install ccache sudo apt-get install libgoogle-perftools-dev Additionally, to build or run Verilator you need these standard packages: From 763f621d4c48da181f555a9ff3ae445a1751c3b9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 16:45:53 -0400 Subject: [PATCH 017/127] Deprecate VL_ULL. --- include/verilatedos.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/verilatedos.h b/include/verilatedos.h index 4052c3009..7acc92183 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -140,7 +140,10 @@ #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 +# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant +// Was "(c##ui64)". C++11 has standardized on ULL, and MSVC now supports this. +// We propose to no longer require using this macro no sooner than June 2020. +// File an issue ASAP if this breaks anything. #else # define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant #endif From ff31abe341a663855e85b862bec6fb61a9352aa5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 17:01:33 -0400 Subject: [PATCH 018/127] Commenary --- README.adoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.adoc b/README.adoc index b20317532..5fd864f76 100644 --- a/README.adoc +++ b/README.adoc @@ -88,11 +88,11 @@ interpreted Verilog simulators such as http://iverilog.icarus.com[Icarus Verilog]. Another 2-10x speedup might be gained from multithreading (yielding 200-1000x total over interpreted simulators). -Verilator has typically similar or better performance versus the commercial -Verilog simulators (Carbon Design Systems Carbonator, Modelsim, Cadence -Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic CVer/CVC). But, -Verilator is open-sourced, so you can spend on computes rather than -licenses. Thus Verilator gives you the best cycles/dollar. +Verilator has typically similar or better performance versus the +closed-source Verilog simulators (Carbon Design Systems Carbonator, +Modelsim, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic +CVer/CVC). But, Verilator is open-sourced, so you can spend on computes +rather than licenses. Thus Verilator gives you the best cycles/dollar. For more information on how Verilator stacks up to some of the other closed-sourced and open-sourced Verilog simulators, see the From 50535a1894f87b81bca7937e9268d11906c50920 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 18:30:46 -0400 Subject: [PATCH 019/127] Internals: cppcheck 1.90 fixes. No functional change intended. --- include/verilated.cpp | 12 +++++----- include/verilated_heavy.h | 4 +++- include/verilated_threads.cpp | 1 + include/verilated_vpi.cpp | 9 ++++---- src/V3AstNodes.h | 12 +++++++++- src/V3Broken.cpp | 1 + src/V3CUse.cpp | 2 +- src/V3EmitC.cpp | 15 +++++++------ src/V3File.cpp | 2 ++ src/V3FileLine.cpp | 5 +++++ src/V3FileLine.h | 42 +++++++++++++++++------------------ src/V3Global.h | 27 +++++++++++----------- src/V3LinkLValue.cpp | 1 - src/V3Localize.cpp | 1 + src/V3Number.cpp | 12 +++++----- src/V3Options.cpp | 3 +++ src/V3Param.cpp | 10 ++++----- src/V3Simulate.h | 4 ++-- src/V3SplitVar.cpp | 10 ++++----- src/V3SymTable.h | 8 +++---- src/V3Task.cpp | 17 +++++++------- src/V3Width.cpp | 8 +++---- src/VlcBucket.h | 3 ++- 23 files changed, 116 insertions(+), 93 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 7620d76a6..13af6f3b4 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -857,9 +857,12 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } } -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 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) VL_MT_SAFE { if (fp) fgetc(fp); @@ -1689,7 +1692,6 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) { if (c == '_') continue; // Ignore _ e.g. inside a number if (indata && !isxdigit(c) && c != 'x' && c != 'X') { // printf("Got data @%lx = %s\n", m_addr, valuer.c_str()); - indata = false; ungetc(c, m_fp); addrr = m_addr; ++m_addr; @@ -1860,8 +1862,6 @@ void VL_READMEM_N(bool hex, // Hex format, else binary ) VL_MT_SAFE { QData addr_max = array_lsb + depth - 1; if (start < static_cast(array_lsb)) start = array_lsb; - QData addr_end = end; - if (addr_end > addr_max) addr_end = addr_max; VlReadMem rmem(hex, bits, filename, start, end); if (VL_UNLIKELY(!rmem.isOpen())) return; diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 8f8d9d383..557ad45f3 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -85,7 +85,9 @@ template class VlWide { WData m_storage[T_Words]; public: - // Default constructor/destructor/copy are fine + // cppcheck-suppress uninitVar + VlWide() {} + ~VlWide() {} const WData& at(size_t index) const { return m_storage[index]; } WData& at(size_t index) { return m_storage[index]; } WData* data() { return &m_storage[0]; } diff --git a/include/verilated_threads.cpp b/include/verilated_threads.cpp index 77d19b700..f4f23149f 100644 --- a/include/verilated_threads.cpp +++ b/include/verilated_threads.cpp @@ -142,6 +142,7 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) { FILE* fp = fopen(filenamep, "w"); if (VL_UNLIKELY(!fp)) { VL_FATAL_MT(filenamep, 0, "", "+prof+threads+file file not writable"); + // cppcheck-suppress resourceLeak // bug, doesn't realize fp is nullptr return; } diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 3d5cd6651..11d6ae561 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -930,15 +930,14 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE { #define CHECK_RESULT_CSTR(got, exp) \ if (strcmp((got), (exp))) { \ - std::string msg = std::string("%Error: ") \ - + "GOT = '"+((got)?(got):"")+"'" \ - + " EXP = '"+((exp)?(exp):"")+"'"; \ - VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \ + std::string msg \ + = std::string("%Error: ") + "GOT = '" + got + "'" + " EXP = '" + exp + "'"; \ + VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \ } #define CHECK_ENUM_STR(fn, enum) \ do { \ - const char* strVal = VerilatedVpiError::fn(enum); \ + const char* strVal = VerilatedVpiError::fn(enum); \ CHECK_RESULT_CSTR(strVal, #enum); \ } while (0) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 9741eba32..5343bf1ad 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -255,7 +255,8 @@ class AstClassPackage : public AstNodeModule { AstClass* m_classp; // Class package this is under (weak pointer, hard link is other way) public: AstClassPackage(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER(fl, name) + , m_classp(NULL) {} ASTNODE_NODE_FUNCS(ClassPackage) virtual string verilogKwd() const { return "/*class*/package"; } virtual const char* broken() const; @@ -948,8 +949,11 @@ public: virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } // METHODS virtual AstBasicDType* basicp() const { return NULL; } + // cppcheck-suppress csyleCast virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } @@ -1111,8 +1115,11 @@ public: virtual void virtRefDTypep(AstNodeDType* nodep) { } virtual bool similarDType(AstNodeDType* samep) const { return this==samep; } virtual AstBasicDType* basicp() const { return NULL; } + // cppcheck-suppress csyleCast virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } virtual int widthAlignBytes() const { return 1; } virtual int widthTotalBytes() const { return 1; } @@ -1207,6 +1214,7 @@ public: virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); } virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); } + // cppcheck-suppress csyleCast virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } @@ -1225,7 +1233,9 @@ public: virtual bool similarDType(AstNodeDType* samep) const { return this==samep; } virtual AstBasicDType* basicp() const { return NULL; } virtual AstNodeDType* skipRefp() const { return NULL; } + // cppcheck-suppress csyleCast virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } virtual int widthAlignBytes() const { return 0; } virtual int widthTotalBytes() const { return 0; } diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index e76cc351e..b27dc4b04 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -87,6 +87,7 @@ public: } static void addInTree(AstNode* nodep, bool linkable) { #ifndef VL_LEAK_CHECKS + // cppcheck-suppress knownConditionTrueFalse if (!linkable) return; // save some time, else the map will get huge! #endif NodeMap::iterator iter = s_nodes.find(nodep); diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index e0539d773..fe1f6f073 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -178,7 +178,7 @@ class CUseVisitor : public AstNVisitor { if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) { string stmt = "out += \""; if (!comma.empty()) stmt += "\", \"+ "; - comma = ", "; + // comma = ", "; // Nothing further so not needed stmt += nodep->extendsp()->dtypep()->nameProtect(); stmt += "::to_string_middle();\n"; nodep->user1(true); // So what we extend dumps this diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 9c8b0ba97..17030feae 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1878,9 +1878,8 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) { putbs(","); iterate(dispp->lhsp()); putbs(","); - } else if (const AstSFormatF* dispp = VN_CAST(nodep, SFormatF)) { + } else if (VN_IS(nodep, SFormatF)) { isStmt = false; - if (dispp) {} puts("VL_SFORMATF_NX("); } else { nodep->v3fatalSrc("Unknown displayEmit node type"); @@ -2916,11 +2915,13 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("\n// INTERNAL METHODS\n"); if (modp->isTop()) { ofp()->putsPrivate(true); // private: - puts("static void "+protect("_eval_initial_loop") - +"("+EmitCBaseVisitor::symClassVar()+");\n"); - if (v3Global.needTraceDumper() && !optSystemC()) puts("void _traceDump();"); - if (v3Global.needTraceDumper()) puts("void _traceDumpOpen();"); - if (v3Global.needTraceDumper()) puts("void _traceDumpClose();"); + puts("static void " + protect("_eval_initial_loop") + "(" + EmitCBaseVisitor::symClassVar() + + ");\n"); + if (v3Global.needTraceDumper()) { + if (!optSystemC()) puts("void _traceDump();"); + puts("void _traceDumpOpen();"); + puts("void _traceDumpClose();"); + } } if (!VN_IS(modp, Class)) { diff --git a/src/V3File.cpp b/src/V3File.cpp index 8a0ae3e08..dee1298f2 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -116,6 +116,7 @@ public: // ACCESSOR METHODS void addSrcDepend(const string& filename) { if (m_filenameSet.find(filename) == m_filenameSet.end()) { + // cppcheck-suppress stlFindInsert // cppcheck 1.90 bug m_filenameSet.insert(filename); DependFile df (filename, false); df.loadStats(); // Get size now, in case changes during the run @@ -124,6 +125,7 @@ public: } void addTgtDepend(const string& filename) { if (m_filenameSet.find(filename) == m_filenameSet.end()) { + // cppcheck-suppress stlFindInsert // cppcheck 1.90 bug m_filenameSet.insert(filename); m_filenameList.insert(DependFile(filename, true)); } diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 60984003b..85324f015 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -155,6 +155,11 @@ FileLine::FileLine(FileLine::EmptySecret) { } } +void FileLine::newContent() { + m_contentp = new VFileContent; + m_contentLineno = 1; +} + const string FileLine::xmlDetailedLocation() const { return "loc=\"" + cvtToStr(filenameLetters()) + "," + diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 09953ef14..de09fc0f1 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -115,26 +115,26 @@ private: return *defFilelinep; } public: - explicit FileLine(const string& filename) { - m_lastLineno = m_firstLineno = 0; - m_lastColumn = m_firstColumn = 0; - m_filenameno = singleton().nameToNumber(filename); - m_contentLineno = 0; - m_contentp = NULL; - m_parent = NULL; - m_warnOn = defaultFileLine().m_warnOn; - } - explicit FileLine(FileLine* fromp) { - m_firstLineno = fromp->m_firstLineno; - m_firstColumn = fromp->m_firstColumn; - m_lastLineno = fromp->m_lastLineno; - m_lastColumn = fromp->m_lastColumn; - m_filenameno = fromp->m_filenameno; - m_contentLineno = fromp->m_contentLineno; - m_contentp = fromp->m_contentp; - m_parent = fromp->m_parent; - m_warnOn = fromp->m_warnOn; - } + explicit FileLine(const string& filename) + : m_firstLineno(0) + , m_firstColumn(0) + , m_lastLineno(0) + , m_lastColumn(0) + , m_filenameno(singleton().nameToNumber(filename)) + , m_contentLineno(0) + , m_contentp(NULL) + , m_parent(NULL) + , m_warnOn(defaultFileLine().m_warnOn) {} + explicit FileLine(FileLine* fromp) + : m_firstLineno(fromp->m_firstLineno) + , m_firstColumn(fromp->m_firstColumn) + , m_lastLineno(fromp->m_lastLineno) + , m_lastColumn(fromp->m_lastColumn) + , m_filenameno(fromp->m_filenameno) + , m_contentLineno(fromp->m_contentLineno) + , m_contentp(fromp->m_contentp) + , m_parent(fromp->m_parent) + , m_warnOn(fromp->m_warnOn) {} struct EmptySecret {}; // Constructor selection explicit FileLine(EmptySecret); FileLine* copyOrSameFileLine(); @@ -144,8 +144,8 @@ public: static void* operator new(size_t size); static void operator delete(void* obj, size_t size); #endif - void newContent() { m_contentp = new VFileContent; m_contentLineno = 1; } // METHODS + void newContent(); void lineno(int num) { m_firstLineno = num; m_lastLineno = num; m_firstColumn = m_lastColumn = 1; } void language(V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); } diff --git a/src/V3Global.h b/src/V3Global.h index 5c9503032..5ae33fbf9 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -83,22 +83,21 @@ public: // Options V3Options opt; // All options; let user see them directly - public: +public: // CONSTRUCTORS - V3Global() { - m_debugFileNumber = 0; - m_widthMinUsage = VWidthMinUsage::LINT_WIDTH; - m_assertDTypesResolved = false; - m_constRemoveXs = false; - m_needC11 = false; - m_needHInlines = false; - m_needHeavy = false; - m_needTraceDumper = false; - m_dpi = false; - m_rootp = NULL; // created by makeInitNetlist() so static constructors run first - } + V3Global() + : m_rootp(NULL) // created by makeInitNetlist() so static constructors run first + , m_widthMinUsage(VWidthMinUsage::LINT_WIDTH) + , m_debugFileNumber(0) + , m_assertDTypesResolved(false) + , m_constRemoveXs(false) + , m_needC11(false) + , m_needHInlines(false) + , m_needHeavy(false) + , m_needTraceDumper(false) + , m_dpi(false) {} AstNetlist* makeNetlist(); - void boot() { UASSERT(!m_rootp,"call once"); m_rootp = makeNetlist(); } + void boot() { UASSERT(!m_rootp, "call once"); m_rootp = makeNetlist(); } void clear(); // ACCESSORS (general) AstNetlist* rootp() const { return m_rootp; } diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 6788e1d9b..4a6e32d92 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -108,7 +108,6 @@ private: m_setRefLvalue = true; iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->strp()); - m_setRefLvalue = false; } m_setRefLvalue = last_setRefLvalue; } diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index 25667dc9e..870c1f3fa 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -74,6 +74,7 @@ private: // METHODS virtual void visit(AstVarRef* nodep) VL_OVERRIDE { + // cppcheck-suppress unreadVariable // cppcheck 1.90 bug VarFlags flags (nodep->varp()); if (flags.m_done) { nodep->hiername(""); // Remove this-> diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 4a4a757ac..72d6a61e6 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -457,14 +457,14 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const { ); //out<<"-"<modp(), Iface)) - || (nonIf==1 && !VN_IS(nodep->modp(), Iface))) { + AstCell* cellp = *it; + if ((nonIf==0 && VN_IS(cellp->modp(), Iface)) + || (nonIf==1 && !VN_IS(cellp->modp(), Iface))) { string fullName (m_modp->hierName()); - if (string* genHierNamep = (string *) nodep->user5p()) { + if (string* genHierNamep = (string *) cellp->user5p()) { fullName += *genHierNamep; } - visitCell(nodep, fullName); + visitCell(cellp, fullName); } } } diff --git a/src/V3Simulate.h b/src/V3Simulate.h index ca09d8615..c48ee7907 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -273,11 +273,11 @@ private: } public: AstNode* fetchValueNull(AstNode* nodep) { - return (AstNode*)(nodep->user3p()); + return nodep->user3p(); } private: AstNode* fetchOutValueNull(AstNode* nodep) { - return (AstNode*)(nodep->user2p()); + return nodep->user2p(); } AstConst* fetchConstNull(AstNode* nodep) { return VN_CAST(fetchValueNull(nodep), Const); diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 5289d2047..729daca0f 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -732,19 +732,19 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { sit->lvalue()); } else { AstVarRef* refp = VN_CAST(sit->nodep(), VarRef); - AstUnpackArrayDType* dtypep; + AstUnpackArrayDType* adtypep; int lsb = 0; if (refp) { - dtypep = VN_CAST(refp->dtypep()->skipRefp(), UnpackArrayDType); + adtypep = VN_CAST(refp->dtypep()->skipRefp(), UnpackArrayDType); } else { AstSliceSel* selp = VN_CAST(sit->nodep(), SliceSel); UASSERT_OBJ(selp, sit->nodep(), "Unexpected op is registered"); refp = VN_CAST(selp->fromp(), VarRef); UASSERT_OBJ(refp, selp, "Unexpected op is registered"); - dtypep = VN_CAST(selp->dtypep()->skipRefp(), UnpackArrayDType); - lsb = dtypep->lsb(); + adtypep = VN_CAST(selp->dtypep()->skipRefp(), UnpackArrayDType); + lsb = adtypep->lsb(); } - AstVarRef* newrefp = createTempVar(sit->context(), refp, dtypep, varp->name(), + AstVarRef* newrefp = createTempVar(sit->context(), refp, adtypep, varp->name(), vars, lsb, refp->lvalue(), sit->ftask()); newp = newrefp; refp->varp()->addNextHere(newrefp->varp()); diff --git a/src/V3SymTable.h b/src/V3SymTable.h index f935f1e46..afbd4a9d1 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -97,10 +97,10 @@ public: ~VSymEnt() { // Change links so we coredump if used #ifdef VL_DEBUG - m_nodep = (AstNode*)1; - m_fallbackp = (VSymEnt*)1; - m_parentp = (VSymEnt*)1; - m_packagep = (AstPackage*)1; + m_nodep = reinterpret_cast(1); + m_fallbackp = reinterpret_cast(1); + m_parentp = reinterpret_cast(1); + m_packagep = reinterpret_cast(1); #endif } #if defined(VL_DEBUG) && !defined(VL_LEAK_CHECKS) diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 3ea7d97f6..ffe18e221 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -526,14 +526,15 @@ private: // Even if it's referencing a varref, we still make a temporary // Else task(x,x,x) might produce incorrect results - AstVarScope* outvscp - = createVarScope(portp, namePrefix+"__"+portp->shortName()); - portp->user2p(outvscp); - pinp->replaceWith(new AstVarRef(outvscp->fileline(), outvscp, true)); - AstAssign* assp = new AstAssign(pinp->fileline(), - pinp, - new AstVarRef(outvscp->fileline(), outvscp, false)); - assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block + AstVarScope* newvscp + = createVarScope(portp, namePrefix + "__" + portp->shortName()); + portp->user2p(newvscp); + pinp->replaceWith(new AstVarRef(newvscp->fileline(), newvscp, true)); + AstAssign* assp + = new AstAssign(pinp->fileline(), pinp, + new AstVarRef(newvscp->fileline(), newvscp, false)); + assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, + true); // Ok if in <= block // Put assignment BEHIND of all other statements beginp->addNext(assp); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index c71102b12..36e454514 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1142,9 +1142,9 @@ private: default: nodep->v3error("Unhandled attribute type"); } } else { - std::pair dimp + std::pair dimpair = nodep->fromp()->dtypep()->skipRefp()->dimensions(true); - uint32_t msbdim = dimp.first + dimp.second; + uint32_t msbdim = dimpair.first + dimpair.second; if (!nodep->dimp() || msbdim < 1) { int dim = 1; AstConst* newp = dimensionValue(nodep->fileline(), nodep->fromp()->dtypep(), @@ -2457,7 +2457,6 @@ private: if (nodep->didWidthAndSet()) return; AstDynArrayDType* adtypep = VN_CAST(m_vup->dtypeNullp(), DynArrayDType); if (!adtypep) { // e.g. int a = new; - if (adtypep) UINFO(1, "Got adtypep " << adtypep << endl); nodep->v3error("dynamic new() not expected in this context (data type must be dynamic array)"); return; } @@ -4698,11 +4697,10 @@ private: declRange = VNumRange(); // ranged() set false if (AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) { declRange = adtypep->declRange(); - if (isubDTypep()->skipRefp(); + if (i < dim) dtypep = adtypep->subDTypep()->skipRefp(); continue; } else if (AstNodeUOrStructDType* adtypep = VN_CAST(dtypep, NodeUOrStructDType)) { declRange = adtypep->declRange(); - if (adtypep) {} // UNUSED break; // Sub elements don't look like arrays and can't iterate into } else if (AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) { if (adtypep->isRanged()) declRange = adtypep->declRange(); diff --git a/src/VlcBucket.h b/src/VlcBucket.h index 24c23d1f1..5e09e82d9 100644 --- a/src/VlcBucket.h +++ b/src/VlcBucket.h @@ -40,8 +40,9 @@ private: if (m_dataSize < point) m_dataSize = (point + 64) & ~63ULL; // Keep power of two m_dataSize *= 2; // UINFO(9, "Realloc "<(realloc(m_datap, allocSize())); if (!newp) { + // cppcheck-suppress doubleFree // cppcheck 1.90 bug - realloc doesn't free on fail free(m_datap); v3fatal("Out of memory increasing buckets"); } From 383f9832d4f9e2ef1425388e3c352d639539be82 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Apr 2020 21:53:24 -0400 Subject: [PATCH 020/127] Tests: Standardize verilog indentation. --- examples/make_protect_lib/secret_impl.v | 16 +++++++++------- examples/make_tracing_c/top.v | 10 +++++----- examples/make_tracing_sc/top.v | 12 ++++++------ examples/xml_py/sub.v | 2 +- examples/xml_py/top.v | 12 ++++++------ test_regress/t/t_EXAMPLE.v | 8 ++++---- 6 files changed, 31 insertions(+), 29 deletions(-) diff --git a/examples/make_protect_lib/secret_impl.v b/examples/make_protect_lib/secret_impl.v index fd8557af1..1e39257f5 100644 --- a/examples/make_protect_lib/secret_impl.v +++ b/examples/make_protect_lib/secret_impl.v @@ -6,14 +6,16 @@ // This module will be used as libsecret.a or libsecret.so without // exposing the source. -module secret_impl( - input [31:0] a, - input [31:0] b, - output logic [31:0] x, - input clk); - logic [31:0] accum_q = 0; - logic [31:0] secret_value = 9; +module secret_impl + ( + input [31:0] a, + input [31:0] b, + output logic [31:0] x, + input clk); + + logic [31:0] accum_q = 0; + logic [31:0] secret_value = 9; initial $display("%m: initialized"); diff --git a/examples/make_tracing_c/top.v b/examples/make_tracing_c/top.v index a11027546..dbc852814 100644 --- a/examples/make_tracing_c/top.v +++ b/examples/make_tracing_c/top.v @@ -11,15 +11,15 @@ module top ( // Declare some signals so we can see how I/O works - input clk, - input reset_l, + input clk, + input reset_l, output wire [1:0] out_small, output wire [39:0] out_quad, output wire [69:0] out_wide, - input [1:0] in_small, - input [39:0] in_quad, - input [69:0] in_wide + input [1:0] in_small, + input [39:0] in_quad, + input [69:0] in_wide ); // Connect up the outputs, using some trivial logic diff --git a/examples/make_tracing_sc/top.v b/examples/make_tracing_sc/top.v index 534acb8e1..a31254951 100644 --- a/examples/make_tracing_sc/top.v +++ b/examples/make_tracing_sc/top.v @@ -11,16 +11,16 @@ module top ( // Declare some signals so we can see how I/O works - input clk, - input fastclk, - input reset_l, + input clk, + input fastclk, + input reset_l, output wire [1:0] out_small, output wire [39:0] out_quad, output wire [69:0] out_wide, - input [1:0] in_small, - input [39:0] in_quad, - input [69:0] in_wide + input [1:0] in_small, + input [39:0] in_quad, + input [69:0] in_wide ); // Connect up the outputs, using some trivial logic diff --git a/examples/xml_py/sub.v b/examples/xml_py/sub.v index ba2eed35c..67b577285 100644 --- a/examples/xml_py/sub.v +++ b/examples/xml_py/sub.v @@ -8,7 +8,7 @@ module sub #(parameter type TYPE_t = logic) ( - input TYPE_t in, + input TYPE_t in, output TYPE_t out ); diff --git a/examples/xml_py/top.v b/examples/xml_py/top.v index 405bf46c5..1106464f1 100644 --- a/examples/xml_py/top.v +++ b/examples/xml_py/top.v @@ -7,16 +7,16 @@ module top ( - input clk, - input fastclk, - input reset_l, + input clk, + input fastclk, + input reset_l, output wire [1:0] out_small, output wire [39:0] out_quad, output wire [69:0] out_wide, - input [1:0] in_small, - input [39:0] in_quad, - input [69:0] in_wide + input [1:0] in_small, + input [39:0] in_quad, + input [69:0] in_wide ); sub #(.TYPE_t(logic [1:0])) sub_small diff --git a/test_regress/t/t_EXAMPLE.v b/test_regress/t/t_EXAMPLE.v index befacfb1a..4e1051614 100644 --- a/test_regress/t/t_EXAMPLE.v +++ b/test_regress/t/t_EXAMPLE.v @@ -22,12 +22,12 @@ module t(/*AUTOARG*/ ); input clk; - integer cyc=0; - reg [63:0] crc; - reg [63:0] sum; + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; // Take CRC data and apply to testblock inputs - wire [31:0] in = crc[31:0]; + wire [31:0] in = crc[31:0]; /*AUTOWIRE*/ // Beginning of automatic wires (for undeclared instantiated-module outputs) From 26301a4133f4fdbef04cbe69fe3a77dd3088ee67 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 6 Apr 2020 08:19:32 -0400 Subject: [PATCH 021/127] Commentary --- test_regress/t/t_dist_contributors.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/t/t_dist_contributors.pl b/test_regress/t/t_dist_contributors.pl index dd2a848b2..5f5338991 100755 --- a/test_regress/t/t_dist_contributors.pl +++ b/test_regress/t/t_dist_contributors.pl @@ -35,7 +35,7 @@ sub check { for my $author (sort keys %Authors) { print "Check: $author\n" if $Self->{verbose}; if (!$Contributors{$author}) { - error("Certify your contribution by appending '$author' to docs/CONTRIBUTORS.\n" + error("Certify your contribution by sorted-inserting '$author' into docs/CONTRIBUTORS.\n" ." If '$author' is not your real name, please fix 'name=' in ~/.gitconfig\n" ." Also check your https://github.com account's Settings->Profile->Name\n" ." matches your ~/.gitconfig 'name='.\n"); From b6c21ad21ae0fe3db5964bbbb4692c3c37465c5e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 6 Apr 2020 08:33:51 -0400 Subject: [PATCH 022/127] Fix duplicate traces with $dumpfile, part of #2237. --- src/V3EmitC.cpp | 9 --------- test_regress/t/t_trace_two_dumpfst_cc.out | 4 +--- test_regress/t/t_trace_two_portfst_cc.out | 4 +--- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 17030feae..e707dd4e7 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2397,15 +2397,6 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) { putsDecoration("// Initialize\n"); puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) " +protect("_eval_initial_loop")+"(vlSymsp);\n"); - if (v3Global.opt.trace()) { - puts("#ifdef VM_TRACE\n"); - putsDecoration("// Tracing\n"); - // SystemC's eval loop deals with calling trace, not us - if (v3Global.needTraceDumper() && !optSystemC()) { - puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) _traceDump();\n"); - } - puts("#endif // VM_TRACE\n"); - } if (v3Global.opt.inhibitSim()) { puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n"); } diff --git a/test_regress/t/t_trace_two_dumpfst_cc.out b/test_regress/t/t_trace_two_dumpfst_cc.out index 1ec523a92..b956e40cd 100755 --- a/test_regress/t/t_trace_two_dumpfst_cc.out +++ b/test_regress/t/t_trace_two_dumpfst_cc.out @@ -1,5 +1,5 @@ $date - Sat Mar 7 18:39:05 2020 + Mon Apr 6 08:10:23 2020 $end $version @@ -25,8 +25,6 @@ $dumpvars b00000000000000000000000000000001 " b00000000000000000000000000000000 # b00000000000000000000000000000001 $ -#10 -1! #15 0! #20 diff --git a/test_regress/t/t_trace_two_portfst_cc.out b/test_regress/t/t_trace_two_portfst_cc.out index 39390199f..60ff90a86 100755 --- a/test_regress/t/t_trace_two_portfst_cc.out +++ b/test_regress/t/t_trace_two_portfst_cc.out @@ -1,5 +1,5 @@ $date - Sat Mar 7 18:37:58 2020 + Mon Apr 6 08:24:52 2020 $end $version @@ -25,8 +25,6 @@ $dumpvars b00000000000000000000000000000001 " b00000000000000000000000000000000 # b00000000000000000000000000000001 $ -#10 -1! #15 0! #20 From f13bd1aec4b0fd67bc2e01feea196f4b554aa30f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 6 Apr 2020 08:53:19 -0400 Subject: [PATCH 023/127] Fix clang unused warning. --- src/V3CCtors.cpp | 8 ++++---- src/V3EmitC.cpp | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index b02e0ffb0..88821abba 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -162,10 +162,10 @@ void V3CCtors::cctorsAll() { } } if (v3Global.opt.coverage()) { - V3CCtorsVisitor configure_coverage - (modp, "_configure_coverage", - EmitCBaseVisitor::symClassVar()+ ", bool first", "vlSymsp, first", - "if (0 && vlSymsp && first) {} // Prevent unused\n"); + V3CCtorsVisitor configure_coverage( + modp, "_configure_coverage", + EmitCBaseVisitor::symClassVar() + ", bool first", "vlSymsp, first", + "if (false && vlSymsp && first) {} // Prevent unused\n"); for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { if (AstCoverDecl* coverp = VN_CAST(np, CoverDecl)) { AstNode* backp = coverp->backp(); diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index e707dd4e7..2a9c1d1d2 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2137,8 +2137,9 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { void EmitCImp::emitConfigureImp(AstNodeModule* modp) { puts("\nvoid " + prefixNameProtect(modp) + "::" + protect("__Vconfigure") + "(" + symClassName() + "* vlSymsp, bool first) {\n"); - puts( "if (0 && first) {} // Prevent unused\n"); + puts( "if (false && first) {} // Prevent unused\n"); puts( "this->__VlSymsp = vlSymsp;\n"); // First, as later stuff needs it. + puts( "if (false && this->__VlSymsp) {} // Prevent unused\n"); if (v3Global.opt.coverage() ) { puts(protect("_configure_coverage")+"(vlSymsp, first);\n"); } @@ -3451,7 +3452,7 @@ class EmitCTrace : EmitCStmts { if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign()+"\n"); puts("int c = code;\n"); - puts("if (0 && vcdp && c) {} // Prevent unused\n"); + puts("if (false && vcdp && c) {} // Prevent unused\n"); if (nodep->funcType() == AstCFuncType::TRACE_INIT) { puts("vcdp->module(vlSymsp->name()); // Setup signal names\n"); } else if (nodep->funcType() == AstCFuncType::TRACE_INIT_SUB) { From 2abbae8dd0e0a9df4eb13233fcde36a758ae2374 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 6 Apr 2020 19:26:31 -0400 Subject: [PATCH 024/127] Internals: Remove strncpy to appease codacity. --- include/verilated.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 13af6f3b4..663080372 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -611,7 +611,6 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA // Note also assumes variables < 64 are not wide, this assumption is // sometimes not true in low-level routines written here in verilated.cpp static VL_THREAD_LOCAL char tmp[VL_VALUE_STRING_MAX_WIDTH]; - static VL_THREAD_LOCAL char tmpf[VL_VALUE_STRING_MAX_WIDTH]; const char* pctp = NULL; // Most recent %##.##g format bool inPct = false; bool widthSet = false; @@ -685,9 +684,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA break; } default: { - strncpy(tmpf, pctp, pos-pctp+1); - tmpf[pos-pctp+1] = '\0'; - sprintf(tmp, tmpf, d); + std::string fmt(pctp, pos - pctp + 1); + sprintf(tmp, fmt.c_str(), d); output += tmp; break; } @@ -1517,9 +1515,9 @@ 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.empty()) return NULL; - strncpy(outstr, match.c_str()+strlen(prefixp)+1, // +1 to skip the "+" + outstr[0] = '\0'; + strncat(outstr, match.c_str() + strlen(prefixp) + 1, // +1 to skip the "+" VL_VALUE_STRING_MAX_WIDTH); - outstr[VL_VALUE_STRING_MAX_WIDTH-1] = '\0'; return outstr; } @@ -2094,8 +2092,8 @@ const char* Verilated::commandArgsPlusMatch(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.empty()) return ""; - strncpy(outstr, match.c_str(), VL_VALUE_STRING_MAX_WIDTH); - outstr[VL_VALUE_STRING_MAX_WIDTH-1] = '\0'; + outstr[0] = '\0'; + strncat(outstr, match.c_str(), VL_VALUE_STRING_MAX_WIDTH - 1); return outstr; } From cba05480baac933743a5379b04d700f669b719f2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 6 Apr 2020 20:13:24 -0400 Subject: [PATCH 025/127] Fix clang warning. --- include/verilated.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 663080372..94b7ed6b7 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1517,7 +1517,7 @@ const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE { if (match.empty()) return NULL; outstr[0] = '\0'; strncat(outstr, match.c_str() + strlen(prefixp) + 1, // +1 to skip the "+" - VL_VALUE_STRING_MAX_WIDTH); + VL_VALUE_STRING_MAX_WIDTH - 1); return outstr; } From 4556b6c0229da863fe3c36c6bb97521f276d29e2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 7 Apr 2020 12:17:48 -0400 Subject: [PATCH 026/127] Fix clang warning. --- src/V3EmitC.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 2a9c1d1d2..1bf5cbc19 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2791,8 +2791,10 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("\n// INTERNAL VARIABLES\n"); if (modp->isTop()) puts("// Internals; generally not touched by application code\n"); - ofp()->putsPrivate(!modp->isTop()); // private: unless top - puts(symClassName()+"* __VlSymsp; // Symbol table\n"); + if (!VN_IS(modp, Class)) { // Avoid clang unused error (& don't want in every object) + ofp()->putsPrivate(!modp->isTop()); // private: unless top + puts(symClassName()+"* __VlSymsp; // Symbol table\n"); + } ofp()->putsPrivate(false); // public: if (modp->isTop()) { if (v3Global.opt.inhibitSim()) { From 0cfa82857230c60dc487ed0cc6659992262d1742 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 7 Apr 2020 19:07:47 -0400 Subject: [PATCH 027/127] Fix DPI import/export to be standard compliant, #2236. --- Changes | 2 + include/verilated_dpi.h | 22 +- src/V3Ast.cpp | 5 + src/V3Ast.h | 29 +- src/V3AstNodes.cpp | 34 +- src/V3AstNodes.h | 9 + src/V3ProtectLib.cpp | 9 +- src/V3Task.cpp | 159 +- src/V3Task.h | 8 +- src/V3Width.cpp | 2 +- test_regress/driver.pl | 2 +- test_regress/input.vc | 2 - test_regress/t/t_dpi_accessors.cpp | 18 +- test_regress/t/t_dpi_arg_inout_type.cpp | 1320 +++++++++++++++++ test_regress/t/t_dpi_arg_inout_type.out | 265 ++++ test_regress/t/t_dpi_arg_inout_type.pl | 45 + test_regress/t/t_dpi_arg_inout_type.v | 1075 ++++++++++++++ test_regress/t/t_dpi_arg_inout_type__Dpi.out | 287 ++++ test_regress/t/t_dpi_arg_input_type.cpp | 815 ++++++++++ test_regress/t/t_dpi_arg_input_type.out | 265 ++++ test_regress/t/t_dpi_arg_input_type.pl | 45 + test_regress/t/t_dpi_arg_input_type.v | 917 ++++++++++++ test_regress/t/t_dpi_arg_input_type__Dpi.out | 287 ++++ test_regress/t/t_dpi_arg_output_type.cpp | 966 ++++++++++++ test_regress/t/t_dpi_arg_output_type.out | 265 ++++ test_regress/t/t_dpi_arg_output_type.pl | 45 + test_regress/t/t_dpi_arg_output_type.v | 989 ++++++++++++ test_regress/t/t_dpi_arg_output_type__Dpi.out | 287 ++++ test_regress/t/t_dpi_exp_bad.out | 4 - test_regress/t/t_dpi_exp_bad.v | 14 - test_regress/t/t_dpi_logic_bad.pl | 19 - test_regress/t/t_dpi_logic_bad.v | 18 - test_regress/t/t_dpi_result_type.cpp | 352 +++++ test_regress/t/t_dpi_result_type.out | 91 ++ test_regress/t/t_dpi_result_type.pl | 45 + test_regress/t/t_dpi_result_type.v | 520 +++++++ test_regress/t/t_dpi_result_type__Dpi.out | 155 ++ test_regress/t/t_dpi_result_type_bad.out | 399 +++++ ...pi_exp_bad.pl => t_dpi_result_type_bad.pl} | 5 +- test_regress/t/t_dpi_result_type_bad.v | 322 ++++ test_regress/t/t_gen_missing_bad.out | 3 - test_regress/t/t_preproc_inc_notfound_bad.out | 3 - 42 files changed, 9907 insertions(+), 217 deletions(-) create mode 100644 test_regress/t/t_dpi_arg_inout_type.cpp create mode 100644 test_regress/t/t_dpi_arg_inout_type.out create mode 100755 test_regress/t/t_dpi_arg_inout_type.pl create mode 100644 test_regress/t/t_dpi_arg_inout_type.v create mode 100644 test_regress/t/t_dpi_arg_inout_type__Dpi.out create mode 100644 test_regress/t/t_dpi_arg_input_type.cpp create mode 100644 test_regress/t/t_dpi_arg_input_type.out create mode 100755 test_regress/t/t_dpi_arg_input_type.pl create mode 100644 test_regress/t/t_dpi_arg_input_type.v create mode 100644 test_regress/t/t_dpi_arg_input_type__Dpi.out create mode 100644 test_regress/t/t_dpi_arg_output_type.cpp create mode 100644 test_regress/t/t_dpi_arg_output_type.out create mode 100755 test_regress/t/t_dpi_arg_output_type.pl create mode 100644 test_regress/t/t_dpi_arg_output_type.v create mode 100644 test_regress/t/t_dpi_arg_output_type__Dpi.out delete mode 100644 test_regress/t/t_dpi_exp_bad.out delete mode 100644 test_regress/t/t_dpi_exp_bad.v delete mode 100755 test_regress/t/t_dpi_logic_bad.pl delete mode 100644 test_regress/t/t_dpi_logic_bad.v create mode 100644 test_regress/t/t_dpi_result_type.cpp create mode 100644 test_regress/t/t_dpi_result_type.out create mode 100755 test_regress/t/t_dpi_result_type.pl create mode 100644 test_regress/t/t_dpi_result_type.v create mode 100644 test_regress/t/t_dpi_result_type__Dpi.out create mode 100644 test_regress/t/t_dpi_result_type_bad.out rename test_regress/t/{t_dpi_exp_bad.pl => t_dpi_result_type_bad.pl} (69%) create mode 100644 test_regress/t/t_dpi_result_type_bad.v diff --git a/Changes b/Changes index 14321ad0e..62bfc017b 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Configuring with ccache present now defaults to using it; see OBJCACHE. +** Fix DPI import/export to be standard compliant, #2236. [Geza Lore] + **** Support $ferror, and $fflush without arguments, #1638. diff --git a/include/verilated_dpi.h b/include/verilated_dpi.h index bad33e130..b15527fb3 100644 --- a/include/verilated_dpi.h +++ b/include/verilated_dpi.h @@ -32,7 +32,7 @@ //=================================================================== // SETTING OPERATORS -/// Return WData from svBitVecVal +/// Convert svBitVecVal to Verilator internal data static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, const svBitVecVal* lwp) VL_MT_SAFE { int words = VL_WORDS_I(obits); for (int i = 0; i < words - 1; ++i) { @@ -40,7 +40,14 @@ static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, const svBitVecVal* lw } owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits); } -/// Return svBitVecVal from WData +static inline QData VL_SET_Q_SVBV(const svBitVecVal* lwp) VL_MT_SAFE { + return _VL_SET_QII(lwp[1], lwp[0]); +} +static inline IData VL_SET_I_SVBV(const svBitVecVal* lwp) VL_MT_SAFE { + return lwp[0]; +} + +/// Convert Verilator internal data to svBitVecVal 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) { @@ -48,8 +55,14 @@ static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) VL_M } owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits); } +static inline void VL_SET_SVBV_I(int, svBitVecVal* owp, IData ld) VL_MT_SAFE { + owp[0] = ld; +} +static inline void VL_SET_SVBV_Q(int, svBitVecVal* owp, QData ld) VL_MT_SAFE { + VL_SET_WQ(owp, ld); +} -/// Convert svLogicVecVal to/from WData +/// Convert svLogicVecVal to Verilator internal data /// Note these functions ignore X/Z in svLogicVecVal static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, const svLogicVecVal* lwp) VL_MT_SAFE { int words = VL_WORDS_I(obits); @@ -64,6 +77,9 @@ static inline QData VL_SET_Q_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE { static inline IData VL_SET_I_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE { return lwp[0].aval; } + +/// Convert Verilator internal data to svLogicVecVal +/// Note these functions never create X/Z in svLogicVecVal static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) VL_MT_SAFE { int words = VL_WORDS_I(obits); for (int i = 0; i < words; ++i) { diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 42ac68911..7d7e1b1f4 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1209,6 +1209,11 @@ AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin, return v3Global.rootp()->typeTablep() ->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, range, widthMin, numeric); } +AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin, + AstNumeric numeric) const { + return v3Global.rootp()->typeTablep() + ->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, range, widthMin, numeric); +} AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) { return v3Global.rootp()->typeTablep() ->findInsertSameDType(nodep); diff --git a/src/V3Ast.h b/src/V3Ast.h index 952377350..f9797bc80 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -397,12 +397,12 @@ public: const char* dpiType() const { static const char* const names[] = { "%E-unk", - "unsigned char", "char", "void*", "int", "int", "svLogic", "long long", - "double", "short int", "float", "long long", + "svBit", "char", "void*", "int", "%E-integer", "svLogic", "long long", + "double", "short", "float", "%E-time", "const char*", "dpiScope", "const char*", "IData", "QData", - "svLogic", // Though shouldn't be needed + "%E-logic-implicit", " MAX" }; return names[m_e]; @@ -446,7 +446,7 @@ public: || m_e==UINT32 || m_e==UINT64; } bool isFourstate() const { - return m_e==INTEGER || m_e==LOGIC || m_e==LOGIC_IMPLICIT; + return m_e == INTEGER || m_e == LOGIC || m_e == LOGIC_IMPLICIT || m_e == TIME; } bool isZeroInit() const { // Otherwise initializes to X return (m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT || m_e==LONGINT || m_e==SHORTINT @@ -462,15 +462,6 @@ public: bool isBitLogic() const { // Bit/logic vector types; can form a packed array return (m_e==LOGIC || m_e==BIT); } - bool isDpiBitVal() const { // DPI uses svBitVecVal - return m_e==BIT; - } - bool isDpiLogicVal() const { // DPI uses svLogicVecVal - return m_e==INTEGER || m_e==LOGIC || m_e==LOGIC_IMPLICIT || m_e==TIME; - } - bool isDpiUnreturnable() const { // Not legal as DPI function return - return isDpiLogicVal(); - } bool isDpiUnsignable() const { // Can add "unsigned" to DPI return (m_e==BYTE || m_e==SHORTINT || m_e==INT || m_e==LONGINT || m_e==INTEGER); } @@ -1561,6 +1552,8 @@ public: AstNodeDType* findLogicDType(int width, int widthMin, AstNumeric numeric) const; AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin, AstNumeric numeric) const; + AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin, + AstNumeric numeric) const; AstNodeDType* findBasicDType(AstBasicDTypeKwd kwd) const; AstBasicDType* findInsertSameDType(AstBasicDType* nodep); @@ -2117,9 +2110,13 @@ public: virtual void dump(std::ostream& str) const; // For basicp() we reuse the size to indicate a "fake" basic type of same size virtual AstBasicDType* basicp() const { - return (isFourstate() - ? VN_CAST(findLogicDType(width(), width(), numeric()), BasicDType) - : VN_CAST(findBitDType(width(), width(), numeric()), BasicDType)); } + return (isFourstate() ? VN_CAST(findLogicRangeDType(VNumRange(width() - 1, 0, false), + width(), numeric()), + BasicDType) + : VN_CAST(findBitRangeDType(VNumRange(width() - 1, 0, false), + width(), numeric()), + BasicDType)); + } virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index fef301062..0aa52a399 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -499,31 +499,21 @@ string AstVar::dpiArgType(bool named, bool forReturn) const { arg = "const svOpenArrayHandle"; } else if (!basicp()) { arg = "UNKNOWN"; - } else if (basicp()->keyword().isDpiBitVal()) { - if (widthMin() == 1) { - arg = "unsigned char"; - if (!forReturn && isWritable()) arg += "*"; + } else if (basicp()->isDpiBitVec()) { + if (forReturn) { + arg = "svBitVecVal"; + } else if (isReadOnly()) { + arg = "const svBitVecVal*"; } else { - if (forReturn) { - arg = "svBitVecVal"; - } else if (isReadOnly()) { - arg = "const svBitVecVal*"; - } else { - arg = "svBitVecVal*"; - } + arg = "svBitVecVal*"; } - } else if (basicp()->keyword().isDpiLogicVal()) { - if (widthMin() == 1) { - arg = "unsigned char"; - if (!forReturn && isWritable()) arg += "*"; + } else if (basicp()->isDpiLogicVec()) { + if (forReturn) { + arg = "svLogicVecVal"; + } else if (isReadOnly()) { + arg = "const svLogicVecVal*"; } else { - if (forReturn) { - arg = "svLogicVecVal"; - } else if (isReadOnly()) { - arg = "const svLogicVecVal*"; - } else { - arg = "svLogicVecVal*"; - } + arg = "svLogicVecVal*"; } } else { arg = basicp()->keyword().dpiType(); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 5343bf1ad..1e7118ad2 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -753,6 +753,15 @@ public: bool isSloppy() const { return keyword().isSloppy(); } bool isZeroInit() const { return keyword().isZeroInit(); } bool isRanged() const { return rangep() || m.m_nrange.ranged(); } + bool isDpiBitVec() const { // DPI uses svBitVecVal + return keyword() == AstBasicDTypeKwd::BIT && isRanged(); + } + bool isDpiLogicVec() const { // DPI uses svLogicVecVal + return keyword().isFourstate() && !(keyword() == AstBasicDTypeKwd::LOGIC && !isRanged()); + } + bool isDpiPrimitive() const { // DPI uses a primitive type + return !isDpiBitVec() && !isDpiLogicVec(); + } const VNumRange& nrange() const { return m.m_nrange; } // Generally the msb/lsb/etc funcs should be used instead int msb() const { return (rangep() ? rangep()->msbConst() : m.m_nrange.hi()); } int lsb() const { return (rangep() ? rangep()->lsbConst() : m.m_nrange.lo()); } diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index b9be66a9b..018a1d4f1 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -367,7 +367,7 @@ class ProtectVisitor : public AstNVisitor { string cInputConnection(AstVar* varp) { string frstmt; - bool useSetWSvlv = V3Task::dpiToInternalFrStmt(varp, varp->name(), true, frstmt); + bool useSetWSvlv = V3Task::dpiToInternalFrStmt(varp, varp->name(), frstmt); if (useSetWSvlv) { return frstmt+" handlep__V->"+varp->name()+", "+varp->name()+");\n"; } @@ -424,11 +424,10 @@ class ProtectVisitor : public AstNVisitor { m_seqAssignsp->addText(fl, varp->name()+" = "+varp->name()+"_seq__V;\n"); m_comboAssignsp->addText(fl, varp->name()+" = "+varp->name()+"_combo__V;\n"); m_cComboParamsp->addText(fl, varp->dpiArgType(true, false)+"\n"); - m_cComboOutsp->addText(fl, V3Task::assignInternalToDpi(varp, false, true, "", "", - "handlep__V->")); + m_cComboOutsp->addText(fl, + V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->")); m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false)+"\n"); - m_cSeqOutsp->addText(fl, V3Task::assignInternalToDpi(varp, false, true, "", "", - "handlep__V->")); + m_cSeqOutsp->addText(fl, V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->")); } public: diff --git a/src/V3Task.cpp b/src/V3Task.cpp index ffe18e221..3477d0591 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -597,34 +597,25 @@ private: } AstNode* createDpiTemp(AstVar* portp, const string& suffix) { - bool bitvec = (portp->basicp()->keyword().isDpiBitVal() && portp->width() > 32); - bool logicvec = (portp->basicp()->keyword().isDpiLogicVal() && portp->width() > 1); - string stmt; - if (bitvec) { - stmt += "svBitVecVal "+portp->name()+suffix; - stmt += " ["+cvtToStr(portp->widthWords())+"]"; - } else if (logicvec) { - stmt += "svLogicVecVal "+portp->name()+suffix; - stmt += " ["+cvtToStr(portp->widthWords())+"]"; - } else { - stmt += portp->dpiArgType(true, true); - stmt += " "+portp->name()+suffix; + string stmt = portp->dpiArgType(false, true) + " " +portp->name()+suffix; + if (!portp->basicp()->isDpiPrimitive()) { + stmt += "[" + cvtToStr(portp->widthWords()) + "]"; } stmt += ";\n"; return new AstCStmt(portp->fileline(), stmt); } - AstNode* createAssignInternalToDpi(AstVar* portp, bool isRtn, bool isPtr, - const string& frSuffix, const string& toSuffix) { - string stmt = V3Task::assignInternalToDpi(portp, isRtn, isPtr, frSuffix, toSuffix); + AstNode* createAssignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, + const string& toSuffix) { + string stmt = V3Task::assignInternalToDpi(portp, isPtr, frSuffix, toSuffix); return new AstCStmt(portp->fileline(), stmt); } - AstNode* createAssignDpiToInternal(AstVarScope* portvscp, const string& frName, bool cvt) { + AstNode* createAssignDpiToInternal(AstVarScope* portvscp, const string& frName) { // Create assignment from DPI temporary into internal format AstVar* portp = portvscp->varp(); string frstmt; - bool useSetWSvlv = V3Task::dpiToInternalFrStmt(portp, frName, cvt, frstmt); + bool useSetWSvlv = V3Task::dpiToInternalFrStmt(portp, frName, frstmt); if (useSetWSvlv) { AstNode* linesp = new AstText(portp->fileline(), frstmt); linesp->addNext(new AstVarRef(portp->fileline(), portvscp, true)); @@ -712,7 +703,10 @@ private: argnodesp = argnodesp->addNextNull(refp); if (portp->isNonOutput()) { - dpip->addStmtsp(createAssignDpiToInternal(outvscp, portp->name(), false)); + std::string frName + = portp->isInoutish() && portp->basicp()->isDpiPrimitive() ? "*" : ""; + frName += portp->name(); + dpip->addStmtsp(createAssignDpiToInternal(outvscp, frName)); } } } @@ -749,15 +743,16 @@ private: for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO() && portp->isWritable() && !portp->isFuncReturn()) { - dpip->addStmtsp(createAssignInternalToDpi(portp, false, true, "__Vcvt", "")); + dpip->addStmtsp(createAssignInternalToDpi(portp, true, "__Vcvt", "")); } } } if (rtnvarp) { dpip->addStmtsp(createDpiTemp(rtnvarp, "")); - dpip->addStmtsp(createAssignInternalToDpi(rtnvarp, true, false, "__Vcvt", "")); - string stmt = "return "+rtnvarp->name()+";\n"; + dpip->addStmtsp(createAssignInternalToDpi(rtnvarp, false, "__Vcvt", "")); + string stmt = "return " + rtnvarp->name(); + stmt += rtnvarp->basicp()->isDpiPrimitive() ? ";\n" : "[0];\n"; dpip->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); } makePortList(nodep, dpip); @@ -842,15 +837,10 @@ private: && portp->name() != "__Vscopep" // Passed to dpiContext, not callee && portp->name() != "__Vfilenamep" && portp->name() != "__Vlineno") { - bool openarray = portp->isDpiOpenArray(); - bool bitvec = (portp->basicp()->keyword().isDpiBitVal() - && portp->width() > 32); - bool logicvec = (portp->basicp()->keyword().isDpiLogicVal() - && portp->width() > 1); if (args != "") { args+= ", "; } - if (openarray) { + if (portp->isDpiOpenArray()) { // Ideally we'd make a table of variable // characteristics, and reuse it wherever we can // At least put them into the module's CTOR as static? @@ -870,18 +860,16 @@ private: args += "&"+name; } else { - if (bitvec) {} - else if (logicvec) {} - else if (portp->isWritable()) args += "&"; - else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal() - && portp->width() != 1) args += "&"; // it's a svBitVecVal (2-32 bits wide) + if (portp->isWritable() && portp->basicp()->isDpiPrimitive()) { + args += "&"; + } args += portp->name()+"__Vcvt"; cfuncp->addStmtsp(createDpiTemp(portp, "__Vcvt")); if (portp->isNonOutput()) { - cfuncp->addStmtsp(createAssignInternalToDpi( - portp, false, false, "", "__Vcvt")); + cfuncp->addStmtsp( + createAssignInternalToDpi(portp, false, "", "__Vcvt")); } } } @@ -897,8 +885,9 @@ private: { // Call the user function string stmt; if (rtnvscp) { // isFunction will no longer work as we unlinked the return var - stmt += (rtnvscp->varp()->dpiArgType(true, true) - + " "+rtnvscp->varp()->name()+"__Vcvt = "); + cfuncp->addStmtsp(createDpiTemp(rtnvscp->varp(), "__Vcvt")); + stmt = rtnvscp->varp()->name() + "__Vcvt"; + stmt += rtnvscp->varp()->basicp()->isDpiPrimitive() ? " = " : "[0] = "; } stmt += nodep->cname()+"("+args+");\n"; cfuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); @@ -911,7 +900,8 @@ private: if (portp->isIO() && (portp->isWritable() || portp->isFuncReturn()) && !portp->isDpiOpenArray()) { AstVarScope* portvscp = VN_CAST(portp->user2p(), VarScope); // Remembered when we created it earlier - cfuncp->addStmtsp(createAssignDpiToInternal(portvscp, portp->name()+"__Vcvt", true)); + cfuncp->addStmtsp( + createAssignDpiToInternal(portvscp, portp->name() + "__Vcvt")); } } } @@ -927,14 +917,30 @@ private: AstVar* portp = VN_CAST(nodep->fvarp(), Var); UASSERT_OBJ(portp, nodep, "function without function output variable"); if (!portp->isFuncReturn()) nodep->v3error("Not marked as function return var"); - if (portp->isWide()) nodep->v3error("Unsupported: Public functions with return > 64 bits wide. (Make it a output instead.)"); - if (ftaskNoInline || nodep->dpiExport()) portp->funcReturn(false); // Converting return to 'outputs' - if ((nodep->dpiImport() || nodep->dpiExport()) - && portp->dtypep()->basicp() - && portp->dtypep()->basicp()->keyword().isDpiUnreturnable()) { - portp->v3error("DPI function may not return type " - <basicp()->prettyTypeName() - <<" (IEEE 1800-2017 35.5.5)"); + if (nodep->dpiImport() || nodep->dpiExport()) { + AstBasicDType* bdtypep = portp->dtypep()->basicp(); + if (!bdtypep->isDpiPrimitive()) { + if (bdtypep->isDpiBitVec() && portp->width() > 32) { + portp->v3error("DPI function may not return a > 32 bits wide type " + "other than basic types.\n" + + V3Error::warnMore() + + "... Suggest make it an output argument instead?"); + } + if (bdtypep->isDpiLogicVec()) { + portp->v3error("DPI function may not return a 4-state type " + "other than a single 'logic' (IEEE 1800-2017 35.5.5)"); + } + } + } else { + if (portp->isWide()) { + nodep->v3error("Unsupported: Public functions with return > 64 bits wide.\n" + + V3Error::warnMore() + + "... Suggest make it an output argument instead?"); + } + } + + if (ftaskNoInline || nodep->dpiExport()) { + portp->funcReturn(false); // Converting return to 'outputs' } portp->unlinkFrBack(); rtnvarp = portp; @@ -1451,34 +1457,22 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) return tconnects; } -string V3Task::assignInternalToDpi(AstVar* portp, bool isRtn, bool isPtr, +string V3Task::assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, const string& toSuffix, const string& frPrefix) { // Create assignment from internal format into DPI temporary - bool bitvec = (portp->basicp()->keyword().isDpiBitVal() && portp->width() > 32); - bool logicvec = (portp->basicp()->keyword().isDpiLogicVal() && portp->width() > 1); - if (isRtn && (bitvec || logicvec)) { - portp->v3error("DPI functions cannot return > 32 bits or four-state;" - " use a two-state type or task instead: "<prettyNameQ()); - // Code below works, but won't compile right, and IEEE illegal - } string stmt; string ket; // Someday we'll have better type support, and this can make variables and casts. // But for now, we'll just text-bash it. string frName = frPrefix+portp->name()+frSuffix; string toName = portp->name()+toSuffix; - if (bitvec) { - if (portp->isWide()) { - stmt += ("VL_SET_SVBV_W("+cvtToStr(portp->width()) - +", "+toName+", "+frName+")"); - } else { - stmt += "VL_SET_WQ("+toName+", "+frName+")"; - } - } else if (logicvec) { + if (portp->basicp()->isDpiBitVec()) { + stmt += ("VL_SET_SVBV_" + string(portp->dtypep()->charIQWN()) + "(" + + cvtToStr(portp->width()) + ", " + toName + ", " + frName + ")"); + } else if (portp->basicp()->isDpiLogicVec()) { stmt += ("VL_SET_SVLV_" + string(portp->dtypep()->charIQWN()) + "(" - + cvtToStr(portp->width()) - + ", "+toName+", "+frName+")"); + + cvtToStr(portp->width()) + ", " + toName + ", " + frName + ")"); } else { if (isPtr) stmt += "*"; // DPI outputs are pointers stmt += toName+" = "; @@ -1495,36 +1489,21 @@ string V3Task::assignInternalToDpi(AstVar* portp, bool isRtn, bool isPtr, return stmt; } -bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, bool cvt, string& frstmt) { +bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt) { if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) { frstmt = "VL_CVT_VP_Q("+frName+")"; - } - else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal() - && portp->width() != 1 && portp->isQuad()) { - // SV is vector, Verilator isn't - frstmt = "VL_SET_QW("+frName+")"; - } - else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal() - && portp->width() != 1 && portp->isQuad()) { - frstmt = "VL_SET_Q_SVLV("+frName+")"; - } - else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal() - && portp->width() != 1 && !portp->isWide()) { - frstmt = "VL_SET_I_SVLV("+frName+")"; - } - else if (!cvt - && portp->basicp() && portp->basicp()->keyword().isDpiBitVal() - && portp->width() != 1 && !portp->isWide()) { - frstmt = "*"+frName; // it's a svBitVecVal, which other code won't think is arrayed (as WData aren't), but really is - } - else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal() - && portp->width() != 1 && portp->isWide()) { - // Need to convert to wide, using special function - frstmt = "VL_SET_W_SVLV("+cvtToStr(portp->width()) + ","; - return true; - } - else { + } else if ((portp->basicp() && portp->basicp()->isDpiPrimitive())) { frstmt = frName; + } else { + const string frSvType = portp->basicp()->isDpiBitVec() ? "SVBV" : "SVLV"; + if (portp->isWide()) { + // Need to convert to wide, using special function + frstmt = "VL_SET_W_" + frSvType + "(" + cvtToStr(portp->width()) + ","; + return true; + } else { + frstmt = "VL_SET_" + string(portp->dtypep()->charIQWN()) + "_" + frSvType + "(" + + frName + ")"; + } } return false; } diff --git a/src/V3Task.h b/src/V3Task.h index 57579b8cb..b711bfcb1 100644 --- a/src/V3Task.h +++ b/src/V3Task.h @@ -37,11 +37,9 @@ public: static void taskAll(AstNetlist* nodep); /// Return vector of [port, pin-connects-to] (SLOW) static V3TaskConnects taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp); - static string assignInternalToDpi(AstVar* portp, bool isRtn, bool isPtr, - const string& frSuffix, const string& toSuffix, - const string& frPrefix=""); - static bool dpiToInternalFrStmt(AstVar* portp, const string& frName, bool cvt, - string& frstmt); + static string assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, + const string& toSuffix, const string& frPrefix = ""); + static bool dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt); }; #endif // Guard diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 36e454514..713914d9f 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1756,7 +1756,7 @@ private: for (itemp = nodep->membersp(); itemp && itemp->nextp(); itemp=VN_CAST(itemp->nextp(), MemberDType)) ; for (AstMemberDType* backip; itemp; itemp=backip) { - if (nodep->isFourstate()) nodep->isFourstate(true); + if (itemp->isFourstate()) nodep->isFourstate(true); backip = VN_CAST(itemp->backp(), MemberDType); itemp->lsb(lsb); if (VN_IS(nodep, UnionDType)) { diff --git a/test_regress/driver.pl b/test_regress/driver.pl index db3f488e5..7b1f82649 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -605,7 +605,7 @@ sub new { nc_run_flags => [split(/\s+/,"+licqueue -q +assert +sv -R")], # ModelSim ms => 0, - ms_flags => [split(/\s+/,("-sv -work $self->{obj_dir}/work"))], + ms_flags => [split(/\s+/, ("-sv -work $self->{obj_dir}/work +define+MS=1 -ccflags \"-DMS=1\""))], ms_flags2 => [], # Overridden in some sim files ms_pli => 1, # need to use pli ms_run_flags => [split(/\s+/,"-lib $self->{obj_dir}/work -c -do 'run -all;quit' ")], diff --git a/test_regress/input.vc b/test_regress/input.vc index 596545587..77e6ce27e 100644 --- a/test_regress/input.vc +++ b/test_regress/input.vc @@ -1,7 +1,5 @@ +librescan +libext+.v -y t - -y obj_dir/ +incdir+t +incdir+../include - +incdir+obj_dir/ diff --git a/test_regress/t/t_dpi_accessors.cpp b/test_regress/t/t_dpi_accessors.cpp index dbec01ec9..e3f227ab1 100644 --- a/test_regress/t/t_dpi_accessors.cpp +++ b/test_regress/t/t_dpi_accessors.cpp @@ -246,7 +246,7 @@ int main() { for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { dut->clk = 1 - dut->clk; a = 1 - (int)a_read(); - a_write(a); + a_write(reinterpret_cast(&a)); logReg(dut->clk, "write a", a, " (before clk)"); a = a_read(); logReg(dut->clk, "read a", a, " (before clk)"); @@ -275,7 +275,7 @@ int main() { for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { dut->clk = 1 - dut->clk; b = (int)b_read() - 1; - b_write((const svBitVecVal*)&b); + b_write(reinterpret_cast(&b)); logRegHex(dut->clk, "write b", 8, b, " (before clk)"); b = (int)b_read(); logRegHex(dut->clk, "read b", 8, b, " (before clk)"); @@ -304,7 +304,7 @@ int main() { for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { dut->clk = 1 - dut->clk; mem32 = (int)mem32_read() - 1; - mem32_write((const svBitVecVal*)&mem32); + mem32_write(reinterpret_cast(&mem32)); logRegHex(dut->clk, "write mem32", 8, mem32, " (before clk)"); mem32 = (int)mem32_read(); logRegHex(dut->clk, "read mem32", 8, mem32, " (before clk)"); @@ -426,7 +426,7 @@ int main() { logRegHex(dut->clk, "read b [3:0]", 4, b_slice, " (before write)"); b_slice--; - b_slice_write((const svBitVecVal*)&b_slice); + b_slice_write(reinterpret_cast(&b_slice)); logRegHex(dut->clk, "write b [3:0]", 4, b_slice, " (before clk)"); int b_after = (int)b_read(); @@ -465,7 +465,7 @@ int main() { logRegHex(dut->clk, "read mem32 [7:6,2:0]", 5, mem32_slice, " (before write)"); mem32_slice--; - mem32_slice_write((const svBitVecVal*)&mem32_slice); + mem32_slice_write(reinterpret_cast(&mem32_slice)); logRegHex(dut->clk, "write mem32 [7:6,2:0]", 5, mem32_slice, " (before clk)"); int mem32_after = (int)mem32_read(); @@ -545,8 +545,8 @@ int main() { e = 0x05 | (i << 4); f = 0xa0 | i; - e_write((const svBitVecVal*)&e); - f_write((const svBitVecVal*)&f); + e_write(reinterpret_cast(&e)); + f_write(reinterpret_cast(&f)); e = (int)e_read(); f = (int)f_read(); @@ -592,7 +592,7 @@ int main() { logRegHex(dut->clk, "read e ", 8, e, " (before write)"); int l1 = 0x5a5a; - l1_write((const svBitVecVal*)&l1); + l1_write(reinterpret_cast(&l1)); logRegHex(dut->clk, "write l1 ", 15, l1, " (before clk)"); int b_after = (int)b_read(); @@ -641,7 +641,7 @@ int main() { logRegHex(dut->clk, "read f ", 8, f, " (before write)"); int l2 = 0xa5 + i; - l2_write((const svBitVecVal*)&l2); + l2_write(reinterpret_cast(&l2)); logRegHex(dut->clk, "write l2", 8, l2, " (before clk)"); int e_after = (int)e_read(); diff --git a/test_regress/t/t_dpi_arg_inout_type.cpp b/test_regress/t/t_dpi_arg_inout_type.cpp new file mode 100644 index 000000000..5cec53ba8 --- /dev/null +++ b/test_regress/t/t_dpi_arg_inout_type.cpp @@ -0,0 +1,1320 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include +#include +#include + +#if defined(NCSC) +// Used by NC's svdpi.h to pick up svLogicVecVal with _.aval and _.bval fields, +// rather than the IEEE 1800-2005 version which has _.a and _.b fields. +# define DPI_COMPATIBILITY_VERSION_1800v2012 +#endif + +#include "svdpi.h" + +#if defined(VERILATOR) // Verilator +# include "Vt_dpi_arg_inout_type__Dpi.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_SHORTREAL +#elif defined(VCS) // VCS +# include "../vc_hdrs.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_TIME +#elif defined(NCSC) // NC +# include "dpi-exp.h" +# include "dpi-imp.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_TIME +# define NO_INTEGER +# define NO_SHORTREAL +#elif defined(MS) // ModelSim +# include "dpi.h" +typedef int64_t sv_longint_t; +typedef uint64_t sv_longint_unsigned_t; +#else +# error "Unknown simulator for DPI test" +#endif + +//====================================================================== +// Implementations of imported functions +//====================================================================== + +#define stop() \ + do { \ + printf(__FILE__ ":%d Bad value\n", __LINE__); \ + abort(); \ + } while (0) + +void check_bvals(const svLogicVecVal* v, unsigned n); +void check_bvals(const svLogicVecVal* v, unsigned n) { + for (unsigned i = 0; i < n; i++) { + if (v[i].bval != 0) { + printf(__FILE__ ":%d Bad svLogicVecVal bval\n", __LINE__); + abort(); + } + } +} + +void set_bvals(svLogicVecVal* v, unsigned n); +void set_bvals(svLogicVecVal* v, unsigned n) { + for (unsigned i = 0; i < n; i++) { + v[i].bval = 0; + } +} + +// Basic types as per IEEE 1800-2017 35.5.6 +void i_byte(char* x) { + static int n = 0; + if (*x != 10 - n++) stop(); + *x += 100; +} + +void i_byte_unsigned(unsigned char* x) { + static int n = 0; + if (*x != 20 - n++) stop(); + *x += 200; +} + +void i_shortint(short* x) { + static int n = 0; + if (*x != 30 - n++) stop(); + *x += 300; +} + +void i_shortint_unsigned(unsigned short* x) { + static int n = 0; + if (*x != 40 - n++) stop(); + *x += 400; +} + +void i_int(int* x) { + static int n = 0; + if (*x != 50 - n++) stop(); + *x += 500; +} + +void i_int_unsigned(unsigned* x) { + static int n = 0; + if (*x != 60 - n++) stop(); + *x += 600; +} + +void i_longint(sv_longint_t* x) { + static int n = 0; + if (*x != 70 - n++) stop(); + *x += 700; +} + +void i_longint_unsigned(sv_longint_unsigned_t* x) { + static int n = 0; + if (*x != 80 - n++) stop(); + *x += 800; +} + +#ifndef NO_TIME +void i_time(svLogicVecVal* x) { + static int n = 0; + if (x[0].aval != 90 - n++) stop(); + if (x[1].aval != 0) stop(); + check_bvals(x, 2); + x[0].aval += 900; +} +#endif + +#ifndef NO_INTEGER +void i_integer(svLogicVecVal* x) { + static int n = 0; + if (x[0].aval != 100 - n++) stop(); + check_bvals(x, 1); + x[0].aval += 1000; +} +#endif + +void i_real(double* x) { + static int n = 0; + if (*x != (-2.0 * n++ - 1.0) / 2.0) stop(); + *x += -100.0; +} + +#ifndef NO_SHORTREAL +void i_shortreal(float* x) { + static int n = 0; + if (*x != (-4.0f * n++ - 1.0f) / 4.0f) stop(); + *x += -200.0f; +} +#endif + +void i_chandle(void** x) { + static int n = 0; + printf("i_chandle %d\n", n); + if (*x != NULL) stop(); + *x = n % 2 ? reinterpret_cast(&i_chandle) : 0; + n++; +} + +void i_string(const char** x) { + static int n = 0; + printf("i_string %d\n", n); + if (n++ % 2 == 0) { + if (strcmp(*x, "Hello") != 0) stop(); + *x = "Good"; + } else { + if (strcmp(*x, "World") != 0) stop(); + *x = "Bye"; + } +} + +void i_bit(svBit* x) { + static int n = 0; + printf("i_bit %d\n", n); + if (*x != !(n++ % 2)) stop(); + *x ^= 1; +} + +void i_logic(svLogic* x) { + static int n = 0; + printf("i_logic %d\n", n); + if (*x != n++ % 2) stop(); + *x ^= 1; +} + +// Basic types via typedefs +void i_byte_t(char* x) { + static int n = 0; + if (*x != 10 - n) stop(); + *x += 101; + n += 2; +} + +void i_byte_unsigned_t(unsigned char* x) { + static int n = 0; + if (*x != 20 - n) stop(); + *x += 202; + n += 2; +} + +void i_shortint_t(short* x) { + static int n = 0; + if (*x != 30 - n) stop(); + *x += 303; + n += 2; +} + +void i_shortint_unsigned_t(unsigned short* x) { + static int n = 0; + if (*x != 40 - n) stop(); + *x += 404; + n += 2; +} + +void i_int_t(int* x) { + static int n = 0; + if (*x != 50 - n) stop(); + *x += 505; + n += 2; +} + +void i_int_unsigned_t(unsigned* x) { + static int n = 0; + if (*x != 60 - n) stop(); + *x += 606; + n += 2; +} + +void i_longint_t(sv_longint_t* x) { + static int n = 0; + if (*x != 70 - n) stop(); + *x += 707; + n += 2; +} + +void i_longint_unsigned_t(sv_longint_unsigned_t* x) { + static int n = 0; + if (*x != 80 - n) stop(); + *x += 808; + n += 2; +} + +#ifndef NO_TIME +void i_time_t(svLogicVecVal* x) { + static int n = 0; + if (x[0].aval != 90 - n) stop(); + if (x[1].aval != 0) stop(); + check_bvals(x, 2); + x[0].aval += 909; + n += 2; +} +#endif + +#ifndef NO_INTEGER +void i_integer_t(svLogicVecVal* x) { + static int n = 0; + if (x[0].aval != 100 - n) stop(); + check_bvals(x, 1); + x[0].aval += 1001; + n += 2; +} +#endif + +void i_real_t(double* x) { + static int n = 0; + if (*x != (-2.0 * n - 1.0) / 2.0) stop(); + *x += -111.0; + n += 2; +} + +#ifndef NO_SHORTREAL +void i_shortreal_t(float* x) { + static int n = 0; + if (*x != (-4.0f * n - 1.0f) / 4.0f) stop(); + *x += -222.0f; + n += 2; +} +#endif + +void i_chandle_t(void** x) { + static int n = 0; + printf("i_chandle_t %d\n", n); + if (*x != NULL) stop(); + *x = n % 2 ? 0 : reinterpret_cast(&i_chandle_t); + n++; +} + +void i_string_t(const char** x) { + static int n = 0; + printf("i_string_t %d\n", n); + if (n++ % 2 == 0) { + if (strcmp(*x, "World") != 0) stop(); + *x = "Bye"; + } else { + if (strcmp(*x, "Hello") != 0) stop(); + *x = "Good"; + } +} + +void i_bit_t(svBit* x) { + static int n = 0; + printf("i_bit_t %d\n", n); + if (*x != !(n++ % 2)) stop(); + *x ^= 1; +} + +void i_logic_t(svLogic* x) { + static int n = 0; + printf("i_logic_t %d\n", n); + if (*x != n++ % 2) stop(); + *x ^= 1; +} + +// 2-state packed arrays +void i_array_2_state_1(svBitVecVal* x) { + static int n = 0; + printf("i_array_2_state_1 %d\n", n); + *x &= 1; + if (*x != !(n++ % 2)) stop(); + *x ^= 1; +} + +void i_array_2_state_32(svBitVecVal* x) { + static int n = 0; + printf("i_array_2_state_32 %d\n", n); + if (*x != 0xffffffffU << n) stop(); + *x >>= n; + n++; +} + +void i_array_2_state_33(svBitVecVal* x) { + static int n = 0; + printf("i_array_2_state_33 %d\n", n); + x[1] &= 1; + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != 1) stop(); + if (n > 0) { + x[0] = x[1] << (32 - n) | x[0] >> n; + x[1] = x[1] >> n; + } + n++; +} + +void i_array_2_state_64(svBitVecVal* x) { + static int n = 0; + printf("i_array_2_state_64 %d\n", n); + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != -1) stop(); + if (n > 0) { + x[0] = x[1] << (32 - n) | x[0] >> n; + x[1] = x[1] >> n; + } + n++; +} + +void i_array_2_state_65(svBitVecVal* x) { + static int n = 0; + printf("i_array_2_state_65 %d\n", n); + x[2] &= 1; + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != -1) stop(); + if (x[2] != 1) stop(); + if (n > 0) { + x[0] = -1; + x[1] = x[2] << (32 - n) | x[1] >> n; + x[2] = x[2] >> n; + } + n++; +} + +void i_array_2_state_128(svBitVecVal* x) { + static int n = 0; + printf("i_array_2_state_128 %d\n", n); + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != -1) stop(); + if (x[2] != -1) stop(); + if (x[3] != -1) stop(); + if (n > 0) { + x[0] = -1; + x[2] = x[3] << (32 - n) | x[2] >> n; + x[3] = x[3] >> n; + } + n++; +} + +// 2-state packed structures +void i_struct_2_state_1(svBitVecVal* x) { + static int n = 0; + printf("i_struct_2_state_1 %d\n", n); + *x &= 1; + if (*x != !(n++ % 2)) stop(); + *x ^= 1; +} + +void i_struct_2_state_32(svBitVecVal* x) { + static int n = 0; + printf("i_struct_2_state_32 %d\n", n); + if (*x != 0xffffffffU << n) stop(); + *x >>= n; + n++; +} + +void i_struct_2_state_33(svBitVecVal* x) { + static int n = 0; + printf("i_struct_2_state_33 %d\n", n); + x[1] &= 1; + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != 1) stop(); + if (n > 0) { + x[0] = x[1] << (32 - n) | x[0] >> n; + x[1] = x[1] >> n; + } + n++; +} + +void i_struct_2_state_64(svBitVecVal* x) { + static int n = 0; + printf("i_struct_2_state_64 %d\n", n); + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != -1) stop(); + if (n > 0) { + x[0] = x[1] << (32 - n) | x[0] >> n; + x[1] = x[1] >> n; + } + n++; +} + +void i_struct_2_state_65(svBitVecVal* x) { + static int n = 0; + printf("i_struct_2_state_65 %d\n", n); + x[2] &= 1; + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != -1) stop(); + if (x[2] != 1) stop(); + if (n > 0) { + x[0] = -1; + x[1] = x[2] << (32 - n) | x[1] >> n; + x[2] = x[2] >> n; + } + n++; +} + +void i_struct_2_state_128(svBitVecVal* x) { + static int n = 0; + printf("i_struct_2_state_128 %d\n", n); + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != -1) stop(); + if (x[2] != -1) stop(); + if (x[3] != -1) stop(); + if (n > 0) { + x[0] = -1; + x[2] = x[3] << (32 - n) | x[2] >> n; + x[3] = x[3] >> n; + } + n++; +} + +// 2-state packed unions +void i_union_2_state_1(svBitVecVal* x) { + static int n = 0; + printf("i_union_2_state_1 %d\n", n); + *x &= 1; + if (*x != !(n++ % 2)) stop(); + *x ^= 1; +} + +void i_union_2_state_32(svBitVecVal* x) { + static int n = 0; + printf("i_union_2_state_32 %d\n", n); + if (*x != 0xffffffffU << n) stop(); + *x >>= n; + n++; +} + +void i_union_2_state_33(svBitVecVal* x) { + static int n = 0; + printf("i_union_2_state_33 %d\n", n); + x[1] &= 1; + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != 1) stop(); + if (n > 0) { + x[0] = x[1] << (32 - n) | x[0] >> n; + x[1] = x[1] >> n; + } + n++; +} + +void i_union_2_state_64(svBitVecVal* x) { + static int n = 0; + printf("i_union_2_state_64 %d\n", n); + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != -1) stop(); + if (n > 0) { + x[0] = x[1] << (32 - n) | x[0] >> n; + x[1] = x[1] >> n; + } + n++; +} + +void i_union_2_state_65(svBitVecVal* x) { + static int n = 0; + printf("i_union_2_state_65 %d\n", n); + x[2] &= 1; + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != -1) stop(); + if (x[2] != 1) stop(); + if (n > 0) { + x[0] = -1; + x[1] = x[2] << (32 - n) | x[1] >> n; + x[2] = x[2] >> n; + } + n++; +} + +void i_union_2_state_128(svBitVecVal* x) { + static int n = 0; + printf("i_union_2_state_128 %d\n", n); + if (x[0] != 0xffffffffU << n) stop(); + if (x[1] != -1) stop(); + if (x[2] != -1) stop(); + if (x[3] != -1) stop(); + if (n > 0) { + x[0] = -1; + x[2] = x[3] << (32 - n) | x[2] >> n; + x[3] = x[3] >> n; + } + n++; +} + +// 4-state packed arrays +void i_array_4_state_1(svLogicVecVal* x) { + static int n = 0; + printf("i_array_4_state_1 %d\n", n); + x[0].aval &= 1; + if (x[0].aval != !(n++ % 2)) stop(); + check_bvals(x, 1); + x[0].aval ^= 1; +} + +void i_array_4_state_32(svLogicVecVal* x) { + static int n = 0; + printf("i_array_4_state_32 %d\n", n); + if (x[0].aval != 0xffffffffU << n) stop(); + check_bvals(x, 1); + x[0].aval >>= n; + n++; +} + +void i_array_4_state_33(svLogicVecVal* x) { + static int n = 0; + printf("i_array_4_state_33 %d\n", n); + x[1].aval &= 1; + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != 1) stop(); + check_bvals(x, 2); + if (n > 0) { + x[0].aval = x[1].aval << (32 - n) | x[0].aval >> n; + x[1].aval = x[1].aval >> n; + } + n++; +} + +void i_array_4_state_64(svLogicVecVal* x) { + static int n = 0; + printf("i_array_4_state_64 %d\n", n); + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != -1) stop(); + check_bvals(x, 2); + if (n > 0) { + x[0].aval = x[1].aval << (32 - n) | x[0].aval >> n; + x[1].aval = x[1].aval >> n; + } + n++; +} + +void i_array_4_state_65(svLogicVecVal* x) { + static int n = 0; + printf("i_array_4_state_65 %d\n", n); + x[2].aval &= 1; + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != -1) stop(); + if (x[2].aval != 1) stop(); + check_bvals(x, 3); + if (n > 0) { + x[0].aval = -1; + x[1].aval = x[2].aval << (32 - n) | x[1].aval >> n; + x[2].aval = x[2].aval >> n; + } + n++; +} + +void i_array_4_state_128(svLogicVecVal* x) { + static int n = 0; + printf("i_array_4_state_128 %d\n", n); + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != -1) stop(); + if (x[2].aval != -1) stop(); + if (x[3].aval != -1) stop(); + check_bvals(x, 4); + if (n > 0) { + x[0].aval = -1; + x[2].aval = x[3].aval << (32 - n) | x[2].aval >> n; + x[3].aval = x[3].aval >> n; + } + n++; +} + +// 4-state packed structures +void i_struct_4_state_1(svLogicVecVal* x) { + static int n = 0; + printf("i_struct_4_state_1 %d\n", n); + x[0].aval &= 1; + if (x[0].aval != !(n++ % 2)) stop(); + check_bvals(x, 1); + x[0].aval ^= 1; +} + +void i_struct_4_state_32(svLogicVecVal* x) { + static int n = 0; + printf("i_struct_4_state_32 %d\n", n); + if (x[0].aval != 0xffffffffU << n) stop(); + check_bvals(x, 1); + x[0].aval >>= n; + n++; +} + +void i_struct_4_state_33(svLogicVecVal* x) { + static int n = 0; + printf("i_struct_4_state_33 %d\n", n); + x[1].aval &= 1; + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != 1) stop(); + check_bvals(x, 2); + if (n > 0) { + x[0].aval = x[1].aval << (32 - n) | x[0].aval >> n; + x[1].aval = x[1].aval >> n; + } + n++; +} + +void i_struct_4_state_64(svLogicVecVal* x) { + static int n = 0; + printf("i_struct_4_state_64 %d\n", n); + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != -1) stop(); + check_bvals(x, 2); + if (n > 0) { + x[0].aval = x[1].aval << (32 - n) | x[0].aval >> n; + x[1].aval = x[1].aval >> n; + } + n++; +} + +void i_struct_4_state_65(svLogicVecVal* x) { + static int n = 0; + printf("i_struct_4_state_65 %d\n", n); + x[2].aval &= 1; + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != -1) stop(); + if (x[2].aval != 1) stop(); + check_bvals(x, 3); + if (n > 0) { + x[0].aval = -1; + x[1].aval = x[2].aval << (32 - n) | x[1].aval >> n; + x[2].aval = x[2].aval >> n; + } + n++; +} + +void i_struct_4_state_128(svLogicVecVal* x) { + static int n = 0; + printf("i_struct_4_state_128 %d\n", n); + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != -1) stop(); + if (x[2].aval != -1) stop(); + if (x[3].aval != -1) stop(); + check_bvals(x, 4); + if (n > 0) { + x[0].aval = -1; + x[2].aval = x[3].aval << (32 - n) | x[2].aval >> n; + x[3].aval = x[3].aval >> n; + } + n++; +} + +// 4-state packed unions +void i_union_4_state_1(svLogicVecVal* x) { + static int n = 0; + printf("i_union_4_state_1 %d\n", n); + x[0].aval &= 1; + if (x[0].aval != !(n++ % 2)) stop(); + check_bvals(x, 1); + x[0].aval ^= 1; +} + +void i_union_4_state_32(svLogicVecVal* x) { + static int n = 0; + printf("i_union_4_state_32 %d\n", n); + if (x[0].aval != 0xffffffffU << n) stop(); + check_bvals(x, 1); + x[0].aval >>= n; + n++; +} + +void i_union_4_state_33(svLogicVecVal* x) { + static int n = 0; + printf("i_union_4_state_33 %d\n", n); + x[1].aval &= 1; + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != 1) stop(); + check_bvals(x, 2); + if (n > 0) { + x[0].aval = x[1].aval << (32 - n) | x[0].aval >> n; + x[1].aval = x[1].aval >> n; + } + n++; +} + +void i_union_4_state_64(svLogicVecVal* x) { + static int n = 0; + printf("i_union_4_state_64 %d\n", n); + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != -1) stop(); + check_bvals(x, 2); + if (n > 0) { + x[0].aval = x[1].aval << (32 - n) | x[0].aval >> n; + x[1].aval = x[1].aval >> n; + } + n++; +} + +void i_union_4_state_65(svLogicVecVal* x) { + static int n = 0; + printf("i_union_4_state_65 %d\n", n); + x[2].aval &= 1; + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != -1) stop(); + if (x[2].aval != 1) stop(); + check_bvals(x, 3); + if (n > 0) { + x[0].aval = -1; + x[1].aval = x[2].aval << (32 - n) | x[1].aval >> n; + x[2].aval = x[2].aval >> n; + } + n++; +} + +void i_union_4_state_128(svLogicVecVal* x) { + static int n = 0; + printf("i_union_4_state_128 %d\n", n); + if (x[0].aval != 0xffffffffU << n) stop(); + if (x[1].aval != -1) stop(); + if (x[2].aval != -1) stop(); + if (x[3].aval != -1) stop(); + check_bvals(x, 4); + if (n > 0) { + x[0].aval = -1; + x[2].aval = x[3].aval << (32 - n) | x[2].aval >> n; + x[3].aval = x[3].aval >> n; + } + n++; +} + +//====================================================================== +// Check exported functions +//====================================================================== + +void check_exports() { + static int n = 0; + + char x_byte; + unsigned char x_byte_unsigned; + short x_shortint; + unsigned short x_shortint_unsigned; + int x_int; + unsigned x_int_unsigned; + sv_longint_t x_longint; + sv_longint_unsigned_t x_longint_unsigned; +#ifndef NO_TIME + svLogicVecVal x_time[2]; +#endif +#ifndef NO_INTEGER + svLogicVecVal x_integer[1]; +#endif + double x_real; +#ifndef NO_SHORTREAL + float x_shortreal; +#endif + void* x_chandle; + const char* x_string; + svBit x_bit; + svLogic x_logic; + + char x_byte_t; + unsigned char x_byte_unsigned_t; + short x_shortint_t; + unsigned short x_shortint_unsigned_t; + int x_int_t; + unsigned x_int_unsigned_t; + sv_longint_t x_longint_t; + sv_longint_unsigned_t x_longint_unsigned_t; +#ifndef NO_TIME + svLogicVecVal x_time_t[2]; +#endif +#ifndef NO_INTEGER + svLogicVecVal x_integer_t[1]; +#endif + double x_real_t; +#ifndef NO_SHORTREAL + float x_shortreal_t; +#endif + void* x_chandle_t; + const char* x_string_t; + svBit x_bit_t; + svLogic x_logic_t; + + svBitVecVal x_array_2_state_1[1]; + svBitVecVal x_array_2_state_32[1]; + svBitVecVal x_array_2_state_33[2]; + svBitVecVal x_array_2_state_64[2]; + svBitVecVal x_array_2_state_65[3]; + svBitVecVal x_array_2_state_128[4]; + + svBitVecVal x_struct_2_state_1[1]; + svBitVecVal x_struct_2_state_32[1]; + svBitVecVal x_struct_2_state_33[2]; + svBitVecVal x_struct_2_state_64[2]; + svBitVecVal x_struct_2_state_65[3]; + svBitVecVal x_struct_2_state_128[4]; + + svBitVecVal x_union_2_state_1[1]; + svBitVecVal x_union_2_state_32[1]; + svBitVecVal x_union_2_state_33[2]; + svBitVecVal x_union_2_state_64[2]; + svBitVecVal x_union_2_state_65[3]; + svBitVecVal x_union_2_state_128[4]; + + svLogicVecVal x_array_4_state_1[1]; + svLogicVecVal x_array_4_state_32[1]; + svLogicVecVal x_array_4_state_33[2]; + svLogicVecVal x_array_4_state_64[2]; + svLogicVecVal x_array_4_state_65[3]; + svLogicVecVal x_array_4_state_128[4]; + + svLogicVecVal x_struct_4_state_1[1]; + svLogicVecVal x_struct_4_state_32[1]; + svLogicVecVal x_struct_4_state_33[2]; + svLogicVecVal x_struct_4_state_64[2]; + svLogicVecVal x_struct_4_state_65[3]; + svLogicVecVal x_struct_4_state_128[4]; + + svLogicVecVal x_union_4_state_1[1]; + svLogicVecVal x_union_4_state_32[1]; + svLogicVecVal x_union_4_state_33[2]; + svLogicVecVal x_union_4_state_64[2]; + svLogicVecVal x_union_4_state_65[3]; + svLogicVecVal x_union_4_state_128[4]; + +#ifndef NO_TIME + set_bvals(x_time, 2); + set_bvals(x_time_t, 2); +#endif +#ifndef NO_INTEGER + set_bvals(x_integer, 1); + set_bvals(x_integer_t, 1); +#endif + + set_bvals(x_array_4_state_1, 1); + set_bvals(x_array_4_state_32, 1); + set_bvals(x_array_4_state_33, 2); + set_bvals(x_array_4_state_64, 2); + set_bvals(x_array_4_state_65, 3); + set_bvals(x_array_4_state_128, 4); + + set_bvals(x_struct_4_state_1, 1); + set_bvals(x_struct_4_state_32, 1); + set_bvals(x_struct_4_state_33, 2); + set_bvals(x_struct_4_state_64, 2); + set_bvals(x_struct_4_state_65, 3); + set_bvals(x_struct_4_state_128, 4); + + set_bvals(x_union_4_state_1, 1); + set_bvals(x_union_4_state_32, 1); + set_bvals(x_union_4_state_33, 2); + set_bvals(x_union_4_state_64, 2); + set_bvals(x_union_4_state_65, 3); + set_bvals(x_union_4_state_128, 4); + + // Basic types as per IEEE 1800-2017 35.5.6 + x_byte = 10 + n; + e_byte(&x_byte); + if (x_byte != 110 + n) stop(); + + x_byte_unsigned = 20 + n; + e_byte_unsigned(&x_byte_unsigned); + if (x_byte_unsigned != 220 + n) stop(); + + x_shortint = 30 + n; + e_shortint(&x_shortint); + if (x_shortint != 330 + n) stop(); + + x_shortint_unsigned = 40 + n; + e_shortint_unsigned(&x_shortint_unsigned); + if (x_shortint_unsigned != 440 + n) stop(); + + x_int = 50 + n; + e_int(&x_int); + if (x_int != 550 + n) stop(); + + x_int_unsigned = 60 + n; + e_int_unsigned(&x_int_unsigned); + if (x_int_unsigned != 660 + n) stop(); + + x_longint = 70 + n; + e_longint(&x_longint); + if (x_longint != 770 + n) stop(); + + x_longint_unsigned = 80 + n; + e_longint_unsigned(&x_longint_unsigned); + if (x_longint_unsigned != 880 + n) stop(); + +#ifndef NO_TIME + x_time[0].aval = 90 + n; + x_time[1].aval = 0; + e_time(x_time); + if (x_time[0].aval != 990 + n || x_time[1].aval != 0) stop(); + check_bvals(x_time, 2); +#endif + +#ifndef NO_INTEGER + x_integer[0].aval = 100 + n; + e_integer(x_integer); + if (x_integer[0].aval != 1100 + n) stop(); + check_bvals(x_integer, 1); +#endif + + x_real = 1.0 * n + 0.50; + e_real(&x_real); + if (x_real != 100.0 + 1.0 * n + 0.5) stop(); + +#ifndef NO_SHORTREAL + x_shortreal = 1.0f * n + 0.25f; + e_shortreal(&x_shortreal); + if (x_shortreal != 200.0f + 1.0f * n + 0.25f) stop(); +#endif + + if (n % 2 == 0) { + x_chandle = reinterpret_cast(&e_chandle); + x_string = "Good"; + } else { + x_chandle = NULL; + x_string = "Bye"; + } + e_chandle(&x_chandle); + e_string(&x_string); + if (n % 2 == 0) { + if (x_chandle != NULL) stop(); + if (strcmp(x_string, "Hello") != 0) stop(); + } else { + if (x_chandle != NULL) stop(); + if (strcmp(x_string, "World") != 0) stop(); + } + + x_bit = n % 2; + e_bit(&x_bit); + if (x_bit != !(n % 2)) stop(); + + x_logic = !(n % 2); + e_logic(&x_logic); + if (x_logic != n % 2) stop(); + + // Basic types via tyepdef + x_byte_t = 10 + 2 * n; + e_byte_t(&x_byte_t); + if (x_byte_t != 111 + 2 * n) stop(); + + x_byte_unsigned_t = 20 + 2 * n; + e_byte_unsigned_t(&x_byte_unsigned_t); + if (x_byte_unsigned_t != 222 + 2 * n) stop(); + + x_shortint_t = 30 + 2 * n; + e_shortint_t(&x_shortint_t); + if (x_shortint_t != 333 + 2 * n) stop(); + + x_shortint_unsigned_t = 40 + 2 * n; + e_shortint_unsigned_t(&x_shortint_unsigned_t); + if (x_shortint_unsigned_t != 444 + 2 * n) stop(); + + x_int_t = 50 + 2 * n; + e_int_t(&x_int_t); + if (x_int_t != 555 + 2 * n) stop(); + + x_int_unsigned_t = 60 + 2 * n; + e_int_unsigned_t(&x_int_unsigned_t); + if (x_int_unsigned_t != 666 + 2 * n) stop(); + + x_longint_t = 70 + 2 * n; + e_longint_t(&x_longint_t); + if (x_longint_t != 777 + 2 * n) stop(); + + x_longint_unsigned_t = 80 + 2 * n; + e_longint_unsigned_t(&x_longint_unsigned_t); + if (x_longint_unsigned_t != 888 + 2 * n) stop(); + +#ifndef NO_TIME + x_time_t[0].aval = 90 + 2 * n; + x_time_t[1].aval = 0; + e_time_t(x_time_t); + if (x_time_t[0].aval != 999 + 2 * n || x_time_t[1].aval != 0) stop(); + check_bvals(x_time_t, 2); +#endif + +#ifndef NO_INTEGER + x_integer_t[0].aval = 100 + 2 * n; + e_integer_t(x_integer_t); + if (x_integer_t[0].aval != 1101 + 2 * n) stop(); + check_bvals(x_integer_t, 1); +#endif + + x_real_t = 1.0 * (2 * n) + 0.50; + e_real_t(&x_real_t); + if (x_real_t != 111.0 + 1.0 * (2 * n) + 0.5) stop(); + +#ifndef NO_SHORTREAL + x_shortreal_t = 1.0f * (2 * n) + 0.25f; + e_shortreal_t(&x_shortreal_t); + if (x_shortreal_t != 222.0f + 1.0f * (2 * n) + 0.25f) stop(); +#endif + + if (n % 2 == 0) { + x_chandle_t = NULL; + x_string_t = "Bye"; + } else { + x_chandle_t = reinterpret_cast(&e_chandle_t); + x_string_t = "Good"; + } + e_chandle_t(&x_chandle_t); + e_string_t(&x_string_t); + if (n % 2 == 0) { + if (x_chandle_t != NULL) stop(); + if (strcmp(x_string_t, "World") != 0) stop(); + } else { + if (x_chandle_t != NULL) stop(); + if (strcmp(x_string_t, "Hello") != 0) stop(); + } + + x_bit_t = n % 2; + e_bit_t(&x_bit_t); + if (x_bit_t != !(n % 2)) stop(); + + x_logic_t = !(n % 2); + e_logic_t(&x_logic_t); + if (x_logic_t != n % 2) stop(); + + const int m = n == 0 ? 0 : n - 1; + + // 2-state packed arrays + x_array_2_state_1[0] = n % 2; + x_array_2_state_32[0] = 0xffffffff >> n; + x_array_2_state_33[1] = 1 >> n; + x_array_2_state_33[0] = 0xffffffff >> m; + x_array_2_state_64[1] = 0xffffffff >> n; + x_array_2_state_64[0] = 0xffffffff; + x_array_2_state_65[2] = 1 >> n; + x_array_2_state_65[1] = 0xffffffff >> m; + x_array_2_state_65[0] = 0xffffffff; + x_array_2_state_128[3] = 0xffffffff >> n; + x_array_2_state_128[2] = x_array_2_state_128[1] = x_array_2_state_128[0] = 0xffffffff; + + e_array_2_state_1(x_array_2_state_1); + if ((x_array_2_state_1[0] & 1) != !(n % 2)) stop(); + + e_array_2_state_32(x_array_2_state_32); + if (x_array_2_state_32[0] != 0xffffffff << n) stop(); + + e_array_2_state_33(x_array_2_state_33); + if ((x_array_2_state_33[1] & 1) != 1) stop(); + if (x_array_2_state_33[0] != 0xffffffff << n) stop(); + + e_array_2_state_64(x_array_2_state_64); + if (x_array_2_state_64[1] != 0xffffffff) stop(); + if (x_array_2_state_64[0] != 0xffffffff << n) stop(); + + e_array_2_state_65(x_array_2_state_65); + if ((x_array_2_state_65[2] & 1) != 1) stop(); + if (x_array_2_state_65[1] != 0xffffffff) stop(); + if (x_array_2_state_65[0] != 0xffffffff << n) stop(); + + e_array_2_state_128(x_array_2_state_128); + if (x_array_2_state_128[3] != 0xffffffff) stop(); + if (x_array_2_state_128[2] != 0xffffffff) stop(); + if (x_array_2_state_128[1] != 0xffffffff) stop(); + if (x_array_2_state_128[0] != 0xffffffff << n) stop(); + + // 2-state packed structures + x_struct_2_state_1[0] = n % 2; + x_struct_2_state_32[0] = 0xffffffff >> n; + x_struct_2_state_33[1] = 1 >> n; + x_struct_2_state_33[0] = 0xffffffff >> m; + x_struct_2_state_64[1] = 0xffffffff >> n; + x_struct_2_state_64[0] = 0xffffffff; + x_struct_2_state_65[2] = 1 >> n; + x_struct_2_state_65[1] = 0xffffffff >> m; + x_struct_2_state_65[0] = 0xffffffff; + x_struct_2_state_128[3] = 0xffffffff >> n; + x_struct_2_state_128[2] = x_struct_2_state_128[1] = x_struct_2_state_128[0] = 0xffffffff; + + e_struct_2_state_1(x_struct_2_state_1); + if ((x_struct_2_state_1[0] & 1) != !(n % 2)) stop(); + + e_struct_2_state_32(x_struct_2_state_32); + if (x_struct_2_state_32[0] != 0xffffffff << n) stop(); + + e_struct_2_state_33(x_struct_2_state_33); + if ((x_struct_2_state_33[1] & 1) != 1) stop(); + if (x_struct_2_state_33[0] != 0xffffffff << n) stop(); + + e_struct_2_state_64(x_struct_2_state_64); + if (x_struct_2_state_64[1] != 0xffffffff) stop(); + if (x_struct_2_state_64[0] != 0xffffffff << n) stop(); + + e_struct_2_state_65(x_struct_2_state_65); + if ((x_struct_2_state_65[2] & 1) != 1) stop(); + if (x_struct_2_state_65[1] != 0xffffffff) stop(); + if (x_struct_2_state_65[0] != 0xffffffff << n) stop(); + + e_struct_2_state_128(x_struct_2_state_128); + if (x_struct_2_state_128[3] != 0xffffffff) stop(); + if (x_struct_2_state_128[2] != 0xffffffff) stop(); + if (x_struct_2_state_128[1] != 0xffffffff) stop(); + if (x_struct_2_state_128[0] != 0xffffffff << n) stop(); + + // 2-state packed unions + x_union_2_state_1[0] = n % 2; + x_union_2_state_32[0] = 0xffffffff >> n; + x_union_2_state_33[1] = 1 >> n; + x_union_2_state_33[0] = 0xffffffff >> m; + x_union_2_state_64[1] = 0xffffffff >> n; + x_union_2_state_64[0] = 0xffffffff; + x_union_2_state_65[2] = 1 >> n; + x_union_2_state_65[1] = 0xffffffff >> m; + x_union_2_state_65[0] = 0xffffffff; + x_union_2_state_128[3] = 0xffffffff >> n; + x_union_2_state_128[2] = x_union_2_state_128[1] = x_union_2_state_128[0] = 0xffffffff; + + e_union_2_state_1(x_union_2_state_1); + if ((x_union_2_state_1[0] & 1) != !(n % 2)) stop(); + + e_union_2_state_32(x_union_2_state_32); + if (x_union_2_state_32[0] != 0xffffffff << n) stop(); + + e_union_2_state_33(x_union_2_state_33); + if ((x_union_2_state_33[1] & 1) != 1) stop(); + if (x_union_2_state_33[0] != 0xffffffff << n) stop(); + + e_union_2_state_64(x_union_2_state_64); + if (x_union_2_state_64[1] != 0xffffffff) stop(); + if (x_union_2_state_64[0] != 0xffffffff << n) stop(); + + e_union_2_state_65(x_union_2_state_65); + if ((x_union_2_state_65[2] & 1) != 1) stop(); + if (x_union_2_state_65[1] != 0xffffffff) stop(); + if (x_union_2_state_65[0] != 0xffffffff << n) stop(); + + e_union_2_state_128(x_union_2_state_128); + if (x_union_2_state_128[3] != 0xffffffff) stop(); + if (x_union_2_state_128[2] != 0xffffffff) stop(); + if (x_union_2_state_128[1] != 0xffffffff) stop(); + if (x_union_2_state_128[0] != 0xffffffff << n) stop(); + + // 4-state packed arrays + x_array_4_state_1[0].aval = n % 2; + x_array_4_state_32[0].aval = 0xffffffff >> n; + x_array_4_state_33[1].aval = 1 >> n; + x_array_4_state_33[0].aval = 0xffffffff >> m; + x_array_4_state_64[1].aval = 0xffffffff >> n; + x_array_4_state_64[0].aval = 0xffffffff; + x_array_4_state_65[2].aval = 1 >> n; + x_array_4_state_65[1].aval = 0xffffffff >> m; + x_array_4_state_65[0].aval = 0xffffffff; + x_array_4_state_128[3].aval = 0xffffffff >> n; + x_array_4_state_128[2].aval = 0xffffffff; + x_array_4_state_128[1].aval = 0xffffffff; + x_array_4_state_128[0].aval = 0xffffffff; + + e_array_4_state_1(x_array_4_state_1); + if ((x_array_4_state_1[0].aval & 1) != !(n % 2)) stop(); + + e_array_4_state_32(x_array_4_state_32); + if (x_array_4_state_32[0].aval != 0xffffffff << n) stop(); + + e_array_4_state_33(x_array_4_state_33); + if ((x_array_4_state_33[1].aval & 1) != 1) stop(); + if (x_array_4_state_33[0].aval != 0xffffffff << n) stop(); + + e_array_4_state_64(x_array_4_state_64); + if (x_array_4_state_64[1].aval != 0xffffffff) stop(); + if (x_array_4_state_64[0].aval != 0xffffffff << n) stop(); + + e_array_4_state_65(x_array_4_state_65); + if ((x_array_4_state_65[2].aval & 1) != 1) stop(); + if (x_array_4_state_65[1].aval != 0xffffffff) stop(); + if (x_array_4_state_65[0].aval != 0xffffffff << n) stop(); + + e_array_4_state_128(x_array_4_state_128); + if (x_array_4_state_128[3].aval != 0xffffffff) stop(); + if (x_array_4_state_128[2].aval != 0xffffffff) stop(); + if (x_array_4_state_128[1].aval != 0xffffffff) stop(); + if (x_array_4_state_128[0].aval != 0xffffffff << n) stop(); + + check_bvals(x_array_4_state_1, 1); + check_bvals(x_array_4_state_32, 1); + check_bvals(x_array_4_state_33, 2); + check_bvals(x_array_4_state_64, 2); + check_bvals(x_array_4_state_65, 3); + check_bvals(x_array_4_state_128, 4); + + // 4-state packed structures + x_struct_4_state_1[0].aval = n % 2; + x_struct_4_state_32[0].aval = 0xffffffff >> n; + x_struct_4_state_33[1].aval = 1 >> n; + x_struct_4_state_33[0].aval = 0xffffffff >> m; + x_struct_4_state_64[1].aval = 0xffffffff >> n; + x_struct_4_state_64[0].aval = 0xffffffff; + x_struct_4_state_65[2].aval = 1 >> n; + x_struct_4_state_65[1].aval = 0xffffffff >> m; + x_struct_4_state_65[0].aval = 0xffffffff; + x_struct_4_state_128[3].aval = 0xffffffff >> n; + x_struct_4_state_128[2].aval = 0xffffffff; + x_struct_4_state_128[1].aval = 0xffffffff; + x_struct_4_state_128[0].aval = 0xffffffff; + + e_struct_4_state_1(x_struct_4_state_1); + if ((x_struct_4_state_1[0].aval & 1) != !(n % 2)) stop(); + + e_struct_4_state_32(x_struct_4_state_32); + if (x_struct_4_state_32[0].aval != 0xffffffff << n) stop(); + + e_struct_4_state_33(x_struct_4_state_33); + if ((x_struct_4_state_33[1].aval & 1) != 1) stop(); + if (x_struct_4_state_33[0].aval != 0xffffffff << n) stop(); + + e_struct_4_state_64(x_struct_4_state_64); + if (x_struct_4_state_64[1].aval != 0xffffffff) stop(); + if (x_struct_4_state_64[0].aval != 0xffffffff << n) stop(); + + e_struct_4_state_65(x_struct_4_state_65); + if ((x_struct_4_state_65[2].aval & 1) != 1) stop(); + if (x_struct_4_state_65[1].aval != 0xffffffff) stop(); + if (x_struct_4_state_65[0].aval != 0xffffffff << n) stop(); + + e_struct_4_state_128(x_struct_4_state_128); + if (x_struct_4_state_128[3].aval != 0xffffffff) stop(); + if (x_struct_4_state_128[2].aval != 0xffffffff) stop(); + if (x_struct_4_state_128[1].aval != 0xffffffff) stop(); + if (x_struct_4_state_128[0].aval != 0xffffffff << n) stop(); + + check_bvals(x_struct_4_state_1, 1); + check_bvals(x_struct_4_state_32, 1); + check_bvals(x_struct_4_state_33, 2); + check_bvals(x_struct_4_state_64, 2); + check_bvals(x_struct_4_state_65, 3); + check_bvals(x_struct_4_state_128, 4); + + // 4-state packed unions + x_union_4_state_1[0].aval = n % 2; + x_union_4_state_32[0].aval = 0xffffffff >> n; + x_union_4_state_33[1].aval = 1 >> n; + x_union_4_state_33[0].aval = 0xffffffff >> m; + x_union_4_state_64[1].aval = 0xffffffff >> n; + x_union_4_state_64[0].aval = 0xffffffff; + x_union_4_state_65[2].aval = 1 >> n; + x_union_4_state_65[1].aval = 0xffffffff >> m; + x_union_4_state_65[0].aval = 0xffffffff; + x_union_4_state_128[3].aval = 0xffffffff >> n; + x_union_4_state_128[2].aval = 0xffffffff; + x_union_4_state_128[1].aval = 0xffffffff; + x_union_4_state_128[0].aval = 0xffffffff; + + e_union_4_state_1(x_union_4_state_1); + if ((x_union_4_state_1[0].aval & 1) != !(n % 2)) stop(); + + e_union_4_state_32(x_union_4_state_32); + if (x_union_4_state_32[0].aval != 0xffffffff << n) stop(); + + e_union_4_state_33(x_union_4_state_33); + if ((x_union_4_state_33[1].aval & 1) != 1) stop(); + if (x_union_4_state_33[0].aval != 0xffffffff << n) stop(); + + e_union_4_state_64(x_union_4_state_64); + if (x_union_4_state_64[1].aval != 0xffffffff) stop(); + if (x_union_4_state_64[0].aval != 0xffffffff << n) stop(); + + e_union_4_state_65(x_union_4_state_65); + if ((x_union_4_state_65[2].aval & 1) != 1) stop(); + if (x_union_4_state_65[1].aval != 0xffffffff) stop(); + if (x_union_4_state_65[0].aval != 0xffffffff << n) stop(); + + e_union_4_state_128(x_union_4_state_128); + if (x_union_4_state_128[3].aval != 0xffffffff) stop(); + if (x_union_4_state_128[2].aval != 0xffffffff) stop(); + if (x_union_4_state_128[1].aval != 0xffffffff) stop(); + if (x_union_4_state_128[0].aval != 0xffffffff << n) stop(); + + check_bvals(x_union_4_state_1, 1); + check_bvals(x_union_4_state_32, 1); + check_bvals(x_union_4_state_33, 2); + check_bvals(x_union_4_state_64, 2); + check_bvals(x_union_4_state_65, 3); + check_bvals(x_union_4_state_128, 4); + + n++; +} diff --git a/test_regress/t/t_dpi_arg_inout_type.out b/test_regress/t/t_dpi_arg_inout_type.out new file mode 100644 index 000000000..a7544a086 --- /dev/null +++ b/test_regress/t/t_dpi_arg_inout_type.out @@ -0,0 +1,265 @@ +i_chandle 0 +i_string 0 +i_bit 0 +i_logic 0 +i_chandle_t 0 +i_string_t 0 +i_bit_t 0 +i_logic_t 0 +i_array_2_state_1 0 +i_array_2_state_32 0 +i_array_2_state_33 0 +i_array_2_state_64 0 +i_array_2_state_65 0 +i_array_2_state_128 0 +i_struct_2_state_1 0 +i_struct_2_state_32 0 +i_struct_2_state_33 0 +i_struct_2_state_64 0 +i_struct_2_state_65 0 +i_struct_2_state_128 0 +i_union_2_state_1 0 +i_union_2_state_32 0 +i_union_2_state_33 0 +i_union_2_state_64 0 +i_union_2_state_65 0 +i_union_2_state_128 0 +i_array_4_state_1 0 +i_array_4_state_32 0 +i_array_4_state_33 0 +i_array_4_state_64 0 +i_array_4_state_65 0 +i_array_4_state_128 0 +i_struct_4_state_1 0 +i_struct_4_state_32 0 +i_struct_4_state_33 0 +i_struct_4_state_64 0 +i_struct_4_state_65 0 +i_struct_4_state_128 0 +i_union_4_state_1 0 +i_union_4_state_32 0 +i_union_4_state_33 0 +i_union_4_state_64 0 +i_union_4_state_65 0 +i_union_4_state_128 0 +e_chandle 0 +e_string 0 +e_bit 0 +e_logic 0 +e_chandle_t 0 +e_string_t 0 +e_bit_t 0 +e_logic_t 0 +e_array_2_state_1 0 +e_array_2_state_32 0 +e_array_2_state_33 0 +e_array_2_state_64 0 +e_array_2_state_65 0 +e_array_2_state_128 0 +e_struct_2_state_1 0 +e_struct_2_state_32 0 +e_struct_2_state_33 0 +e_struct_2_state_64 0 +e_struct_2_state_65 0 +e_struct_2_state_128 0 +e_union_2_state_1 0 +e_union_2_state_32 0 +e_union_2_state_33 0 +e_union_2_state_64 0 +e_union_2_state_65 0 +e_union_2_state_128 0 +e_array_4_state_1 0 +e_array_4_state_32 0 +e_array_4_state_33 0 +e_array_4_state_64 0 +e_array_4_state_65 0 +e_array_4_state_128 0 +e_struct_4_state_1 0 +e_struct_4_state_32 0 +e_struct_4_state_33 0 +e_struct_4_state_64 0 +e_struct_4_state_65 0 +e_struct_4_state_128 0 +e_union_4_state_1 0 +e_union_4_state_32 0 +e_union_4_state_33 0 +e_union_4_state_64 0 +e_union_4_state_65 0 +e_union_4_state_128 0 +i_chandle 1 +i_string 1 +i_bit 1 +i_logic 1 +i_chandle_t 1 +i_string_t 1 +i_bit_t 1 +i_logic_t 1 +i_array_2_state_1 1 +i_array_2_state_32 1 +i_array_2_state_33 1 +i_array_2_state_64 1 +i_array_2_state_65 1 +i_array_2_state_128 1 +i_struct_2_state_1 1 +i_struct_2_state_32 1 +i_struct_2_state_33 1 +i_struct_2_state_64 1 +i_struct_2_state_65 1 +i_struct_2_state_128 1 +i_union_2_state_1 1 +i_union_2_state_32 1 +i_union_2_state_33 1 +i_union_2_state_64 1 +i_union_2_state_65 1 +i_union_2_state_128 1 +i_array_4_state_1 1 +i_array_4_state_32 1 +i_array_4_state_33 1 +i_array_4_state_64 1 +i_array_4_state_65 1 +i_array_4_state_128 1 +i_struct_4_state_1 1 +i_struct_4_state_32 1 +i_struct_4_state_33 1 +i_struct_4_state_64 1 +i_struct_4_state_65 1 +i_struct_4_state_128 1 +i_union_4_state_1 1 +i_union_4_state_32 1 +i_union_4_state_33 1 +i_union_4_state_64 1 +i_union_4_state_65 1 +i_union_4_state_128 1 +e_chandle 1 +e_string 1 +e_bit 1 +e_logic 1 +e_chandle_t 1 +e_string_t 1 +e_bit_t 1 +e_logic_t 1 +e_array_2_state_1 1 +e_array_2_state_32 1 +e_array_2_state_33 1 +e_array_2_state_64 1 +e_array_2_state_65 1 +e_array_2_state_128 1 +e_struct_2_state_1 1 +e_struct_2_state_32 1 +e_struct_2_state_33 1 +e_struct_2_state_64 1 +e_struct_2_state_65 1 +e_struct_2_state_128 1 +e_union_2_state_1 1 +e_union_2_state_32 1 +e_union_2_state_33 1 +e_union_2_state_64 1 +e_union_2_state_65 1 +e_union_2_state_128 1 +e_array_4_state_1 1 +e_array_4_state_32 1 +e_array_4_state_33 1 +e_array_4_state_64 1 +e_array_4_state_65 1 +e_array_4_state_128 1 +e_struct_4_state_1 1 +e_struct_4_state_32 1 +e_struct_4_state_33 1 +e_struct_4_state_64 1 +e_struct_4_state_65 1 +e_struct_4_state_128 1 +e_union_4_state_1 1 +e_union_4_state_32 1 +e_union_4_state_33 1 +e_union_4_state_64 1 +e_union_4_state_65 1 +e_union_4_state_128 1 +i_chandle 2 +i_string 2 +i_bit 2 +i_logic 2 +i_chandle_t 2 +i_string_t 2 +i_bit_t 2 +i_logic_t 2 +i_array_2_state_1 2 +i_array_2_state_32 2 +i_array_2_state_33 2 +i_array_2_state_64 2 +i_array_2_state_65 2 +i_array_2_state_128 2 +i_struct_2_state_1 2 +i_struct_2_state_32 2 +i_struct_2_state_33 2 +i_struct_2_state_64 2 +i_struct_2_state_65 2 +i_struct_2_state_128 2 +i_union_2_state_1 2 +i_union_2_state_32 2 +i_union_2_state_33 2 +i_union_2_state_64 2 +i_union_2_state_65 2 +i_union_2_state_128 2 +i_array_4_state_1 2 +i_array_4_state_32 2 +i_array_4_state_33 2 +i_array_4_state_64 2 +i_array_4_state_65 2 +i_array_4_state_128 2 +i_struct_4_state_1 2 +i_struct_4_state_32 2 +i_struct_4_state_33 2 +i_struct_4_state_64 2 +i_struct_4_state_65 2 +i_struct_4_state_128 2 +i_union_4_state_1 2 +i_union_4_state_32 2 +i_union_4_state_33 2 +i_union_4_state_64 2 +i_union_4_state_65 2 +i_union_4_state_128 2 +e_chandle 2 +e_string 2 +e_bit 2 +e_logic 2 +e_chandle_t 2 +e_string_t 2 +e_bit_t 2 +e_logic_t 2 +e_array_2_state_1 2 +e_array_2_state_32 2 +e_array_2_state_33 2 +e_array_2_state_64 2 +e_array_2_state_65 2 +e_array_2_state_128 2 +e_struct_2_state_1 2 +e_struct_2_state_32 2 +e_struct_2_state_33 2 +e_struct_2_state_64 2 +e_struct_2_state_65 2 +e_struct_2_state_128 2 +e_union_2_state_1 2 +e_union_2_state_32 2 +e_union_2_state_33 2 +e_union_2_state_64 2 +e_union_2_state_65 2 +e_union_2_state_128 2 +e_array_4_state_1 2 +e_array_4_state_32 2 +e_array_4_state_33 2 +e_array_4_state_64 2 +e_array_4_state_65 2 +e_array_4_state_128 2 +e_struct_4_state_1 2 +e_struct_4_state_32 2 +e_struct_4_state_33 2 +e_struct_4_state_64 2 +e_struct_4_state_65 2 +e_struct_4_state_128 2 +e_union_4_state_1 2 +e_union_4_state_32 2 +e_union_4_state_33 2 +e_union_4_state_64 2 +e_union_4_state_65 2 +e_union_4_state_128 2 +*-* All Finished *-* diff --git a/test_regress/t/t_dpi_arg_inout_type.pl b/test_regress/t/t_dpi_arg_inout_type.pl new file mode 100755 index 000000000..dadb11a8e --- /dev/null +++ b/test_regress/t/t_dpi_arg_inout_type.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Geza Lore. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if ($Self->{nc}) { + # For NC, compile twice, first just to generate DPI headers + compile( + nc_flags2 => ["+ncdpiheader+$Self->{obj_dir}/dpi-exp.h", + "+ncdpiimpheader+$Self->{obj_dir}/dpi-imp.h"] + ); +} + +compile( + v_flags2 => ["t/t_dpi_arg_inout_type.cpp"], + verilator_flags2 => ["-Wall -Wno-DECLFILENAME"], + # NC: Gdd the obj_dir to the C include path + nc_flags2 => ["+ncscargs+-I$Self->{obj_dir}"], + # ModelSim: Generate DPI header, add obj_dir to the C include path + ms_flags2 => ["-dpiheader $Self->{obj_dir}/dpi.h", + "-ccflags -I$Self->{obj_dir}"], + ); + +if ($Self->{vlt_all}) { + files_identical( + "$Self->{obj_dir}/Vt_dpi_arg_inout_type__Dpi.h", + "t/t_dpi_arg_inout_type__Dpi.out" + ); +} + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ms_pli => 0 + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_arg_inout_type.v b/test_regress/t/t_dpi_arg_inout_type.v new file mode 100644 index 000000000..3d413ef96 --- /dev/null +++ b/test_regress/t/t_dpi_arg_inout_type.v @@ -0,0 +1,1075 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +`ifdef VCS + `define NO_TIME +`endif + +`ifdef NC + `define NO_TIME + `define NO_INTEGER + `define NO_SHORTREAL +`endif + +`ifdef MS +`endif + +`ifdef VERILATOR + `define NO_SHORTREAL + `define NULL 64'd0 +`else + `define NULL null +`endif + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + +`ifdef VERILATOR + wire _unused = &{1'b0, clk}; +`endif + + // Legal inout argument types for DPI functions + + //====================================================================== + // Type definitions + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + typedef byte byte_t; + typedef byte unsigned byte_unsigned_t; + typedef shortint shortint_t; + typedef shortint unsigned shortint_unsigned_t; + typedef int int_t; + typedef int unsigned int_unsigned_t; + typedef longint longint_t; + typedef longint unsigned longint_unsigned_t; +`ifndef NO_TIME + typedef time time_t; +`endif +`ifndef NO_INTEGER + typedef integer integer_t; +`endif + typedef real real_t; +`ifndef NO_SHORTREAL + typedef shortreal shortreal_t; +`endif + typedef chandle chandle_t; + typedef string string_t; + typedef bit bit_t; + typedef logic logic_t; + + // 2-state packed structures + typedef struct packed { bit x; } struct_2_state_1; + typedef struct packed { bit [15:0] x; bit [15:0] y; } struct_2_state_32; + typedef struct packed { bit [15:0] x; bit [16:0] y; } struct_2_state_33; + typedef struct packed { bit [31:0] x; bit [31:0] y; } struct_2_state_64; + typedef struct packed { bit [31:0] x; bit [32:0] y; } struct_2_state_65; + typedef struct packed { bit [63:0] x; bit [63:0] y; } struct_2_state_128; + + // 2-state packed unions + typedef union packed { bit x; bit y; } union_2_state_1; + typedef union packed { bit [31:0] x; bit [31:0] y; } union_2_state_32; + typedef union packed { bit [32:0] x; bit [32:0] y; } union_2_state_33; + typedef union packed { bit [63:0] x; bit [63:0] y; } union_2_state_64; + typedef union packed { bit [64:0] x; bit [64:0] y; } union_2_state_65; + typedef union packed { bit [127:0] x; bit [127:0] y; } union_2_state_128; + + // 4-state packed structures + typedef struct packed { logic x; } struct_4_state_1; + typedef struct packed { logic [15:0] x; bit [15:0] y; } struct_4_state_32; + typedef struct packed { logic [15:0] x; bit [16:0] y; } struct_4_state_33; + typedef struct packed { logic [31:0] x; bit [31:0] y; } struct_4_state_64; + typedef struct packed { logic [31:0] x; bit [32:0] y; } struct_4_state_65; + typedef struct packed { logic [63:0] x; bit [63:0] y; } struct_4_state_128; + + // 4-state packed unions + typedef union packed { logic x; bit y; } union_4_state_1; + typedef union packed { logic [31:0] x; bit [31:0] y; } union_4_state_32; + typedef union packed { logic [32:0] x; bit [32:0] y; } union_4_state_33; + typedef union packed { logic [63:0] x; bit [63:0] y; } union_4_state_64; + typedef union packed { logic [64:0] x; bit [64:0] y; } union_4_state_65; + typedef union packed { logic [127:0] x; bit [127:0] y; } union_4_state_128; + + //====================================================================== + // Imports + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + import "DPI-C" function void i_byte (inout byte x); + import "DPI-C" function void i_byte_unsigned (inout byte unsigned x); + import "DPI-C" function void i_shortint (inout shortint x); + import "DPI-C" function void i_shortint_unsigned (inout shortint unsigned x); + import "DPI-C" function void i_int (inout int x); + import "DPI-C" function void i_int_unsigned (inout int unsigned x); + import "DPI-C" function void i_longint (inout longint x); + import "DPI-C" function void i_longint_unsigned (inout longint unsigned x); +`ifndef NO_TIME + import "DPI-C" function void i_time (inout time x); +`endif +`ifndef NO_INTEGER + import "DPI-C" function void i_integer (inout integer x); +`endif + import "DPI-C" function void i_real (inout real x); +`ifndef NO_SHORTREAL + import "DPI-C" function void i_shortreal (inout shortreal x); +`endif + import "DPI-C" function void i_chandle (inout chandle x); + import "DPI-C" function void i_string (inout string x); + import "DPI-C" function void i_bit (inout bit x); + import "DPI-C" function void i_logic (inout logic x); + + // Basic types via typedef + import "DPI-C" function void i_byte_t (inout byte_t x); + import "DPI-C" function void i_byte_unsigned_t (inout byte_unsigned_t x); + import "DPI-C" function void i_shortint_t (inout shortint_t x); + import "DPI-C" function void i_shortint_unsigned_t (inout shortint_unsigned_t x); + import "DPI-C" function void i_int_t (inout int_t x); + import "DPI-C" function void i_int_unsigned_t (inout int_unsigned_t x); + import "DPI-C" function void i_longint_t (inout longint_t x); + import "DPI-C" function void i_longint_unsigned_t (inout longint_unsigned_t x); +`ifndef NO_TIME + import "DPI-C" function void i_time_t (inout time_t x); +`endif +`ifndef NO_INTEGER + import "DPI-C" function void i_integer_t (inout integer_t x); +`endif + import "DPI-C" function void i_real_t (inout real_t x); +`ifndef NO_SHORTREAL + import "DPI-C" function void i_shortreal_t (inout shortreal_t x); +`endif + import "DPI-C" function void i_chandle_t (inout chandle_t x); + import "DPI-C" function void i_string_t (inout string_t x); + import "DPI-C" function void i_bit_t (inout bit_t x); + import "DPI-C" function void i_logic_t (inout logic_t x); + + // 2-state packed arrays + import "DPI-C" function void i_array_2_state_1 (inout bit [ 0:0] x); + import "DPI-C" function void i_array_2_state_32 (inout bit [ 31:0] x); + import "DPI-C" function void i_array_2_state_33 (inout bit [ 32:0] x); + import "DPI-C" function void i_array_2_state_64 (inout bit [ 63:0] x); + import "DPI-C" function void i_array_2_state_65 (inout bit [ 64:0] x); + import "DPI-C" function void i_array_2_state_128(inout bit [127:0] x); + + // 2-state packed structures + import "DPI-C" function void i_struct_2_state_1 (inout struct_2_state_1 x); + import "DPI-C" function void i_struct_2_state_32 (inout struct_2_state_32 x); + import "DPI-C" function void i_struct_2_state_33 (inout struct_2_state_33 x); + import "DPI-C" function void i_struct_2_state_64 (inout struct_2_state_64 x); + import "DPI-C" function void i_struct_2_state_65 (inout struct_2_state_65 x); + import "DPI-C" function void i_struct_2_state_128 (inout struct_2_state_128 x); + + // 2-state packed unions + import "DPI-C" function void i_union_2_state_1 (inout union_2_state_1 x); + import "DPI-C" function void i_union_2_state_32 (inout union_2_state_32 x); + import "DPI-C" function void i_union_2_state_33 (inout union_2_state_33 x); + import "DPI-C" function void i_union_2_state_64 (inout union_2_state_64 x); + import "DPI-C" function void i_union_2_state_65 (inout union_2_state_65 x); + import "DPI-C" function void i_union_2_state_128 (inout union_2_state_128 x); + + // 4-state packed arrays + import "DPI-C" function void i_array_4_state_1 (inout logic [ 0:0] x); + import "DPI-C" function void i_array_4_state_32 (inout logic [ 31:0] x); + import "DPI-C" function void i_array_4_state_33 (inout logic [ 32:0] x); + import "DPI-C" function void i_array_4_state_64 (inout logic [ 63:0] x); + import "DPI-C" function void i_array_4_state_65 (inout logic [ 64:0] x); + import "DPI-C" function void i_array_4_state_128(inout logic [127:0] x); + + // 4-state packed structures + import "DPI-C" function void i_struct_4_state_1 (inout struct_4_state_1 x); + import "DPI-C" function void i_struct_4_state_32 (inout struct_4_state_32 x); + import "DPI-C" function void i_struct_4_state_33 (inout struct_4_state_33 x); + import "DPI-C" function void i_struct_4_state_64 (inout struct_4_state_64 x); + import "DPI-C" function void i_struct_4_state_65 (inout struct_4_state_65 x); + import "DPI-C" function void i_struct_4_state_128 (inout struct_4_state_128 x); + + // 4-state packed unions + import "DPI-C" function void i_union_4_state_1 (inout union_4_state_1 x); + import "DPI-C" function void i_union_4_state_32 (inout union_4_state_32 x); + import "DPI-C" function void i_union_4_state_33 (inout union_4_state_33 x); + import "DPI-C" function void i_union_4_state_64 (inout union_4_state_64 x); + import "DPI-C" function void i_union_4_state_65 (inout union_4_state_65 x); + import "DPI-C" function void i_union_4_state_128 (inout union_4_state_128 x); + + //====================================================================== + // Exports + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + export "DPI-C" function e_byte; + export "DPI-C" function e_byte_unsigned; + export "DPI-C" function e_shortint; + export "DPI-C" function e_shortint_unsigned; + export "DPI-C" function e_int; + export "DPI-C" function e_int_unsigned; + export "DPI-C" function e_longint; + export "DPI-C" function e_longint_unsigned; +`ifndef NO_TIME + export "DPI-C" function e_time; +`endif +`ifndef NO_INTEGER + export "DPI-C" function e_integer; +`endif + export "DPI-C" function e_real; +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal; +`endif + export "DPI-C" function e_chandle; + export "DPI-C" function e_string; + export "DPI-C" function e_bit; + export "DPI-C" function e_logic; + + // Basic types via typedef + export "DPI-C" function e_byte_t; + export "DPI-C" function e_byte_unsigned_t; + export "DPI-C" function e_shortint_t; + export "DPI-C" function e_shortint_unsigned_t; + export "DPI-C" function e_int_t; + export "DPI-C" function e_int_unsigned_t; + export "DPI-C" function e_longint_t; + export "DPI-C" function e_longint_unsigned_t; +`ifndef NO_TIME + export "DPI-C" function e_time_t; +`endif +`ifndef NO_INTEGER + export "DPI-C" function e_integer_t; +`endif + export "DPI-C" function e_real_t; +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal_t; +`endif + export "DPI-C" function e_chandle_t; + export "DPI-C" function e_string_t; + export "DPI-C" function e_bit_t; + export "DPI-C" function e_logic_t; + + // 2-state packed arrays + export "DPI-C" function e_array_2_state_1; + export "DPI-C" function e_array_2_state_32; + export "DPI-C" function e_array_2_state_33; + export "DPI-C" function e_array_2_state_64; + export "DPI-C" function e_array_2_state_65; + export "DPI-C" function e_array_2_state_128; + + // 2-state packed structures + export "DPI-C" function e_struct_2_state_1; + export "DPI-C" function e_struct_2_state_32; + export "DPI-C" function e_struct_2_state_33; + export "DPI-C" function e_struct_2_state_64; + export "DPI-C" function e_struct_2_state_65; + export "DPI-C" function e_struct_2_state_128; + + // 2-state packed unions + export "DPI-C" function e_union_2_state_1; + export "DPI-C" function e_union_2_state_32; + export "DPI-C" function e_union_2_state_33; + export "DPI-C" function e_union_2_state_64; + export "DPI-C" function e_union_2_state_65; + export "DPI-C" function e_union_2_state_128; + + // 4-state packed arrays + export "DPI-C" function e_array_4_state_1; + export "DPI-C" function e_array_4_state_32; + export "DPI-C" function e_array_4_state_33; + export "DPI-C" function e_array_4_state_64; + export "DPI-C" function e_array_4_state_65; + export "DPI-C" function e_array_4_state_128; + + // 4-state packed structures + export "DPI-C" function e_struct_4_state_1; + export "DPI-C" function e_struct_4_state_32; + export "DPI-C" function e_struct_4_state_33; + export "DPI-C" function e_struct_4_state_64; + export "DPI-C" function e_struct_4_state_65; + export "DPI-C" function e_struct_4_state_128; + + // 4-state packed unions + export "DPI-C" function e_union_4_state_1; + export "DPI-C" function e_union_4_state_32; + export "DPI-C" function e_union_4_state_33; + export "DPI-C" function e_union_4_state_64; + export "DPI-C" function e_union_4_state_65; + export "DPI-C" function e_union_4_state_128; + + //====================================================================== + // Definitions of exported functions + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + byte n_byte = 0; + function void e_byte(inout byte x); + if (x !== 8'd10 + n_byte) $stop; + x += 8'd100; + n_byte++; + endfunction + + byte n_byte_unsigned = 0; + function void e_byte_unsigned(inout byte unsigned x); + if (x !== 8'd20 + n_byte_unsigned) $stop; + x += 8'd200; + n_byte_unsigned++; + endfunction + + shortint n_shortint = 0; + function void e_shortint(inout shortint x); + if (x !== 16'd30 + n_shortint) $stop; + x += 16'd300; + n_shortint++; + endfunction + + shortint n_shortint_unsigned = 0; + function void e_shortint_unsigned(inout shortint unsigned x); + if (x !== 16'd40 + n_shortint_unsigned) $stop; + x += 16'd400; + n_shortint_unsigned++; + endfunction + + int n_int = 0; + function void e_int(inout int x); + if (x !== 32'd50 + n_int) $stop; + x += 32'd500; + n_int++; + endfunction + + int n_int_unsigned = 0; + function void e_int_unsigned(inout int unsigned x); + if (x !== 32'd60 + n_int_unsigned) $stop; + x += 32'd600; + n_int_unsigned++; + endfunction + + longint n_longint = 0; + function void e_longint(inout longint x); + if (x !== 64'd70 + n_longint) $stop; + x += 64'd700; + n_longint++; + endfunction + + longint n_longint_unsigned = 0; + function void e_longint_unsigned(inout longint unsigned x); + if (x !== 64'd80 + n_longint_unsigned) $stop; + x += 64'd800; + n_longint_unsigned++; + endfunction + +`ifndef NO_TIME + longint n_time = 0; + function void e_time(inout time x); + if (x !== 64'd90 + n_time) $stop; + x += 64'd900; + n_time++; + endfunction +`endif + +`ifndef NO_INTEGER + int n_integer = 0; + function void e_integer(inout integer x); + if (x !== 32'd100 + n_integer) $stop; + x += 32'd1000; + n_integer++; + endfunction +`endif + + int n_real = 0; + function void e_real(inout real x); + if (x != real'(2*n_real + 1) / 2.0) $stop; + x += 100.0; + n_real++; + endfunction + +`ifndef NO_SHORTREAL + int n_shortreal = 0; + function void e_shortreal(inout shortreal x); + if (x != shortreal'(4*n_shortreal + 1)/ 4.0) $stop; + x += 200.0; + n_shortreal++; + endfunction +`endif + + int n_chandle = 0; + function void e_chandle(inout chandle x); + $display("e_chandle %1d", n_chandle); + if (!n_chandle[0]) begin + if (x === `NULL) $stop; + end else begin + if (x !== `NULL) $stop; + end + x = `NULL; + n_chandle++; + endfunction + + int n_string = 0; + function void e_string(inout string x); + $display("e_string %1d", n_string); + if (!n_string[0]) begin + if (x != "Good") $stop; + x = "Hello"; + end else begin + if (x != "Bye") $stop; + x = "World"; + end + n_string++; + endfunction + + int n_bit = 0; + function void e_bit(inout bit x); + $display("e_bit %1d", n_bit); + if (x !== n_bit[0]) $stop; + x = ~x; + n_bit++; + endfunction + + int n_logic = 0; + function void e_logic(inout logic x); + $display("e_logic %1d", n_logic); + if (x !== ~n_logic[0]) $stop; + x = ~x; + n_logic++; + endfunction + + // Basic types via typedefs + byte_t n_byte_t = 0; + function void e_byte_t(inout byte_t x); + if (x !== 8'd10 + n_byte_t) $stop; + x += 8'd101; + n_byte_t += 2; + endfunction + + byte n_byte_unsigned_t = 0; + function void e_byte_unsigned_t(inout byte_unsigned_t x); + if (x !== 8'd20 + n_byte_unsigned_t) $stop; + x += 8'd202; + n_byte_unsigned_t += 2; + endfunction + + shortint_t n_shortint_t = 0; + function void e_shortint_t(inout shortint_t x); + if (x !== 16'd30 + n_shortint_t) $stop; + x += 16'd303; + n_shortint_t += 2; + endfunction + + shortint n_shortint_unsigned_t = 0; + function void e_shortint_unsigned_t(inout shortint_unsigned_t x); + if (x !== 16'd40 + n_shortint_unsigned_t) $stop; + x += 16'd404; + n_shortint_unsigned_t += 2; + endfunction + + int_t n_int_t = 0; + function void e_int_t(inout int_t x); + if (x !== 32'd50 + n_int_t) $stop; + x += 32'd505; + n_int_t += 2; + endfunction + + int n_int_unsigned_t = 0; + function void e_int_unsigned_t(inout int_unsigned_t x); + if (x !== 32'd60 + n_int_unsigned_t) $stop; + x += 32'd606; + n_int_unsigned_t += 2; + endfunction + + longint_t n_longint_t = 0; + function void e_longint_t(inout longint_t x); + if (x !== 64'd70 + n_longint_t) $stop; + x += 64'd707; + n_longint_t += 2; + endfunction + + longint n_longint_unsigned_t = 0; + function void e_longint_unsigned_t(inout longint_unsigned_t x); + if (x !== 64'd80 + n_longint_unsigned_t) $stop; + x += 64'd808; + n_longint_unsigned_t += 2; + endfunction + +`ifndef NO_TIME + longint n_time_t = 0; + function void e_time_t(inout time_t x); + if (x !== 64'd90 + n_time_t) $stop; + x += 64'd909; + n_time_t += 2; + endfunction +`endif + +`ifndef NO_INTEGER + int n_integer_t = 0; + function void e_integer_t(inout integer_t x); + if (x !== 32'd100 + n_integer_t) $stop; + x += 32'd1001; + n_integer_t += 2; + endfunction +`endif + + int n_real_t = 0; + function void e_real_t(inout real_t x); + if (x != real'(2*n_real_t + 1) / 2.0) $stop; + x += 111.0; + n_real_t += 2; + endfunction + +`ifndef NO_SHORTREAL + int n_shortreal_t = 0; + function void e_shortreal_t(inout shortreal_t x); + if (x != shortreal'(4*n_shortreal_t + 1)/ 4.0) $stop; + x += 222.0; + n_shortreal_t += 2; + endfunction +`endif + + int n_chandle_t = 0; + function void e_chandle_t(inout chandle_t x); + $display("e_chandle_t %1d", n_chandle_t); + if (!n_chandle_t[0]) begin + if (x !== `NULL) $stop; + end else begin + if (x === `NULL) $stop; + end + x = `NULL; + n_chandle_t++; + endfunction + + int n_string_t = 0; + function void e_string_t(inout string_t x); + $display("e_string_t %1d", n_string_t); + if (!n_string_t[0]) begin + if (x != "Bye") $stop; + x = "World"; + end else begin + if (x != "Good") $stop; + x = "Hello"; + end + n_string_t++; + endfunction + + int n_bit_t = 0; + function void e_bit_t(inout bit_t x); + $display("e_bit_t %1d", n_bit_t); + if (x !== n_bit_t[0]) $stop; + x = ~x; + n_bit_t++; + endfunction + + int n_logic_t = 0; + function void e_logic_t(inout logic_t x); + $display("e_logic_t %1d", n_logic_t); + if (x !== ~n_logic_t[0]) $stop; + x = ~x; + n_logic_t++; + endfunction + + // 2-state packed arrays + int n_array_2_state_1 = 0; + function void e_array_2_state_1(inout bit [ 0:0] x); + $display("e_array_2_state_1 %1d", n_array_2_state_1); + if (x !== n_array_2_state_1[0]) $stop; + x = ~x; + n_array_2_state_1++; + endfunction + + int n_array_2_state_32 = 0; + function void e_array_2_state_32(inout bit [31:0] x); + $display("e_array_2_state_32 %1d", n_array_2_state_32); + if (x !== ~32'd0 >> n_array_2_state_32) $stop; + x <<= n_array_2_state_32; + n_array_2_state_32++; + endfunction + + int n_array_2_state_33 = 0; + function void e_array_2_state_33(inout bit [32:0] x); + $display("e_array_2_state_33 %1d", n_array_2_state_33); + if (x !== ~33'd0 >> n_array_2_state_33) $stop; + x <<= n_array_2_state_33; + n_array_2_state_33++; + endfunction + + int n_array_2_state_64 = 0; + function void e_array_2_state_64(inout bit [63:0] x); + $display("e_array_2_state_64 %1d", n_array_2_state_64); + if (x !== ~64'd0 >> n_array_2_state_64) $stop; + x <<= n_array_2_state_64; + n_array_2_state_64++; + endfunction + + int n_array_2_state_65 = 0; + function void e_array_2_state_65(inout bit [64:0] x); + $display("e_array_2_state_65 %1d", n_array_2_state_65); + if (x !== ~65'd0 >> n_array_2_state_65) $stop; + x <<= n_array_2_state_65; + n_array_2_state_65++; + endfunction + + int n_array_2_state_128 = 0; + function void e_array_2_state_128(inout bit [127:0] x); + $display("e_array_2_state_128 %1d", n_array_2_state_128); + if (x !== ~128'd0 >> n_array_2_state_128) $stop; + x <<= n_array_2_state_128; + n_array_2_state_128++; + endfunction + + // 2-state packed structures + int n_struct_2_state_1 = 0; + function void e_struct_2_state_1(inout struct_2_state_1 x); + $display("e_struct_2_state_1 %1d", n_struct_2_state_1); + if (x !== n_struct_2_state_1[0]) $stop; + x = ~x; + n_struct_2_state_1++; + endfunction + + int n_struct_2_state_32 = 0; + function void e_struct_2_state_32(inout struct_2_state_32 x); + $display("e_struct_2_state_32 %1d", n_struct_2_state_32); + if (x !== ~32'd0 >> n_struct_2_state_32) $stop; + x <<= n_struct_2_state_32; + n_struct_2_state_32++; + endfunction + + int n_struct_2_state_33 = 0; + function void e_struct_2_state_33(inout struct_2_state_33 x); + $display("e_struct_2_state_33 %1d", n_struct_2_state_33); + if (x !== ~33'd0 >> n_struct_2_state_33) $stop; + x <<= n_struct_2_state_33; + n_struct_2_state_33++; + endfunction + + int n_struct_2_state_64 = 0; + function void e_struct_2_state_64(inout struct_2_state_64 x); + $display("e_struct_2_state_64 %1d", n_struct_2_state_64); + if (x !== ~64'd0 >> n_struct_2_state_64) $stop; + x <<= n_struct_2_state_64; + n_struct_2_state_64++; + endfunction + + int n_struct_2_state_65 = 0; + function void e_struct_2_state_65(inout struct_2_state_65 x); + $display("e_struct_2_state_65 %1d", n_struct_2_state_65); + if (x !== ~65'd0 >> n_struct_2_state_65) $stop; + x <<= n_struct_2_state_65; + n_struct_2_state_65++; + endfunction + + int n_struct_2_state_128 = 0; + function void e_struct_2_state_128(inout struct_2_state_128 x); + $display("e_struct_2_state_128 %1d", n_struct_2_state_128); + if (x !== ~128'd0 >> n_struct_2_state_128) $stop; + x <<= n_struct_2_state_128; + n_struct_2_state_128++; + endfunction + + // 2-state packed unions + int n_union_2_state_1 = 0; + function void e_union_2_state_1(inout union_2_state_1 x); + $display("e_union_2_state_1 %1d", n_union_2_state_1); + if (x !== n_union_2_state_1[0]) $stop; + x = ~x; + n_union_2_state_1++; + endfunction + + int n_union_2_state_32 = 0; + function void e_union_2_state_32(inout union_2_state_32 x); + $display("e_union_2_state_32 %1d", n_union_2_state_32); + if (x !== ~32'd0 >> n_union_2_state_32) $stop; + x <<= n_union_2_state_32; + n_union_2_state_32++; + endfunction + + int n_union_2_state_33 = 0; + function void e_union_2_state_33(inout union_2_state_33 x); + $display("e_union_2_state_33 %1d", n_union_2_state_33); + if (x !== ~33'd0 >> n_union_2_state_33) $stop; + x <<= n_union_2_state_33; + n_union_2_state_33++; + endfunction + + int n_union_2_state_64 = 0; + function void e_union_2_state_64(inout union_2_state_64 x); + $display("e_union_2_state_64 %1d", n_union_2_state_64); + if (x !== ~64'd0 >> n_union_2_state_64) $stop; + x <<= n_union_2_state_64; + n_union_2_state_64++; + endfunction + + int n_union_2_state_65 = 0; + function void e_union_2_state_65(inout union_2_state_65 x); + $display("e_union_2_state_65 %1d", n_union_2_state_65); + if (x !== ~65'd0 >> n_union_2_state_65) $stop; + x <<= n_union_2_state_65; + n_union_2_state_65++; + endfunction + + int n_union_2_state_128 = 0; + function void e_union_2_state_128(inout union_2_state_128 x); + $display("e_union_2_state_128 %1d", n_union_2_state_128); + if (x !== ~128'd0 >> n_union_2_state_128) $stop; + x <<= n_union_2_state_128; + n_union_2_state_128++; + endfunction + + // 4-state packed arrays + int n_array_4_state_1 = 0; + function void e_array_4_state_1(inout logic [ 0:0] x); + $display("e_array_4_state_1 %1d", n_array_4_state_1); + if (x !== n_array_4_state_1[0]) $stop; + x = ~x; + n_array_4_state_1++; + endfunction + + int n_array_4_state_32 = 0; + function void e_array_4_state_32(inout logic [31:0] x); + $display("e_array_4_state_32 %1d", n_array_4_state_32); + if (x !== ~32'd0 >> n_array_4_state_32) $stop; + x <<= n_array_4_state_32; + n_array_4_state_32++; + endfunction + + int n_array_4_state_33 = 0; + function void e_array_4_state_33(inout logic [32:0] x); + $display("e_array_4_state_33 %1d", n_array_4_state_33); + if (x !== ~33'd0 >> n_array_4_state_33) $stop; + x <<= n_array_4_state_33; + n_array_4_state_33++; + endfunction + + int n_array_4_state_64 = 0; + function void e_array_4_state_64(inout logic [63:0] x); + $display("e_array_4_state_64 %1d", n_array_4_state_64); + if (x !== ~64'd0 >> n_array_4_state_64) $stop; + x <<= n_array_4_state_64; + n_array_4_state_64++; + endfunction + + int n_array_4_state_65 = 0; + function void e_array_4_state_65(inout logic [64:0] x); + $display("e_array_4_state_65 %1d", n_array_4_state_65); + if (x !== ~65'd0 >> n_array_4_state_65) $stop; + x <<= n_array_4_state_65; + n_array_4_state_65++; + endfunction + + int n_array_4_state_128 = 0; + function void e_array_4_state_128(inout logic [127:0] x); + $display("e_array_4_state_128 %1d", n_array_4_state_128); + if (x !== ~128'd0 >> n_array_4_state_128) $stop; + x <<= n_array_4_state_128; + n_array_4_state_128++; + endfunction + + // 4-state packed structures + int n_struct_4_state_1 = 0; + function void e_struct_4_state_1(inout struct_4_state_1 x); + $display("e_struct_4_state_1 %1d", n_struct_4_state_1); + if (x !== n_struct_4_state_1[0]) $stop; + x = ~x; + n_struct_4_state_1++; + endfunction + + int n_struct_4_state_32 = 0; + function void e_struct_4_state_32(inout struct_4_state_32 x); + $display("e_struct_4_state_32 %1d", n_struct_4_state_32); + if (x !== ~32'd0 >> n_struct_4_state_32) $stop; + x <<= n_struct_4_state_32; + n_struct_4_state_32++; + endfunction + + int n_struct_4_state_33 = 0; + function void e_struct_4_state_33(inout struct_4_state_33 x); + $display("e_struct_4_state_33 %1d", n_struct_4_state_33); + if (x !== ~33'd0 >> n_struct_4_state_33) $stop; + x <<= n_struct_4_state_33; + n_struct_4_state_33++; + endfunction + + int n_struct_4_state_64 = 0; + function void e_struct_4_state_64(inout struct_4_state_64 x); + $display("e_struct_4_state_64 %1d", n_struct_4_state_64); + if (x !== ~64'd0 >> n_struct_4_state_64) $stop; + x <<= n_struct_4_state_64; + n_struct_4_state_64++; + endfunction + + int n_struct_4_state_65 = 0; + function void e_struct_4_state_65(inout struct_4_state_65 x); + $display("e_struct_4_state_65 %1d", n_struct_4_state_65); + if (x !== ~65'd0 >> n_struct_4_state_65) $stop; + x <<= n_struct_4_state_65; + n_struct_4_state_65++; + endfunction + + int n_struct_4_state_128 = 0; + function void e_struct_4_state_128(inout struct_4_state_128 x); + $display("e_struct_4_state_128 %1d", n_struct_4_state_128); + if (x !== ~128'd0 >> n_struct_4_state_128) $stop; + x <<= n_struct_4_state_128; + n_struct_4_state_128++; + endfunction + + // 4-state packed unions + int n_union_4_state_1 = 0; + function void e_union_4_state_1(inout union_4_state_1 x); + $display("e_union_4_state_1 %1d", n_union_4_state_1); + if (x !== n_union_4_state_1[0]) $stop; + x = ~x; + n_union_4_state_1++; + endfunction + + int n_union_4_state_32 = 0; + function void e_union_4_state_32(inout union_4_state_32 x); + $display("e_union_4_state_32 %1d", n_union_4_state_32); + if (x !== ~32'd0 >> n_union_4_state_32) $stop; + x <<= n_union_4_state_32; + n_union_4_state_32++; + endfunction + + int n_union_4_state_33 = 0; + function void e_union_4_state_33(inout union_4_state_33 x); + $display("e_union_4_state_33 %1d", n_union_4_state_33); + if (x !== ~33'd0 >> n_union_4_state_33) $stop; + x <<= n_union_4_state_33; + n_union_4_state_33++; + endfunction + + int n_union_4_state_64 = 0; + function void e_union_4_state_64(inout union_4_state_64 x); + $display("e_union_4_state_64 %1d", n_union_4_state_64); + if (x !== ~64'd0 >> n_union_4_state_64) $stop; + x <<= n_union_4_state_64; + n_union_4_state_64++; + endfunction + + int n_union_4_state_65 = 0; + function void e_union_4_state_65(inout union_4_state_65 x); + $display("e_union_4_state_65 %1d", n_union_4_state_65); + if (x !== ~65'd0 >> n_union_4_state_65) $stop; + x <<= n_union_4_state_65; + n_union_4_state_65++; + endfunction + + int n_union_4_state_128 = 0; + function void e_union_4_state_128(inout union_4_state_128 x); + $display("e_union_4_state_128 %1d", n_union_4_state_128); + if (x !== ~128'd0 >> n_union_4_state_128) $stop; + x <<= n_union_4_state_128; + n_union_4_state_128++; + endfunction + + //====================================================================== + // Invoke all functions 3 times (they have side effects) + //====================================================================== + + import "DPI-C" context function void check_exports(); + + initial begin + for (int i = 0 ; i < 3; i++) begin + // Check the imports + + byte x_byte; + byte unsigned x_byte_unsigned; + shortint x_shortint; + shortint unsigned x_shortint_unsigned; + int x_int; + int unsigned x_int_unsigned; + longint x_longint; + longint unsigned x_longint_unsigned; +`ifndef NO_TIME + time x_time; +`endif +`ifndef NO_INTEGER + integer x_integer; +`endif + real x_real; +`ifndef NO_SHORTREAL + shortreal x_shortreal; +`endif + chandle x_chandle; + string x_string; + bit x_bit; + logic x_logic; + + byte_t x_byte_t; + byte_unsigned_t x_byte_unsigned_t; + shortint_t x_shortint_t; + shortint_unsigned_t x_shortint_unsigned_t; + int_t x_int_t; + int_unsigned_t x_int_unsigned_t; + longint_t x_longint_t; + longint_unsigned_t x_longint_unsigned_t; +`ifndef NO_TIME + time_t x_time_t; +`endif +`ifndef NO_INTEGER + integer_t x_integer_t; +`endif + real_t x_real_t; +`ifndef NO_SHORTREAL + shortreal_t x_shortreal_t; +`endif + chandle_t x_chandle_t; + string_t x_string_t; + bit_t x_bit_t; + logic_t x_logic_t; + + bit [ 0:0] x_bit_1; + bit [ 31:0] x_bit_32; + bit [ 32:0] x_bit_33; + bit [ 63:0] x_bit_64; + bit [ 64:0] x_bit_65; + bit [127:0] x_bit_128; + + struct_2_state_1 x_struct_2_state_1; + struct_2_state_32 x_struct_2_state_32; + struct_2_state_33 x_struct_2_state_33; + struct_2_state_64 x_struct_2_state_64; + struct_2_state_65 x_struct_2_state_65; + struct_2_state_128 x_struct_2_state_128; + + union_2_state_1 x_union_2_state_1; + union_2_state_32 x_union_2_state_32; + union_2_state_33 x_union_2_state_33; + union_2_state_64 x_union_2_state_64; + union_2_state_65 x_union_2_state_65; + union_2_state_128 x_union_2_state_128; + + logic [ 0:0] x_logic_1; + logic [ 31:0] x_logic_32; + logic [ 32:0] x_logic_33; + logic [ 63:0] x_logic_64; + logic [ 64:0] x_logic_65; + logic [127:0] x_logic_128; + + struct_4_state_1 x_struct_4_state_1; + struct_4_state_32 x_struct_4_state_32; + struct_4_state_33 x_struct_4_state_33; + struct_4_state_64 x_struct_4_state_64; + struct_4_state_65 x_struct_4_state_65; + struct_4_state_128 x_struct_4_state_128; + + union_4_state_1 x_union_4_state_1; + union_4_state_32 x_union_4_state_32; + union_4_state_33 x_union_4_state_33; + union_4_state_64 x_union_4_state_64; + union_4_state_65 x_union_4_state_65; + union_4_state_128 x_union_4_state_128; + + // Basic types as per IEEE 1800-2017 35.5.6 + x_byte = 8'd10 - 8'(i); i_byte(x_byte); if (x_byte !== 8'd110 - 8'(i)) $stop; + x_byte_unsigned = 8'd20 - 8'(i); i_byte_unsigned(x_byte_unsigned); if (x_byte_unsigned !== 8'd220 - 8'(i)) $stop; + x_shortint = 16'd30 - 16'(i); i_shortint(x_shortint); if (x_shortint !== 16'd330 - 16'(i)) $stop; + x_shortint_unsigned = 16'd40 - 16'(i); i_shortint_unsigned(x_shortint_unsigned); if (x_shortint_unsigned !== 16'd440 - 16'(i)) $stop; + x_int = 32'd50 - 32'(i); i_int(x_int); if (x_int !== 32'd550 - 32'(i)) $stop; + x_int_unsigned = 32'd60 - 32'(i); i_int_unsigned(x_int_unsigned); if (x_int_unsigned !== 32'd660 - 32'(i)) $stop; + x_longint = 64'd70 - 64'(i); i_longint(x_longint); if (x_longint !== 64'd770 - 64'(i)) $stop; + x_longint_unsigned = 64'd80 - 64'(i); i_longint_unsigned(x_longint_unsigned); if (x_longint_unsigned !== 64'd880 - 64'(i)) $stop; +`ifndef NO_TIME + x_time = 64'd90 - 64'(i); i_time(x_time); if (x_time !== 64'd990 - 64'(i)) $stop; +`endif +`ifndef NO_INTEGER + x_integer = 32'd100- 32'(i); i_integer(x_integer); if (x_integer !== 32'd1100- 32'(i)) $stop; +`endif + x_real = -1.0*i - 0.50; i_real(x_real); if (x_real != -100.0 + -1.0*i - 0.50) $stop; +`ifndef NO_SHORTREAL + x_shortreal = -1.0*i - 0.25; i_shortreal(x_shortreal); if (x_shortreal != -200.0 + -1.0*i - 0.25) $stop; +`endif + if (~i[0]) begin + x_chandle = `NULL; i_chandle(x_chandle); if (x_chandle !== `NULL) $stop; + x_string = "Hello"; i_string(x_string); if (x_string != "Good") $stop; + end else begin + x_chandle = `NULL; i_chandle(x_chandle); if (x_chandle === `NULL) $stop; + x_string = "World"; i_string(x_string); if (x_string != "Bye" ) $stop; + end + x_bit = ~i[0]; i_bit(x_bit); if (x_bit !== i[0]) $stop; + x_logic = i[0]; i_logic(x_logic); if (x_logic !== ~i[0]) $stop; + + // Basic types via typedefs + x_byte_t = 8'd10 - 8'(2*i); i_byte_t(x_byte_t); if (x_byte_t !== 8'd111 - 8'(2*i)) $stop; + x_byte_unsigned_t = 8'd20 - 8'(2*i); i_byte_unsigned_t(x_byte_unsigned_t); if (x_byte_unsigned_t !== 8'd222 - 8'(2*i)) $stop; + x_shortint_t = 16'd30 - 16'(2*i); i_shortint_t(x_shortint_t); if (x_shortint_t !== 16'd333 - 16'(2*i)) $stop; + x_shortint_unsigned_t = 16'd40 - 16'(2*i); i_shortint_unsigned_t(x_shortint_unsigned_t); if (x_shortint_unsigned_t !== 16'd444 - 16'(2*i)) $stop; + x_int_t = 32'd50 - 32'(2*i); i_int_t(x_int_t); if (x_int_t !== 32'd555 - 32'(2*i)) $stop; + x_int_unsigned_t = 32'd60 - 32'(2*i); i_int_unsigned_t(x_int_unsigned_t); if (x_int_unsigned_t !== 32'd666 - 32'(2*i)) $stop; + x_longint_t = 64'd70 - 64'(2*i); i_longint_t(x_longint_t); if (x_longint_t !== 64'd777 - 64'(2*i)) $stop; + x_longint_unsigned_t = 64'd80 - 64'(2*i); i_longint_unsigned_t(x_longint_unsigned_t); if (x_longint_unsigned_t !== 64'd888 - 64'(2*i)) $stop; +`ifndef NO_TIME + x_time_t = 64'd90 - 64'(2*i); i_time_t(x_time_t); if (x_time_t !== 64'd999 - 64'(2*i)) $stop; +`endif +`ifndef NO_INTEGER + x_integer_t = 32'd100- 32'(2*i); i_integer_t(x_integer_t); if (x_integer_t !== 32'd1101- 32'(2*i)) $stop; +`endif + x_real_t = -1.0*(2*i) - 0.50; i_real_t(x_real_t); if (x_real_t != -111.0 + -1.0*(2*i) - 0.50) $stop; +`ifndef NO_SHORTREAL + x_shortreal_t = -1.0*(2*i) - 0.25; i_shortreal_t(x_shortreal_t); if (x_shortreal_t != -222.0 + -1.0*(2*i) - 0.25) $stop; +`endif + if (~i[0]) begin + x_chandle_t = `NULL; i_chandle_t(x_chandle_t); if (x_chandle_t === `NULL) $stop; + x_string_t = "World"; i_string_t(x_string_t); if (x_string_t != "Bye") $stop; + end else begin + x_chandle_t = `NULL; i_chandle_t(x_chandle_t); if (x_chandle_t !== `NULL) $stop; + x_string_t = "Hello"; i_string_t(x_string_t); if (x_string_t != "Good") $stop; + end + x_bit_t = ~i[0]; i_bit_t(x_bit_t); if (x_bit_t !== i[0]) $stop; + x_logic_t = i[0]; i_logic_t(x_logic_t); if (x_logic_t !== ~i[0]) $stop; + + // 2-state packed arrays + x_bit_1 = ~i[0]; i_array_2_state_1(x_bit_1); if (x_bit_1 !== i[0] ) $stop; + x_bit_32 = ~32'd0 << i; i_array_2_state_32(x_bit_32); if (x_bit_32 !== ~32'd0 >> i) $stop; + x_bit_33 = ~33'd0 << i; i_array_2_state_33(x_bit_33); if (x_bit_33 !== ~33'd0 >> i) begin $display("%d %x %0x", i, x_bit_33, ~33'd0 >> i); $stop; end + x_bit_64 = ~64'd0 << i; i_array_2_state_64(x_bit_64); if (x_bit_64 !== ~64'd0 >> i) $stop; + x_bit_65 = ~65'd0 << i; i_array_2_state_65(x_bit_65); if (x_bit_65 !== ~65'd0 >> i) $stop; + x_bit_128 = ~128'd0<< i; i_array_2_state_128(x_bit_128); if (x_bit_128 !== ~128'd0>> i) $stop; + + // 2-state packed structures + x_struct_2_state_1 = ~i[0]; i_struct_2_state_1(x_struct_2_state_1); if (x_struct_2_state_1 !== i[0] ) $stop; + x_struct_2_state_32 = ~32'd0 << i; i_struct_2_state_32(x_struct_2_state_32); if (x_struct_2_state_32 !== ~32'd0 >> i) $stop; + x_struct_2_state_33 = ~33'd0 << i; i_struct_2_state_33(x_struct_2_state_33); if (x_struct_2_state_33 !== ~33'd0 >> i) $stop; + x_struct_2_state_64 = ~64'd0 << i; i_struct_2_state_64(x_struct_2_state_64); if (x_struct_2_state_64 !== ~64'd0 >> i) $stop; + x_struct_2_state_65 = ~65'd0 << i; i_struct_2_state_65(x_struct_2_state_65); if (x_struct_2_state_65 !== ~65'd0 >> i) $stop; + x_struct_2_state_128= ~128'd0<< i; i_struct_2_state_128(x_struct_2_state_128); if (x_struct_2_state_128!== ~128'd0>> i) $stop; + + // 2-state packed unions + x_union_2_state_1 = ~i[0]; i_union_2_state_1(x_union_2_state_1); if (x_union_2_state_1 !== i[0] ) $stop; + x_union_2_state_32 = ~32'd0 << i; i_union_2_state_32(x_union_2_state_32); if (x_union_2_state_32 !== ~32'd0 >> i) $stop; + x_union_2_state_33 = ~33'd0 << i; i_union_2_state_33(x_union_2_state_33); if (x_union_2_state_33 !== ~33'd0 >> i) $stop; + x_union_2_state_64 = ~64'd0 << i; i_union_2_state_64(x_union_2_state_64); if (x_union_2_state_64 !== ~64'd0 >> i) $stop; + x_union_2_state_65 = ~65'd0 << i; i_union_2_state_65(x_union_2_state_65); if (x_union_2_state_65 !== ~65'd0 >> i) $stop; + x_union_2_state_128 = ~128'd0<< i; i_union_2_state_128(x_union_2_state_128); if (x_union_2_state_128 !== ~128'd0>> i) $stop; + + // 4-state packed arrays + x_logic_1 = ~i[0]; i_array_4_state_1(x_logic_1); if (x_logic_1 !== i[0] ) $stop; + x_logic_32 = ~32'd0 << i; i_array_4_state_32(x_logic_32); if (x_logic_32 !== ~32'd0 >> i) $stop; + x_logic_33 = ~33'd0 << i; i_array_4_state_33(x_logic_33); if (x_logic_33 !== ~33'd0 >> i) $stop; + x_logic_64 = ~64'd0 << i; i_array_4_state_64(x_logic_64); if (x_logic_64 !== ~64'd0 >> i) $stop; + x_logic_65 = ~65'd0 << i; i_array_4_state_65(x_logic_65); if (x_logic_65 !== ~65'd0 >> i) $stop; + x_logic_128 = ~128'd0<< i; i_array_4_state_128(x_logic_128); if (x_logic_128 !== ~128'd0>> i) $stop; + + // 4-state packed structures + x_struct_4_state_1 = ~i[0]; i_struct_4_state_1(x_struct_4_state_1); if (x_struct_4_state_1 !== i[0] ) $stop; + x_struct_4_state_32 = ~32'd0 << i; i_struct_4_state_32(x_struct_4_state_32); if (x_struct_4_state_32 !== ~32'd0 >> i) $stop; + x_struct_4_state_33 = ~33'd0 << i; i_struct_4_state_33(x_struct_4_state_33); if (x_struct_4_state_33 !== ~33'd0 >> i) $stop; + x_struct_4_state_64 = ~64'd0 << i; i_struct_4_state_64(x_struct_4_state_64); if (x_struct_4_state_64 !== ~64'd0 >> i) $stop; + x_struct_4_state_65 = ~65'd0 << i; i_struct_4_state_65(x_struct_4_state_65); if (x_struct_4_state_65 !== ~65'd0 >> i) $stop; + x_struct_4_state_128= ~128'd0<< i; i_struct_4_state_128(x_struct_4_state_128); if (x_struct_4_state_128!== ~128'd0>> i) $stop; + + // 4-state packed unions + x_union_4_state_1 = ~i[0]; i_union_4_state_1(x_union_4_state_1); if (x_union_4_state_1 !== i[0] ) $stop; + x_union_4_state_32 = ~32'd0 << i; i_union_4_state_32(x_union_4_state_32); if (x_union_4_state_32 !== ~32'd0 >> i) $stop; + x_union_4_state_33 = ~33'd0 << i; i_union_4_state_33(x_union_4_state_33); if (x_union_4_state_33 !== ~33'd0 >> i) $stop; + x_union_4_state_64 = ~64'd0 << i; i_union_4_state_64(x_union_4_state_64); if (x_union_4_state_64 !== ~64'd0 >> i) $stop; + x_union_4_state_65 = ~65'd0 << i; i_union_4_state_65(x_union_4_state_65); if (x_union_4_state_65 !== ~65'd0 >> i) $stop; + x_union_4_state_128 = ~128'd0<< i; i_union_4_state_128(x_union_4_state_128); if (x_union_4_state_128 !== ~128'd0>> i) $stop; + + // Check the exports + check_exports(); + end + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_dpi_arg_inout_type__Dpi.out b/test_regress/t/t_dpi_arg_inout_type__Dpi.out new file mode 100644 index 000000000..36221d574 --- /dev/null +++ b/test_regress/t/t_dpi_arg_inout_type__Dpi.out @@ -0,0 +1,287 @@ +// Verilated -*- C++ -*- +// DESCRIPTION: Verilator output: Prototypes for DPI import and export functions. +// +// Verilator includes this file in all generated .cpp files that use DPI functions. +// Manually include this file where DPI .c import functions are declared to ensure +// the C functions match the expectations of the DPI imports. + +#include "svdpi.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + // DPI EXPORTS + // DPI export at t/t_dpi_arg_inout_type.v:571:18 + extern void e_array_2_state_1(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:611:18 + extern void e_array_2_state_128(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:579:18 + extern void e_array_2_state_32(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:587:18 + extern void e_array_2_state_33(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:595:18 + extern void e_array_2_state_64(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:603:18 + extern void e_array_2_state_65(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:718:18 + extern void e_array_4_state_1(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:758:18 + extern void e_array_4_state_128(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:726:18 + extern void e_array_4_state_32(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:734:18 + extern void e_array_4_state_33(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:742:18 + extern void e_array_4_state_64(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:750:18 + extern void e_array_4_state_65(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:422:18 + extern void e_bit(svBit* x); + // DPI export at t/t_dpi_arg_inout_type.v:554:18 + extern void e_bit_t(svBit* x); + // DPI export at t/t_dpi_arg_inout_type.v:307:18 + extern void e_byte(char* x); + // DPI export at t/t_dpi_arg_inout_type.v:439:18 + extern void e_byte_t(char* x); + // DPI export at t/t_dpi_arg_inout_type.v:314:18 + extern void e_byte_unsigned(unsigned char* x); + // DPI export at t/t_dpi_arg_inout_type.v:446:18 + extern void e_byte_unsigned_t(unsigned char* x); + // DPI export at t/t_dpi_arg_inout_type.v:397:18 + extern void e_chandle(void** x); + // DPI export at t/t_dpi_arg_inout_type.v:529:18 + extern void e_chandle_t(void** x); + // DPI export at t/t_dpi_arg_inout_type.v:335:18 + extern void e_int(int* x); + // DPI export at t/t_dpi_arg_inout_type.v:467:18 + extern void e_int_t(int* x); + // DPI export at t/t_dpi_arg_inout_type.v:342:18 + extern void e_int_unsigned(unsigned int* x); + // DPI export at t/t_dpi_arg_inout_type.v:474:18 + extern void e_int_unsigned_t(unsigned int* x); + // DPI export at t/t_dpi_arg_inout_type.v:373:18 + extern void e_integer(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:505:18 + extern void e_integer_t(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:430:18 + extern void e_logic(svLogic* x); + // DPI export at t/t_dpi_arg_inout_type.v:562:18 + extern void e_logic_t(svLogic* x); + // DPI export at t/t_dpi_arg_inout_type.v:349:18 + extern void e_longint(long long* x); + // DPI export at t/t_dpi_arg_inout_type.v:481:18 + extern void e_longint_t(long long* x); + // DPI export at t/t_dpi_arg_inout_type.v:356:18 + extern void e_longint_unsigned(unsigned long long* x); + // DPI export at t/t_dpi_arg_inout_type.v:488:18 + extern void e_longint_unsigned_t(unsigned long long* x); + // DPI export at t/t_dpi_arg_inout_type.v:381:18 + extern void e_real(double* x); + // DPI export at t/t_dpi_arg_inout_type.v:513:18 + extern void e_real_t(double* x); + // DPI export at t/t_dpi_arg_inout_type.v:321:18 + extern void e_shortint(short* x); + // DPI export at t/t_dpi_arg_inout_type.v:453:18 + extern void e_shortint_t(short* x); + // DPI export at t/t_dpi_arg_inout_type.v:328:18 + extern void e_shortint_unsigned(unsigned short* x); + // DPI export at t/t_dpi_arg_inout_type.v:460:18 + extern void e_shortint_unsigned_t(unsigned short* x); + // DPI export at t/t_dpi_arg_inout_type.v:409:18 + extern void e_string(const char** x); + // DPI export at t/t_dpi_arg_inout_type.v:541:18 + extern void e_string_t(const char** x); + // DPI export at t/t_dpi_arg_inout_type.v:620:18 + extern void e_struct_2_state_1(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:660:18 + extern void e_struct_2_state_128(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:628:18 + extern void e_struct_2_state_32(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:636:18 + extern void e_struct_2_state_33(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:644:18 + extern void e_struct_2_state_64(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:652:18 + extern void e_struct_2_state_65(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:767:18 + extern void e_struct_4_state_1(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:807:18 + extern void e_struct_4_state_128(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:775:18 + extern void e_struct_4_state_32(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:783:18 + extern void e_struct_4_state_33(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:791:18 + extern void e_struct_4_state_64(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:799:18 + extern void e_struct_4_state_65(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:364:18 + extern void e_time(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:496:18 + extern void e_time_t(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:669:18 + extern void e_union_2_state_1(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:709:18 + extern void e_union_2_state_128(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:677:18 + extern void e_union_2_state_32(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:685:18 + extern void e_union_2_state_33(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:693:18 + extern void e_union_2_state_64(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:701:18 + extern void e_union_2_state_65(svBitVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:816:18 + extern void e_union_4_state_1(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:856:18 + extern void e_union_4_state_128(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:824:18 + extern void e_union_4_state_32(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:832:18 + extern void e_union_4_state_33(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:840:18 + extern void e_union_4_state_64(svLogicVecVal* x); + // DPI export at t/t_dpi_arg_inout_type.v:848:18 + extern void e_union_4_state_65(svLogicVecVal* x); + + // DPI IMPORTS + // DPI import at t/t_dpi_arg_inout_type.v:867:41 + extern void check_exports(); + // DPI import at t/t_dpi_arg_inout_type.v:154:33 + extern void i_array_2_state_1(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:159:33 + extern void i_array_2_state_128(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:155:33 + extern void i_array_2_state_32(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:156:33 + extern void i_array_2_state_33(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:157:33 + extern void i_array_2_state_64(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:158:33 + extern void i_array_2_state_65(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:178:33 + extern void i_array_4_state_1(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:183:33 + extern void i_array_4_state_128(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:179:33 + extern void i_array_4_state_32(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:180:33 + extern void i_array_4_state_33(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:181:33 + extern void i_array_4_state_64(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:182:33 + extern void i_array_4_state_65(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:126:33 + extern void i_bit(svBit* x); + // DPI import at t/t_dpi_arg_inout_type.v:150:33 + extern void i_bit_t(svBit* x); + // DPI import at t/t_dpi_arg_inout_type.v:106:33 + extern void i_byte(char* x); + // DPI import at t/t_dpi_arg_inout_type.v:130:33 + extern void i_byte_t(char* x); + // DPI import at t/t_dpi_arg_inout_type.v:107:33 + extern void i_byte_unsigned(unsigned char* x); + // DPI import at t/t_dpi_arg_inout_type.v:131:33 + extern void i_byte_unsigned_t(unsigned char* x); + // DPI import at t/t_dpi_arg_inout_type.v:124:33 + extern void i_chandle(void** x); + // DPI import at t/t_dpi_arg_inout_type.v:148:33 + extern void i_chandle_t(void** x); + // DPI import at t/t_dpi_arg_inout_type.v:110:33 + extern void i_int(int* x); + // DPI import at t/t_dpi_arg_inout_type.v:134:33 + extern void i_int_t(int* x); + // DPI import at t/t_dpi_arg_inout_type.v:111:33 + extern void i_int_unsigned(unsigned int* x); + // DPI import at t/t_dpi_arg_inout_type.v:135:33 + extern void i_int_unsigned_t(unsigned int* x); + // DPI import at t/t_dpi_arg_inout_type.v:118:33 + extern void i_integer(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:142:33 + extern void i_integer_t(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:127:33 + extern void i_logic(svLogic* x); + // DPI import at t/t_dpi_arg_inout_type.v:151:33 + extern void i_logic_t(svLogic* x); + // DPI import at t/t_dpi_arg_inout_type.v:112:33 + extern void i_longint(long long* x); + // DPI import at t/t_dpi_arg_inout_type.v:136:33 + extern void i_longint_t(long long* x); + // DPI import at t/t_dpi_arg_inout_type.v:113:33 + extern void i_longint_unsigned(unsigned long long* x); + // DPI import at t/t_dpi_arg_inout_type.v:137:33 + extern void i_longint_unsigned_t(unsigned long long* x); + // DPI import at t/t_dpi_arg_inout_type.v:120:33 + extern void i_real(double* x); + // DPI import at t/t_dpi_arg_inout_type.v:144:33 + extern void i_real_t(double* x); + // DPI import at t/t_dpi_arg_inout_type.v:108:33 + extern void i_shortint(short* x); + // DPI import at t/t_dpi_arg_inout_type.v:132:33 + extern void i_shortint_t(short* x); + // DPI import at t/t_dpi_arg_inout_type.v:109:33 + extern void i_shortint_unsigned(unsigned short* x); + // DPI import at t/t_dpi_arg_inout_type.v:133:33 + extern void i_shortint_unsigned_t(unsigned short* x); + // DPI import at t/t_dpi_arg_inout_type.v:125:33 + extern void i_string(const char** x); + // DPI import at t/t_dpi_arg_inout_type.v:149:33 + extern void i_string_t(const char** x); + // DPI import at t/t_dpi_arg_inout_type.v:162:33 + extern void i_struct_2_state_1(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:167:33 + extern void i_struct_2_state_128(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:163:33 + extern void i_struct_2_state_32(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:164:33 + extern void i_struct_2_state_33(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:165:33 + extern void i_struct_2_state_64(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:166:33 + extern void i_struct_2_state_65(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:186:33 + extern void i_struct_4_state_1(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:191:33 + extern void i_struct_4_state_128(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:187:33 + extern void i_struct_4_state_32(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:188:33 + extern void i_struct_4_state_33(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:189:33 + extern void i_struct_4_state_64(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:190:33 + extern void i_struct_4_state_65(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:115:33 + extern void i_time(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:139:33 + extern void i_time_t(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:170:33 + extern void i_union_2_state_1(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:175:33 + extern void i_union_2_state_128(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:171:33 + extern void i_union_2_state_32(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:172:33 + extern void i_union_2_state_33(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:173:33 + extern void i_union_2_state_64(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:174:33 + extern void i_union_2_state_65(svBitVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:194:33 + extern void i_union_4_state_1(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:199:33 + extern void i_union_4_state_128(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:195:33 + extern void i_union_4_state_32(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:196:33 + extern void i_union_4_state_33(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:197:33 + extern void i_union_4_state_64(svLogicVecVal* x); + // DPI import at t/t_dpi_arg_inout_type.v:198:33 + extern void i_union_4_state_65(svLogicVecVal* x); + +#ifdef __cplusplus +} +#endif diff --git a/test_regress/t/t_dpi_arg_input_type.cpp b/test_regress/t/t_dpi_arg_input_type.cpp new file mode 100644 index 000000000..730740cb3 --- /dev/null +++ b/test_regress/t/t_dpi_arg_input_type.cpp @@ -0,0 +1,815 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include +#include +#include + +#if defined(NCSC) +// Used by NC's svdpi.h to pick up svLogicVecVal with _.aval and _.bval fields, +// rather than the IEEE 1800-2005 version which has _.a and _.b fields. +# define DPI_COMPATIBILITY_VERSION_1800v2012 +#endif + +#include "svdpi.h" + +#if defined(VERILATOR) // Verilator +# include "Vt_dpi_arg_input_type__Dpi.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_SHORTREAL +# define CONSTARG const +#elif defined(VCS) // VCS +# include "../vc_hdrs.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_TIME +# define CONSTARG const +#elif defined(NCSC) // NC +# include "dpi-exp.h" +# include "dpi-imp.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_TIME +# define NO_INTEGER +# define NO_SHORTREAL +// Sadly NC does not declare pass-by reference input arguments as const +# define CONSTARG +#elif defined(MS) // ModelSim +# include "dpi.h" +typedef int64_t sv_longint_t; +typedef uint64_t sv_longint_unsigned_t; +# define CONSTARG const +#else +# error "Unknown simulator for DPI test" +#endif + +//====================================================================== +// Implementations of imported functions +//====================================================================== + +#define stop() \ + do { \ + printf(__FILE__ ":%d Bad value\n", __LINE__); \ + abort(); \ + } while (0) + +void check_bvals(CONSTARG svLogicVecVal* v, unsigned n); +void check_bvals(CONSTARG svLogicVecVal* v, unsigned n) { + for (unsigned i = 0; i < n; i++) { + if (v[i].bval != 0) { + printf(__FILE__ ":%d Bad svLogicVecVal bval\n", __LINE__); + abort(); + } + } +} + +// Basic types as per IEEE 1800-2017 35.5.6 +void i_byte(char i) { + static int n = 0; + if (i != 10 - n++) stop(); +} + +void i_byte_unsigned(unsigned char i) { + static int n = 0; + if (i != 20 - n++) stop(); +} + +void i_shortint(short i) { + static int n = 0; + if (i != 30 - n++) stop(); +} + +void i_shortint_unsigned(unsigned short i) { + static int n = 0; + if (i != 40 - n++) stop(); +} + +void i_int(int i) { + static int n = 0; + if (i != 50 - n++) stop(); +} + +void i_int_unsigned(unsigned i) { + static int n = 0; + if (i != 60 - n++) stop(); +} + +void i_longint(sv_longint_t i) { + static int n = 0; + if (i != 70 - n++) stop(); +} + +void i_longint_unsigned(sv_longint_unsigned_t i) { + static int n = 0; + if (i != 80 - n++) stop(); +} + +#ifndef NO_TIME +void i_time(CONSTARG svLogicVecVal* i) { + static int n = 0; + if (i[0].aval != 90 - n++) stop(); + if (i[1].aval != 0) stop(); + check_bvals(i, 2); +} +#endif + +#ifndef NO_INTEGER +void i_integer(CONSTARG svLogicVecVal* i) { + static int n = 0; + if (i[0].aval != 100 - n++) stop(); + check_bvals(i, 1); +} +#endif + +void i_real(double i) { + static int n = 0; + if (i != (-2.0 * n++ - 1.0) / 2.0) stop(); +} + +#ifndef NO_SHORTREAL +void i_shortreal(float i) { + static int n = 0; + if (i != (-4.0f * n++ - 1.0f) / 4.0f) stop(); +} +#endif + +void i_chandle(void* i) { + static int n = 0; + printf("i_chandle %d\n", n); + if (i != NULL) stop(); + n++; +} + +void i_string(const char* i) { + static int n = 0; + printf("i_string %d\n", n); + if (n++ % 2 == 0) { + if (strcmp(i, "World") != 0) stop(); + } else { + if (strcmp(i, "Hello") != 0) stop(); + } +} + +void i_bit(svBit i) { + static int n = 0; + printf("i_bit %d\n", n); + if (i != !(n++ % 2)) stop(); +} + +void i_logic(svLogic i) { + static int n = 0; + printf("i_logic %d\n", n); + if (i != n++ % 2) stop(); +} + +// Basic types via typedefs +void i_byte_t(char i) { + static int n = 0; + if (i != 10 - n) stop(); + n += 2; +} + +void i_byte_unsigned_t(unsigned char i) { + static int n = 0; + if (i != 20 - n) stop(); + n += 2; +} + +void i_shortint_t(short i) { + static int n = 0; + if (i != 30 - n) stop(); + n += 2; +} + +void i_shortint_unsigned_t(unsigned short i) { + static int n = 0; + if (i != 40 - n) stop(); + n += 2; +} + +void i_int_t(int i) { + static int n = 0; + if (i != 50 - n) stop(); + n += 2; +} + +void i_int_unsigned_t(unsigned i) { + static int n = 0; + if (i != 60 - n) stop(); + n += 2; +} + +void i_longint_t(sv_longint_t i) { + static int n = 0; + if (i != 70 - n) stop(); + n += 2; +} + +void i_longint_unsigned_t(sv_longint_unsigned_t i) { + static int n = 0; + if (i != 80 - n) stop(); + n += 2; +} + +#ifndef NO_TIME +void i_time_t(CONSTARG svLogicVecVal* i) { + static int n = 0; + if (i[0].aval != 90 - n) stop(); + if (i[1].aval != 0) stop(); + check_bvals(i, 2); + n += 2; +} +#endif + +#ifndef NO_INTEGER +void i_integer_t(CONSTARG svLogicVecVal* i) { + static int n = 0; + if (i[0].aval != 100 - n) stop(); + check_bvals(i, 1); + n += 2; +} +#endif + +void i_real_t(double i) { + static int n = 0; + if (i != (-2.0 * n - 1.0) / 2.0) stop(); + n += 2; +} + +#ifndef NO_SHORTREAL +void i_shortreal_t(float i) { + static int n = 0; + if (i != (-4.0f * n - 1.0f) / 4.0f) stop(); + n += 2; +} +#endif + +void i_chandle_t(void* i) { + static int n = 0; + printf("i_chandle_t %d\n", n); + if (i != NULL) stop(); + n++; +} + +void i_string_t(const char* i) { + static int n = 0; + printf("i_string_t %d\n", n); + if (n++ % 2 == 0) { + if (strcmp(i, "World") != 0) stop(); + } else { + if (strcmp(i, "Hello") != 0) stop(); + } +} + +void i_bit_t(svBit i) { + static int n = 0; + printf("i_bit_t %d\n", n); + if (i != !(n++ % 2)) stop(); +} + +void i_logic_t(svLogic i) { + static int n = 0; + printf("i_logic_t %d\n", n); + if (i != n++ % 2) stop(); +} + +// 2-state packed arrays +void i_array_2_state_1(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_array_2_state_1 %d\n", n); + if ((*i & 1) != !(n++ % 2)) stop(); +} + +void i_array_2_state_32(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_array_2_state_32 %d\n", n); + if (*i != 0xffffffffU << n++) stop(); +} + +void i_array_2_state_33(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_array_2_state_33 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if ((i[1] & 1) != 1) stop(); +} + +void i_array_2_state_64(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_array_2_state_64 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if (i[1] != -1) stop(); +} + +void i_array_2_state_65(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_array_2_state_65 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if (i[1] != -1) stop(); + if ((i[2] & 1) != 1) stop(); +} + +void i_array_2_state_128(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_array_2_state_128 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if (i[1] != -1) stop(); + if (i[2] != -1) stop(); + if (i[3] != -1) stop(); +} + +// 2-state packed structures +void i_struct_2_state_1(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_struct_2_state_1 %d\n", n); + if ((*i & 1) != !(n++ % 2)) stop(); +} + +void i_struct_2_state_32(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_struct_2_state_32 %d\n", n); + if (*i != 0xffffffffU << n++) stop(); +} + +void i_struct_2_state_33(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_struct_2_state_33 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if ((i[1] & 1) != 1) stop(); +} + +void i_struct_2_state_64(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_struct_2_state_64 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if (i[1] != -1) stop(); +} + +void i_struct_2_state_65(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_struct_2_state_65 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if (i[1] != -1) stop(); + if ((i[2] & 1) != 1) stop(); +} + +void i_struct_2_state_128(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_struct_2_state_128 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if (i[1] != -1) stop(); + if (i[2] != -1) stop(); + if (i[3] != -1) stop(); +} + +// 2-state packed unions +void i_union_2_state_1(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_union_2_state_1 %d\n", n); + if ((*i & 1) != !(n++ % 2)) stop(); +} + +void i_union_2_state_32(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_union_2_state_32 %d\n", n); + if (*i != 0xffffffffU << n++) stop(); +} + +void i_union_2_state_33(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_union_2_state_33 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if ((i[1] & 1) != 1) stop(); +} + +void i_union_2_state_64(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_union_2_state_64 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if (i[1] != -1) stop(); +} + +void i_union_2_state_65(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_union_2_state_65 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if (i[1] != -1) stop(); + if ((i[2] & 1) != 1) stop(); +} + +void i_union_2_state_128(CONSTARG svBitVecVal* i) { + static int n = 0; + printf("i_union_2_state_128 %d\n", n); + if (i[0] != 0xffffffffU << n++) stop(); + if (i[1] != -1) stop(); + if (i[2] != -1) stop(); + if (i[3] != -1) stop(); +} + +// 4-state packed arrays +void i_array_4_state_1(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_array_4_state_1 %d\n", n); + if ((i->aval & 1) != !(n++ % 2)) stop(); + check_bvals(i, 1); +} + +void i_array_4_state_32(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_array_4_state_32 %d\n", n); + if (i->aval != 0xffffffffU << n++) stop(); + check_bvals(i, 1); +} + +void i_array_4_state_33(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_array_4_state_33 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if ((i[1].aval & 1) != 1) stop(); + check_bvals(i, 2); +} + +void i_array_4_state_64(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_array_4_state_64 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if (i[1].aval != -1) stop(); + check_bvals(i, 2); +} + +void i_array_4_state_65(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_array_4_state_65 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if (i[1].aval != -1) stop(); + if ((i[2].aval & 1) != 1) stop(); + check_bvals(i, 3); +} + +void i_array_4_state_128(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_array_4_state_128 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if (i[1].aval != -1) stop(); + if (i[2].aval != -1) stop(); + if (i[3].aval != -1) stop(); + check_bvals(i, 4); +} + +// 4-state packed structures +void i_struct_4_state_1(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_struct_4_state_1 %d\n", n); + if ((i->aval & 1) != !(n++ % 2)) stop(); + check_bvals(i, 1); +} + +void i_struct_4_state_32(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_struct_4_state_32 %d\n", n); + if (i->aval != 0xffffffffU << n++) stop(); + check_bvals(i, 1); +} + +void i_struct_4_state_33(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_struct_4_state_33 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if ((i[1].aval & 1) != 1) stop(); + check_bvals(i, 2); +} + +void i_struct_4_state_64(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_struct_4_state_64 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if (i[1].aval != -1) stop(); + check_bvals(i, 2); +} + +void i_struct_4_state_65(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_struct_4_state_65 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if (i[1].aval != -1) stop(); + if ((i[2].aval & 1) != 1) stop(); + check_bvals(i, 3); +} + +void i_struct_4_state_128(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_struct_4_state_128 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if (i[1].aval != -1) stop(); + if (i[2].aval != -1) stop(); + if (i[3].aval != -1) stop(); + check_bvals(i, 4); +} + +// 4-state packed unions +void i_union_4_state_1(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_union_4_state_1 %d\n", n); + if ((i->aval & 1) != !(n++ % 2)) stop(); + check_bvals(i, 1); +} + +void i_union_4_state_32(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_union_4_state_32 %d\n", n); + if (i->aval != 0xffffffffU << n++) stop(); + check_bvals(i, 1); +} + +void i_union_4_state_33(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_union_4_state_33 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if ((i[1].aval & 1) != 1) stop(); + check_bvals(i, 2); +} + +void i_union_4_state_64(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_union_4_state_64 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if (i[1].aval != -1) stop(); + check_bvals(i, 2); +} + +void i_union_4_state_65(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_union_4_state_65 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if (i[1].aval != -1) stop(); + if ((i[2].aval & 1) != 1) stop(); + check_bvals(i, 3); +} + +void i_union_4_state_128(CONSTARG svLogicVecVal* i) { + static int n = 0; + printf("i_union_4_state_128 %d\n", n); + if (i[0].aval != 0xffffffffU << n++) stop(); + if (i[1].aval != -1) stop(); + if (i[2].aval != -1) stop(); + if (i[3].aval != -1) stop(); + check_bvals(i, 4); +} + +//====================================================================== +// Check exported functions +//====================================================================== + +void set_bvals(svLogicVecVal* v, unsigned n); +void set_bvals(svLogicVecVal* v, unsigned n) { + for (unsigned i = 0; i < n; i++) { + v[i].bval = 0; + } +} + +void check_exports() { + static int n = 0; + +#ifndef NO_TIME + svLogicVecVal x_time[2]; + svLogicVecVal x_time_t[2]; +#endif +#ifndef NO_INTEGER + svLogicVecVal x_integer[1]; + svLogicVecVal x_integer_t[1]; +#endif + +#ifndef NO_TIME + set_bvals(x_time, 2); + set_bvals(x_time_t, 2); +#endif +#ifndef NO_INTEGER + set_bvals(x_integer, 1); + set_bvals(x_integer_t, 1); +#endif + + // Basic types as per IEEE 1800-2017 35.5.6 + e_byte(10 + n); + e_byte_unsigned(20 + n); + e_shortint(30 + n); + e_shortint_unsigned(40 + n); + e_int(50 + n); + e_int_unsigned(60 + n); + e_longint(70 + n); + e_longint_unsigned(80 + n); +#ifndef NO_TIME + x_time[0].aval = 90 + n; + x_time[1].aval = 0; + e_time(x_time); +#endif +#ifndef NO_INTEGER + x_integer[0].aval = 100 + n; + e_integer(x_integer); +#endif + e_real(1.0 * n + 0.5); +#ifndef NO_SHORTREAL + e_shortreal(1.0f * n + 0.25f); +#endif + e_chandle(n % 2 ? reinterpret_cast(&e_chandle) : NULL); + e_string(n % 2 ? "World" : "Hello"); + e_bit(n % 2); + e_logic(!(n % 2)); + + // Basic types via tyepdef + e_byte_t(10 + 2 * n); + e_byte_unsigned_t(20 + 2 * n); + e_shortint_t(30 + 2 * n); + e_shortint_unsigned_t(40 + 2 * n); + e_int_t(50 + 2 * n); + e_int_unsigned_t(60 + 2 * n); + e_longint_t(70 + 2 * n); + e_longint_unsigned_t(80 + 2 * n); +#ifndef NO_TIME + x_time_t[0].aval = 90 + 2 * n; + x_time_t[1].aval = 0; + e_time_t(x_time_t); +#endif +#ifndef NO_INTEGER + x_integer_t[0].aval = 100 + 2 * n; + e_integer_t(x_integer_t); +#endif + e_real_t(1.0 * (2 * n) + 0.5); +#ifndef NO_SHORTREAL + e_shortreal_t(1.0f * (2 * n) + 0.25f); +#endif + e_chandle_t(n % 2 ? NULL : reinterpret_cast(&e_chandle_t)); + e_string_t(n % 2 ? "Hello" : "World"); + e_bit_t(n % 2); + e_logic_t(!(n % 2)); + + const int m = n == 0 ? 0 : n - 1; + + svBitVecVal b1[1]; + svBitVecVal b2[2]; + svBitVecVal b3[3]; + svBitVecVal b4[4]; + + b3[0] = 0xffffffff; + b4[0] = 0xffffffff; + b4[1] = 0xffffffff; + b4[2] = 0xffffffff; + + // 2-state packed arrays + b1[0] = n % 2; + e_array_2_state_1(b1); + + b1[0] = 0xffffffff >> n; + e_array_2_state_32(b1); + + b2[1] = 1 >> n; + b2[0] = 0xffffffff >> m; + e_array_2_state_33(b2); + + b2[1] = 0xffffffff >> n; + b2[0] = 0xffffffff; + e_array_2_state_64(b2); + + b3[2] = 1 >> n; + b3[1] = 0xffffffff >> m; + e_array_2_state_65(b3); + + b4[3] = 0xffffffff >> n; + e_array_2_state_128(b4); + + // 2-state packed structures + b1[0] = n % 2; + e_struct_2_state_1(b1); + + b1[0] = 0xffffffff >> n; + e_struct_2_state_32(b1); + + b2[1] = 1 >> n; + b2[0] = 0xffffffff >> m; + e_struct_2_state_33(b2); + + b2[1] = 0xffffffff >> n; + b2[0] = 0xffffffff; + e_struct_2_state_64(b2); + + b3[2] = 1 >> n; + b3[1] = 0xffffffff >> m; + e_struct_2_state_65(b3); + + b4[3] = 0xffffffff >> n; + e_struct_2_state_128(b4); + + // 2-state packed unions + b1[0] = n % 2; + e_union_2_state_1(b1); + + b1[0] = 0xffffffff >> n; + e_union_2_state_32(b1); + + b2[1] = 1 >> n; + b2[0] = 0xffffffff >> m; + e_union_2_state_33(b2); + + b2[1] = 0xffffffff >> n; + b2[0] = 0xffffffff; + e_union_2_state_64(b2); + + b3[2] = 1 >> n; + b3[1] = 0xffffffff >> m; + e_union_2_state_65(b3); + + b4[3] = 0xffffffff >> n; + e_union_2_state_128(b4); + + svLogicVecVal l1[1]; + svLogicVecVal l2[2]; + svLogicVecVal l3[3]; + svLogicVecVal l4[4]; + + // bvals should be ignored, leave them un-initialized + + set_bvals(l1, 1); + set_bvals(l2, 2); + set_bvals(l3, 3); + set_bvals(l4, 4); + + l3[0].aval = 0xffffffff; + l4[0].aval = 0xffffffff; + l4[1].aval = 0xffffffff; + l4[2].aval = 0xffffffff; + + // 4-state packed arrays + l1[0].aval = n % 2; + e_array_4_state_1(l1); + + l1[0].aval = 0xffffffff >> n; + e_array_4_state_32(l1); + + l2[1].aval = 1 >> n; + l2[0].aval = 0xffffffff >> m; + e_array_4_state_33(l2); + + l2[1].aval = 0xffffffff >> n; + l2[0].aval = 0xffffffff; + e_array_4_state_64(l2); + + l3[2].aval = 1 >> n; + l3[1].aval = 0xffffffff >> m; + e_array_4_state_65(l3); + + l4[3].aval = 0xffffffff >> n; + e_array_4_state_128(l4); + + // 4-state packed structures + l1[0].aval = n % 2; + e_struct_4_state_1(l1); + + l1[0].aval = 0xffffffff >> n; + e_struct_4_state_32(l1); + + l2[1].aval = 1 >> n; + l2[0].aval = 0xffffffff >> m; + e_struct_4_state_33(l2); + + l2[1].aval = 0xffffffff >> n; + l2[0].aval = 0xffffffff; + e_struct_4_state_64(l2); + + l3[2].aval = 1 >> n; + l3[1].aval = 0xffffffff >> m; + e_struct_4_state_65(l3); + + l4[3].aval = 0xffffffff >> n; + e_struct_4_state_128(l4); + + // 4-state packed unions + l1[0].aval = n % 2; + e_union_4_state_1(l1); + + l1[0].aval = 0xffffffff >> n; + e_union_4_state_32(l1); + + l2[1].aval = 1 >> n; + l2[0].aval = 0xffffffff >> m; + e_union_4_state_33(l2); + + l2[1].aval = 0xffffffff >> n; + l2[0].aval = 0xffffffff; + e_union_4_state_64(l2); + + l3[2].aval = 1 >> n; + l3[1].aval = 0xffffffff >> m; + e_union_4_state_65(l3); + + l4[3].aval = 0xffffffff >> n; + e_union_4_state_128(l4); + + n++; +} diff --git a/test_regress/t/t_dpi_arg_input_type.out b/test_regress/t/t_dpi_arg_input_type.out new file mode 100644 index 000000000..a7544a086 --- /dev/null +++ b/test_regress/t/t_dpi_arg_input_type.out @@ -0,0 +1,265 @@ +i_chandle 0 +i_string 0 +i_bit 0 +i_logic 0 +i_chandle_t 0 +i_string_t 0 +i_bit_t 0 +i_logic_t 0 +i_array_2_state_1 0 +i_array_2_state_32 0 +i_array_2_state_33 0 +i_array_2_state_64 0 +i_array_2_state_65 0 +i_array_2_state_128 0 +i_struct_2_state_1 0 +i_struct_2_state_32 0 +i_struct_2_state_33 0 +i_struct_2_state_64 0 +i_struct_2_state_65 0 +i_struct_2_state_128 0 +i_union_2_state_1 0 +i_union_2_state_32 0 +i_union_2_state_33 0 +i_union_2_state_64 0 +i_union_2_state_65 0 +i_union_2_state_128 0 +i_array_4_state_1 0 +i_array_4_state_32 0 +i_array_4_state_33 0 +i_array_4_state_64 0 +i_array_4_state_65 0 +i_array_4_state_128 0 +i_struct_4_state_1 0 +i_struct_4_state_32 0 +i_struct_4_state_33 0 +i_struct_4_state_64 0 +i_struct_4_state_65 0 +i_struct_4_state_128 0 +i_union_4_state_1 0 +i_union_4_state_32 0 +i_union_4_state_33 0 +i_union_4_state_64 0 +i_union_4_state_65 0 +i_union_4_state_128 0 +e_chandle 0 +e_string 0 +e_bit 0 +e_logic 0 +e_chandle_t 0 +e_string_t 0 +e_bit_t 0 +e_logic_t 0 +e_array_2_state_1 0 +e_array_2_state_32 0 +e_array_2_state_33 0 +e_array_2_state_64 0 +e_array_2_state_65 0 +e_array_2_state_128 0 +e_struct_2_state_1 0 +e_struct_2_state_32 0 +e_struct_2_state_33 0 +e_struct_2_state_64 0 +e_struct_2_state_65 0 +e_struct_2_state_128 0 +e_union_2_state_1 0 +e_union_2_state_32 0 +e_union_2_state_33 0 +e_union_2_state_64 0 +e_union_2_state_65 0 +e_union_2_state_128 0 +e_array_4_state_1 0 +e_array_4_state_32 0 +e_array_4_state_33 0 +e_array_4_state_64 0 +e_array_4_state_65 0 +e_array_4_state_128 0 +e_struct_4_state_1 0 +e_struct_4_state_32 0 +e_struct_4_state_33 0 +e_struct_4_state_64 0 +e_struct_4_state_65 0 +e_struct_4_state_128 0 +e_union_4_state_1 0 +e_union_4_state_32 0 +e_union_4_state_33 0 +e_union_4_state_64 0 +e_union_4_state_65 0 +e_union_4_state_128 0 +i_chandle 1 +i_string 1 +i_bit 1 +i_logic 1 +i_chandle_t 1 +i_string_t 1 +i_bit_t 1 +i_logic_t 1 +i_array_2_state_1 1 +i_array_2_state_32 1 +i_array_2_state_33 1 +i_array_2_state_64 1 +i_array_2_state_65 1 +i_array_2_state_128 1 +i_struct_2_state_1 1 +i_struct_2_state_32 1 +i_struct_2_state_33 1 +i_struct_2_state_64 1 +i_struct_2_state_65 1 +i_struct_2_state_128 1 +i_union_2_state_1 1 +i_union_2_state_32 1 +i_union_2_state_33 1 +i_union_2_state_64 1 +i_union_2_state_65 1 +i_union_2_state_128 1 +i_array_4_state_1 1 +i_array_4_state_32 1 +i_array_4_state_33 1 +i_array_4_state_64 1 +i_array_4_state_65 1 +i_array_4_state_128 1 +i_struct_4_state_1 1 +i_struct_4_state_32 1 +i_struct_4_state_33 1 +i_struct_4_state_64 1 +i_struct_4_state_65 1 +i_struct_4_state_128 1 +i_union_4_state_1 1 +i_union_4_state_32 1 +i_union_4_state_33 1 +i_union_4_state_64 1 +i_union_4_state_65 1 +i_union_4_state_128 1 +e_chandle 1 +e_string 1 +e_bit 1 +e_logic 1 +e_chandle_t 1 +e_string_t 1 +e_bit_t 1 +e_logic_t 1 +e_array_2_state_1 1 +e_array_2_state_32 1 +e_array_2_state_33 1 +e_array_2_state_64 1 +e_array_2_state_65 1 +e_array_2_state_128 1 +e_struct_2_state_1 1 +e_struct_2_state_32 1 +e_struct_2_state_33 1 +e_struct_2_state_64 1 +e_struct_2_state_65 1 +e_struct_2_state_128 1 +e_union_2_state_1 1 +e_union_2_state_32 1 +e_union_2_state_33 1 +e_union_2_state_64 1 +e_union_2_state_65 1 +e_union_2_state_128 1 +e_array_4_state_1 1 +e_array_4_state_32 1 +e_array_4_state_33 1 +e_array_4_state_64 1 +e_array_4_state_65 1 +e_array_4_state_128 1 +e_struct_4_state_1 1 +e_struct_4_state_32 1 +e_struct_4_state_33 1 +e_struct_4_state_64 1 +e_struct_4_state_65 1 +e_struct_4_state_128 1 +e_union_4_state_1 1 +e_union_4_state_32 1 +e_union_4_state_33 1 +e_union_4_state_64 1 +e_union_4_state_65 1 +e_union_4_state_128 1 +i_chandle 2 +i_string 2 +i_bit 2 +i_logic 2 +i_chandle_t 2 +i_string_t 2 +i_bit_t 2 +i_logic_t 2 +i_array_2_state_1 2 +i_array_2_state_32 2 +i_array_2_state_33 2 +i_array_2_state_64 2 +i_array_2_state_65 2 +i_array_2_state_128 2 +i_struct_2_state_1 2 +i_struct_2_state_32 2 +i_struct_2_state_33 2 +i_struct_2_state_64 2 +i_struct_2_state_65 2 +i_struct_2_state_128 2 +i_union_2_state_1 2 +i_union_2_state_32 2 +i_union_2_state_33 2 +i_union_2_state_64 2 +i_union_2_state_65 2 +i_union_2_state_128 2 +i_array_4_state_1 2 +i_array_4_state_32 2 +i_array_4_state_33 2 +i_array_4_state_64 2 +i_array_4_state_65 2 +i_array_4_state_128 2 +i_struct_4_state_1 2 +i_struct_4_state_32 2 +i_struct_4_state_33 2 +i_struct_4_state_64 2 +i_struct_4_state_65 2 +i_struct_4_state_128 2 +i_union_4_state_1 2 +i_union_4_state_32 2 +i_union_4_state_33 2 +i_union_4_state_64 2 +i_union_4_state_65 2 +i_union_4_state_128 2 +e_chandle 2 +e_string 2 +e_bit 2 +e_logic 2 +e_chandle_t 2 +e_string_t 2 +e_bit_t 2 +e_logic_t 2 +e_array_2_state_1 2 +e_array_2_state_32 2 +e_array_2_state_33 2 +e_array_2_state_64 2 +e_array_2_state_65 2 +e_array_2_state_128 2 +e_struct_2_state_1 2 +e_struct_2_state_32 2 +e_struct_2_state_33 2 +e_struct_2_state_64 2 +e_struct_2_state_65 2 +e_struct_2_state_128 2 +e_union_2_state_1 2 +e_union_2_state_32 2 +e_union_2_state_33 2 +e_union_2_state_64 2 +e_union_2_state_65 2 +e_union_2_state_128 2 +e_array_4_state_1 2 +e_array_4_state_32 2 +e_array_4_state_33 2 +e_array_4_state_64 2 +e_array_4_state_65 2 +e_array_4_state_128 2 +e_struct_4_state_1 2 +e_struct_4_state_32 2 +e_struct_4_state_33 2 +e_struct_4_state_64 2 +e_struct_4_state_65 2 +e_struct_4_state_128 2 +e_union_4_state_1 2 +e_union_4_state_32 2 +e_union_4_state_33 2 +e_union_4_state_64 2 +e_union_4_state_65 2 +e_union_4_state_128 2 +*-* All Finished *-* diff --git a/test_regress/t/t_dpi_arg_input_type.pl b/test_regress/t/t_dpi_arg_input_type.pl new file mode 100755 index 000000000..7b2d8aa9a --- /dev/null +++ b/test_regress/t/t_dpi_arg_input_type.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Geza Lore. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if ($Self->{nc}) { + # For NC, compile twice, first just to generate DPI headers + compile( + nc_flags2 => ["+ncdpiheader+$Self->{obj_dir}/dpi-exp.h", + "+ncdpiimpheader+$Self->{obj_dir}/dpi-imp.h"] + ); +} + +compile( + v_flags2 => ["t/t_dpi_arg_input_type.cpp"], + verilator_flags2 => ["-Wall -Wno-DECLFILENAME"], + # NC: Gdd the obj_dir to the C include path + nc_flags2 => ["+ncscargs+-I$Self->{obj_dir}"], + # ModelSim: Generate DPI header, add obj_dir to the C include path + ms_flags2 => ["-dpiheader $Self->{obj_dir}/dpi.h", + "-ccflags -I$Self->{obj_dir}"], + ); + +if ($Self->{vlt_all}) { + files_identical( + "$Self->{obj_dir}/Vt_dpi_arg_input_type__Dpi.h", + "t/t_dpi_arg_input_type__Dpi.out" + ); +} + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ms_pli => 0 + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_arg_input_type.v b/test_regress/t/t_dpi_arg_input_type.v new file mode 100644 index 000000000..d6e6134be --- /dev/null +++ b/test_regress/t/t_dpi_arg_input_type.v @@ -0,0 +1,917 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +`ifdef VCS + `define NO_TIME +`endif + +`ifdef NC + `define NO_TIME + `define NO_INTEGER + `define NO_SHORTREAL +`endif + +`ifdef MS +`endif + +`ifdef VERILATOR + `define NO_SHORTREAL + `define NULL 64'd0 +`else + `define NULL null +`endif + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + +`ifdef VERILATOR + wire _unused = &{1'b0, clk}; +`endif + + // Legal input argument types for DPI functions + + //====================================================================== + // Type definitions + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + typedef byte byte_t; + typedef byte unsigned byte_unsigned_t; + typedef shortint shortint_t; + typedef shortint unsigned shortint_unsigned_t; + typedef int int_t; + typedef int unsigned int_unsigned_t; + typedef longint longint_t; + typedef longint unsigned longint_unsigned_t; +`ifndef NO_TIME + typedef time time_t; +`endif +`ifndef NO_INTEGER + typedef integer integer_t; +`endif + typedef real real_t; +`ifndef NO_SHORTREAL + typedef shortreal shortreal_t; +`endif + typedef chandle chandle_t; + typedef string string_t; + typedef bit bit_t; + typedef logic logic_t; + + // 2-state packed structures + typedef struct packed { bit x; } struct_2_state_1; + typedef struct packed { bit [15:0] x; bit [15:0] y; } struct_2_state_32; + typedef struct packed { bit [15:0] x; bit [16:0] y; } struct_2_state_33; + typedef struct packed { bit [31:0] x; bit [31:0] y; } struct_2_state_64; + typedef struct packed { bit [31:0] x; bit [32:0] y; } struct_2_state_65; + typedef struct packed { bit [63:0] x; bit [63:0] y; } struct_2_state_128; + + // 2-state packed unions + typedef union packed { bit x; bit y; } union_2_state_1; + typedef union packed { bit [31:0] x; bit [31:0] y; } union_2_state_32; + typedef union packed { bit [32:0] x; bit [32:0] y; } union_2_state_33; + typedef union packed { bit [63:0] x; bit [63:0] y; } union_2_state_64; + typedef union packed { bit [64:0] x; bit [64:0] y; } union_2_state_65; + typedef union packed { bit [127:0] x; bit [127:0] y; } union_2_state_128; + + // 4-state packed structures + typedef struct packed { logic x; } struct_4_state_1; + typedef struct packed { logic [15:0] x; bit [15:0] y; } struct_4_state_32; + typedef struct packed { logic [15:0] x; bit [16:0] y; } struct_4_state_33; + typedef struct packed { logic [31:0] x; bit [31:0] y; } struct_4_state_64; + typedef struct packed { logic [31:0] x; bit [32:0] y; } struct_4_state_65; + typedef struct packed { logic [63:0] x; bit [63:0] y; } struct_4_state_128; + + // 4-state packed unions + typedef union packed { logic x; bit y; } union_4_state_1; + typedef union packed { logic [31:0] x; bit [31:0] y; } union_4_state_32; + typedef union packed { logic [32:0] x; bit [32:0] y; } union_4_state_33; + typedef union packed { logic [63:0] x; bit [63:0] y; } union_4_state_64; + typedef union packed { logic [64:0] x; bit [64:0] y; } union_4_state_65; + typedef union packed { logic [127:0] x; bit [127:0] y; } union_4_state_128; + + //====================================================================== + // Imports + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + import "DPI-C" function void i_byte (input byte i); + import "DPI-C" function void i_byte_unsigned (input byte unsigned i); + import "DPI-C" function void i_shortint (input shortint i); + import "DPI-C" function void i_shortint_unsigned (input shortint unsigned i); + import "DPI-C" function void i_int (input int i); + import "DPI-C" function void i_int_unsigned (input int unsigned i); + import "DPI-C" function void i_longint (input longint i); + import "DPI-C" function void i_longint_unsigned (input longint unsigned i); +`ifndef NO_TIME + import "DPI-C" function void i_time (input time i); +`endif +`ifndef NO_INTEGER + import "DPI-C" function void i_integer (input integer i); +`endif + import "DPI-C" function void i_real (input real i); +`ifndef NO_SHORTREAL + import "DPI-C" function void i_shortreal (input shortreal i); +`endif + import "DPI-C" function void i_chandle (input chandle i); + import "DPI-C" function void i_string (input string i); + import "DPI-C" function void i_bit (input bit i); + import "DPI-C" function void i_logic (input logic i); + + // Basic types via typedef + import "DPI-C" function void i_byte_t (input byte_t i); + import "DPI-C" function void i_byte_unsigned_t (input byte_unsigned_t i); + import "DPI-C" function void i_shortint_t (input shortint_t i); + import "DPI-C" function void i_shortint_unsigned_t (input shortint_unsigned_t i); + import "DPI-C" function void i_int_t (input int_t i); + import "DPI-C" function void i_int_unsigned_t (input int_unsigned_t i); + import "DPI-C" function void i_longint_t (input longint_t i); + import "DPI-C" function void i_longint_unsigned_t (input longint_unsigned_t i); +`ifndef NO_TIME + import "DPI-C" function void i_time_t (input time_t i); +`endif +`ifndef NO_INTEGER + import "DPI-C" function void i_integer_t (input integer_t i); +`endif + import "DPI-C" function void i_real_t (input real_t i); +`ifndef NO_SHORTREAL + import "DPI-C" function void i_shortreal_t (input shortreal_t i); +`endif + import "DPI-C" function void i_chandle_t (input chandle_t i); + import "DPI-C" function void i_string_t (input string_t i); + import "DPI-C" function void i_bit_t (input bit_t i); + import "DPI-C" function void i_logic_t (input logic_t i); + + // 2-state packed arrays + import "DPI-C" function void i_array_2_state_1 (input bit [ 0:0] i); + import "DPI-C" function void i_array_2_state_32 (input bit [ 31:0] i); + import "DPI-C" function void i_array_2_state_33 (input bit [ 32:0] i); + import "DPI-C" function void i_array_2_state_64 (input bit [ 63:0] i); + import "DPI-C" function void i_array_2_state_65 (input bit [ 64:0] i); + import "DPI-C" function void i_array_2_state_128(input bit [127:0] i); + + // 2-state packed structures + import "DPI-C" function void i_struct_2_state_1 (input struct_2_state_1 i); + import "DPI-C" function void i_struct_2_state_32 (input struct_2_state_32 i); + import "DPI-C" function void i_struct_2_state_33 (input struct_2_state_33 i); + import "DPI-C" function void i_struct_2_state_64 (input struct_2_state_64 i); + import "DPI-C" function void i_struct_2_state_65 (input struct_2_state_65 i); + import "DPI-C" function void i_struct_2_state_128 (input struct_2_state_128 i); + + // 2-state packed unions + import "DPI-C" function void i_union_2_state_1 (input union_2_state_1 i); + import "DPI-C" function void i_union_2_state_32 (input union_2_state_32 i); + import "DPI-C" function void i_union_2_state_33 (input union_2_state_33 i); + import "DPI-C" function void i_union_2_state_64 (input union_2_state_64 i); + import "DPI-C" function void i_union_2_state_65 (input union_2_state_65 i); + import "DPI-C" function void i_union_2_state_128(input union_2_state_128 i); + + // 4-state packed arrays + import "DPI-C" function void i_array_4_state_1 (input logic [ 0:0] i); + import "DPI-C" function void i_array_4_state_32 (input logic [ 31:0] i); + import "DPI-C" function void i_array_4_state_33 (input logic [ 32:0] i); + import "DPI-C" function void i_array_4_state_64 (input logic [ 63:0] i); + import "DPI-C" function void i_array_4_state_65 (input logic [ 64:0] i); + import "DPI-C" function void i_array_4_state_128(input logic [127:0] i); + + // 4-state packed structures + import "DPI-C" function void i_struct_4_state_1 (input struct_4_state_1 i); + import "DPI-C" function void i_struct_4_state_32 (input struct_4_state_32 i); + import "DPI-C" function void i_struct_4_state_33 (input struct_4_state_33 i); + import "DPI-C" function void i_struct_4_state_64 (input struct_4_state_64 i); + import "DPI-C" function void i_struct_4_state_65 (input struct_4_state_65 i); + import "DPI-C" function void i_struct_4_state_128 (input struct_4_state_128 i); + + // 4-state packed unions + import "DPI-C" function void i_union_4_state_1 (input union_4_state_1 i); + import "DPI-C" function void i_union_4_state_32 (input union_4_state_32 i); + import "DPI-C" function void i_union_4_state_33 (input union_4_state_33 i); + import "DPI-C" function void i_union_4_state_64 (input union_4_state_64 i); + import "DPI-C" function void i_union_4_state_65 (input union_4_state_65 i); + import "DPI-C" function void i_union_4_state_128(input union_4_state_128 i); + + //====================================================================== + // Exports + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + export "DPI-C" function e_byte; + export "DPI-C" function e_byte_unsigned; + export "DPI-C" function e_shortint; + export "DPI-C" function e_shortint_unsigned; + export "DPI-C" function e_int; + export "DPI-C" function e_int_unsigned; + export "DPI-C" function e_longint; + export "DPI-C" function e_longint_unsigned; +`ifndef NO_TIME + export "DPI-C" function e_time; +`endif +`ifndef NO_INTEGER + export "DPI-C" function e_integer; +`endif + export "DPI-C" function e_real; +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal; +`endif + export "DPI-C" function e_chandle; + export "DPI-C" function e_string; + export "DPI-C" function e_bit; + export "DPI-C" function e_logic; + + // Basic types via typedef + export "DPI-C" function e_byte_t; + export "DPI-C" function e_byte_unsigned_t; + export "DPI-C" function e_shortint_t; + export "DPI-C" function e_shortint_unsigned_t; + export "DPI-C" function e_int_t; + export "DPI-C" function e_int_unsigned_t; + export "DPI-C" function e_longint_t; + export "DPI-C" function e_longint_unsigned_t; +`ifndef NO_TIME + export "DPI-C" function e_time_t; +`endif +`ifndef NO_INTEGER + export "DPI-C" function e_integer_t; +`endif + export "DPI-C" function e_real_t; +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal_t; +`endif + export "DPI-C" function e_chandle_t; + export "DPI-C" function e_string_t; + export "DPI-C" function e_bit_t; + export "DPI-C" function e_logic_t; + + // 2-state packed arrays + export "DPI-C" function e_array_2_state_1; + export "DPI-C" function e_array_2_state_32; + export "DPI-C" function e_array_2_state_33; + export "DPI-C" function e_array_2_state_64; + export "DPI-C" function e_array_2_state_65; + export "DPI-C" function e_array_2_state_128; + + // 2-state packed structures + export "DPI-C" function e_struct_2_state_1; + export "DPI-C" function e_struct_2_state_32; + export "DPI-C" function e_struct_2_state_33; + export "DPI-C" function e_struct_2_state_64; + export "DPI-C" function e_struct_2_state_65; + export "DPI-C" function e_struct_2_state_128; + + // 2-state packed unions + export "DPI-C" function e_union_2_state_1; + export "DPI-C" function e_union_2_state_32; + export "DPI-C" function e_union_2_state_33; + export "DPI-C" function e_union_2_state_64; + export "DPI-C" function e_union_2_state_65; + export "DPI-C" function e_union_2_state_128; + + // 4-state packed arrays + export "DPI-C" function e_array_4_state_1; + export "DPI-C" function e_array_4_state_32; + export "DPI-C" function e_array_4_state_33; + export "DPI-C" function e_array_4_state_64; + export "DPI-C" function e_array_4_state_65; + export "DPI-C" function e_array_4_state_128; + + // 4-state packed structures + export "DPI-C" function e_struct_4_state_1; + export "DPI-C" function e_struct_4_state_32; + export "DPI-C" function e_struct_4_state_33; + export "DPI-C" function e_struct_4_state_64; + export "DPI-C" function e_struct_4_state_65; + export "DPI-C" function e_struct_4_state_128; + + // 4-state packed unions + export "DPI-C" function e_union_4_state_1; + export "DPI-C" function e_union_4_state_32; + export "DPI-C" function e_union_4_state_33; + export "DPI-C" function e_union_4_state_64; + export "DPI-C" function e_union_4_state_65; + export "DPI-C" function e_union_4_state_128; + + //====================================================================== + // Definitions of exported functions + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + byte n_byte = 0; + function void e_byte(input byte i); + if (i !== 8'd10 + n_byte) $stop; + n_byte++; + endfunction + + byte n_byte_unsigned = 0; + function void e_byte_unsigned(input byte unsigned i); + if (i !== 8'd20 + n_byte_unsigned) $stop; + n_byte_unsigned++; + endfunction + + shortint n_shortint = 0; + function void e_shortint(input shortint i); + if (i !== 16'd30 + n_shortint) $stop; + n_shortint++; + endfunction + + shortint n_shortint_unsigned = 0; + function void e_shortint_unsigned(input shortint unsigned i); + if (i !== 16'd40 + n_shortint_unsigned) $stop; + n_shortint_unsigned++; + endfunction + + int n_int = 0; + function void e_int(input int i); + if (i !== 32'd50 + n_int) $stop; + n_int++; + endfunction + + int n_int_unsigned = 0; + function void e_int_unsigned(input int unsigned i); + if (i !== 32'd60 + n_int_unsigned) $stop; + n_int_unsigned++; + endfunction + + longint n_longint = 0; + function void e_longint(input longint i); + if (i !== 64'd70 + n_longint) $stop; + n_longint++; + endfunction + + longint n_longint_unsigned = 0; + function void e_longint_unsigned(input longint unsigned i); + if (i !== 64'd80 + n_longint_unsigned) $stop; + n_longint_unsigned++; + endfunction + +`ifndef NO_TIME + longint n_time = 0; + function void e_time(input time i); + if (i !== 64'd90 + n_time) $stop; + n_time++; + endfunction +`endif + +`ifndef NO_INTEGER + int n_integer = 0; + function void e_integer(input integer i); + if (i !== 32'd100 + n_integer) $stop; + n_integer++; + endfunction +`endif + + int n_real = 0; + function void e_real(input real i); + if (i != real'(2*n_real + 1) / 2.0) $stop; + n_real++; + endfunction + +`ifndef NO_SHORTREAL + int n_shortreal = 0; + function void e_shortreal(input shortreal i); + if (i != shortreal'(4*n_shortreal + 1)/ 4.0) $stop; + n_shortreal++; + endfunction +`endif + + int n_chandle = 0; + function void e_chandle(input chandle i); + $display("e_chandle %1d", n_chandle); + if (!n_chandle[0]) begin + if (i !== `NULL) $stop; + end else begin + if (i === `NULL) $stop; + end + n_chandle++; + endfunction + + int n_string = 0; + function void e_string(input string i); + $display("e_string %1d", n_string); + if (!n_string[0]) begin + if (i != "Hello") $stop; + end else begin + if (i != "World") $stop; + end + n_string++; + endfunction + + int n_bit = 0; + function void e_bit(input bit i); + $display("e_bit %1d", n_bit); + if (i !== n_bit[0]) $stop; + n_bit++; + endfunction + + int n_logic = 0; + function void e_logic(input logic i); + $display("e_logic %1d", n_logic); + if (i !== ~n_logic[0]) $stop; + n_logic++; + endfunction + + // Basic types via typedefs + byte_t n_byte_t = 0; + function void e_byte_t(input byte_t i); + if (i !== 8'd10 + n_byte_t) $stop; + n_byte_t += 2; + endfunction + + byte n_byte_unsigned_t = 0; + function void e_byte_unsigned_t(input byte_unsigned_t i); + if (i !== 8'd20 + n_byte_unsigned_t) $stop; + n_byte_unsigned_t += 2; + endfunction + + shortint_t n_shortint_t = 0; + function void e_shortint_t(input shortint_t i); + if (i !== 16'd30 + n_shortint_t) $stop; + n_shortint_t += 2; + endfunction + + shortint n_shortint_unsigned_t = 0; + function void e_shortint_unsigned_t(input shortint_unsigned_t i); + if (i !== 16'd40 + n_shortint_unsigned_t) $stop; + n_shortint_unsigned_t += 2; + endfunction + + int_t n_int_t = 0; + function void e_int_t(input int_t i); + if (i !== 32'd50 + n_int_t) $stop; + n_int_t += 2; + endfunction + + int n_int_unsigned_t = 0; + function void e_int_unsigned_t(input int_unsigned_t i); + if (i !== 32'd60 + n_int_unsigned_t) $stop; + n_int_unsigned_t += 2; + endfunction + + longint_t n_longint_t = 0; + function void e_longint_t(input longint_t i); + if (i !== 64'd70 + n_longint_t) $stop; + n_longint_t += 2; + endfunction + + longint n_longint_unsigned_t = 0; + function void e_longint_unsigned_t(input longint_unsigned_t i); + if (i !== 64'd80 + n_longint_unsigned_t) $stop; + n_longint_unsigned_t += 2; + endfunction + +`ifndef NO_TIME + longint n_time_t = 0; + function void e_time_t(input time_t i); + if (i !== 64'd90 + n_time_t) $stop; + n_time_t += 2; + endfunction +`endif + +`ifndef NO_INTEGER + int n_integer_t = 0; + function void e_integer_t(input integer_t i); + if (i !== 32'd100 + n_integer_t) $stop; + n_integer_t += 2; + endfunction +`endif + + int n_real_t = 0; + function void e_real_t(input real_t i); + if (i != real'(2*n_real_t + 1) / 2.0) $stop; + n_real_t += 2; + endfunction + +`ifndef NO_SHORTREAL + int n_shortreal_t = 0; + function void e_shortreal_t(input shortreal_t i); + if (i != shortreal'(4*n_shortreal_t + 1)/ 4.0) $stop; + n_shortreal_t += 2; + endfunction +`endif + + int n_chandle_t = 0; + function void e_chandle_t(input chandle_t i); + $display("e_chandle_t %1d", n_chandle_t); + if (!n_chandle_t[0]) begin + if (i === `NULL) $stop; + end else begin + if (i !== `NULL) $stop; + end + n_chandle_t++; + endfunction + + int n_string_t = 0; + function void e_string_t(input string_t i); + $display("e_string_t %1d", n_string_t); + if (!n_string_t[0]) begin + if (i != "World") $stop; + end else begin + if (i != "Hello") $stop; + end + n_string_t++; + endfunction + + int n_bit_t = 0; + function void e_bit_t(input bit_t i); + $display("e_bit_t %1d", n_bit_t); + if (i !== n_bit_t[0]) $stop; + n_bit_t++; + endfunction + + int n_logic_t = 0; + function void e_logic_t(input logic_t i); + $display("e_logic_t %1d", n_logic_t); + if (i !== ~n_logic_t[0]) $stop; + n_logic_t++; + endfunction + + // 2-state packed arrays + int n_array_2_state_1 = 0; + function void e_array_2_state_1(input bit [ 0:0] i); + $display("e_array_2_state_1 %1d", n_array_2_state_1); + if (i !== n_array_2_state_1[0]) $stop; + n_array_2_state_1++; + endfunction + + int n_array_2_state_32 = 0; + function void e_array_2_state_32(input bit [31:0] i); + $display("e_array_2_state_32 %1d", n_array_2_state_32); + if (i !== ~32'd0 >> n_array_2_state_32) $stop; + n_array_2_state_32++; + endfunction + + int n_array_2_state_33 = 0; + function void e_array_2_state_33(input bit [32:0] i); + $display("e_array_2_state_33 %1d", n_array_2_state_33); + if (i !== ~33'd0 >> n_array_2_state_33) $stop; + n_array_2_state_33++; + endfunction + + int n_array_2_state_64 = 0; + function void e_array_2_state_64(input bit [63:0] i); + $display("e_array_2_state_64 %1d", n_array_2_state_64); + if (i !== ~64'd0 >> n_array_2_state_64) $stop; + n_array_2_state_64++; + endfunction + + int n_array_2_state_65 = 0; + function void e_array_2_state_65(input bit [64:0] i); + $display("e_array_2_state_65 %1d", n_array_2_state_65); + if (i !== ~65'd0 >> n_array_2_state_65) $stop; + n_array_2_state_65++; + endfunction + + int n_array_2_state_128 = 0; + function void e_array_2_state_128(input bit [127:0] i); + $display("e_array_2_state_128 %1d", n_array_2_state_128); + if (i !== ~128'd0 >> n_array_2_state_128) $stop; + n_array_2_state_128++; + endfunction + + // 2-state packed structures + int n_struct_2_state_1 = 0; + function void e_struct_2_state_1(input struct_2_state_1 i); + $display("e_struct_2_state_1 %1d", n_struct_2_state_1); + if (i !== n_struct_2_state_1[0]) $stop; + n_struct_2_state_1++; + endfunction + + int n_struct_2_state_32 = 0; + function void e_struct_2_state_32(input struct_2_state_32 i); + $display("e_struct_2_state_32 %1d", n_struct_2_state_32); + if (i !== ~32'd0 >> n_struct_2_state_32) $stop; + n_struct_2_state_32++; + endfunction + + int n_struct_2_state_33 = 0; + function void e_struct_2_state_33(input struct_2_state_33 i); + $display("e_struct_2_state_33 %1d", n_struct_2_state_33); + if (i !== ~33'd0 >> n_struct_2_state_33) $stop; + n_struct_2_state_33++; + endfunction + + int n_struct_2_state_64 = 0; + function void e_struct_2_state_64(input struct_2_state_64 i); + $display("e_struct_2_state_64 %1d", n_struct_2_state_64); + if (i !== ~64'd0 >> n_struct_2_state_64) $stop; + n_struct_2_state_64++; + endfunction + + int n_struct_2_state_65 = 0; + function void e_struct_2_state_65(input struct_2_state_65 i); + $display("e_struct_2_state_65 %1d", n_struct_2_state_65); + if (i !== ~65'd0 >> n_struct_2_state_65) $stop; + n_struct_2_state_65++; + endfunction + + int n_struct_2_state_128 = 0; + function void e_struct_2_state_128(input struct_2_state_128 i); + $display("e_struct_2_state_128 %1d", n_struct_2_state_128); + if (i !== ~128'd0 >> n_struct_2_state_128) $stop; + n_struct_2_state_128++; + endfunction + + // 2-state packed unions + int n_union_2_state_1 = 0; + function void e_union_2_state_1(input union_2_state_1 i); + $display("e_union_2_state_1 %1d", n_union_2_state_1); + if (i !== n_union_2_state_1[0]) $stop; + n_union_2_state_1++; + endfunction + + int n_union_2_state_32 = 0; + function void e_union_2_state_32(input union_2_state_32 i); + $display("e_union_2_state_32 %1d", n_union_2_state_32); + if (i !== ~32'd0 >> n_union_2_state_32) $stop; + n_union_2_state_32++; + endfunction + + int n_union_2_state_33 = 0; + function void e_union_2_state_33(input union_2_state_33 i); + $display("e_union_2_state_33 %1d", n_union_2_state_33); + if (i !== ~33'd0 >> n_union_2_state_33) $stop; + n_union_2_state_33++; + endfunction + + int n_union_2_state_64 = 0; + function void e_union_2_state_64(input union_2_state_64 i); + $display("e_union_2_state_64 %1d", n_union_2_state_64); + if (i !== ~64'd0 >> n_union_2_state_64) $stop; + n_union_2_state_64++; + endfunction + + int n_union_2_state_65 = 0; + function void e_union_2_state_65(input union_2_state_65 i); + $display("e_union_2_state_65 %1d", n_union_2_state_65); + if (i !== ~65'd0 >> n_union_2_state_65) $stop; + n_union_2_state_65++; + endfunction + + int n_union_2_state_128 = 0; + function void e_union_2_state_128(input union_2_state_128 i); + $display("e_union_2_state_128 %1d", n_union_2_state_128); + if (i !== ~128'd0 >> n_union_2_state_128) $stop; + n_union_2_state_128++; + endfunction + + // 4-state packed arrays + int n_array_4_state_1 = 0; + function void e_array_4_state_1(input logic [ 0:0] i); + $display("e_array_4_state_1 %1d", n_array_4_state_1); + if (i !== n_array_4_state_1[0]) $stop; + n_array_4_state_1++; + endfunction + + int n_array_4_state_32 = 0; + function void e_array_4_state_32(input logic [31:0] i); + $display("e_array_4_state_32 %1d", n_array_4_state_32); + if (i !== ~32'd0 >> n_array_4_state_32) $stop; + n_array_4_state_32++; + endfunction + + int n_array_4_state_33 = 0; + function void e_array_4_state_33(input logic [32:0] i); + $display("e_array_4_state_33 %1d", n_array_4_state_33); + if (i !== ~33'd0 >> n_array_4_state_33) $stop; + n_array_4_state_33++; + endfunction + + int n_array_4_state_64 = 0; + function void e_array_4_state_64(input logic [63:0] i); + $display("e_array_4_state_64 %1d", n_array_4_state_64); + if (i !== ~64'd0 >> n_array_4_state_64) $stop; + n_array_4_state_64++; + endfunction + + int n_array_4_state_65 = 0; + function void e_array_4_state_65(input logic [64:0] i); + $display("e_array_4_state_65 %1d", n_array_4_state_65); + if (i !== ~65'd0 >> n_array_4_state_65) $stop; + n_array_4_state_65++; + endfunction + + int n_array_4_state_128 = 0; + function void e_array_4_state_128(input logic [127:0] i); + $display("e_array_4_state_128 %1d", n_array_4_state_128); + if (i !== ~128'd0 >> n_array_4_state_128) $stop; + n_array_4_state_128++; + endfunction + + // 4-state packed structures + int n_struct_4_state_1 = 0; + function void e_struct_4_state_1(input struct_4_state_1 i); + $display("e_struct_4_state_1 %1d", n_struct_4_state_1); + if (i !== n_struct_4_state_1[0]) $stop; + n_struct_4_state_1++; + endfunction + + int n_struct_4_state_32 = 0; + function void e_struct_4_state_32(input struct_4_state_32 i); + $display("e_struct_4_state_32 %1d", n_struct_4_state_32); + if (i !== ~32'd0 >> n_struct_4_state_32) $stop; + n_struct_4_state_32++; + endfunction + + int n_struct_4_state_33 = 0; + function void e_struct_4_state_33(input struct_4_state_33 i); + $display("e_struct_4_state_33 %1d", n_struct_4_state_33); + if (i !== ~33'd0 >> n_struct_4_state_33) $stop; + n_struct_4_state_33++; + endfunction + + int n_struct_4_state_64 = 0; + function void e_struct_4_state_64(input struct_4_state_64 i); + $display("e_struct_4_state_64 %1d", n_struct_4_state_64); + if (i !== ~64'd0 >> n_struct_4_state_64) $stop; + n_struct_4_state_64++; + endfunction + + int n_struct_4_state_65 = 0; + function void e_struct_4_state_65(input struct_4_state_65 i); + $display("e_struct_4_state_65 %1d", n_struct_4_state_65); + if (i !== ~65'd0 >> n_struct_4_state_65) $stop; + n_struct_4_state_65++; + endfunction + + int n_struct_4_state_128 = 0; + function void e_struct_4_state_128(input struct_4_state_128 i); + $display("e_struct_4_state_128 %1d", n_struct_4_state_128); + if (i !== ~128'd0 >> n_struct_4_state_128) $stop; + n_struct_4_state_128++; + endfunction + + // 4-state packed unions + int n_union_4_state_1 = 0; + function void e_union_4_state_1(input union_4_state_1 i); + $display("e_union_4_state_1 %1d", n_union_4_state_1); + if (i !== n_union_4_state_1[0]) $stop; + n_union_4_state_1++; + endfunction + + int n_union_4_state_32 = 0; + function void e_union_4_state_32(input union_4_state_32 i); + $display("e_union_4_state_32 %1d", n_union_4_state_32); + if (i !== ~32'd0 >> n_union_4_state_32) $stop; + n_union_4_state_32++; + endfunction + + int n_union_4_state_33 = 0; + function void e_union_4_state_33(input union_4_state_33 i); + $display("e_union_4_state_33 %1d", n_union_4_state_33); + if (i !== ~33'd0 >> n_union_4_state_33) $stop; + n_union_4_state_33++; + endfunction + + int n_union_4_state_64 = 0; + function void e_union_4_state_64(input union_4_state_64 i); + $display("e_union_4_state_64 %1d", n_union_4_state_64); + if (i !== ~64'd0 >> n_union_4_state_64) $stop; + n_union_4_state_64++; + endfunction + + int n_union_4_state_65 = 0; + function void e_union_4_state_65(input union_4_state_65 i); + $display("e_union_4_state_65 %1d", n_union_4_state_65); + if (i !== ~65'd0 >> n_union_4_state_65) $stop; + n_union_4_state_65++; + endfunction + + int n_union_4_state_128 = 0; + function void e_union_4_state_128(input union_4_state_128 i); + $display("e_union_4_state_128 %1d", n_union_4_state_128); + if (i !== ~128'd0 >> n_union_4_state_128) $stop; + n_union_4_state_128++; + endfunction + + //====================================================================== + // Invoke all functions 3 times (they have side effects) + //====================================================================== + + import "DPI-C" context function void check_exports(); + + initial begin + for (int i = 0 ; i < 3; i++) begin + // Check the imports + + // Basic types as per IEEE 1800-2017 35.5.6 + i_byte( 8'd10 - 8'(i)); + i_byte_unsigned( 8'd20 - 8'(i)); + i_shortint( 16'd30 - 16'(i)); + i_shortint_unsigned( 16'd40 - 16'(i)); + i_int( 32'd50 - 32'(i)); + i_int_unsigned( 32'd60 - 32'(i)); + i_longint( 64'd70 - 64'(i)); + i_longint_unsigned( 64'd80 - 64'(i)); +`ifndef NO_TIME + i_time( 64'd90 - 64'(i)); +`endif +`ifndef NO_INTEGER + i_integer( 32'd100- 32'(i)); +`endif + i_real( -1.0*i - 0.50); +`ifndef NO_SHORTREAL + i_shortreal( -1.0*i - 0.25); +`endif + if (~i[0]) begin + i_chandle(`NULL); + i_string("World"); + end else begin + i_chandle(`NULL); + i_string("Hello"); + end + i_bit(~i[0]); + i_logic(i[0]); + + // Basic types via typedefs + i_byte_t( 8'd10 - 8'(2*i)); + i_byte_unsigned_t( 8'd20 - 8'(2*i)); + i_shortint_t( 16'd30 - 16'(2*i)); + i_shortint_unsigned_t( 16'd40 - 16'(2*i)); + i_int_t( 32'd50 - 32'(2*i)); + i_int_unsigned_t( 32'd60 - 32'(2*i)); + i_longint_t( 64'd70 - 64'(2*i)); + i_longint_unsigned_t( 64'd80 - 64'(2*i)); +`ifndef NO_TIME + i_time_t( 64'd90 - 64'(2*i)); +`endif +`ifndef NO_INTEGER + i_integer_t( 32'd100- 32'(2*i)); +`endif + i_real_t( -1.0*(2*i) - 0.50); +`ifndef NO_SHORTREAL + i_shortreal_t( -1.0*(2*i) - 0.25); +`endif + if (~i[0]) begin + i_chandle_t(`NULL); + i_string_t("World"); + end else begin + i_chandle_t(`NULL); + i_string_t("Hello"); + end + i_bit_t(~i[0]); + i_logic_t(i[0]); + + // 2-state packed arrays + i_array_2_state_1(~i[0]); + i_array_2_state_32(~32'd0 << i); + i_array_2_state_33(~33'd0 << i); + i_array_2_state_64(~64'd0 << i); + i_array_2_state_65(~65'd0 << i); + i_array_2_state_128(~128'd0 << i); + + // 2-state packed structures + i_struct_2_state_1(~i[0]); + i_struct_2_state_32(~32'd0 << i); + i_struct_2_state_33(~33'd0 << i); + i_struct_2_state_64(~64'd0 << i); + i_struct_2_state_65(~65'd0 << i); + i_struct_2_state_128(~128'd0 << i); + + // 2-state packed unions + i_union_2_state_1(~i[0]); + i_union_2_state_32(~32'd0 << i); + i_union_2_state_33(~33'd0 << i); + i_union_2_state_64(~64'd0 << i); + i_union_2_state_65(~65'd0 << i); + i_union_2_state_128(~128'd0 << i); + + // 4-state packed arrays + i_array_4_state_1(~i[0]); + i_array_4_state_32(~32'd0 << i); + i_array_4_state_33(~33'd0 << i); + i_array_4_state_64(~64'd0 << i); + i_array_4_state_65(~65'd0 << i); + i_array_4_state_128(~128'd0 << i); + + // 4-state packed structures + i_struct_4_state_1(~i[0]); + i_struct_4_state_32(~32'd0 << i); + i_struct_4_state_33(~33'd0 << i); + i_struct_4_state_64(~64'd0 << i); + i_struct_4_state_65(~65'd0 << i); + i_struct_4_state_128(~128'd0 << i); + + // 4-state packed unions + i_union_4_state_1(~i[0]); + i_union_4_state_32(~32'd0 << i); + i_union_4_state_33(~33'd0 << i); + i_union_4_state_64(~64'd0 << i); + i_union_4_state_65(~65'd0 << i); + i_union_4_state_128(~128'd0 << i); + + // Check the exports + check_exports(); + end + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_dpi_arg_input_type__Dpi.out b/test_regress/t/t_dpi_arg_input_type__Dpi.out new file mode 100644 index 000000000..26a75f7ee --- /dev/null +++ b/test_regress/t/t_dpi_arg_input_type__Dpi.out @@ -0,0 +1,287 @@ +// Verilated -*- C++ -*- +// DESCRIPTION: Verilator output: Prototypes for DPI import and export functions. +// +// Verilator includes this file in all generated .cpp files that use DPI functions. +// Manually include this file where DPI .c import functions are declared to ensure +// the C functions match the expectations of the DPI imports. + +#include "svdpi.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + // DPI EXPORTS + // DPI export at t/t_dpi_arg_input_type.v:537:18 + extern void e_array_2_state_1(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:572:18 + extern void e_array_2_state_128(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:544:18 + extern void e_array_2_state_32(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:551:18 + extern void e_array_2_state_33(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:558:18 + extern void e_array_2_state_64(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:565:18 + extern void e_array_2_state_65(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:666:18 + extern void e_array_4_state_1(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:701:18 + extern void e_array_4_state_128(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:673:18 + extern void e_array_4_state_32(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:680:18 + extern void e_array_4_state_33(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:687:18 + extern void e_array_4_state_64(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:694:18 + extern void e_array_4_state_65(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:407:18 + extern void e_bit(svBit i); + // DPI export at t/t_dpi_arg_input_type.v:522:18 + extern void e_bit_t(svBit i); + // DPI export at t/t_dpi_arg_input_type.v:307:18 + extern void e_byte(char i); + // DPI export at t/t_dpi_arg_input_type.v:422:18 + extern void e_byte_t(char i); + // DPI export at t/t_dpi_arg_input_type.v:313:18 + extern void e_byte_unsigned(unsigned char i); + // DPI export at t/t_dpi_arg_input_type.v:428:18 + extern void e_byte_unsigned_t(unsigned char i); + // DPI export at t/t_dpi_arg_input_type.v:385:18 + extern void e_chandle(void* i); + // DPI export at t/t_dpi_arg_input_type.v:500:18 + extern void e_chandle_t(void* i); + // DPI export at t/t_dpi_arg_input_type.v:331:18 + extern void e_int(int i); + // DPI export at t/t_dpi_arg_input_type.v:446:18 + extern void e_int_t(int i); + // DPI export at t/t_dpi_arg_input_type.v:337:18 + extern void e_int_unsigned(unsigned int i); + // DPI export at t/t_dpi_arg_input_type.v:452:18 + extern void e_int_unsigned_t(unsigned int i); + // DPI export at t/t_dpi_arg_input_type.v:364:18 + extern void e_integer(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:479:18 + extern void e_integer_t(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:414:18 + extern void e_logic(svLogic i); + // DPI export at t/t_dpi_arg_input_type.v:529:18 + extern void e_logic_t(svLogic i); + // DPI export at t/t_dpi_arg_input_type.v:343:18 + extern void e_longint(long long i); + // DPI export at t/t_dpi_arg_input_type.v:458:18 + extern void e_longint_t(long long i); + // DPI export at t/t_dpi_arg_input_type.v:349:18 + extern void e_longint_unsigned(unsigned long long i); + // DPI export at t/t_dpi_arg_input_type.v:464:18 + extern void e_longint_unsigned_t(unsigned long long i); + // DPI export at t/t_dpi_arg_input_type.v:371:18 + extern void e_real(double i); + // DPI export at t/t_dpi_arg_input_type.v:486:18 + extern void e_real_t(double i); + // DPI export at t/t_dpi_arg_input_type.v:319:18 + extern void e_shortint(short i); + // DPI export at t/t_dpi_arg_input_type.v:434:18 + extern void e_shortint_t(short i); + // DPI export at t/t_dpi_arg_input_type.v:325:18 + extern void e_shortint_unsigned(unsigned short i); + // DPI export at t/t_dpi_arg_input_type.v:440:18 + extern void e_shortint_unsigned_t(unsigned short i); + // DPI export at t/t_dpi_arg_input_type.v:396:18 + extern void e_string(const char* i); + // DPI export at t/t_dpi_arg_input_type.v:511:18 + extern void e_string_t(const char* i); + // DPI export at t/t_dpi_arg_input_type.v:580:18 + extern void e_struct_2_state_1(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:615:18 + extern void e_struct_2_state_128(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:587:18 + extern void e_struct_2_state_32(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:594:18 + extern void e_struct_2_state_33(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:601:18 + extern void e_struct_2_state_64(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:608:18 + extern void e_struct_2_state_65(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:709:18 + extern void e_struct_4_state_1(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:744:18 + extern void e_struct_4_state_128(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:716:18 + extern void e_struct_4_state_32(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:723:18 + extern void e_struct_4_state_33(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:730:18 + extern void e_struct_4_state_64(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:737:18 + extern void e_struct_4_state_65(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:356:18 + extern void e_time(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:471:18 + extern void e_time_t(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:623:18 + extern void e_union_2_state_1(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:658:18 + extern void e_union_2_state_128(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:630:18 + extern void e_union_2_state_32(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:637:18 + extern void e_union_2_state_33(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:644:18 + extern void e_union_2_state_64(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:651:18 + extern void e_union_2_state_65(const svBitVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:752:18 + extern void e_union_4_state_1(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:787:18 + extern void e_union_4_state_128(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:759:18 + extern void e_union_4_state_32(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:766:18 + extern void e_union_4_state_33(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:773:18 + extern void e_union_4_state_64(const svLogicVecVal* i); + // DPI export at t/t_dpi_arg_input_type.v:780:18 + extern void e_union_4_state_65(const svLogicVecVal* i); + + // DPI IMPORTS + // DPI import at t/t_dpi_arg_input_type.v:797:41 + extern void check_exports(); + // DPI import at t/t_dpi_arg_input_type.v:154:33 + extern void i_array_2_state_1(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:159:33 + extern void i_array_2_state_128(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:155:33 + extern void i_array_2_state_32(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:156:33 + extern void i_array_2_state_33(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:157:33 + extern void i_array_2_state_64(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:158:33 + extern void i_array_2_state_65(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:178:33 + extern void i_array_4_state_1(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:183:33 + extern void i_array_4_state_128(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:179:33 + extern void i_array_4_state_32(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:180:33 + extern void i_array_4_state_33(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:181:33 + extern void i_array_4_state_64(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:182:33 + extern void i_array_4_state_65(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:126:33 + extern void i_bit(svBit i); + // DPI import at t/t_dpi_arg_input_type.v:150:33 + extern void i_bit_t(svBit i); + // DPI import at t/t_dpi_arg_input_type.v:106:33 + extern void i_byte(char i); + // DPI import at t/t_dpi_arg_input_type.v:130:33 + extern void i_byte_t(char i); + // DPI import at t/t_dpi_arg_input_type.v:107:33 + extern void i_byte_unsigned(unsigned char i); + // DPI import at t/t_dpi_arg_input_type.v:131:33 + extern void i_byte_unsigned_t(unsigned char i); + // DPI import at t/t_dpi_arg_input_type.v:124:33 + extern void i_chandle(void* i); + // DPI import at t/t_dpi_arg_input_type.v:148:33 + extern void i_chandle_t(void* i); + // DPI import at t/t_dpi_arg_input_type.v:110:33 + extern void i_int(int i); + // DPI import at t/t_dpi_arg_input_type.v:134:33 + extern void i_int_t(int i); + // DPI import at t/t_dpi_arg_input_type.v:111:33 + extern void i_int_unsigned(unsigned int i); + // DPI import at t/t_dpi_arg_input_type.v:135:33 + extern void i_int_unsigned_t(unsigned int i); + // DPI import at t/t_dpi_arg_input_type.v:118:33 + extern void i_integer(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:142:33 + extern void i_integer_t(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:127:33 + extern void i_logic(svLogic i); + // DPI import at t/t_dpi_arg_input_type.v:151:33 + extern void i_logic_t(svLogic i); + // DPI import at t/t_dpi_arg_input_type.v:112:33 + extern void i_longint(long long i); + // DPI import at t/t_dpi_arg_input_type.v:136:33 + extern void i_longint_t(long long i); + // DPI import at t/t_dpi_arg_input_type.v:113:33 + extern void i_longint_unsigned(unsigned long long i); + // DPI import at t/t_dpi_arg_input_type.v:137:33 + extern void i_longint_unsigned_t(unsigned long long i); + // DPI import at t/t_dpi_arg_input_type.v:120:33 + extern void i_real(double i); + // DPI import at t/t_dpi_arg_input_type.v:144:33 + extern void i_real_t(double i); + // DPI import at t/t_dpi_arg_input_type.v:108:33 + extern void i_shortint(short i); + // DPI import at t/t_dpi_arg_input_type.v:132:33 + extern void i_shortint_t(short i); + // DPI import at t/t_dpi_arg_input_type.v:109:33 + extern void i_shortint_unsigned(unsigned short i); + // DPI import at t/t_dpi_arg_input_type.v:133:33 + extern void i_shortint_unsigned_t(unsigned short i); + // DPI import at t/t_dpi_arg_input_type.v:125:33 + extern void i_string(const char* i); + // DPI import at t/t_dpi_arg_input_type.v:149:33 + extern void i_string_t(const char* i); + // DPI import at t/t_dpi_arg_input_type.v:162:33 + extern void i_struct_2_state_1(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:167:33 + extern void i_struct_2_state_128(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:163:33 + extern void i_struct_2_state_32(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:164:33 + extern void i_struct_2_state_33(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:165:33 + extern void i_struct_2_state_64(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:166:33 + extern void i_struct_2_state_65(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:186:33 + extern void i_struct_4_state_1(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:191:33 + extern void i_struct_4_state_128(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:187:33 + extern void i_struct_4_state_32(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:188:33 + extern void i_struct_4_state_33(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:189:33 + extern void i_struct_4_state_64(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:190:33 + extern void i_struct_4_state_65(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:115:33 + extern void i_time(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:139:33 + extern void i_time_t(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:170:33 + extern void i_union_2_state_1(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:175:33 + extern void i_union_2_state_128(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:171:33 + extern void i_union_2_state_32(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:172:33 + extern void i_union_2_state_33(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:173:33 + extern void i_union_2_state_64(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:174:33 + extern void i_union_2_state_65(const svBitVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:194:33 + extern void i_union_4_state_1(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:199:33 + extern void i_union_4_state_128(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:195:33 + extern void i_union_4_state_32(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:196:33 + extern void i_union_4_state_33(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:197:33 + extern void i_union_4_state_64(const svLogicVecVal* i); + // DPI import at t/t_dpi_arg_input_type.v:198:33 + extern void i_union_4_state_65(const svLogicVecVal* i); + +#ifdef __cplusplus +} +#endif diff --git a/test_regress/t/t_dpi_arg_output_type.cpp b/test_regress/t/t_dpi_arg_output_type.cpp new file mode 100644 index 000000000..e23375e6c --- /dev/null +++ b/test_regress/t/t_dpi_arg_output_type.cpp @@ -0,0 +1,966 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include +#include +#include + +#if defined(NCSC) +// Used by NC's svdpi.h to pick up svLogicVecVal with _.aval and _.bval fields, +// rather than the IEEE 1800-2005 version which has _.a and _.b fields. +# define DPI_COMPATIBILITY_VERSION_1800v2012 +#endif + +#include "svdpi.h" + +#if defined(VERILATOR) // Verilator +# include "Vt_dpi_arg_output_type__Dpi.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_SHORTREAL +#elif defined(VCS) // VCS +# include "../vc_hdrs.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_TIME +#elif defined(NCSC) // NC +# include "dpi-exp.h" +# include "dpi-imp.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_TIME +# define NO_INTEGER +# define NO_SHORTREAL +#elif defined(MS) // ModelSim +# include "dpi.h" +typedef int64_t sv_longint_t; +typedef uint64_t sv_longint_unsigned_t; +# else +# error "Unknown simulator for DPI test" +#endif + +//====================================================================== +// Implementations of imported functions +//====================================================================== + +void set_bvals(svLogicVecVal* v, unsigned n); +void set_bvals(svLogicVecVal* v, unsigned n) { + for (unsigned i = 0; i < n; i++) { + v[i].bval = 0; + } +} + +// Basic types as per IEEE 1800-2017 35.5.6 +void i_byte(char* o) { + static int n = 0; + *o = 10 - n++; +} + +void i_byte_unsigned(unsigned char* o) { + static int n = 0; + *o = 20 - n++; +} + +void i_shortint(short* o) { + static int n = 0; + *o = 30 - n++; +} + +void i_shortint_unsigned(unsigned short* o) { + static int n = 0; + *o = 40 - n++; +} + +void i_int(int* o) { + static int n = 0; + *o = 50 - n++; +} + +void i_int_unsigned(unsigned* o) { + static int n = 0; + *o = 60 - n++; +} + +void i_longint(sv_longint_t* o) { + static int n = 0; + *o = 70 - n++; +} + +void i_longint_unsigned(sv_longint_unsigned_t* o) { + static int n = 0; + *o = 80 - n++; +} + +#ifndef NO_TIME +void i_time(svLogicVecVal* o) { + static int n = 0; + o[0].aval = 90 - n++; + o[1].aval = 0; + set_bvals(o, 2); +} +#endif + +#ifndef NO_INTEGER +void i_integer(svLogicVecVal* o) { + static int n = 0; + o->aval = 100 - n++; + set_bvals(o, 1); +} +#endif + +void i_real(double* o) { + static int n = 0; + *o = (-2.0 * n++ - 1.0) / 2.0; +} + +#ifndef NO_SHORTREAL +void i_shortreal(float* o) { + static int n = 0; + *o = (-4.0f * n++ - 1.0f) / 4.0f; +} +#endif + +void i_chandle(void** o) { + static int n = 0; + printf("i_chandle %d\n", n); + *o = n++ % 2 ? reinterpret_cast(&i_chandle) : NULL; +} + +void i_string(const char** o) { + static int n = 0; + printf("i_string %d\n", n); + *o = n++ % 2 ? "Hello" : "World"; +} + +void i_bit(svBit* o) { + static int n = 0; + printf("i_bit %d\n", n); + *o = !(n++ % 2); +} + +void i_logic(svLogic* o) { + static int n = 0; + printf("i_logic %d\n", n); + *o = n++ % 2; +} + +// Basic types via typedefs +void i_byte_t(char* o) { + static int n = 0; + const char r = 10 - n; + n += 2; + *o = r; +} + +void i_byte_unsigned_t(unsigned char* o) { + static int n = 0; + const unsigned char r = 20 - n; + n += 2; + *o = r; +} + +void i_shortint_t(short* o) { + static int n = 0; + const short r = 30 - n; + n += 2; + *o = r; +} + +void i_shortint_unsigned_t(unsigned short* o) { + static int n = 0; + const unsigned short r = 40 - n; + n += 2; + *o = r; +} + +void i_int_t(int* o) { + static int n = 0; + const int r = 50 - n; + n += 2; + *o = r; +} + +void i_int_unsigned_t(unsigned* o) { + static int n = 0; + const unsigned r = 60 - n; + n += 2; + *o = r; +} + +void i_longint_t(sv_longint_t* o) { + static int n = 0; + const long long r = 70 - n; + n += 2; + *o = r; +} + +void i_longint_unsigned_t(sv_longint_unsigned_t* o) { + static int n = 0; + const unsigned long long r = 80 - n; + n += 2; + *o = r; +} + +#ifndef NO_TIME +void i_time_t(svLogicVecVal* o) { + static int n = 0; + o[0].aval = 90 - n; + o[1].aval = 0; + set_bvals(o, 2); + n += 2; +} +#endif + +#ifndef NO_INTEGER +void i_integer_t(svLogicVecVal* o) { + static int n = 0; + o->aval = 100 - n; + set_bvals(o, 1); + n += 2; +} +#endif + +void i_real_t(double* o) { + static int n = 0; + const double r = (-2.0 * n - 1.0) / 2.0; + n += 2; + *o = r; +} + +#ifndef NO_SHORTREAL +void i_shortreal_t(float* o) { + static int n = 0; + const float r = (-4.0f * n - 1.0f) / 4.0f; + n += 2; + *o = r; +} +#endif + +void i_chandle_t(void** o) { + static int n = 0; + printf("i_chandle_t %d\n", n); + *o = n++ % 2 ? reinterpret_cast(&i_chandle) : NULL; +} + +void i_string_t(const char** o) { + static int n = 0; + printf("i_string_t %d\n", n); + *o = n++ % 2 ? "Hello" : "World"; +} + +void i_bit_t(svBit* o) { + static int n = 0; + printf("i_bit_t %d\n", n); + *o = !(n++ % 2); +} + +void i_logic_t(svLogic* o) { + static int n = 0; + printf("i_logic_t %d\n", n); + *o = n++ % 2; +} + +// 2-state packed arrays +void i_array_2_state_1(svBitVecVal* o) { + static int n = 0; + printf("i_array_2_state_1 %d\n", n); + *o = !(n++ % 2); +} + +void i_array_2_state_32(svBitVecVal* o) { + static int n = 0; + printf("i_array_2_state_32 %d\n", n); + *o = 0xffffffffU << n++; +} + +void i_array_2_state_33(svBitVecVal* o) { + static int n = 0; + printf("i_array_2_state_33 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = 1; +} + +void i_array_2_state_64(svBitVecVal* o) { + static int n = 0; + printf("i_array_2_state_64 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = -1; +} + +void i_array_2_state_65(svBitVecVal* o) { + static int n = 0; + printf("i_array_2_state_65 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = -1; + o[2] = 1; +} + +void i_array_2_state_128(svBitVecVal* o) { + static int n = 0; + printf("i_array_2_state_128 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = -1; + o[2] = -1; + o[3] = -1; +} + +// 2-state packed structures +void i_struct_2_state_1(svBitVecVal* o) { + static int n = 0; + printf("i_struct_2_state_1 %d\n", n); + *o = !(n++ % 2); +} + +void i_struct_2_state_32(svBitVecVal* o) { + static int n = 0; + printf("i_struct_2_state_32 %d\n", n); + *o = 0xffffffffU << n++; +} + +void i_struct_2_state_33(svBitVecVal* o) { + static int n = 0; + printf("i_struct_2_state_33 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = 1; +} + +void i_struct_2_state_64(svBitVecVal* o) { + static int n = 0; + printf("i_struct_2_state_64 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = -1; +} + +void i_struct_2_state_65(svBitVecVal* o) { + static int n = 0; + printf("i_struct_2_state_65 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = -1; + o[2] = 1; +} + +void i_struct_2_state_128(svBitVecVal* o) { + static int n = 0; + printf("i_struct_2_state_128 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = -1; + o[2] = -1; + o[3] = -1; +} + +// 2-state packed unions +void i_union_2_state_1(svBitVecVal* o) { + static int n = 0; + printf("i_union_2_state_1 %d\n", n); + *o = !(n++ % 2); +} + +void i_union_2_state_32(svBitVecVal* o) { + static int n = 0; + printf("i_union_2_state_32 %d\n", n); + *o = 0xffffffffU << n++; +} + +void i_union_2_state_33(svBitVecVal* o) { + static int n = 0; + printf("i_union_2_state_33 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = 1; +} + +void i_union_2_state_64(svBitVecVal* o) { + static int n = 0; + printf("i_union_2_state_64 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = -1; +} + +void i_union_2_state_65(svBitVecVal* o) { + static int n = 0; + printf("i_union_2_state_65 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = -1; + o[2] = 1; +} + +void i_union_2_state_128(svBitVecVal* o) { + static int n = 0; + printf("i_union_2_state_128 %d\n", n); + o[0] = 0xffffffffU << n++; + o[1] = -1; + o[2] = -1; + o[3] = -1; +} + +// 4-state packed arrays +void i_array_4_state_1(svLogicVecVal* o) { + static int n = 0; + printf("i_array_4_state_1 %d\n", n); + o->aval = !(n++ % 2); + set_bvals(o, 1); +} + +void i_array_4_state_32(svLogicVecVal* o) { + static int n = 0; + printf("i_array_4_state_32 %d\n", n); + o->aval = 0xffffffffU << n++; + set_bvals(o, 1); +} + +void i_array_4_state_33(svLogicVecVal* o) { + static int n = 0; + printf("i_array_4_state_33 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = 1; + set_bvals(o, 2); +} + +void i_array_4_state_64(svLogicVecVal* o) { + static int n = 0; + printf("i_array_4_state_64 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = -1; + set_bvals(o, 2); +} + +void i_array_4_state_65(svLogicVecVal* o) { + static int n = 0; + printf("i_array_4_state_65 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = -1; + o[2].aval = 1; + set_bvals(o, 3); +} + +void i_array_4_state_128(svLogicVecVal* o) { + static int n = 0; + printf("i_array_4_state_128 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = -1; + o[2].aval = -1; + o[3].aval = -1; + set_bvals(o, 4); +} + +// 4-state packed structures +void i_struct_4_state_1(svLogicVecVal* o) { + static int n = 0; + printf("i_struct_4_state_1 %d\n", n); + o->aval = !(n++ % 2); + set_bvals(o, 1); +} + +void i_struct_4_state_32(svLogicVecVal* o) { + static int n = 0; + printf("i_struct_4_state_32 %d\n", n); + o->aval = 0xffffffffU << n++; + set_bvals(o, 1); +} + +void i_struct_4_state_33(svLogicVecVal* o) { + static int n = 0; + printf("i_struct_4_state_33 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = 1; + set_bvals(o, 2); +} + +void i_struct_4_state_64(svLogicVecVal* o) { + static int n = 0; + printf("i_struct_4_state_64 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = -1; + set_bvals(o, 2); +} + +void i_struct_4_state_65(svLogicVecVal* o) { + static int n = 0; + printf("i_struct_4_state_65 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = -1; + o[2].aval = 1; + set_bvals(o, 3); +} + +void i_struct_4_state_128(svLogicVecVal* o) { + static int n = 0; + printf("i_struct_4_state_128 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = -1; + o[2].aval = -1; + o[3].aval = -1; + set_bvals(o, 4); +} + +// 4-state packed unions +void i_union_4_state_1(svLogicVecVal* o) { + static int n = 0; + printf("i_union_4_state_1 %d\n", n); + o->aval = !(n++ % 2); + set_bvals(o, 1); +} + +void i_union_4_state_32(svLogicVecVal* o) { + static int n = 0; + printf("i_union_4_state_32 %d\n", n); + o->aval = 0xffffffffU << n++; + set_bvals(o, 1); +} + +void i_union_4_state_33(svLogicVecVal* o) { + static int n = 0; + printf("i_union_4_state_33 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = 1; + set_bvals(o, 2); +} + +void i_union_4_state_64(svLogicVecVal* o) { + static int n = 0; + printf("i_union_4_state_64 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = -1; + set_bvals(o, 2); +} + +void i_union_4_state_65(svLogicVecVal* o) { + static int n = 0; + printf("i_union_4_state_65 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = -1; + o[2].aval = 1; + set_bvals(o, 3); +} + +void i_union_4_state_128(svLogicVecVal* o) { + static int n = 0; + printf("i_union_4_state_128 %d\n", n); + o[0].aval = 0xffffffffU << n++; + o[1].aval = -1; + o[2].aval = -1; + o[3].aval = -1; + set_bvals(o, 4); +} + +//====================================================================== +// Check exported functions +//====================================================================== + +#define stop() \ + do { \ + printf(__FILE__ ":%d Bad value\n", __LINE__); \ + abort(); \ + } while (0) + +void check_bvals(const svLogicVecVal* v, unsigned n); +void check_bvals(const svLogicVecVal* v, unsigned n) { + for (unsigned i = 0; i < n; i++) { + if (v[i].bval != 0) { + printf(__FILE__ ":%d Bad svLogicVecVal bval\n", __LINE__); + abort(); + } + } +} + +void check_exports() { + static unsigned n = 0; + + char x_byte; + unsigned char x_byte_unsigned; + short x_shortint; + unsigned short x_shortint_unsigned; + int x_int; + unsigned x_int_unsigned; + sv_longint_t x_longint; + sv_longint_unsigned_t x_longint_unsigned; +#ifndef NO_TIME + svLogicVecVal x_time[2]; +#endif +#ifndef NO_INTEGER + svLogicVecVal x_integer[1]; +#endif + double x_real; +#ifndef NO_SHORTREAL + float x_shortreal; +#endif + void* x_chandle; + const char* x_string; + svBit x_bit; + svLogic x_logic; + + char x_byte_t; + unsigned char x_byte_unsigned_t; + short x_shortint_t; + unsigned short x_shortint_unsigned_t; + int x_int_t; + unsigned x_int_unsigned_t; + sv_longint_t x_longint_t; + sv_longint_unsigned_t x_longint_unsigned_t; +#ifndef NO_TIME + svLogicVecVal x_time_t[2]; +#endif +#ifndef NO_INTEGER + svLogicVecVal x_integer_t[1]; +#endif + double x_real_t; +#ifndef NO_SHORTREAL + float x_shortreal_t; +#endif + void* x_chandle_t; + const char* x_string_t; + svBit x_bit_t; + svLogic x_logic_t; + + svBitVecVal x_array_2_state_1[1]; + svBitVecVal x_array_2_state_32[1]; + svBitVecVal x_array_2_state_33[2]; + svBitVecVal x_array_2_state_64[2]; + svBitVecVal x_array_2_state_65[3]; + svBitVecVal x_array_2_state_128[4]; + + svBitVecVal x_struct_2_state_1[1]; + svBitVecVal x_struct_2_state_32[1]; + svBitVecVal x_struct_2_state_33[2]; + svBitVecVal x_struct_2_state_64[2]; + svBitVecVal x_struct_2_state_65[3]; + svBitVecVal x_struct_2_state_128[4]; + + svBitVecVal x_union_2_state_1[1]; + svBitVecVal x_union_2_state_32[1]; + svBitVecVal x_union_2_state_33[2]; + svBitVecVal x_union_2_state_64[2]; + svBitVecVal x_union_2_state_65[3]; + svBitVecVal x_union_2_state_128[4]; + + svLogicVecVal x_array_4_state_1[1]; + svLogicVecVal x_array_4_state_32[1]; + svLogicVecVal x_array_4_state_33[2]; + svLogicVecVal x_array_4_state_64[2]; + svLogicVecVal x_array_4_state_65[3]; + svLogicVecVal x_array_4_state_128[4]; + + svLogicVecVal x_struct_4_state_1[1]; + svLogicVecVal x_struct_4_state_32[1]; + svLogicVecVal x_struct_4_state_33[2]; + svLogicVecVal x_struct_4_state_64[2]; + svLogicVecVal x_struct_4_state_65[3]; + svLogicVecVal x_struct_4_state_128[4]; + + svLogicVecVal x_union_4_state_1[1]; + svLogicVecVal x_union_4_state_32[1]; + svLogicVecVal x_union_4_state_33[2]; + svLogicVecVal x_union_4_state_64[2]; + svLogicVecVal x_union_4_state_65[3]; + svLogicVecVal x_union_4_state_128[4]; + + // Basic types as per IEEE 1800-2017 35.5.6 + e_byte(&x_byte); + if (x_byte != 10 + n) stop(); + + e_byte_unsigned(&x_byte_unsigned); + if (x_byte_unsigned != 20 + n) stop(); + + e_shortint(&x_shortint); + if (x_shortint != 30 + n) stop(); + + e_shortint_unsigned(&x_shortint_unsigned); + if (x_shortint_unsigned != 40 + n) stop(); + + e_int(&x_int); + if (x_int != 50 + n) stop(); + + e_int_unsigned(&x_int_unsigned); + if (x_int_unsigned != 60 + n) stop(); + + e_longint(&x_longint); + if (x_longint != 70 + n) stop(); + + e_longint_unsigned(&x_longint_unsigned); + if (x_longint_unsigned != 80 + n) stop(); + +#ifndef NO_TIME + e_time(x_time); + if (x_time[0].aval != 90 + n || x_time[1].aval != 0) stop(); + check_bvals(x_time, 2); +#endif + +#ifndef NO_INTEGER + e_integer(x_integer); + if (x_integer[0].aval != 100 + n) stop(); + check_bvals(x_integer, 1); +#endif + + e_real(&x_real); + if (x_real != 1.0 * n + 0.5) stop(); + +#ifndef NO_SHORTREAL + e_shortreal(&x_shortreal); + if (x_shortreal != 1.0f * n + 0.25f) stop(); +#endif + + e_chandle(&x_chandle); + if (x_chandle != NULL) stop(); + + e_string(&x_string); + if (n % 2 == 0) { + if (strcmp(x_string, "Hello") != 0) stop(); + } else { + if (strcmp(x_string, "World") != 0) stop(); + } + + e_bit(&x_bit); + if (x_bit != n % 2) stop(); + + e_logic(&x_logic); + if (x_logic != !(n % 2)) stop(); + + // Basic types via tyepdef + e_byte_t(&x_byte_t); + if (x_byte_t != 10 + 2 * n) stop(); + + e_byte_unsigned_t(&x_byte_unsigned_t); + if (x_byte_unsigned_t != 20 + 2 * n) stop(); + + e_shortint_t(&x_shortint_t); + if (x_shortint_t != 30 + 2 * n) stop(); + + e_shortint_unsigned_t(&x_shortint_unsigned_t); + if (x_shortint_unsigned_t != 40 + 2 * n) stop(); + + e_int_t(&x_int_t); + if (x_int_t != 50 + 2 * n) stop(); + + e_int_unsigned_t(&x_int_unsigned_t); + if (x_int_unsigned_t != 60 + 2 * n) stop(); + + e_longint_t(&x_longint_t); + if (x_longint_t != 70 + 2 * n) stop(); + + e_longint_unsigned_t(&x_longint_unsigned_t); + if (x_longint_unsigned_t != 80 + 2 * n) stop(); + +#ifndef NO_TIME + e_time_t(x_time_t); + if (x_time_t[0].aval != 90 + 2 * n || x_time_t[1].aval != 0) stop(); + check_bvals(x_time_t, 2); +#endif + +#ifndef NO_INTEGER + e_integer_t(x_integer_t); + if (x_integer_t[0].aval != 100 + 2 * n) stop(); + check_bvals(x_integer_t, 1); +#endif + + e_real_t(&x_real_t); + if (x_real_t != 1.0 * (2 * n) + 0.5) stop(); + +#ifndef NO_SHORTREAL + e_shortreal_t(&x_shortreal_t); + if (x_shortreal_t != 1.0f * (2 * n) + 0.25f) stop(); +#endif + + e_chandle_t(&x_chandle_t); + if (x_chandle_t != NULL) stop(); + + e_string_t(&x_string_t); + if (n % 2 == 0) { + if (strcmp(x_string_t, "Hello") != 0) stop(); + } else { + if (strcmp(x_string_t, "World") != 0) stop(); + } + + e_bit_t(&x_bit_t); + if (x_bit_t != n % 2) stop(); + + e_logic_t(&x_logic_t); + if (x_logic_t != !(n % 2)) stop(); + + const int m = n == 0 ? 0 : n - 1; + + // 2-state packed arrays + e_array_2_state_1(x_array_2_state_1); + if (x_array_2_state_1[0] != n % 2) stop(); + + e_array_2_state_32(x_array_2_state_32); + if (x_array_2_state_32[0] != 0xffffffff >> n) stop(); + + e_array_2_state_33(x_array_2_state_33); + if (x_array_2_state_33[1] != 1 >> n) stop(); + if (x_array_2_state_33[0] != 0xffffffff >> m) stop(); + + e_array_2_state_64(x_array_2_state_64); + if (x_array_2_state_64[1] != 0xffffffff >> n) stop(); + if (x_array_2_state_64[0] != 0xffffffff) stop(); + + e_array_2_state_65(x_array_2_state_65); + if (x_array_2_state_65[2] != 1 >> n) stop(); + if (x_array_2_state_65[1] != 0xffffffff >> m) stop(); + if (x_array_2_state_65[0] != 0xffffffff) stop(); + + e_array_2_state_128(x_array_2_state_128); + if (x_array_2_state_128[3] != 0xffffffff >> n) stop(); + if (x_array_2_state_128[2] != 0xffffffff) stop(); + if (x_array_2_state_128[1] != 0xffffffff) stop(); + if (x_array_2_state_64[0] != 0xffffffff) stop(); + + // 2-state packed structures + e_struct_2_state_1(x_struct_2_state_1); + if (x_struct_2_state_1[0] != n % 2) stop(); + + e_struct_2_state_32(x_struct_2_state_32); + if (x_struct_2_state_32[0] != 0xffffffff >> n) stop(); + + e_struct_2_state_33(x_struct_2_state_33); + if (x_struct_2_state_33[1] != 1 >> n) stop(); + if (x_struct_2_state_33[0] != 0xffffffff >> m) stop(); + + e_struct_2_state_64(x_struct_2_state_64); + if (x_struct_2_state_64[1] != 0xffffffff >> n) stop(); + if (x_struct_2_state_64[0] != 0xffffffff) stop(); + + e_struct_2_state_65(x_struct_2_state_65); + if (x_struct_2_state_65[2] != 1 >> n) stop(); + if (x_struct_2_state_65[1] != 0xffffffff >> m) stop(); + if (x_struct_2_state_65[0] != 0xffffffff) stop(); + + e_struct_2_state_128(x_struct_2_state_128); + if (x_struct_2_state_128[3] != 0xffffffff >> n) stop(); + if (x_struct_2_state_128[2] != 0xffffffff) stop(); + if (x_struct_2_state_128[1] != 0xffffffff) stop(); + if (x_struct_2_state_64[0] != 0xffffffff) stop(); + + // 2-state packed unions + e_union_2_state_1(x_union_2_state_1); + if (x_union_2_state_1[0] != n % 2) stop(); + + e_union_2_state_32(x_union_2_state_32); + if (x_union_2_state_32[0] != 0xffffffff >> n) stop(); + + e_union_2_state_33(x_union_2_state_33); + if (x_union_2_state_33[1] != 1 >> n) stop(); + if (x_union_2_state_33[0] != 0xffffffff >> m) stop(); + + e_union_2_state_64(x_union_2_state_64); + if (x_union_2_state_64[1] != 0xffffffff >> n) stop(); + if (x_union_2_state_64[0] != 0xffffffff) stop(); + + e_union_2_state_65(x_union_2_state_65); + if (x_union_2_state_65[2] != 1 >> n) stop(); + if (x_union_2_state_65[1] != 0xffffffff >> m) stop(); + if (x_union_2_state_65[0] != 0xffffffff) stop(); + + e_union_2_state_128(x_union_2_state_128); + if (x_union_2_state_128[3] != 0xffffffff >> n) stop(); + if (x_union_2_state_128[2] != 0xffffffff) stop(); + if (x_union_2_state_128[1] != 0xffffffff) stop(); + if (x_union_2_state_64[0] != 0xffffffff) stop(); + + // 4-state packed arrays + e_array_4_state_1(x_array_4_state_1); + if (x_array_4_state_1[0].aval != n % 2) stop(); + + e_array_4_state_32(x_array_4_state_32); + if (x_array_4_state_32[0].aval != 0xffffffff >> n) stop(); + + e_array_4_state_33(x_array_4_state_33); + if (x_array_4_state_33[1].aval != 1 >> n) stop(); + if (x_array_4_state_33[0].aval != 0xffffffff >> m) stop(); + + e_array_4_state_64(x_array_4_state_64); + if (x_array_4_state_64[1].aval != 0xffffffff >> n) stop(); + if (x_array_4_state_64[0].aval != 0xffffffff) stop(); + + e_array_4_state_65(x_array_4_state_65); + if (x_array_4_state_65[2].aval != 1 >> n) stop(); + if (x_array_4_state_65[1].aval != 0xffffffff >> m) stop(); + if (x_array_4_state_65[0].aval != 0xffffffff) stop(); + + e_array_4_state_128(x_array_4_state_128); + if (x_array_4_state_128[3].aval != 0xffffffff >> n) stop(); + if (x_array_4_state_128[2].aval != 0xffffffff) stop(); + if (x_array_4_state_128[1].aval != 0xffffffff) stop(); + if (x_array_4_state_64[0].aval != 0xffffffff) stop(); + + check_bvals(x_array_4_state_1, 1); + check_bvals(x_array_4_state_32, 1); + check_bvals(x_array_4_state_33, 2); + check_bvals(x_array_4_state_64, 2); + check_bvals(x_array_4_state_65, 3); + check_bvals(x_array_4_state_128, 4); + + // 4-state packed structures + e_struct_4_state_1(x_struct_4_state_1); + if (x_struct_4_state_1[0].aval != n % 2) stop(); + + e_struct_4_state_32(x_struct_4_state_32); + if (x_struct_4_state_32[0].aval != 0xffffffff >> n) stop(); + + e_struct_4_state_33(x_struct_4_state_33); + if (x_struct_4_state_33[1].aval != 1 >> n) stop(); + if (x_struct_4_state_33[0].aval != 0xffffffff >> m) stop(); + + e_struct_4_state_64(x_struct_4_state_64); + if (x_struct_4_state_64[1].aval != 0xffffffff >> n) stop(); + if (x_struct_4_state_64[0].aval != 0xffffffff) stop(); + + e_struct_4_state_65(x_struct_4_state_65); + if (x_struct_4_state_65[2].aval != 1 >> n) stop(); + if (x_struct_4_state_65[1].aval != 0xffffffff >> m) stop(); + if (x_struct_4_state_65[0].aval != 0xffffffff) stop(); + + e_struct_4_state_128(x_struct_4_state_128); + if (x_struct_4_state_128[3].aval != 0xffffffff >> n) stop(); + if (x_struct_4_state_128[2].aval != 0xffffffff) stop(); + if (x_struct_4_state_128[1].aval != 0xffffffff) stop(); + if (x_struct_4_state_64[0].aval != 0xffffffff) stop(); + + check_bvals(x_struct_4_state_1, 1); + check_bvals(x_struct_4_state_32, 1); + check_bvals(x_struct_4_state_33, 2); + check_bvals(x_struct_4_state_64, 2); + check_bvals(x_struct_4_state_65, 3); + check_bvals(x_struct_4_state_128, 4); + + // 4-state packed unions + e_union_4_state_1(x_union_4_state_1); + if (x_union_4_state_1[0].aval != n % 2) stop(); + + e_union_4_state_32(x_union_4_state_32); + if (x_union_4_state_32[0].aval != 0xffffffff >> n) stop(); + + e_union_4_state_33(x_union_4_state_33); + if (x_union_4_state_33[1].aval != 1 >> n) stop(); + if (x_union_4_state_33[0].aval != 0xffffffff >> m) stop(); + + e_union_4_state_64(x_union_4_state_64); + if (x_union_4_state_64[1].aval != 0xffffffff >> n) stop(); + if (x_union_4_state_64[0].aval != 0xffffffff) stop(); + + e_union_4_state_65(x_union_4_state_65); + if (x_union_4_state_65[2].aval != 1 >> n) stop(); + if (x_union_4_state_65[1].aval != 0xffffffff >> m) stop(); + if (x_union_4_state_65[0].aval != 0xffffffff) stop(); + + e_union_4_state_128(x_union_4_state_128); + if (x_union_4_state_128[3].aval != 0xffffffff >> n) stop(); + if (x_union_4_state_128[2].aval != 0xffffffff) stop(); + if (x_union_4_state_128[1].aval != 0xffffffff) stop(); + if (x_union_4_state_64[0].aval != 0xffffffff) stop(); + + check_bvals(x_union_4_state_1, 1); + check_bvals(x_union_4_state_32, 1); + check_bvals(x_union_4_state_33, 2); + check_bvals(x_union_4_state_64, 2); + check_bvals(x_union_4_state_65, 3); + check_bvals(x_union_4_state_128, 4); + + n++; +} diff --git a/test_regress/t/t_dpi_arg_output_type.out b/test_regress/t/t_dpi_arg_output_type.out new file mode 100644 index 000000000..a7544a086 --- /dev/null +++ b/test_regress/t/t_dpi_arg_output_type.out @@ -0,0 +1,265 @@ +i_chandle 0 +i_string 0 +i_bit 0 +i_logic 0 +i_chandle_t 0 +i_string_t 0 +i_bit_t 0 +i_logic_t 0 +i_array_2_state_1 0 +i_array_2_state_32 0 +i_array_2_state_33 0 +i_array_2_state_64 0 +i_array_2_state_65 0 +i_array_2_state_128 0 +i_struct_2_state_1 0 +i_struct_2_state_32 0 +i_struct_2_state_33 0 +i_struct_2_state_64 0 +i_struct_2_state_65 0 +i_struct_2_state_128 0 +i_union_2_state_1 0 +i_union_2_state_32 0 +i_union_2_state_33 0 +i_union_2_state_64 0 +i_union_2_state_65 0 +i_union_2_state_128 0 +i_array_4_state_1 0 +i_array_4_state_32 0 +i_array_4_state_33 0 +i_array_4_state_64 0 +i_array_4_state_65 0 +i_array_4_state_128 0 +i_struct_4_state_1 0 +i_struct_4_state_32 0 +i_struct_4_state_33 0 +i_struct_4_state_64 0 +i_struct_4_state_65 0 +i_struct_4_state_128 0 +i_union_4_state_1 0 +i_union_4_state_32 0 +i_union_4_state_33 0 +i_union_4_state_64 0 +i_union_4_state_65 0 +i_union_4_state_128 0 +e_chandle 0 +e_string 0 +e_bit 0 +e_logic 0 +e_chandle_t 0 +e_string_t 0 +e_bit_t 0 +e_logic_t 0 +e_array_2_state_1 0 +e_array_2_state_32 0 +e_array_2_state_33 0 +e_array_2_state_64 0 +e_array_2_state_65 0 +e_array_2_state_128 0 +e_struct_2_state_1 0 +e_struct_2_state_32 0 +e_struct_2_state_33 0 +e_struct_2_state_64 0 +e_struct_2_state_65 0 +e_struct_2_state_128 0 +e_union_2_state_1 0 +e_union_2_state_32 0 +e_union_2_state_33 0 +e_union_2_state_64 0 +e_union_2_state_65 0 +e_union_2_state_128 0 +e_array_4_state_1 0 +e_array_4_state_32 0 +e_array_4_state_33 0 +e_array_4_state_64 0 +e_array_4_state_65 0 +e_array_4_state_128 0 +e_struct_4_state_1 0 +e_struct_4_state_32 0 +e_struct_4_state_33 0 +e_struct_4_state_64 0 +e_struct_4_state_65 0 +e_struct_4_state_128 0 +e_union_4_state_1 0 +e_union_4_state_32 0 +e_union_4_state_33 0 +e_union_4_state_64 0 +e_union_4_state_65 0 +e_union_4_state_128 0 +i_chandle 1 +i_string 1 +i_bit 1 +i_logic 1 +i_chandle_t 1 +i_string_t 1 +i_bit_t 1 +i_logic_t 1 +i_array_2_state_1 1 +i_array_2_state_32 1 +i_array_2_state_33 1 +i_array_2_state_64 1 +i_array_2_state_65 1 +i_array_2_state_128 1 +i_struct_2_state_1 1 +i_struct_2_state_32 1 +i_struct_2_state_33 1 +i_struct_2_state_64 1 +i_struct_2_state_65 1 +i_struct_2_state_128 1 +i_union_2_state_1 1 +i_union_2_state_32 1 +i_union_2_state_33 1 +i_union_2_state_64 1 +i_union_2_state_65 1 +i_union_2_state_128 1 +i_array_4_state_1 1 +i_array_4_state_32 1 +i_array_4_state_33 1 +i_array_4_state_64 1 +i_array_4_state_65 1 +i_array_4_state_128 1 +i_struct_4_state_1 1 +i_struct_4_state_32 1 +i_struct_4_state_33 1 +i_struct_4_state_64 1 +i_struct_4_state_65 1 +i_struct_4_state_128 1 +i_union_4_state_1 1 +i_union_4_state_32 1 +i_union_4_state_33 1 +i_union_4_state_64 1 +i_union_4_state_65 1 +i_union_4_state_128 1 +e_chandle 1 +e_string 1 +e_bit 1 +e_logic 1 +e_chandle_t 1 +e_string_t 1 +e_bit_t 1 +e_logic_t 1 +e_array_2_state_1 1 +e_array_2_state_32 1 +e_array_2_state_33 1 +e_array_2_state_64 1 +e_array_2_state_65 1 +e_array_2_state_128 1 +e_struct_2_state_1 1 +e_struct_2_state_32 1 +e_struct_2_state_33 1 +e_struct_2_state_64 1 +e_struct_2_state_65 1 +e_struct_2_state_128 1 +e_union_2_state_1 1 +e_union_2_state_32 1 +e_union_2_state_33 1 +e_union_2_state_64 1 +e_union_2_state_65 1 +e_union_2_state_128 1 +e_array_4_state_1 1 +e_array_4_state_32 1 +e_array_4_state_33 1 +e_array_4_state_64 1 +e_array_4_state_65 1 +e_array_4_state_128 1 +e_struct_4_state_1 1 +e_struct_4_state_32 1 +e_struct_4_state_33 1 +e_struct_4_state_64 1 +e_struct_4_state_65 1 +e_struct_4_state_128 1 +e_union_4_state_1 1 +e_union_4_state_32 1 +e_union_4_state_33 1 +e_union_4_state_64 1 +e_union_4_state_65 1 +e_union_4_state_128 1 +i_chandle 2 +i_string 2 +i_bit 2 +i_logic 2 +i_chandle_t 2 +i_string_t 2 +i_bit_t 2 +i_logic_t 2 +i_array_2_state_1 2 +i_array_2_state_32 2 +i_array_2_state_33 2 +i_array_2_state_64 2 +i_array_2_state_65 2 +i_array_2_state_128 2 +i_struct_2_state_1 2 +i_struct_2_state_32 2 +i_struct_2_state_33 2 +i_struct_2_state_64 2 +i_struct_2_state_65 2 +i_struct_2_state_128 2 +i_union_2_state_1 2 +i_union_2_state_32 2 +i_union_2_state_33 2 +i_union_2_state_64 2 +i_union_2_state_65 2 +i_union_2_state_128 2 +i_array_4_state_1 2 +i_array_4_state_32 2 +i_array_4_state_33 2 +i_array_4_state_64 2 +i_array_4_state_65 2 +i_array_4_state_128 2 +i_struct_4_state_1 2 +i_struct_4_state_32 2 +i_struct_4_state_33 2 +i_struct_4_state_64 2 +i_struct_4_state_65 2 +i_struct_4_state_128 2 +i_union_4_state_1 2 +i_union_4_state_32 2 +i_union_4_state_33 2 +i_union_4_state_64 2 +i_union_4_state_65 2 +i_union_4_state_128 2 +e_chandle 2 +e_string 2 +e_bit 2 +e_logic 2 +e_chandle_t 2 +e_string_t 2 +e_bit_t 2 +e_logic_t 2 +e_array_2_state_1 2 +e_array_2_state_32 2 +e_array_2_state_33 2 +e_array_2_state_64 2 +e_array_2_state_65 2 +e_array_2_state_128 2 +e_struct_2_state_1 2 +e_struct_2_state_32 2 +e_struct_2_state_33 2 +e_struct_2_state_64 2 +e_struct_2_state_65 2 +e_struct_2_state_128 2 +e_union_2_state_1 2 +e_union_2_state_32 2 +e_union_2_state_33 2 +e_union_2_state_64 2 +e_union_2_state_65 2 +e_union_2_state_128 2 +e_array_4_state_1 2 +e_array_4_state_32 2 +e_array_4_state_33 2 +e_array_4_state_64 2 +e_array_4_state_65 2 +e_array_4_state_128 2 +e_struct_4_state_1 2 +e_struct_4_state_32 2 +e_struct_4_state_33 2 +e_struct_4_state_64 2 +e_struct_4_state_65 2 +e_struct_4_state_128 2 +e_union_4_state_1 2 +e_union_4_state_32 2 +e_union_4_state_33 2 +e_union_4_state_64 2 +e_union_4_state_65 2 +e_union_4_state_128 2 +*-* All Finished *-* diff --git a/test_regress/t/t_dpi_arg_output_type.pl b/test_regress/t/t_dpi_arg_output_type.pl new file mode 100755 index 000000000..74588e732 --- /dev/null +++ b/test_regress/t/t_dpi_arg_output_type.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Geza Lore. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if ($Self->{nc}) { + # For NC, compile twice, first just to generate DPI headers + compile( + nc_flags2 => ["+ncdpiheader+$Self->{obj_dir}/dpi-exp.h", + "+ncdpiimpheader+$Self->{obj_dir}/dpi-imp.h"] + ); +} + +compile( + v_flags2 => ["t/t_dpi_arg_output_type.cpp"], + verilator_flags2 => ["-Wall -Wno-DECLFILENAME"], + # NC: Gdd the obj_dir to the C include path + nc_flags2 => ["+ncscargs+-I$Self->{obj_dir}"], + # ModelSim: Generate DPI header, add obj_dir to the C include path + ms_flags2 => ["-dpiheader $Self->{obj_dir}/dpi.h", + "-ccflags -I$Self->{obj_dir}"], + ); + +if ($Self->{vlt_all}) { + files_identical( + "$Self->{obj_dir}/Vt_dpi_arg_output_type__Dpi.h", + "t/t_dpi_arg_output_type__Dpi.out" + ); +} + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ms_pli => 0 + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_arg_output_type.v b/test_regress/t/t_dpi_arg_output_type.v new file mode 100644 index 000000000..86aeafb15 --- /dev/null +++ b/test_regress/t/t_dpi_arg_output_type.v @@ -0,0 +1,989 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +`ifdef VCS + `define NO_TIME +`endif + +`ifdef NC + `define NO_TIME + `define NO_INTEGER + `define NO_SHORTREAL +`endif + +`ifdef MS +`endif + +`ifdef VERILATOR + `define NO_SHORTREAL + `define NULL 64'd0 +`else + `define NULL null +`endif + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + +`ifdef VERILATOR + wire _unused = &{1'b0, clk}; +`endif + + // Legal output argument types for DPI functions + + //====================================================================== + // Type definitions + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + typedef byte byte_t; + typedef byte unsigned byte_unsigned_t; + typedef shortint shortint_t; + typedef shortint unsigned shortint_unsigned_t; + typedef int int_t; + typedef int unsigned int_unsigned_t; + typedef longint longint_t; + typedef longint unsigned longint_unsigned_t; +`ifndef NO_TIME + typedef time time_t; +`endif +`ifndef NO_INTEGER + typedef integer integer_t; +`endif + typedef real real_t; +`ifndef NO_SHORTREAL + typedef shortreal shortreal_t; +`endif + typedef chandle chandle_t; + typedef string string_t; + typedef bit bit_t; + typedef logic logic_t; + + // 2-state packed structures + typedef struct packed { bit x; } struct_2_state_1; + typedef struct packed { bit [15:0] x; bit [15:0] y; } struct_2_state_32; + typedef struct packed { bit [15:0] x; bit [16:0] y; } struct_2_state_33; + typedef struct packed { bit [31:0] x; bit [31:0] y; } struct_2_state_64; + typedef struct packed { bit [31:0] x; bit [32:0] y; } struct_2_state_65; + typedef struct packed { bit [63:0] x; bit [63:0] y; } struct_2_state_128; + + // 2-state packed unions + typedef union packed { bit x; bit y; } union_2_state_1; + typedef union packed { bit [31:0] x; bit [31:0] y; } union_2_state_32; + typedef union packed { bit [32:0] x; bit [32:0] y; } union_2_state_33; + typedef union packed { bit [63:0] x; bit [63:0] y; } union_2_state_64; + typedef union packed { bit [64:0] x; bit [64:0] y; } union_2_state_65; + typedef union packed { bit [127:0] x; bit [127:0] y; } union_2_state_128; + + // 4-state packed structures + typedef struct packed { logic x; } struct_4_state_1; + typedef struct packed { logic [15:0] x; bit [15:0] y; } struct_4_state_32; + typedef struct packed { logic [15:0] x; bit [16:0] y; } struct_4_state_33; + typedef struct packed { logic [31:0] x; bit [31:0] y; } struct_4_state_64; + typedef struct packed { logic [31:0] x; bit [32:0] y; } struct_4_state_65; + typedef struct packed { logic [63:0] x; bit [63:0] y; } struct_4_state_128; + + // 4-state packed unions + typedef union packed { logic x; bit y; } union_4_state_1; + typedef union packed { logic [31:0] x; bit [31:0] y; } union_4_state_32; + typedef union packed { logic [32:0] x; bit [32:0] y; } union_4_state_33; + typedef union packed { logic [63:0] x; bit [63:0] y; } union_4_state_64; + typedef union packed { logic [64:0] x; bit [64:0] y; } union_4_state_65; + typedef union packed { logic [127:0] x; bit [127:0] y; } union_4_state_128; + + //====================================================================== + // Imports + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + import "DPI-C" function void i_byte (output byte o); + import "DPI-C" function void i_byte_unsigned (output byte unsigned o); + import "DPI-C" function void i_shortint (output shortint o); + import "DPI-C" function void i_shortint_unsigned (output shortint unsigned o); + import "DPI-C" function void i_int (output int o); + import "DPI-C" function void i_int_unsigned (output int unsigned o); + import "DPI-C" function void i_longint (output longint o); + import "DPI-C" function void i_longint_unsigned (output longint unsigned o); +`ifndef NO_TIME + import "DPI-C" function void i_time (output time o); +`endif +`ifndef NO_INTEGER + import "DPI-C" function void i_integer (output integer o); +`endif + import "DPI-C" function void i_real (output real o); +`ifndef NO_SHORTREAL + import "DPI-C" function void i_shortreal (output shortreal o); +`endif + import "DPI-C" function void i_chandle (output chandle o); + import "DPI-C" function void i_string (output string o); + import "DPI-C" function void i_bit (output bit o); + import "DPI-C" function void i_logic (output logic o); + + // Basic types via typedef + import "DPI-C" function void i_byte_t (output byte_t o); + import "DPI-C" function void i_byte_unsigned_t (output byte_unsigned_t o); + import "DPI-C" function void i_shortint_t (output shortint_t o); + import "DPI-C" function void i_shortint_unsigned_t (output shortint_unsigned_t o); + import "DPI-C" function void i_int_t (output int_t o); + import "DPI-C" function void i_int_unsigned_t (output int_unsigned_t o); + import "DPI-C" function void i_longint_t (output longint_t o); + import "DPI-C" function void i_longint_unsigned_t (output longint_unsigned_t o); +`ifndef NO_TIME + import "DPI-C" function void i_time_t (output time_t o); +`endif +`ifndef NO_INTEGER + import "DPI-C" function void i_integer_t (output integer_t o); +`endif + import "DPI-C" function void i_real_t (output real_t o); +`ifndef NO_SHORTREAL + import "DPI-C" function void i_shortreal_t (output shortreal_t o); +`endif + import "DPI-C" function void i_chandle_t (output chandle_t o); + import "DPI-C" function void i_string_t (output string_t o); + import "DPI-C" function void i_bit_t (output bit_t o); + import "DPI-C" function void i_logic_t (output logic_t o); + + // 2-state packed arrays + import "DPI-C" function void i_array_2_state_1 (output bit [ 0:0] o); + import "DPI-C" function void i_array_2_state_32 (output bit [ 31:0] o); + import "DPI-C" function void i_array_2_state_33 (output bit [ 32:0] o); + import "DPI-C" function void i_array_2_state_64 (output bit [ 63:0] o); + import "DPI-C" function void i_array_2_state_65 (output bit [ 64:0] o); + import "DPI-C" function void i_array_2_state_128(output bit [127:0] o); + + // 2-state packed structures + import "DPI-C" function void i_struct_2_state_1 (output struct_2_state_1 o); + import "DPI-C" function void i_struct_2_state_32 (output struct_2_state_32 o); + import "DPI-C" function void i_struct_2_state_33 (output struct_2_state_33 o); + import "DPI-C" function void i_struct_2_state_64 (output struct_2_state_64 o); + import "DPI-C" function void i_struct_2_state_65 (output struct_2_state_65 o); + import "DPI-C" function void i_struct_2_state_128 (output struct_2_state_128 o); + + // 2-state packed unions + import "DPI-C" function void i_union_2_state_1 (output union_2_state_1 o); + import "DPI-C" function void i_union_2_state_32 (output union_2_state_32 o); + import "DPI-C" function void i_union_2_state_33 (output union_2_state_33 o); + import "DPI-C" function void i_union_2_state_64 (output union_2_state_64 o); + import "DPI-C" function void i_union_2_state_65 (output union_2_state_65 o); + import "DPI-C" function void i_union_2_state_128 (output union_2_state_128 o); + + // 4-state packed arrays + import "DPI-C" function void i_array_4_state_1 (output logic [ 0:0] o); + import "DPI-C" function void i_array_4_state_32 (output logic [ 31:0] o); + import "DPI-C" function void i_array_4_state_33 (output logic [ 32:0] o); + import "DPI-C" function void i_array_4_state_64 (output logic [ 63:0] o); + import "DPI-C" function void i_array_4_state_65 (output logic [ 64:0] o); + import "DPI-C" function void i_array_4_state_128(output logic [127:0] o); + + // 4-state packed structures + import "DPI-C" function void i_struct_4_state_1 (output struct_4_state_1 o); + import "DPI-C" function void i_struct_4_state_32 (output struct_4_state_32 o); + import "DPI-C" function void i_struct_4_state_33 (output struct_4_state_33 o); + import "DPI-C" function void i_struct_4_state_64 (output struct_4_state_64 o); + import "DPI-C" function void i_struct_4_state_65 (output struct_4_state_65 o); + import "DPI-C" function void i_struct_4_state_128 (output struct_4_state_128 o); + + // 4-state packed unions + import "DPI-C" function void i_union_4_state_1 (output union_4_state_1 o); + import "DPI-C" function void i_union_4_state_32 (output union_4_state_32 o); + import "DPI-C" function void i_union_4_state_33 (output union_4_state_33 o); + import "DPI-C" function void i_union_4_state_64 (output union_4_state_64 o); + import "DPI-C" function void i_union_4_state_65 (output union_4_state_65 o); + import "DPI-C" function void i_union_4_state_128 (output union_4_state_128 o); + + //====================================================================== + // Exports + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + export "DPI-C" function e_byte; + export "DPI-C" function e_byte_unsigned; + export "DPI-C" function e_shortint; + export "DPI-C" function e_shortint_unsigned; + export "DPI-C" function e_int; + export "DPI-C" function e_int_unsigned; + export "DPI-C" function e_longint; + export "DPI-C" function e_longint_unsigned; +`ifndef NO_TIME + export "DPI-C" function e_time; +`endif +`ifndef NO_INTEGER + export "DPI-C" function e_integer; +`endif + export "DPI-C" function e_real; +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal; +`endif + export "DPI-C" function e_chandle; + export "DPI-C" function e_string; + export "DPI-C" function e_bit; + export "DPI-C" function e_logic; + + // Basic types via typedef + export "DPI-C" function e_byte_t; + export "DPI-C" function e_byte_unsigned_t; + export "DPI-C" function e_shortint_t; + export "DPI-C" function e_shortint_unsigned_t; + export "DPI-C" function e_int_t; + export "DPI-C" function e_int_unsigned_t; + export "DPI-C" function e_longint_t; + export "DPI-C" function e_longint_unsigned_t; +`ifndef NO_TIME + export "DPI-C" function e_time_t; +`endif +`ifndef NO_INTEGER + export "DPI-C" function e_integer_t; +`endif + export "DPI-C" function e_real_t; +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal_t; +`endif + export "DPI-C" function e_chandle_t; + export "DPI-C" function e_string_t; + export "DPI-C" function e_bit_t; + export "DPI-C" function e_logic_t; + + // 2-state packed arrays + export "DPI-C" function e_array_2_state_1; + export "DPI-C" function e_array_2_state_32; + export "DPI-C" function e_array_2_state_33; + export "DPI-C" function e_array_2_state_64; + export "DPI-C" function e_array_2_state_65; + export "DPI-C" function e_array_2_state_128; + + // 2-state packed structures + export "DPI-C" function e_struct_2_state_1; + export "DPI-C" function e_struct_2_state_32; + export "DPI-C" function e_struct_2_state_33; + export "DPI-C" function e_struct_2_state_64; + export "DPI-C" function e_struct_2_state_65; + export "DPI-C" function e_struct_2_state_128; + + // 2-state packed unions + export "DPI-C" function e_union_2_state_1; + export "DPI-C" function e_union_2_state_32; + export "DPI-C" function e_union_2_state_33; + export "DPI-C" function e_union_2_state_64; + export "DPI-C" function e_union_2_state_65; + export "DPI-C" function e_union_2_state_128; + + // 4-state packed arrays + export "DPI-C" function e_array_4_state_1; + export "DPI-C" function e_array_4_state_32; + export "DPI-C" function e_array_4_state_33; + export "DPI-C" function e_array_4_state_64; + export "DPI-C" function e_array_4_state_65; + export "DPI-C" function e_array_4_state_128; + + // 4-state packed structures + export "DPI-C" function e_struct_4_state_1; + export "DPI-C" function e_struct_4_state_32; + export "DPI-C" function e_struct_4_state_33; + export "DPI-C" function e_struct_4_state_64; + export "DPI-C" function e_struct_4_state_65; + export "DPI-C" function e_struct_4_state_128; + + // 4-state packed unions + export "DPI-C" function e_union_4_state_1; + export "DPI-C" function e_union_4_state_32; + export "DPI-C" function e_union_4_state_33; + export "DPI-C" function e_union_4_state_64; + export "DPI-C" function e_union_4_state_65; + export "DPI-C" function e_union_4_state_128; + + //====================================================================== + // Definitions of exported functions + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.6 + byte n_byte = 0; + function void e_byte(output byte o); + o = 8'd10 + n_byte; + n_byte++; + endfunction + + byte n_byte_unsigned = 0; + function void e_byte_unsigned(output byte unsigned o); + o = 8'd20 + n_byte_unsigned; + n_byte_unsigned++; + endfunction + + shortint n_shortint = 0; + function void e_shortint(output shortint o); + o = 16'd30 + n_shortint; + n_shortint++; + endfunction + + shortint n_shortint_unsigned = 0; + function void e_shortint_unsigned(output shortint unsigned o); + o = 16'd40 + n_shortint_unsigned; + n_shortint_unsigned++; + endfunction + + int n_int = 0; + function void e_int(output int o); + o = 32'd50 + n_int; + n_int++; + endfunction + + int n_int_unsigned = 0; + function void e_int_unsigned(output int unsigned o); + o = 32'd60 + n_int_unsigned; + n_int_unsigned++; + endfunction + + longint n_longint = 0; + function void e_longint(output longint o); + o = 64'd70 + n_longint; + n_longint++; + endfunction + + longint n_longint_unsigned = 0; + function void e_longint_unsigned(output longint unsigned o); + o = 64'd80 + n_longint_unsigned; + n_longint_unsigned++; + endfunction + +`ifndef NO_TIME + longint n_time = 0; + function void e_time(output time o); + o = 64'd90 + n_time; + n_time++; + endfunction +`endif + +`ifndef NO_INTEGER + int n_integer = 0; + function void e_integer(output integer o); + o = 32'd100 + n_integer; + n_integer++; + endfunction +`endif + + int n_real = 0; + function void e_real(output real o); + o = real'(2*n_real + 1) / 2.0; + n_real++; + endfunction + +`ifndef NO_SHORTREAL + int n_shortreal = 0; + function void e_shortreal(output shortreal o); + o = shortreal'(4*n_shortreal + 1) / 4.0; + n_shortreal++; + endfunction +`endif + + int n_chandle = 0; + function void e_chandle(output chandle o); + $display("e_chandle %1d", n_chandle); + o = `NULL; + n_chandle++; + endfunction + + int n_string = 0; + function void e_string(output string o); + $display("e_string %1d", n_string); + o = n_string[0] ? "World" : "Hello"; + n_string++; + endfunction + + int n_bit = 0; + function void e_bit(output bit o); + $display("e_bit %1d", n_bit); + o = n_bit[0]; + n_bit++; + endfunction + + int n_logic = 0; + function void e_logic(output logic o); + $display("e_logic %1d", n_logic); + o = ~n_logic[0]; + n_logic++; + endfunction + + // Basic types via typedefs + byte_t n_byte_t = 0; + function void e_byte_t(output byte_t o); + o = 8'd10 + n_byte_t; + n_byte_t += 2; + endfunction + + byte n_byte_unsigned_t = 0; + function void e_byte_unsigned_t(output byte_unsigned_t o); + o = 8'd20 + n_byte_unsigned_t; + n_byte_unsigned_t += 2; + endfunction + + shortint_t n_shortint_t = 0; + function void e_shortint_t(output shortint_t o); + o = 16'd30 + n_shortint_t; + n_shortint_t += 2; + endfunction + + shortint n_shortint_unsigned_t = 0; + function void e_shortint_unsigned_t(output shortint_unsigned_t o); + o = 16'd40 + n_shortint_unsigned_t; + n_shortint_unsigned_t += 2; + endfunction + + int_t n_int_t = 0; + function void e_int_t(output int_t o); + o = 32'd50 + n_int_t; + n_int_t += 2; + endfunction + + int n_int_unsigned_t = 0; + function void e_int_unsigned_t(output int_unsigned_t o); + o = 32'd60 + n_int_unsigned_t; + n_int_unsigned_t += 2; + endfunction + + longint_t n_longint_t = 0; + function void e_longint_t(output longint_t o); + o = 64'd70 + n_longint_t; + n_longint_t += 2; + endfunction + + longint n_longint_unsigned_t = 0; + function void e_longint_unsigned_t(output longint_unsigned_t o); + o = 64'd80 + n_longint_unsigned_t; + n_longint_unsigned_t += 2; + endfunction + +`ifndef NO_TIME + longint n_time_t = 0; + function void e_time_t(output time_t o); + o = 64'd90 + n_time_t; + n_time_t += 2; + endfunction +`endif + +`ifndef NO_INTEGER + int n_integer_t = 0; + function void e_integer_t(output integer o); + o = 32'd100 + n_integer_t; + n_integer_t += 2; + endfunction +`endif + + int n_real_t = 0; + function void e_real_t(output real_t o); + o = real'(2*n_real_t + 1) / 2.0; + n_real_t += 2; + endfunction + +`ifndef NO_SHORTREAL + int n_shortreal_t = 0; + function void e_shortreal_t(output shortreal_t o); + o = shortreal'(4*n_shortreal_t + 1) / 4.0; + n_shortreal_t += 2; + endfunction +`endif + + int n_chandle_t = 0; + function void e_chandle_t(output chandle_t o); + $display("e_chandle_t %1d", n_chandle_t); + o = `NULL; + n_chandle_t++; + endfunction + + int n_string_t = 0; + function void e_string_t(output string_t o); + $display("e_string_t %1d", n_string_t); + o = n_string_t[0] ? "World" : "Hello"; + n_string_t++; + endfunction + + int n_bit_t = 0; + function void e_bit_t(output bit_t o); + $display("e_bit_t %1d", n_bit_t); + o = n_bit_t[0]; + n_bit_t++; + endfunction + + int n_logic_t = 0; + function void e_logic_t(output logic_t o); + $display("e_logic_t %1d", n_logic_t); + o = ~n_logic_t[0]; + n_logic_t++; + endfunction + + // 2-state packed arrays + int n_array_2_state_1 = 0; + function void e_array_2_state_1(output bit [ 0:0] o); + $display("e_array_2_state_1 %1d", n_array_2_state_1); + o = n_array_2_state_1[0]; + n_array_2_state_1++; + endfunction + + int n_array_2_state_32 = 0; + function void e_array_2_state_32(output bit [31:0] o); + $display("e_array_2_state_32 %1d", n_array_2_state_32); + o = ~32'd0 >> n_array_2_state_32; + n_array_2_state_32++; + endfunction + + int n_array_2_state_33 = 0; + function void e_array_2_state_33(output bit [32:0] o); + $display("e_array_2_state_33 %1d", n_array_2_state_33); + o = ~33'd0 >> n_array_2_state_33; + n_array_2_state_33++; + endfunction + + int n_array_2_state_64 = 0; + function void e_array_2_state_64(output bit [63:0] o); + $display("e_array_2_state_64 %1d", n_array_2_state_64); + o = ~64'd0 >> n_array_2_state_64; + n_array_2_state_64++; + endfunction + + int n_array_2_state_65 = 0; + function void e_array_2_state_65(output bit [64:0] o); + $display("e_array_2_state_65 %1d", n_array_2_state_65); + o = ~65'd0 >> n_array_2_state_65; + n_array_2_state_65++; + endfunction + + int n_array_2_state_128 = 0; + function void e_array_2_state_128(output bit [127:0] o); + $display("e_array_2_state_128 %1d", n_array_2_state_128); + o = ~128'd0 >> n_array_2_state_128; + n_array_2_state_128++; + endfunction + + // 2-state packed structures + int n_struct_2_state_1 = 0; + function void e_struct_2_state_1(output struct_2_state_1 o); + $display("e_struct_2_state_1 %1d", n_struct_2_state_1); + o = n_struct_2_state_1[0]; + n_struct_2_state_1++; + endfunction + + int n_struct_2_state_32 = 0; + function void e_struct_2_state_32(output struct_2_state_32 o); + $display("e_struct_2_state_32 %1d", n_struct_2_state_32); + o = ~32'd0 >> n_struct_2_state_32; + n_struct_2_state_32++; + endfunction + + int n_struct_2_state_33 = 0; + function void e_struct_2_state_33(output struct_2_state_33 o); + $display("e_struct_2_state_33 %1d", n_struct_2_state_33); + o = ~33'd0 >> n_struct_2_state_33; + n_struct_2_state_33++; + endfunction + + int n_struct_2_state_64 = 0; + function void e_struct_2_state_64(output struct_2_state_64 o); + $display("e_struct_2_state_64 %1d", n_struct_2_state_64); + o = ~64'd0 >> n_struct_2_state_64; + n_struct_2_state_64++; + endfunction + + int n_struct_2_state_65 = 0; + function void e_struct_2_state_65(output struct_2_state_65 o); + $display("e_struct_2_state_65 %1d", n_struct_2_state_65); + o = ~65'd0 >> n_struct_2_state_65; + n_struct_2_state_65++; + endfunction + + int n_struct_2_state_128 = 0; + function void e_struct_2_state_128(output struct_2_state_128 o); + $display("e_struct_2_state_128 %1d", n_struct_2_state_128); + o = ~128'd0 >> n_struct_2_state_128; + n_struct_2_state_128++; + endfunction + + // 2-state packed unions + int n_union_2_state_1 = 0; + function void e_union_2_state_1(output union_2_state_1 o); + $display("e_union_2_state_1 %1d", n_union_2_state_1); + o = n_union_2_state_1[0]; + n_union_2_state_1++; + endfunction + + int n_union_2_state_32 = 0; + function void e_union_2_state_32(output union_2_state_32 o); + $display("e_union_2_state_32 %1d", n_union_2_state_32); + o = ~32'd0 >> n_union_2_state_32; + n_union_2_state_32++; + endfunction + + int n_union_2_state_33 = 0; + function void e_union_2_state_33(output union_2_state_33 o); + $display("e_union_2_state_33 %1d", n_union_2_state_33); + o = ~33'd0 >> n_union_2_state_33; + n_union_2_state_33++; + endfunction + + int n_union_2_state_64 = 0; + function void e_union_2_state_64(output union_2_state_64 o); + $display("e_union_2_state_64 %1d", n_union_2_state_64); + o = ~64'd0 >> n_union_2_state_64; + n_union_2_state_64++; + endfunction + + int n_union_2_state_65 = 0; + function void e_union_2_state_65(output union_2_state_65 o); + $display("e_union_2_state_65 %1d", n_union_2_state_65); + o = ~65'd0 >> n_union_2_state_65; + n_union_2_state_65++; + endfunction + + int n_union_2_state_128 = 0; + function void e_union_2_state_128(output union_2_state_128 o); + $display("e_union_2_state_128 %1d", n_union_2_state_128); + o = ~128'd0 >> n_union_2_state_128; + n_union_2_state_128++; + endfunction + + // 4-state packed arrays + int n_array_4_state_1 = 0; + function void e_array_4_state_1(output logic [ 0:0] o); + $display("e_array_4_state_1 %1d", n_array_4_state_1); + o = n_array_4_state_1[0]; + n_array_4_state_1++; + endfunction + + int n_array_4_state_32 = 0; + function void e_array_4_state_32(output logic [31:0] o); + $display("e_array_4_state_32 %1d", n_array_4_state_32); + o = ~32'd0 >> n_array_4_state_32; + n_array_4_state_32++; + endfunction + + int n_array_4_state_33 = 0; + function void e_array_4_state_33(output logic [32:0] o); + $display("e_array_4_state_33 %1d", n_array_4_state_33); + o = ~33'd0 >> n_array_4_state_33; + n_array_4_state_33++; + endfunction + + int n_array_4_state_64 = 0; + function void e_array_4_state_64(output logic [63:0] o); + $display("e_array_4_state_64 %1d", n_array_4_state_64); + o = ~64'd0 >> n_array_4_state_64; + n_array_4_state_64++; + endfunction + + int n_array_4_state_65 = 0; + function void e_array_4_state_65(output logic [64:0] o); + $display("e_array_4_state_65 %1d", n_array_4_state_65); + o = ~65'd0 >> n_array_4_state_65; + n_array_4_state_65++; + endfunction + + int n_array_4_state_128 = 0; + function void e_array_4_state_128(output logic [127:0] o); + $display("e_array_4_state_128 %1d", n_array_4_state_128); + o = ~128'd0 >> n_array_4_state_128; + n_array_4_state_128++; + endfunction + + // 4-state packed structures + int n_struct_4_state_1 = 0; + function void e_struct_4_state_1(output struct_4_state_1 o); + $display("e_struct_4_state_1 %1d", n_struct_4_state_1); + o = n_struct_4_state_1[0]; + n_struct_4_state_1++; + endfunction + + int n_struct_4_state_32 = 0; + function void e_struct_4_state_32(output struct_4_state_32 o); + $display("e_struct_4_state_32 %1d", n_struct_4_state_32); + o = ~32'd0 >> n_struct_4_state_32; + n_struct_4_state_32++; + endfunction + + int n_struct_4_state_33 = 0; + function void e_struct_4_state_33(output struct_4_state_33 o); + $display("e_struct_4_state_33 %1d", n_struct_4_state_33); + o = ~33'd0 >> n_struct_4_state_33; + n_struct_4_state_33++; + endfunction + + int n_struct_4_state_64 = 0; + function void e_struct_4_state_64(output struct_4_state_64 o); + $display("e_struct_4_state_64 %1d", n_struct_4_state_64); + o = ~64'd0 >> n_struct_4_state_64; + n_struct_4_state_64++; + endfunction + + int n_struct_4_state_65 = 0; + function void e_struct_4_state_65(output struct_4_state_65 o); + $display("e_struct_4_state_65 %1d", n_struct_4_state_65); + o = ~65'd0 >> n_struct_4_state_65; + n_struct_4_state_65++; + endfunction + + int n_struct_4_state_128 = 0; + function void e_struct_4_state_128(output struct_4_state_128 o); + $display("e_struct_4_state_128 %1d", n_struct_4_state_128); + o = ~128'd0 >> n_struct_4_state_128; + n_struct_4_state_128++; + endfunction + + // 4-state packed unions + int n_union_4_state_1 = 0; + function void e_union_4_state_1(output union_4_state_1 o); + $display("e_union_4_state_1 %1d", n_union_4_state_1); + o = n_union_4_state_1[0]; + n_union_4_state_1++; + endfunction + + int n_union_4_state_32 = 0; + function void e_union_4_state_32(output union_4_state_32 o); + $display("e_union_4_state_32 %1d", n_union_4_state_32); + o = ~32'd0 >> n_union_4_state_32; + n_union_4_state_32++; + endfunction + + int n_union_4_state_33 = 0; + function void e_union_4_state_33(output union_4_state_33 o); + $display("e_union_4_state_33 %1d", n_union_4_state_33); + o = ~33'd0 >> n_union_4_state_33; + n_union_4_state_33++; + endfunction + + int n_union_4_state_64 = 0; + function void e_union_4_state_64(output union_4_state_64 o); + $display("e_union_4_state_64 %1d", n_union_4_state_64); + o = ~64'd0 >> n_union_4_state_64; + n_union_4_state_64++; + endfunction + + int n_union_4_state_65 = 0; + function void e_union_4_state_65(output union_4_state_65 o); + $display("e_union_4_state_65 %1d", n_union_4_state_65); + o = ~65'd0 >> n_union_4_state_65; + n_union_4_state_65++; + endfunction + + int n_union_4_state_128 = 0; + function void e_union_4_state_128(output union_4_state_128 o); + $display("e_union_4_state_128 %1d", n_union_4_state_128); + o = ~128'd0 >> n_union_4_state_128; + n_union_4_state_128++; + endfunction + + //====================================================================== + // Invoke all functions 3 times (they have side effects) + //====================================================================== + + import "DPI-C" context function void check_exports(); + + initial begin + for (int i = 0 ; i < 3; i++) begin + // Check the imports + + byte x_byte; + byte unsigned x_byte_unsigned; + shortint x_shortint; + shortint unsigned x_shortint_unsigned; + int x_int; + int unsigned x_int_unsigned; + longint x_longint; + longint unsigned x_longint_unsigned; +`ifndef NO_TIME + time x_time; +`endif +`ifndef NO_INTEGER + integer x_integer; +`endif + real x_real; +`ifndef NO_SHORTREAL + shortreal x_shortreal; +`endif + chandle x_chandle; + string x_string; + bit x_bit; + logic x_logic; + + byte_t x_byte_t; + byte_unsigned_t x_byte_unsigned_t; + shortint_t x_shortint_t; + shortint_unsigned_t x_shortint_unsigned_t; + int_t x_int_t; + int_unsigned_t x_int_unsigned_t; + longint_t x_longint_t; + longint_unsigned_t x_longint_unsigned_t; +`ifndef NO_TIME + time_t x_time_t; +`endif +`ifndef NO_INTEGER + integer_t x_integer_t; +`endif + real_t x_real_t; +`ifndef NO_SHORTREAL + shortreal_t x_shortreal_t; +`endif + chandle_t x_chandle_t; + string_t x_string_t; + bit_t x_bit_t; + logic_t x_logic_t; + + bit [ 0:0] x_bit_1; + bit [ 31:0] x_bit_32; + bit [ 32:0] x_bit_33; + bit [ 63:0] x_bit_64; + bit [ 64:0] x_bit_65; + bit [127:0] x_bit_128; + + struct_2_state_1 x_struct_2_state_1; + struct_2_state_32 x_struct_2_state_32; + struct_2_state_33 x_struct_2_state_33; + struct_2_state_64 x_struct_2_state_64; + struct_2_state_65 x_struct_2_state_65; + struct_2_state_128 x_struct_2_state_128; + + union_2_state_1 x_union_2_state_1; + union_2_state_32 x_union_2_state_32; + union_2_state_33 x_union_2_state_33; + union_2_state_64 x_union_2_state_64; + union_2_state_65 x_union_2_state_65; + union_2_state_128 x_union_2_state_128; + + logic [ 0:0] x_logic_1; + logic [ 31:0] x_logic_32; + logic [ 32:0] x_logic_33; + logic [ 63:0] x_logic_64; + logic [ 64:0] x_logic_65; + logic [127:0] x_logic_128; + + struct_4_state_1 x_struct_4_state_1; + struct_4_state_32 x_struct_4_state_32; + struct_4_state_33 x_struct_4_state_33; + struct_4_state_64 x_struct_4_state_64; + struct_4_state_65 x_struct_4_state_65; + struct_4_state_128 x_struct_4_state_128; + + union_4_state_1 x_union_4_state_1; + union_4_state_32 x_union_4_state_32; + union_4_state_33 x_union_4_state_33; + union_4_state_64 x_union_4_state_64; + union_4_state_65 x_union_4_state_65; + union_4_state_128 x_union_4_state_128; + + // Basic types as per IEEE 1800-2017 35.5.6 + i_byte(x_byte); if (x_byte !== 8'd10 - 8'(i)) $stop; + i_byte_unsigned(x_byte_unsigned); if (x_byte_unsigned !== 8'd20 - 8'(i)) $stop; + i_shortint(x_shortint); if (x_shortint !== 16'd30 - 16'(i)) $stop; + i_shortint_unsigned(x_shortint_unsigned); if (x_shortint_unsigned !== 16'd40 - 16'(i)) $stop; + i_int(x_int); if (x_int !== 32'd50 - 32'(i)) $stop; + i_int_unsigned(x_int_unsigned); if (x_int_unsigned !== 32'd60 - 32'(i)) $stop; + i_longint(x_longint); if (x_longint !== 64'd70 - 64'(i)) $stop; + i_longint_unsigned(x_longint_unsigned); if (x_longint_unsigned !== 64'd80 - 64'(i)) $stop; +`ifndef NO_TIME + i_time(x_time); if (x_time !== 64'd90 - 64'(i)) $stop; +`endif +`ifndef NO_INTEGER + i_integer(x_integer); if (x_integer !== 32'd100- 32'(i)) $stop; +`endif + i_real(x_real); if (x_real != -1.0*i - 0.5 ) $stop; +`ifndef NO_SHORTREAL + i_shortreal(x_shortreal); if (x_shortreal != -1.0*i - 0.25) $stop; +`endif + if (~i[0]) begin + i_chandle(x_chandle); if (x_chandle !== `NULL) $stop; + i_string(x_string); if (x_string != "World") $stop; + end else begin + i_chandle(x_chandle); if (x_chandle === `NULL) $stop; + i_string(x_string); if (x_string != "Hello") $stop; + end + i_bit(x_bit); if (x_bit !== ~i[0]) $stop; + i_logic(x_logic); if (x_logic !== i[0]) $stop; + + // Basic types via typedefs + i_byte_t(x_byte_t); if (x_byte_t !== 8'd10 - 8'(2*i)) $stop; + i_byte_unsigned_t(x_byte_unsigned_t); if (x_byte_unsigned_t !== 8'd20 - 8'(2*i)) $stop; + i_shortint_t(x_shortint_t); if (x_shortint_t !== 16'd30 - 16'(2*i)) $stop; + i_shortint_unsigned_t(x_shortint_unsigned_t); if (x_shortint_unsigned_t !== 16'd40 - 16'(2*i)) $stop; + i_int_t(x_int_t); if (x_int_t !== 32'd50 - 32'(2*i)) $stop; + i_int_unsigned_t(x_int_unsigned_t); if (x_int_unsigned_t !== 32'd60 - 32'(2*i)) $stop; + i_longint_t(x_longint_t); if (x_longint_t !== 64'd70 - 64'(2*i)) $stop; + i_longint_unsigned_t(x_longint_unsigned_t); if (x_longint_unsigned_t !== 64'd80 - 64'(2*i)) $stop; +`ifndef NO_TIME + i_time_t(x_time_t); if (x_time_t !== 64'd90 - 64'(2*i)) $stop; +`endif +`ifndef NO_INTEGER + i_integer_t(x_integer_t); if (x_integer_t !== 32'd100- 32'(2*i)) $stop; +`endif + i_real_t(x_real_t); if (x_real_t != -1.0*(2*i) - 0.5 ) $stop; +`ifndef NO_SHORTREAL + i_shortreal_t(x_shortreal_t); if (x_shortreal_t != -1.0*(2*i) - 0.25) $stop; +`endif + if (~i[0]) begin + i_chandle_t(x_chandle_t); if (x_chandle_t !== `NULL) $stop; + i_string_t(x_string_t); if (x_string_t != "World") $stop; + end else begin + i_chandle_t(x_chandle_t); if (x_chandle_t === `NULL) $stop; + i_string_t(x_string_t); if (x_string_t != "Hello") $stop; + end + i_bit_t(x_bit_t); if (x_bit_t !== ~i[0]) $stop; + i_logic_t(x_logic_t); if (x_logic_t !== i[0]) $stop; + + // 2-state packed arrays + i_array_2_state_1(x_bit_1); if (x_bit_1 !== ~i[0] ) $stop; + i_array_2_state_32(x_bit_32); if (x_bit_32 !== ~32'd0 << i) $stop; + i_array_2_state_33(x_bit_33); if (x_bit_33 !== ~33'd0 << i) $stop; + i_array_2_state_64(x_bit_64); if (x_bit_64 !== ~64'd0 << i) $stop; + i_array_2_state_65(x_bit_65); if (x_bit_65 !== ~65'd0 << i) $stop; + i_array_2_state_128(x_bit_128); if (x_bit_128 !== ~128'd0<< i) $stop; + + // 2-state packed structures + i_struct_2_state_1(x_struct_2_state_1); if (x_struct_2_state_1 !== ~i[0] ) $stop; + i_struct_2_state_32(x_struct_2_state_32); if (x_struct_2_state_32 !== ~32'd0 << i) $stop; + i_struct_2_state_33(x_struct_2_state_33); if (x_struct_2_state_33 !== ~33'd0 << i) $stop; + i_struct_2_state_64(x_struct_2_state_64); if (x_struct_2_state_64 !== ~64'd0 << i) $stop; + i_struct_2_state_65(x_struct_2_state_65); if (x_struct_2_state_65 !== ~65'd0 << i) $stop; + i_struct_2_state_128(x_struct_2_state_128); if (x_struct_2_state_128 !== ~128'd0<< i) $stop; + + // 2-state packed unions + i_union_2_state_1(x_union_2_state_1); if (x_union_2_state_1 !== ~i[0] ) $stop; + i_union_2_state_32(x_union_2_state_32); if (x_union_2_state_32 !== ~32'd0 << i) $stop; + i_union_2_state_33(x_union_2_state_33); if (x_union_2_state_33 !== ~33'd0 << i) $stop; + i_union_2_state_64(x_union_2_state_64); if (x_union_2_state_64 !== ~64'd0 << i) $stop; + i_union_2_state_65(x_union_2_state_65); if (x_union_2_state_65 !== ~65'd0 << i) $stop; + i_union_2_state_128(x_union_2_state_128); if (x_union_2_state_128 !== ~128'd0<< i) $stop; + + // 4-state packed arrays + i_array_4_state_1(x_logic_1); if (x_logic_1 !== ~i[0] ) $stop; + i_array_4_state_32(x_logic_32); if (x_logic_32 !== ~32'd0 << i) $stop; + i_array_4_state_33(x_logic_33); if (x_logic_33 !== ~33'd0 << i) $stop; + i_array_4_state_64(x_logic_64); if (x_logic_64 !== ~64'd0 << i) $stop; + i_array_4_state_65(x_logic_65); if (x_logic_65 !== ~65'd0 << i) $stop; + i_array_4_state_128(x_logic_128); if (x_logic_128 !== ~128'd0<< i) $stop; + + // 4-state packed structures + i_struct_4_state_1(x_struct_4_state_1); if (x_struct_4_state_1 !== ~i[0] ) $stop; + i_struct_4_state_32(x_struct_4_state_32); if (x_struct_4_state_32 !== ~32'd0 << i) $stop; + i_struct_4_state_33(x_struct_4_state_33); if (x_struct_4_state_33 !== ~33'd0 << i) $stop; + i_struct_4_state_64(x_struct_4_state_64); if (x_struct_4_state_64 !== ~64'd0 << i) $stop; + i_struct_4_state_65(x_struct_4_state_65); if (x_struct_4_state_65 !== ~65'd0 << i) $stop; + i_struct_4_state_128(x_struct_4_state_128); if (x_struct_4_state_128 !== ~128'd0<< i) $stop; + + // 4-state packed unions + i_union_4_state_1(x_union_4_state_1); if (x_union_4_state_1 !== ~i[0] ) $stop; + i_union_4_state_32(x_union_4_state_32); if (x_union_4_state_32 !== ~32'd0 << i) $stop; + i_union_4_state_33(x_union_4_state_33); if (x_union_4_state_33 !== ~33'd0 << i) $stop; + i_union_4_state_64(x_union_4_state_64); if (x_union_4_state_64 !== ~64'd0 << i) $stop; + i_union_4_state_65(x_union_4_state_65); if (x_union_4_state_65 !== ~65'd0 << i) $stop; + i_union_4_state_128(x_union_4_state_128); if (x_union_4_state_128 !== ~128'd0<< i) $stop; + + // Check the exports + check_exports(); + end + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_dpi_arg_output_type__Dpi.out b/test_regress/t/t_dpi_arg_output_type__Dpi.out new file mode 100644 index 000000000..5f24130ff --- /dev/null +++ b/test_regress/t/t_dpi_arg_output_type__Dpi.out @@ -0,0 +1,287 @@ +// Verilated -*- C++ -*- +// DESCRIPTION: Verilator output: Prototypes for DPI import and export functions. +// +// Verilator includes this file in all generated .cpp files that use DPI functions. +// Manually include this file where DPI .c import functions are declared to ensure +// the C functions match the expectations of the DPI imports. + +#include "svdpi.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + // DPI EXPORTS + // DPI export at t/t_dpi_arg_output_type.v:521:18 + extern void e_array_2_state_1(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:556:18 + extern void e_array_2_state_128(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:528:18 + extern void e_array_2_state_32(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:535:18 + extern void e_array_2_state_33(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:542:18 + extern void e_array_2_state_64(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:549:18 + extern void e_array_2_state_65(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:650:18 + extern void e_array_4_state_1(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:685:18 + extern void e_array_4_state_128(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:657:18 + extern void e_array_4_state_32(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:664:18 + extern void e_array_4_state_33(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:671:18 + extern void e_array_4_state_64(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:678:18 + extern void e_array_4_state_65(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:399:18 + extern void e_bit(svBit* o); + // DPI export at t/t_dpi_arg_output_type.v:506:18 + extern void e_bit_t(svBit* o); + // DPI export at t/t_dpi_arg_output_type.v:307:18 + extern void e_byte(char* o); + // DPI export at t/t_dpi_arg_output_type.v:414:18 + extern void e_byte_t(char* o); + // DPI export at t/t_dpi_arg_output_type.v:313:18 + extern void e_byte_unsigned(unsigned char* o); + // DPI export at t/t_dpi_arg_output_type.v:420:18 + extern void e_byte_unsigned_t(unsigned char* o); + // DPI export at t/t_dpi_arg_output_type.v:385:18 + extern void e_chandle(void** o); + // DPI export at t/t_dpi_arg_output_type.v:492:18 + extern void e_chandle_t(void** o); + // DPI export at t/t_dpi_arg_output_type.v:331:18 + extern void e_int(int* o); + // DPI export at t/t_dpi_arg_output_type.v:438:18 + extern void e_int_t(int* o); + // DPI export at t/t_dpi_arg_output_type.v:337:18 + extern void e_int_unsigned(unsigned int* o); + // DPI export at t/t_dpi_arg_output_type.v:444:18 + extern void e_int_unsigned_t(unsigned int* o); + // DPI export at t/t_dpi_arg_output_type.v:364:18 + extern void e_integer(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:471:18 + extern void e_integer_t(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:406:18 + extern void e_logic(svLogic* o); + // DPI export at t/t_dpi_arg_output_type.v:513:18 + extern void e_logic_t(svLogic* o); + // DPI export at t/t_dpi_arg_output_type.v:343:18 + extern void e_longint(long long* o); + // DPI export at t/t_dpi_arg_output_type.v:450:18 + extern void e_longint_t(long long* o); + // DPI export at t/t_dpi_arg_output_type.v:349:18 + extern void e_longint_unsigned(unsigned long long* o); + // DPI export at t/t_dpi_arg_output_type.v:456:18 + extern void e_longint_unsigned_t(unsigned long long* o); + // DPI export at t/t_dpi_arg_output_type.v:371:18 + extern void e_real(double* o); + // DPI export at t/t_dpi_arg_output_type.v:478:18 + extern void e_real_t(double* o); + // DPI export at t/t_dpi_arg_output_type.v:319:18 + extern void e_shortint(short* o); + // DPI export at t/t_dpi_arg_output_type.v:426:18 + extern void e_shortint_t(short* o); + // DPI export at t/t_dpi_arg_output_type.v:325:18 + extern void e_shortint_unsigned(unsigned short* o); + // DPI export at t/t_dpi_arg_output_type.v:432:18 + extern void e_shortint_unsigned_t(unsigned short* o); + // DPI export at t/t_dpi_arg_output_type.v:392:18 + extern void e_string(const char** o); + // DPI export at t/t_dpi_arg_output_type.v:499:18 + extern void e_string_t(const char** o); + // DPI export at t/t_dpi_arg_output_type.v:564:18 + extern void e_struct_2_state_1(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:599:18 + extern void e_struct_2_state_128(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:571:18 + extern void e_struct_2_state_32(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:578:18 + extern void e_struct_2_state_33(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:585:18 + extern void e_struct_2_state_64(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:592:18 + extern void e_struct_2_state_65(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:693:18 + extern void e_struct_4_state_1(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:728:18 + extern void e_struct_4_state_128(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:700:18 + extern void e_struct_4_state_32(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:707:18 + extern void e_struct_4_state_33(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:714:18 + extern void e_struct_4_state_64(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:721:18 + extern void e_struct_4_state_65(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:356:18 + extern void e_time(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:463:18 + extern void e_time_t(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:607:18 + extern void e_union_2_state_1(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:642:18 + extern void e_union_2_state_128(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:614:18 + extern void e_union_2_state_32(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:621:18 + extern void e_union_2_state_33(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:628:18 + extern void e_union_2_state_64(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:635:18 + extern void e_union_2_state_65(svBitVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:736:18 + extern void e_union_4_state_1(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:771:18 + extern void e_union_4_state_128(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:743:18 + extern void e_union_4_state_32(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:750:18 + extern void e_union_4_state_33(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:757:18 + extern void e_union_4_state_64(svLogicVecVal* o); + // DPI export at t/t_dpi_arg_output_type.v:764:18 + extern void e_union_4_state_65(svLogicVecVal* o); + + // DPI IMPORTS + // DPI import at t/t_dpi_arg_output_type.v:781:41 + extern void check_exports(); + // DPI import at t/t_dpi_arg_output_type.v:154:33 + extern void i_array_2_state_1(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:159:33 + extern void i_array_2_state_128(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:155:33 + extern void i_array_2_state_32(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:156:33 + extern void i_array_2_state_33(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:157:33 + extern void i_array_2_state_64(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:158:33 + extern void i_array_2_state_65(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:178:33 + extern void i_array_4_state_1(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:183:33 + extern void i_array_4_state_128(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:179:33 + extern void i_array_4_state_32(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:180:33 + extern void i_array_4_state_33(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:181:33 + extern void i_array_4_state_64(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:182:33 + extern void i_array_4_state_65(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:126:33 + extern void i_bit(svBit* o); + // DPI import at t/t_dpi_arg_output_type.v:150:33 + extern void i_bit_t(svBit* o); + // DPI import at t/t_dpi_arg_output_type.v:106:33 + extern void i_byte(char* o); + // DPI import at t/t_dpi_arg_output_type.v:130:33 + extern void i_byte_t(char* o); + // DPI import at t/t_dpi_arg_output_type.v:107:33 + extern void i_byte_unsigned(unsigned char* o); + // DPI import at t/t_dpi_arg_output_type.v:131:33 + extern void i_byte_unsigned_t(unsigned char* o); + // DPI import at t/t_dpi_arg_output_type.v:124:33 + extern void i_chandle(void** o); + // DPI import at t/t_dpi_arg_output_type.v:148:33 + extern void i_chandle_t(void** o); + // DPI import at t/t_dpi_arg_output_type.v:110:33 + extern void i_int(int* o); + // DPI import at t/t_dpi_arg_output_type.v:134:33 + extern void i_int_t(int* o); + // DPI import at t/t_dpi_arg_output_type.v:111:33 + extern void i_int_unsigned(unsigned int* o); + // DPI import at t/t_dpi_arg_output_type.v:135:33 + extern void i_int_unsigned_t(unsigned int* o); + // DPI import at t/t_dpi_arg_output_type.v:118:33 + extern void i_integer(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:142:33 + extern void i_integer_t(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:127:33 + extern void i_logic(svLogic* o); + // DPI import at t/t_dpi_arg_output_type.v:151:33 + extern void i_logic_t(svLogic* o); + // DPI import at t/t_dpi_arg_output_type.v:112:33 + extern void i_longint(long long* o); + // DPI import at t/t_dpi_arg_output_type.v:136:33 + extern void i_longint_t(long long* o); + // DPI import at t/t_dpi_arg_output_type.v:113:33 + extern void i_longint_unsigned(unsigned long long* o); + // DPI import at t/t_dpi_arg_output_type.v:137:33 + extern void i_longint_unsigned_t(unsigned long long* o); + // DPI import at t/t_dpi_arg_output_type.v:120:33 + extern void i_real(double* o); + // DPI import at t/t_dpi_arg_output_type.v:144:33 + extern void i_real_t(double* o); + // DPI import at t/t_dpi_arg_output_type.v:108:33 + extern void i_shortint(short* o); + // DPI import at t/t_dpi_arg_output_type.v:132:33 + extern void i_shortint_t(short* o); + // DPI import at t/t_dpi_arg_output_type.v:109:33 + extern void i_shortint_unsigned(unsigned short* o); + // DPI import at t/t_dpi_arg_output_type.v:133:33 + extern void i_shortint_unsigned_t(unsigned short* o); + // DPI import at t/t_dpi_arg_output_type.v:125:33 + extern void i_string(const char** o); + // DPI import at t/t_dpi_arg_output_type.v:149:33 + extern void i_string_t(const char** o); + // DPI import at t/t_dpi_arg_output_type.v:162:33 + extern void i_struct_2_state_1(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:167:33 + extern void i_struct_2_state_128(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:163:33 + extern void i_struct_2_state_32(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:164:33 + extern void i_struct_2_state_33(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:165:33 + extern void i_struct_2_state_64(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:166:33 + extern void i_struct_2_state_65(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:186:33 + extern void i_struct_4_state_1(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:191:33 + extern void i_struct_4_state_128(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:187:33 + extern void i_struct_4_state_32(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:188:33 + extern void i_struct_4_state_33(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:189:33 + extern void i_struct_4_state_64(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:190:33 + extern void i_struct_4_state_65(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:115:33 + extern void i_time(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:139:33 + extern void i_time_t(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:170:33 + extern void i_union_2_state_1(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:175:33 + extern void i_union_2_state_128(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:171:33 + extern void i_union_2_state_32(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:172:33 + extern void i_union_2_state_33(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:173:33 + extern void i_union_2_state_64(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:174:33 + extern void i_union_2_state_65(svBitVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:194:33 + extern void i_union_4_state_1(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:199:33 + extern void i_union_4_state_128(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:195:33 + extern void i_union_4_state_32(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:196:33 + extern void i_union_4_state_33(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:197:33 + extern void i_union_4_state_64(svLogicVecVal* o); + // DPI import at t/t_dpi_arg_output_type.v:198:33 + extern void i_union_4_state_65(svLogicVecVal* o); + +#ifdef __cplusplus +} +#endif diff --git a/test_regress/t/t_dpi_exp_bad.out b/test_regress/t/t_dpi_exp_bad.out deleted file mode 100644 index 4db2d6559..000000000 --- a/test_regress/t/t_dpi_exp_bad.out +++ /dev/null @@ -1,4 +0,0 @@ -%Error: t/t_dpi_exp_bad.v:12:24: DPI functions cannot return > 32 bits or four-state; use a two-state type or task instead: 'dpix_f_bit48__Vfuncrtn' - 12 | function bit [47:0] dpix_f_bit48(bit [47:0] i); dpix_f_bit48 = ~i; endfunction - | ^~~~~~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_dpi_exp_bad.v b/test_regress/t/t_dpi_exp_bad.v deleted file mode 100644 index 4f0cb56c9..000000000 --- a/test_regress/t/t_dpi_exp_bad.v +++ /dev/null @@ -1,14 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// Copyright 2009 by Wilson Snyder. This program is free software; you can -// redistribute it and/or modify it under the terms of either the GNU -// Lesser General Public License Version 3 or the Perl Artistic License -// Version 2.0. -// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -module t; - - export "DPI-C" function dpix_f_bit48; - function bit [47:0] dpix_f_bit48(bit [47:0] i); dpix_f_bit48 = ~i; endfunction - -endmodule diff --git a/test_regress/t/t_dpi_logic_bad.pl b/test_regress/t/t_dpi_logic_bad.pl deleted file mode 100755 index 056b9974f..000000000 --- a/test_regress/t/t_dpi_logic_bad.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } -# DESCRIPTION: Verilator: Verilog Test driver/expect definition -# -# Copyright 2003 by Wilson Snyder. This program is free software; you -# can redistribute it and/or modify it under the terms of either the GNU -# Lesser General Public License Version 3 or the Perl Artistic License -# Version 2.0. -# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -scenarios(linter => 1); - -lint( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, - ); - -ok(1); -1; diff --git a/test_regress/t/t_dpi_logic_bad.v b/test_regress/t/t_dpi_logic_bad.v deleted file mode 100644 index 2eccc0af4..000000000 --- a/test_regress/t/t_dpi_logic_bad.v +++ /dev/null @@ -1,18 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// Copyright 2009 by Wilson Snyder. This program is free software; you can -// redistribute it and/or modify it under the terms of either the GNU -// Lesser General Public License Version 3 or the Perl Artistic License -// Version 2.0. -// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -module t (); - - // Can't handle time (yet?) - import "DPI-C" dpii_fa_bit = function logic [2:0] oth_f_int1(input time i); - - initial begin - $stop; - end - -endmodule diff --git a/test_regress/t/t_dpi_result_type.cpp b/test_regress/t/t_dpi_result_type.cpp new file mode 100644 index 000000000..27bffe8c5 --- /dev/null +++ b/test_regress/t/t_dpi_result_type.cpp @@ -0,0 +1,352 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include +#include +#include + +#include "svdpi.h" + +#if defined(VERILATOR) // Verilator +# include "Vt_dpi_result_type__Dpi.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_SHORTREAL +#elif defined(VCS) // VCS +# include "../vc_hdrs.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_REAL_EXPORT +#elif defined(NCSC) // NC +# include "dpi-exp.h" +# include "dpi-imp.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_STRUCT_OR_UNION +# define NO_SHORTREAL +#elif defined(MS) // ModelSim +# include "dpi.h" +typedef int64_t sv_longint_t; +typedef uint64_t sv_longint_unsigned_t; +# define NO_STRUCT_OR_UNION +# define NO_ARRAY +#else +# error "Unknown simulator for DPI test" +#endif + +//====================================================================== +// Implementations of imported functions +//====================================================================== + +// Basic types as per IEEE 1800-2017 35.5.5 +void i_void() { + static int n = 0; + printf("i_void %d\n", n); + n++; +} + +char i_byte() { + static int n = 0; + return 10 - n++; +} + +unsigned char i_byte_unsigned() { + static int n = 0; + return 20 - n++; +} + +short i_shortint() { + static int n = 0; + return 30 - n++; +} + +unsigned short i_shortint_unsigned() { + static int n = 0; + return 40 - n++; +} + +int i_int() { + static int n = 0; + return 50 - n++; +} + +unsigned i_int_unsigned() { + static int n = 0; + return 60 - n++; +} + +sv_longint_t i_longint() { + static int n = 0; + return 70 - n++; +} + +sv_longint_unsigned_t i_longint_unsigned() { + static int n = 0; + return 80 - n++; +} + +double i_real() { + static int n = 0; + return (-2.0 * n++ - 1.0) / 2.0; +} + +#ifndef NO_SHORTREAL +float i_shortreal() { + static int n = 0; + return (-4.0f * n++ - 1.0f) / 4.0f; +} +#endif + +void* i_chandle() { + static int n = 0; + printf("i_chandle %d\n", n); + return n++ % 2 ? reinterpret_cast(&i_chandle) : NULL; +} + +const char* i_string() { + static int n = 0; + printf("i_string %d\n", n); + return n++ % 2 ? "Hello" : "World"; +} + +svBit i_bit() { + static int n = 0; + printf("i_bit %d\n", n); + return !(n++ % 2); +} + +svLogic i_logic() { + static int n = 0; + printf("i_logic %d\n", n); + return n++ % 2; +} + +// Basic types via typedefs +char i_byte_t() { + static int n = 0; + const char r = 10 - n; + n += 2; + return r; +} + +unsigned char i_byte_unsigned_t() { + static int n = 0; + const unsigned char r = 20 - n; + n += 2; + return r; +} + +short i_shortint_t() { + static int n = 0; + const short r = 30 - n; + n += 2; + return r; +} + +unsigned short i_shortint_unsigned_t() { + static int n = 0; + const unsigned short r = 40 - n; + n += 2; + return r; +} + +int i_int_t() { + static int n = 0; + const int r = 50 - n; + n += 2; + return r; +} + +unsigned i_int_unsigned_t() { + static int n = 0; + const unsigned r = 60 - n; + n += 2; + return r; +} + +sv_longint_t i_longint_t() { + static int n = 0; + const sv_longint_t r = 70 - n; + n += 2; + return r; +} + +sv_longint_unsigned_t i_longint_unsigned_t() { + static int n = 0; + const sv_longint_unsigned_t r = 80 - n; + n += 2; + return r; +} + +double i_real_t() { + static int n = 0; + const double r = (-2.0 * n - 1.0) / 2.0; + n += 2; + return r; +} + +#ifndef NO_SHORTREAL +float i_shortreal_t() { + static int n = 0; + const float r = (-4.0f * n - 1.0f) / 4.0f; + n += 2; + return r; +} +#endif + +void* i_chandle_t() { + static int n = 0; + printf("i_chandle_t %d\n", n); + return n++ % 2 ? reinterpret_cast(&i_chandle) : NULL; +} + +const char* i_string_t() { + static int n = 0; + printf("i_string_t %d\n", n); + return n++ % 2 ? "Hello" : "World"; +} + +svBit i_bit_t() { + static int n = 0; + printf("i_bit_t %d\n", n); + return !(n++ % 2); +} + +svLogic i_logic_t() { + static int n = 0; + printf("i_logic_t %d\n", n); + return n++ % 2; +} + +#ifndef NO_ARRAY +// 2-state packed arrays of width <= 32 +svBitVecVal i_array_2_state_1() { + static int n = 0; + printf("i_array_2_state_1 %d\n", n); + return !(n++ % 2); +} + +svBitVecVal i_array_2_state_32() { + static int n = 0; + printf("i_array_2_state_32 %d\n", n); + return 0xffffffffU << n++; +} +#endif + +#ifndef NO_STRUCT_OR_UNION +// 2-state packed structures of width <= 32 +svBitVecVal i_struct_2_state_1() { + static int n = 0; + printf("i_struct_2_state_1 %d\n", n); + return !(n++ % 2); +} + +svBitVecVal i_struct_2_state_32() { + static int n = 0; + printf("i_struct_2_state_32 %d\n", n); + return 0xffffffffU << n++; +} + +// 2-state packed unions of width <= 32 +svBitVecVal i_union_2_state_1() { + static int n = 0; + printf("i_union_2_state_1 %d\n", n); + return !(n++ % 2); +} + +svBitVecVal i_union_2_state_32() { + static int n = 0; + printf("i_union_2_state_32 %d\n", n); + return 0xffffffffU << n++; +} +#endif + +//====================================================================== +// Check exported functions +//====================================================================== + +#define stop() \ + do { \ + printf(__FILE__ ":%d Bad value\n", __LINE__); \ + abort(); \ + } while (0) + +void check_exports() { + static int n = 0; + + e_void(); + + // Basic types as per IEEE 1800-2017 35.5.5 + if (e_byte() != 10 + n) stop(); + if (e_byte_unsigned() != 20 + n) stop(); + if (e_shortint() != 30 + n) stop(); + if (e_shortint_unsigned() != 40 + n) stop(); + if (e_int() != 50 + n) stop(); + if (e_int_unsigned() != 60 + n) stop(); + if (e_longint() != 70 + n) stop(); + if (e_longint_unsigned() != 80 + n) stop(); +#ifndef NO_REAL_EXPORT + if (e_real() != 1.0 * n + 0.5) stop(); +#endif +#ifndef NO_SHORTREAL + if (e_shortreal() != 1.0f * n + 0.25f) stop(); +#endif + if (e_chandle() != NULL) stop(); + if (n % 2 == 0) { + if (strcmp(e_string(), "Hello") != 0) stop(); + } else { + if (strcmp(e_string(), "World") != 0) stop(); + } + if (e_bit() != n % 2) stop(); + if (e_logic() != !(n % 2)) stop(); + + // Basic types via tyepdef + if (e_byte_t() != 10 + 2 * n) stop(); + if (e_byte_unsigned_t() != 20 + 2 * n) stop(); + if (e_shortint_t() != 30 + 2 * n) stop(); + if (e_shortint_unsigned_t() != 40 + 2 * n) stop(); + if (e_int_t() != 50 + 2 * n) stop(); + if (e_int_unsigned_t() != 60 + 2 * n) stop(); + if (e_longint_t() != 70 + 2 * n) stop(); + if (e_longint_unsigned_t() != 80 + 2 * n) stop(); +#ifndef NO_REAL_EXPORT + if (e_real_t() != 1.0 * (2 * n) + 0.5) stop(); +#endif +#ifndef NO_SHORTREAL + if (e_shortreal_t() != 1.0f * (2 * n) + 0.25f) stop(); +#endif + if (e_chandle_t() != NULL) stop(); + if (n % 2 == 0) { + if (strcmp(e_string_t(), "Hello") != 0) stop(); + } else { + if (strcmp(e_string_t(), "World") != 0) stop(); + } + if (e_bit_t() != n % 2) stop(); + if (e_logic_t() != !(n % 2)) stop(); + +#ifndef NO_ARRAY + // 2-state packed arrays of width <= 32 + if (e_array_2_state_1() != n % 2) stop(); + if (e_array_2_state_32() != 0xffffffff >> n) stop(); +#endif + +#ifndef NO_STRUCT_OR_UNION + // 2-state packed structures of width <= 32 + if (e_struct_2_state_1() != n % 2) stop(); + if (e_struct_2_state_32() != 0xffffffff >> n) stop(); + + // 2-state packed unions of width <= 32 + if (e_union_2_state_1() != n % 2) stop(); + if (e_union_2_state_32() != 0xffffffff >> n) stop(); +#endif + + n++; +} diff --git a/test_regress/t/t_dpi_result_type.out b/test_regress/t/t_dpi_result_type.out new file mode 100644 index 000000000..9cfc62e10 --- /dev/null +++ b/test_regress/t/t_dpi_result_type.out @@ -0,0 +1,91 @@ +i_void 0 +i_chandle 0 +i_string 0 +i_bit 0 +i_logic 0 +i_chandle_t 0 +i_string_t 0 +i_bit_t 0 +i_logic_t 0 +i_array_2_state_1 0 +i_array_2_state_32 0 +i_struct_2_state_1 0 +i_struct_2_state_32 0 +i_union_2_state_1 0 +i_union_2_state_32 0 +e_void 0 +e_chandle 0 +e_string 0 +e_bit 0 +e_logic 0 +e_chandle_t 0 +e_string_t 0 +e_bit_t 0 +e_logic_t 0 +e_array_2_state_1 0 +e_array_2_state_32 0 +e_struct_2_state_1 0 +e_struct_2_state_32 0 +e_union_2_state_1 0 +e_union_2_state_32 0 +i_void 1 +i_chandle 1 +i_string 1 +i_bit 1 +i_logic 1 +i_chandle_t 1 +i_string_t 1 +i_bit_t 1 +i_logic_t 1 +i_array_2_state_1 1 +i_array_2_state_32 1 +i_struct_2_state_1 1 +i_struct_2_state_32 1 +i_union_2_state_1 1 +i_union_2_state_32 1 +e_void 1 +e_chandle 1 +e_string 1 +e_bit 1 +e_logic 1 +e_chandle_t 1 +e_string_t 1 +e_bit_t 1 +e_logic_t 1 +e_array_2_state_1 1 +e_array_2_state_32 1 +e_struct_2_state_1 1 +e_struct_2_state_32 1 +e_union_2_state_1 1 +e_union_2_state_32 1 +i_void 2 +i_chandle 2 +i_string 2 +i_bit 2 +i_logic 2 +i_chandle_t 2 +i_string_t 2 +i_bit_t 2 +i_logic_t 2 +i_array_2_state_1 2 +i_array_2_state_32 2 +i_struct_2_state_1 2 +i_struct_2_state_32 2 +i_union_2_state_1 2 +i_union_2_state_32 2 +e_void 2 +e_chandle 2 +e_string 2 +e_bit 2 +e_logic 2 +e_chandle_t 2 +e_string_t 2 +e_bit_t 2 +e_logic_t 2 +e_array_2_state_1 2 +e_array_2_state_32 2 +e_struct_2_state_1 2 +e_struct_2_state_32 2 +e_union_2_state_1 2 +e_union_2_state_32 2 +*-* All Finished *-* diff --git a/test_regress/t/t_dpi_result_type.pl b/test_regress/t/t_dpi_result_type.pl new file mode 100755 index 000000000..b876371e8 --- /dev/null +++ b/test_regress/t/t_dpi_result_type.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Geza Lore. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if ($Self->{nc}) { + # For NC, compile twice, first just to generate DPI headers + compile( + nc_flags2 => ["+ncdpiheader+$Self->{obj_dir}/dpi-exp.h", + "+ncdpiimpheader+$Self->{obj_dir}/dpi-imp.h"] + ); +} + +compile( + v_flags2 => ["t/t_dpi_result_type.cpp"], + verilator_flags2 => ["-Wall -Wno-DECLFILENAME"], + # NC: Gdd the obj_dir to the C include path + nc_flags2 => ["+ncscargs+-I$Self->{obj_dir}"], + # ModelSim: Generate DPI header, add obj_dir to the C include path + ms_flags2 => ["-dpiheader $Self->{obj_dir}/dpi.h", + "-ccflags -I$Self->{obj_dir}"], + ); + +if ($Self->{vlt_all}) { + files_identical( + "$Self->{obj_dir}/Vt_dpi_result_type__Dpi.h", + "t/t_dpi_result_type__Dpi.out" + ); +} + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ms_pli => 0 + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_result_type.v b/test_regress/t/t_dpi_result_type.v new file mode 100644 index 000000000..5f777e368 --- /dev/null +++ b/test_regress/t/t_dpi_result_type.v @@ -0,0 +1,520 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +`ifdef VCS + `define NO_REAL_EXPORT +`endif + +`ifdef NC + `define NO_STRUCT_OR_UNION + `define NO_SHORTREAL +`endif + +`ifdef MS + `define NO_STRUCT_OR_UNION + `define NO_ARRAY +`endif + +`ifdef VERILATOR + `define NO_SHORTREAL + `define NULL 64'd0 +`else + `define NULL null +`endif + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + +`ifdef VERILATOR + wire _unused = &{1'b0, clk}; +`endif + + // Legal result types for DPI functions + + //====================================================================== + // Type definitions + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.5 + typedef byte byte_t; + typedef byte unsigned byte_unsigned_t; + typedef shortint shortint_t; + typedef shortint unsigned shortint_unsigned_t; + typedef int int_t; + typedef int unsigned int_unsigned_t; + typedef longint longint_t; + typedef longint unsigned longint_unsigned_t; + typedef real real_t; +`ifndef NO_SHORTREAL + typedef shortreal shortreal_t; +`endif + typedef chandle chandle_t; + typedef string string_t; + typedef bit bit_t; + typedef logic logic_t; + + // 2-state packed structures of width <= 32 + typedef struct packed { bit x; } struct_2_state_1; + typedef struct packed { bit [15:0] x; bit [15:0] y; } struct_2_state_32; + + // 2-state packed unions of width <= 32 + typedef union packed { bit x; bit y; } union_2_state_1; + typedef union packed { bit [31:0] x; bit [31:0] y; } union_2_state_32; + + //====================================================================== + // Imports + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.5 + import "DPI-C" function void i_void (); + import "DPI-C" function byte i_byte (); + import "DPI-C" function byte unsigned i_byte_unsigned (); + import "DPI-C" function shortint i_shortint (); + import "DPI-C" function shortint unsigned i_shortint_unsigned (); + import "DPI-C" function int i_int (); + import "DPI-C" function int unsigned i_int_unsigned (); + import "DPI-C" function longint i_longint (); + import "DPI-C" function longint unsigned i_longint_unsigned (); + import "DPI-C" function real i_real (); +`ifndef NO_SHORTREAL + import "DPI-C" function shortreal i_shortreal (); +`endif + import "DPI-C" function chandle i_chandle (); + import "DPI-C" function string i_string (); + import "DPI-C" function bit i_bit (); + import "DPI-C" function logic i_logic (); + + // Basic types via typedef + import "DPI-C" function byte_t i_byte_t (); + import "DPI-C" function byte_unsigned_t i_byte_unsigned_t (); + import "DPI-C" function shortint_t i_shortint_t (); + import "DPI-C" function shortint_unsigned_t i_shortint_unsigned_t (); + import "DPI-C" function int_t i_int_t (); + import "DPI-C" function int_unsigned_t i_int_unsigned_t (); + import "DPI-C" function longint_t i_longint_t (); + import "DPI-C" function longint_unsigned_t i_longint_unsigned_t (); + import "DPI-C" function real_t i_real_t (); +`ifndef NO_SHORTREAL + import "DPI-C" function shortreal_t i_shortreal_t (); +`endif + import "DPI-C" function chandle_t i_chandle_t (); + import "DPI-C" function string_t i_string_t (); + import "DPI-C" function bit_t i_bit_t (); + import "DPI-C" function logic_t i_logic_t (); + +`ifndef NO_ARRAY + // 2-state packed arrays of width <= 32 + import "DPI-C" function bit [ 0:0] i_array_2_state_1 (); + import "DPI-C" function bit [31:0] i_array_2_state_32 (); +`endif + +`ifndef NO_STRUCT_OR_UNION + // 2-state packed structures of width <= 32 + import "DPI-C" function struct_2_state_1 i_struct_2_state_1 (); + import "DPI-C" function struct_2_state_32 i_struct_2_state_32(); + + // 2-state packed unions of width <= 32 + import "DPI-C" function union_2_state_1 i_union_2_state_1 (); + import "DPI-C" function union_2_state_32 i_union_2_state_32(); +`endif + + //====================================================================== + // Exports + //====================================================================== + + // Basic types as per IEEE 1800-2017 35.5.5 + export "DPI-C" function e_void; + export "DPI-C" function e_byte; + export "DPI-C" function e_byte_unsigned; + export "DPI-C" function e_shortint; + export "DPI-C" function e_shortint_unsigned; + export "DPI-C" function e_int; + export "DPI-C" function e_int_unsigned; + export "DPI-C" function e_longint; + export "DPI-C" function e_longint_unsigned; +`ifndef NO_REAL_EXPORT + export "DPI-C" function e_real; +`endif +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal; +`endif + export "DPI-C" function e_chandle; + export "DPI-C" function e_string; + export "DPI-C" function e_bit; + export "DPI-C" function e_logic; + + // Basic types via typedef + export "DPI-C" function e_byte_t; + export "DPI-C" function e_byte_unsigned_t; + export "DPI-C" function e_shortint_t; + export "DPI-C" function e_shortint_unsigned_t; + export "DPI-C" function e_int_t; + export "DPI-C" function e_int_unsigned_t; + export "DPI-C" function e_longint_t; + export "DPI-C" function e_longint_unsigned_t; +`ifndef NO_REAL_EXPORT + export "DPI-C" function e_real_t; +`endif +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal_t; +`endif + export "DPI-C" function e_chandle_t; + export "DPI-C" function e_string_t; + export "DPI-C" function e_bit_t; + export "DPI-C" function e_logic_t; + +`ifndef NO_ARRAY + // 2-state packed arrays of width <= 32 + export "DPI-C" function e_array_2_state_1; + export "DPI-C" function e_array_2_state_32; +`endif + +`ifndef NO_STRUCT_OR_UNION + // 2-state packed structures of width <= 32 + export "DPI-C" function e_struct_2_state_1; + export "DPI-C" function e_struct_2_state_32; + + // 2-state packed unions of width <= 32 + export "DPI-C" function e_union_2_state_1; + export "DPI-C" function e_union_2_state_32; +`endif + + //====================================================================== + // Definitions of exported functions + //====================================================================== + + // Static variables (Note: Verilator strangely assumes everything inside + // a function is automatic, which is exactly the opposite of the standard + // see IEEE 1800-2017 13.3.1 and 13.4.2 + + // Basic types as per IEEE 1800-2017 35.5.5 + int n_void = 0; + function void e_void(); + $display("e_void %1d", n_void); + n_void++; + endfunction + + byte n_byte = 0; + function byte e_byte(); + e_byte = 8'd10 + n_byte; + n_byte++; + endfunction + + byte n_byte_unsigned = 0; + function byte unsigned e_byte_unsigned(); + e_byte_unsigned = 8'd20 + n_byte_unsigned; + n_byte_unsigned++; + endfunction + + shortint n_shortint = 0; + function shortint e_shortint(); + e_shortint = 16'd30 + n_shortint; + n_shortint++; + endfunction + + shortint n_shortint_unsigned = 0; + function shortint unsigned e_shortint_unsigned(); + e_shortint_unsigned = 16'd40 + n_shortint_unsigned; + n_shortint_unsigned++; + endfunction + + int n_int = 0; + function int e_int(); + e_int = 32'd50 + n_int; + n_int++; + endfunction + + int n_int_unsigned = 0; + function int unsigned e_int_unsigned(); + e_int_unsigned = 32'd60 + n_int_unsigned; + n_int_unsigned++; + endfunction + + longint n_longint = 0; + function longint e_longint(); + e_longint = 64'd70 + n_longint; + n_longint++; + endfunction + + longint n_longint_unsigned = 0; + function longint unsigned e_longint_unsigned(); + e_longint_unsigned = 64'd80 + n_longint_unsigned; + n_longint_unsigned++; + endfunction + +`ifndef NO_REAL_EXPORT + int n_real = 0; + function real e_real(); + e_real = real'(2*n_real + 1) / 2.0; + n_real++; + endfunction +`endif + +`ifndef NO_SHORTREAL + int n_shortreal = 0; + function shortreal e_shortreal(); + e_shortreal = shortreal'(4*n_shortreal + 1)/ 4.0; + n_shortreal++; + endfunction +`endif + + int n_chandle = 0; + function chandle e_chandle(); + $display("e_chandle %1d", n_chandle); + e_chandle = `NULL; + n_chandle++; + endfunction + + int n_string = 0; + function string e_string(); + $display("e_string %1d", n_string); + e_string = n_string[0] ? "World" : "Hello"; + n_string++; + endfunction + + int n_bit = 0; + function bit e_bit(); + $display("e_bit %1d", n_bit); + e_bit = n_bit[0]; + n_bit++; + endfunction + + int n_logic = 0; + function logic e_logic(); + $display("e_logic %1d", n_logic); + e_logic = ~n_logic[0]; + n_logic++; + endfunction + + // Basic types via typedefs + byte_t n_byte_t = 0; + function byte_t e_byte_t(); + e_byte_t = 8'd10 + n_byte_t; + n_byte_t += 2; + endfunction + + byte n_byte_unsigned_t = 0; + function byte_unsigned_t e_byte_unsigned_t(); + e_byte_unsigned_t = 8'd20 + n_byte_unsigned_t; + n_byte_unsigned_t += 2; + endfunction + + shortint_t n_shortint_t = 0; + function shortint_t e_shortint_t(); + e_shortint_t = 16'd30 + n_shortint_t; + n_shortint_t += 2; + endfunction + + shortint n_shortint_unsigned_t = 0; + function shortint_unsigned_t e_shortint_unsigned_t(); + e_shortint_unsigned_t = 16'd40 + n_shortint_unsigned_t; + n_shortint_unsigned_t += 2; + endfunction + + int_t n_int_t = 0; + function int_t e_int_t(); + e_int_t = 32'd50 + n_int_t; + n_int_t += 2; + endfunction + + int n_int_unsigned_t = 0; + function int_unsigned_t e_int_unsigned_t(); + e_int_unsigned_t = 32'd60 + n_int_unsigned_t; + n_int_unsigned_t += 2; + endfunction + + longint_t n_longint_t = 0; + function longint_t e_longint_t(); + e_longint_t = 64'd70 + n_longint_t; + n_longint_t += 2; + endfunction + + longint n_longint_unsigned_t = 0; + function longint_unsigned_t e_longint_unsigned_t(); + e_longint_unsigned_t = 64'd80 + n_longint_unsigned_t; + n_longint_unsigned_t += 2; + endfunction + +`ifndef NO_REAL_EXPORT + int n_real_t = 0; + function real_t e_real_t(); + e_real_t = real'(2*n_real_t + 1) / 2.0; + n_real_t += 2; + endfunction +`endif + +`ifndef NO_SHORTREAL + int n_shortreal_t = 0; + function shortreal_t e_shortreal_t(); + e_shortreal_t = shortreal'(4*n_shortreal_t + 1)/ 4.0; + n_shortreal_t += 2; + endfunction +`endif + + int n_chandle_t = 0; + function chandle_t e_chandle_t(); + $display("e_chandle_t %1d", n_chandle_t); + e_chandle_t = `NULL; + n_chandle_t++; + endfunction + + int n_string_t = 0; + function string_t e_string_t(); + $display("e_string_t %1d", n_string_t); + e_string_t = n_string_t[0] ? "World" : "Hello"; + n_string_t++; + endfunction + + int n_bit_t = 0; + function bit_t e_bit_t(); + $display("e_bit_t %1d", n_bit_t); + e_bit_t = n_bit_t[0]; + n_bit_t++; + endfunction + + int n_logic_t = 0; + function logic_t e_logic_t(); + $display("e_logic_t %1d", n_logic_t); + e_logic_t = ~n_logic_t[0]; + n_logic_t++; + endfunction + +`ifndef NO_ARRAY + // 2-state packed arrays of width <= 32 + int n_array_2_state_1 = 0; + function bit [ 0:0] e_array_2_state_1(); + $display("e_array_2_state_1 %1d", n_array_2_state_1); + e_array_2_state_1 = n_array_2_state_1[0]; + n_array_2_state_1++; + endfunction + + int n_array_2_state_32 = 0; + function bit [31:0] e_array_2_state_32(); + $display("e_array_2_state_32 %1d", n_array_2_state_32); + e_array_2_state_32 = ~32'd0 >> n_array_2_state_32; + n_array_2_state_32++; + endfunction +`endif + +`ifndef NO_STRUCT_OR_UNION + // 2-state packed structures of width <= 32 + int n_struct_2_state_1 = 0; + function struct_2_state_1 e_struct_2_state_1(); + $display("e_struct_2_state_1 %1d", n_struct_2_state_1); + e_struct_2_state_1 = n_struct_2_state_1[0]; + n_struct_2_state_1++; + endfunction + + int n_struct_2_state_32 = 0; + function struct_2_state_32 e_struct_2_state_32(); + $display("e_struct_2_state_32 %1d", n_struct_2_state_32); + e_struct_2_state_32 = ~32'd0 >> n_struct_2_state_32; + n_struct_2_state_32++; + endfunction + + // 2-state packed unions of width <= 32 + int n_union_2_state_1 = 0; + function union_2_state_1 e_union_2_state_1(); + $display("e_union_2_state_1 %1d", n_union_2_state_1); + e_union_2_state_1 = n_union_2_state_1[0]; + n_union_2_state_1++; + endfunction + + int n_union_2_state_32 = 0; + function union_2_state_32 e_union_2_state_32(); + $display("e_union_2_state_32 %1d", n_union_2_state_32); + e_union_2_state_32 = ~32'd0 >> n_union_2_state_32; + n_union_2_state_32++; + endfunction +`endif + + //====================================================================== + // Invoke all functions 3 times (they have side effects) + //====================================================================== + + import "DPI-C" context function void check_exports(); + + initial begin + for (int i = 0 ; i < 3; i++) begin + // Check the imports + + // Basic types as per IEEE 1800-2017 35.5.5 + i_void(); + if (i_byte() !== 8'd10 - 8'(i)) $stop; + if (i_byte_unsigned() !== 8'd20 - 8'(i)) $stop; + if (i_shortint() !== 16'd30 - 16'(i)) $stop; + if (i_shortint_unsigned() !== 16'd40 - 16'(i)) $stop; + if (i_int() !== 32'd50 - 32'(i)) $stop; + if (i_int_unsigned() !== 32'd60 - 32'(i)) $stop; + if (i_longint() !== 64'd70 - 64'(i)) $stop; + if (i_longint_unsigned() !== 64'd80 - 64'(i)) $stop; + if (i_real() != -1.0*i - 0.5 ) $stop; +`ifndef NO_SHORTREAL + if (i_shortreal() != -1.0*i - 0.25) $stop; +`endif + if (~i[0]) begin + if (i_chandle() !== `NULL) $stop; + if (i_string() != "World") $stop; + end else begin + if (i_chandle() === `NULL) $stop; + if (i_string() != "Hello") $stop; + end + if (i_bit() !== ~i[0]) $stop; + if (i_logic() !== i[0]) $stop; + + // Basic types via typedefs + if (i_byte_t() !== 8'd10 - 8'(2*i)) $stop; + if (i_byte_unsigned_t() !== 8'd20 - 8'(2*i)) $stop; + if (i_shortint_t() !== 16'd30 - 16'(2*i)) $stop; + if (i_shortint_unsigned_t() !== 16'd40 - 16'(2*i)) $stop; + if (i_int_t() !== 32'd50 - 32'(2*i)) $stop; + if (i_int_unsigned_t() !== 32'd60 - 32'(2*i)) $stop; + if (i_longint_t() !== 64'd70 - 64'(2*i)) $stop; + if (i_longint_unsigned_t() !== 64'd80 - 64'(2*i)) $stop; + if (i_real_t() != -1.0*(2*i) - 0.5 ) $stop; +`ifndef NO_SHORTREAL + if (i_shortreal_t() != -1.0*(2*i) - 0.25) $stop; +`endif + if (~i[0]) begin + if (i_chandle_t() !== `NULL) $stop; + if (i_string_t() != "World") $stop; + end else begin + if (i_chandle_t() === `NULL) $stop; + if (i_string_t() != "Hello") $stop; + end + if (i_bit_t() !== ~i[0]) $stop; + if (i_logic_t() !== i[0]) $stop; + +`ifndef NO_ARRAY + // 2-state packed arrays of width <= 32 + if (i_array_2_state_1() !== ~i[0] ) $stop; + if (i_array_2_state_32() !== ~32'd0 << i) $stop; +`endif + +`ifndef NO_STRUCT_OR_UNION + // 2-state packed structures of width <= 32 + if (i_struct_2_state_1() !== ~i[0] ) $stop; + if (i_struct_2_state_32() !== ~32'd0 << i) $stop; + + // 2-state packed unions of width <= 32 + if (i_union_2_state_1() !== ~i[0] ) $stop; + if (i_union_2_state_32() !== ~32'd0 << i) $stop; +`endif + + // Check the exports + check_exports(); + end + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_dpi_result_type__Dpi.out b/test_regress/t/t_dpi_result_type__Dpi.out new file mode 100644 index 000000000..680a6d05c --- /dev/null +++ b/test_regress/t/t_dpi_result_type__Dpi.out @@ -0,0 +1,155 @@ +// Verilated -*- C++ -*- +// DESCRIPTION: Verilator output: Prototypes for DPI import and export functions. +// +// Verilator includes this file in all generated .cpp files that use DPI functions. +// Manually include this file where DPI .c import functions are declared to ensure +// the C functions match the expectations of the DPI imports. + +#include "svdpi.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + // DPI EXPORTS + // DPI export at t/t_dpi_result_type.v:393:24 + extern svBitVecVal e_array_2_state_1(); + // DPI export at t/t_dpi_result_type.v:400:24 + extern svBitVecVal e_array_2_state_32(); + // DPI export at t/t_dpi_result_type.v:284:17 + extern svBit e_bit(); + // DPI export at t/t_dpi_result_type.v:377:19 + extern svBit e_bit_t(); + // DPI export at t/t_dpi_result_type.v:206:18 + extern char e_byte(); + // DPI export at t/t_dpi_result_type.v:299:20 + extern char e_byte_t(); + // DPI export at t/t_dpi_result_type.v:212:27 + extern unsigned char e_byte_unsigned(); + // DPI export at t/t_dpi_result_type.v:305:29 + extern unsigned char e_byte_unsigned_t(); + // DPI export at t/t_dpi_result_type.v:270:21 + extern void* e_chandle(); + // DPI export at t/t_dpi_result_type.v:363:23 + extern void* e_chandle_t(); + // DPI export at t/t_dpi_result_type.v:230:17 + extern int e_int(); + // DPI export at t/t_dpi_result_type.v:323:19 + extern int e_int_t(); + // DPI export at t/t_dpi_result_type.v:236:26 + extern unsigned int e_int_unsigned(); + // DPI export at t/t_dpi_result_type.v:329:28 + extern unsigned int e_int_unsigned_t(); + // DPI export at t/t_dpi_result_type.v:291:19 + extern svLogic e_logic(); + // DPI export at t/t_dpi_result_type.v:384:21 + extern svLogic e_logic_t(); + // DPI export at t/t_dpi_result_type.v:242:21 + extern long long e_longint(); + // DPI export at t/t_dpi_result_type.v:335:23 + extern long long e_longint_t(); + // DPI export at t/t_dpi_result_type.v:248:30 + extern unsigned long long e_longint_unsigned(); + // DPI export at t/t_dpi_result_type.v:341:32 + extern unsigned long long e_longint_unsigned_t(); + // DPI export at t/t_dpi_result_type.v:255:18 + extern double e_real(); + // DPI export at t/t_dpi_result_type.v:348:20 + extern double e_real_t(); + // DPI export at t/t_dpi_result_type.v:218:22 + extern short e_shortint(); + // DPI export at t/t_dpi_result_type.v:311:24 + extern short e_shortint_t(); + // DPI export at t/t_dpi_result_type.v:224:31 + extern unsigned short e_shortint_unsigned(); + // DPI export at t/t_dpi_result_type.v:317:33 + extern unsigned short e_shortint_unsigned_t(); + // DPI export at t/t_dpi_result_type.v:277:20 + extern const char* e_string(); + // DPI export at t/t_dpi_result_type.v:370:22 + extern const char* e_string_t(); + // DPI export at t/t_dpi_result_type.v:410:30 + extern svBitVecVal e_struct_2_state_1(); + // DPI export at t/t_dpi_result_type.v:417:32 + extern svBitVecVal e_struct_2_state_32(); + // DPI export at t/t_dpi_result_type.v:425:29 + extern svBitVecVal e_union_2_state_1(); + // DPI export at t/t_dpi_result_type.v:432:30 + extern svBitVecVal e_union_2_state_32(); + // DPI export at t/t_dpi_result_type.v:200:18 + extern void e_void(); + + // DPI IMPORTS + // DPI import at t/t_dpi_result_type.v:443:41 + extern void check_exports(); + // DPI import at t/t_dpi_result_type.v:115:39 + extern svBitVecVal i_array_2_state_1(); + // DPI import at t/t_dpi_result_type.v:116:39 + extern svBitVecVal i_array_2_state_32(); + // DPI import at t/t_dpi_result_type.v:92:46 + extern svBit i_bit(); + // DPI import at t/t_dpi_result_type.v:110:48 + extern svBit i_bit_t(); + // DPI import at t/t_dpi_result_type.v:78:46 + extern char i_byte(); + // DPI import at t/t_dpi_result_type.v:96:48 + extern char i_byte_t(); + // DPI import at t/t_dpi_result_type.v:79:46 + extern unsigned char i_byte_unsigned(); + // DPI import at t/t_dpi_result_type.v:97:48 + extern unsigned char i_byte_unsigned_t(); + // DPI import at t/t_dpi_result_type.v:90:46 + extern void* i_chandle(); + // DPI import at t/t_dpi_result_type.v:108:48 + extern void* i_chandle_t(); + // DPI import at t/t_dpi_result_type.v:82:46 + extern int i_int(); + // DPI import at t/t_dpi_result_type.v:100:48 + extern int i_int_t(); + // DPI import at t/t_dpi_result_type.v:83:46 + extern unsigned int i_int_unsigned(); + // DPI import at t/t_dpi_result_type.v:101:48 + extern unsigned int i_int_unsigned_t(); + // DPI import at t/t_dpi_result_type.v:93:46 + extern svLogic i_logic(); + // DPI import at t/t_dpi_result_type.v:111:48 + extern svLogic i_logic_t(); + // DPI import at t/t_dpi_result_type.v:84:46 + extern long long i_longint(); + // DPI import at t/t_dpi_result_type.v:102:48 + extern long long i_longint_t(); + // DPI import at t/t_dpi_result_type.v:85:46 + extern unsigned long long i_longint_unsigned(); + // DPI import at t/t_dpi_result_type.v:103:48 + extern unsigned long long i_longint_unsigned_t(); + // DPI import at t/t_dpi_result_type.v:86:46 + extern double i_real(); + // DPI import at t/t_dpi_result_type.v:104:48 + extern double i_real_t(); + // DPI import at t/t_dpi_result_type.v:80:46 + extern short i_shortint(); + // DPI import at t/t_dpi_result_type.v:98:48 + extern short i_shortint_t(); + // DPI import at t/t_dpi_result_type.v:81:46 + extern unsigned short i_shortint_unsigned(); + // DPI import at t/t_dpi_result_type.v:99:48 + extern unsigned short i_shortint_unsigned_t(); + // DPI import at t/t_dpi_result_type.v:91:46 + extern const char* i_string(); + // DPI import at t/t_dpi_result_type.v:109:48 + extern const char* i_string_t(); + // DPI import at t/t_dpi_result_type.v:121:47 + extern svBitVecVal i_struct_2_state_1(); + // DPI import at t/t_dpi_result_type.v:122:47 + extern svBitVecVal i_struct_2_state_32(); + // DPI import at t/t_dpi_result_type.v:125:46 + extern svBitVecVal i_union_2_state_1(); + // DPI import at t/t_dpi_result_type.v:126:46 + extern svBitVecVal i_union_2_state_32(); + // DPI import at t/t_dpi_result_type.v:77:46 + extern void i_void(); + +#ifdef __cplusplus +} +#endif diff --git a/test_regress/t/t_dpi_result_type_bad.out b/test_regress/t/t_dpi_result_type_bad.out new file mode 100644 index 000000000..b95b58dc6 --- /dev/null +++ b/test_regress/t/t_dpi_result_type_bad.out @@ -0,0 +1,399 @@ +%Error: t/t_dpi_result_type_bad.v:79:40: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 79 | import "DPI-C" function bit [ 32:0] i_array_2_state_33(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:80:40: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 80 | import "DPI-C" function bit [ 63:0] i_array_2_state_64(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:81:40: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 81 | import "DPI-C" function bit [ 64:0] i_array_2_state_65(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:82:40: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 82 | import "DPI-C" function bit [127:0] i_array_2_state_128(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:85:48: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 85 | import "DPI-C" function array_2_state_33_t i_array_2_state_33_t(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:86:48: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 86 | import "DPI-C" function array_2_state_64_t i_array_2_state_64_t(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:87:48: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 87 | import "DPI-C" function array_2_state_65_t i_array_2_state_65_t(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:88:48: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 88 | import "DPI-C" function array_2_state_128_t i_array_2_state_128_t(); + | ^~~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:91:47: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 91 | import "DPI-C" function struct_2_state_33 i_struct_2_state_33(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:92:47: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 92 | import "DPI-C" function struct_2_state_64 i_struct_2_state_64(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:93:47: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 93 | import "DPI-C" function struct_2_state_65 i_struct_2_state_65(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:94:47: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 94 | import "DPI-C" function struct_2_state_128 i_struct_2_state_128(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:97:46: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 97 | import "DPI-C" function union_2_state_33 i_union_2_state_33(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:98:46: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 98 | import "DPI-C" function union_2_state_64 i_union_2_state_64(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:99:46: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 99 | import "DPI-C" function union_2_state_65 i_union_2_state_65(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:100:46: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 100 | import "DPI-C" function union_2_state_128 i_union_2_state_128(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:103:36: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 103 | import "DPI-C" function integer i_integer(); + | ^~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:106:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 106 | import "DPI-C" function logic [ 0:0] i_array_4_state_1(); + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:107:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 107 | import "DPI-C" function logic [ 1:0] i_array_4_state_2(); + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:108:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 108 | import "DPI-C" function logic [ 7:0] i_array_4_state_8(); + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:109:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 109 | import "DPI-C" function logic [ 8:0] i_array_4_state_9(); + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:110:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 110 | import "DPI-C" function logic [ 15:0] i_array_4_state_16(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:111:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 111 | import "DPI-C" function logic [ 16:0] i_array_4_state_17(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:112:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 112 | import "DPI-C" function logic [ 31:0] i_array_4_state_32(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:113:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 113 | import "DPI-C" function logic [ 32:0] i_array_4_state_33(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:114:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 114 | import "DPI-C" function logic [ 63:0] i_array_4_state_64(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:115:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 115 | import "DPI-C" function logic [ 64:0] i_array_4_state_65(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:116:42: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 116 | import "DPI-C" function logic [127:0] i_array_4_state_128(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:119:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 119 | import "DPI-C" function array_4_state_1_t i_array_4_state_1_t(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:120:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 120 | import "DPI-C" function array_4_state_2_t i_array_4_state_2_t(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:121:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 121 | import "DPI-C" function array_4_state_8_t i_array_4_state_8_t(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:122:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 122 | import "DPI-C" function array_4_state_9_t i_array_4_state_9_t(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:123:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 123 | import "DPI-C" function array_4_state_16_t i_array_4_state_16_t(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:124:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 124 | import "DPI-C" function array_4_state_17_t i_array_4_state_17_t(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:125:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 125 | import "DPI-C" function array_4_state_32_t i_array_4_state_32_t(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:126:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 126 | import "DPI-C" function array_4_state_33_t i_array_4_state_33_t(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:127:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 127 | import "DPI-C" function array_4_state_64_t i_array_4_state_64_t(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:128:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 128 | import "DPI-C" function array_4_state_65_t i_array_4_state_65_t(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:129:48: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 129 | import "DPI-C" function array_4_state_128_t i_array_4_state_128_t(); + | ^~~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:132:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 132 | import "DPI-C" function struct_4_state_1 i_struct_4_state_1(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:133:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 133 | import "DPI-C" function struct_4_state_2 i_struct_4_state_2(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:134:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 134 | import "DPI-C" function struct_4_state_8 i_struct_4_state_8(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:135:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 135 | import "DPI-C" function struct_4_state_9 i_struct_4_state_9(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:136:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 136 | import "DPI-C" function struct_4_state_16 i_struct_4_state_16(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:137:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 137 | import "DPI-C" function struct_4_state_17 i_struct_4_state_17(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:138:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 138 | import "DPI-C" function struct_4_state_32 i_struct_4_state_32(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:139:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 139 | import "DPI-C" function struct_4_state_33 i_struct_4_state_33(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:140:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 140 | import "DPI-C" function struct_4_state_64 i_struct_4_state_64(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:141:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 141 | import "DPI-C" function struct_4_state_65 i_struct_4_state_65(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:142:47: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 142 | import "DPI-C" function struct_4_state_128 i_struct_4_state_128(); + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:145:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 145 | import "DPI-C" function union_4_state_1 i_union_4_state_1(); + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:146:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 146 | import "DPI-C" function union_4_state_2 i_union_4_state_2(); + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:147:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 147 | import "DPI-C" function union_4_state_8 i_union_4_state_8(); + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:148:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 148 | import "DPI-C" function union_4_state_9 i_union_4_state_9(); + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:149:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 149 | import "DPI-C" function union_4_state_16 i_union_4_state_16(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:150:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 150 | import "DPI-C" function union_4_state_17 i_union_4_state_17(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:151:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 151 | import "DPI-C" function union_4_state_32 i_union_4_state_32(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:152:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 152 | import "DPI-C" function union_4_state_33 i_union_4_state_33(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:153:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 153 | import "DPI-C" function union_4_state_64 i_union_4_state_64(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:154:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 154 | import "DPI-C" function union_4_state_65 i_union_4_state_65(); + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:155:46: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 155 | import "DPI-C" function union_4_state_128 i_union_4_state_128(); + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:245:25: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 245 | function bit [ 32:0] e_array_2_state_33(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:246:25: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 246 | function bit [ 63:0] e_array_2_state_64(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:247:25: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 247 | function bit [ 64:0] e_array_2_state_65(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:248:25: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 248 | function bit [127:0] e_array_2_state_128(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:251:33: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 251 | function array_2_state_33_t e_array_2_state_33_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:252:33: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 252 | function array_2_state_64_t e_array_2_state_64_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:253:33: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 253 | function array_2_state_65_t e_array_2_state_65_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:254:33: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 254 | function array_2_state_128_t e_array_2_state_128_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:257:32: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 257 | function struct_2_state_33 e_struct_2_state_33(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:258:32: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 258 | function struct_2_state_64 e_struct_2_state_64(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:259:32: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 259 | function struct_2_state_65 e_struct_2_state_65(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:260:32: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 260 | function struct_2_state_128 e_struct_2_state_128(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:263:31: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 263 | function union_2_state_33 e_union_2_state_33(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:264:31: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 264 | function union_2_state_64 e_union_2_state_64(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:265:31: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 265 | function union_2_state_65 e_union_2_state_65(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:266:31: DPI function may not return a > 32 bits wide type other than basic types. + ... Suggest make it an output argument instead? + 266 | function union_2_state_128 e_union_2_state_128(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:269:21: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 269 | function integer e_integer(); return 0; endfunction + | ^~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:272:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 272 | function logic [ 0:0] e_array_4_state_1(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:273:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 273 | function logic [ 1:0] e_array_4_state_2(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:274:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 274 | function logic [ 7:0] e_array_4_state_8(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:275:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 275 | function logic [ 8:0] e_array_4_state_9(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:276:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 276 | function logic [ 15:0] e_array_4_state_16(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:277:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 277 | function logic [ 16:0] e_array_4_state_17(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:278:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 278 | function logic [ 31:0] e_array_4_state_32(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:279:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 279 | function logic [ 32:0] e_array_4_state_33(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:280:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 280 | function logic [ 63:0] e_array_4_state_64(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:281:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 281 | function logic [ 64:0] e_array_4_state_65(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:282:27: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 282 | function logic [127:0] e_array_4_state_128(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:285:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 285 | function array_4_state_1_t e_array_4_state_1_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:286:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 286 | function array_4_state_2_t e_array_4_state_2_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:287:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 287 | function array_4_state_8_t e_array_4_state_8_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:288:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 288 | function array_4_state_9_t e_array_4_state_9_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:289:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 289 | function array_4_state_16_t e_array_4_state_16_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:290:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 290 | function array_4_state_17_t e_array_4_state_17_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:291:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 291 | function array_4_state_32_t e_array_4_state_32_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:292:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 292 | function array_4_state_33_t e_array_4_state_33_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:293:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 293 | function array_4_state_64_t e_array_4_state_64_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:294:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 294 | function array_4_state_65_t e_array_4_state_65_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:295:33: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 295 | function array_4_state_128_t e_array_4_state_128_t(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:298:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 298 | function struct_4_state_1 e_struct_4_state_1(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:299:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 299 | function struct_4_state_2 e_struct_4_state_2(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:300:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 300 | function struct_4_state_8 e_struct_4_state_8(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:301:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 301 | function struct_4_state_9 e_struct_4_state_9(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:302:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 302 | function struct_4_state_16 e_struct_4_state_16(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:303:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 303 | function struct_4_state_17 e_struct_4_state_17(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:304:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 304 | function struct_4_state_32 e_struct_4_state_32(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:305:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 305 | function struct_4_state_33 e_struct_4_state_33(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:306:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 306 | function struct_4_state_64 e_struct_4_state_64(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:307:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 307 | function struct_4_state_65 e_struct_4_state_65(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:308:32: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 308 | function struct_4_state_128 e_struct_4_state_128(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:311:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 311 | function union_4_state_1 e_union_4_state_1(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:312:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 312 | function union_4_state_2 e_union_4_state_2(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:313:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 313 | function union_4_state_8 e_union_4_state_8(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:314:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 314 | function union_4_state_9 e_union_4_state_9(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:315:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 315 | function union_4_state_16 e_union_4_state_16(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:316:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 316 | function union_4_state_17 e_union_4_state_17(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:317:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 317 | function union_4_state_32 e_union_4_state_32(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:318:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 318 | function union_4_state_33 e_union_4_state_33(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:319:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 319 | function union_4_state_64 e_union_4_state_64(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:320:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 320 | function union_4_state_65 e_union_4_state_65(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_dpi_result_type_bad.v:321:31: DPI function may not return a 4-state type other than a single 'logic' (IEEE 1800-2017 35.5.5) + 321 | function union_4_state_128 e_union_4_state_128(); return 0; endfunction + | ^~~~~~~~~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_dpi_exp_bad.pl b/test_regress/t/t_dpi_result_type_bad.pl similarity index 69% rename from test_regress/t/t_dpi_exp_bad.pl rename to test_regress/t/t_dpi_result_type_bad.pl index 67a7abcb0..9979ce572 100755 --- a/test_regress/t/t_dpi_exp_bad.pl +++ b/test_regress/t/t_dpi_result_type_bad.pl @@ -2,8 +2,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2003 by Wilson Snyder. This program is free software; you -# can redistribute it and/or modify it under the terms of either the GNU +# Copyright 2020 by Geza Lore. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 @@ -13,6 +13,7 @@ scenarios(linter => 1); lint( fails => 1, expect_filename => $Self->{golden_filename}, + verilator_flags2 => ["-Wall --error-limit 0"], ); ok(1); diff --git a/test_regress/t/t_dpi_result_type_bad.v b/test_regress/t/t_dpi_result_type_bad.v new file mode 100644 index 000000000..9f5634000 --- /dev/null +++ b/test_regress/t/t_dpi_result_type_bad.v @@ -0,0 +1,322 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +module t_dpi_result_type_bad; + + // Illegal result types for DPI functions + + //====================================================================== + // Type definitions + //====================================================================== + + // 2-state packed arrays of width > 32 + typedef bit [ 32:0] array_2_state_33_t; + typedef bit [ 63:0] array_2_state_64_t; + typedef bit [ 64:0] array_2_state_65_t; + typedef bit [127:0] array_2_state_128_t; + + // 2-state packed structures of width > 32 + typedef struct packed { bit [15:0] x; bit [16:0] y; } struct_2_state_33; + typedef struct packed { bit [31:0] x; bit [31:0] y; } struct_2_state_64; + typedef struct packed { bit [31:0] x; bit [32:0] y; } struct_2_state_65; + typedef struct packed { bit [63:0] x; bit [63:0] y; } struct_2_state_128; + + // 2-state packed unions of width > 32 + typedef union packed { bit [ 32:0] x; bit y; } union_2_state_33; + typedef union packed { bit [ 63:0] x; bit y; } union_2_state_64; + typedef union packed { bit [ 64:0] x; bit y; } union_2_state_65; + typedef union packed { bit [127:0] x; bit y; } union_2_state_128; + + // 4-state packed arrays of any size + typedef logic [ 0:0] array_4_state_1_t; + typedef logic [ 1:0] array_4_state_2_t; + typedef logic [ 7:0] array_4_state_8_t; + typedef logic [ 8:0] array_4_state_9_t; + typedef logic [ 15:0] array_4_state_16_t; + typedef logic [ 16:0] array_4_state_17_t; + typedef logic [ 31:0] array_4_state_32_t; + typedef logic [ 32:0] array_4_state_33_t; + typedef logic [ 63:0] array_4_state_64_t; + typedef logic [ 64:0] array_4_state_65_t; + typedef logic [127:0] array_4_state_128_t; + + // 4-state packed structures of any size + typedef struct packed { logic [ 0:0] x; } struct_4_state_1; + typedef struct packed { logic [ 0:0] x; bit [ 0:0] y; } struct_4_state_2; + typedef struct packed { logic [ 3:0] x; bit [ 3:0] y; } struct_4_state_8; + typedef struct packed { logic [ 3:0] x; bit [ 4:0] y; } struct_4_state_9; + typedef struct packed { logic [ 7:0] x; bit [ 7:0] y; } struct_4_state_16; + typedef struct packed { logic [ 7:0] x; bit [ 8:0] y; } struct_4_state_17; + typedef struct packed { logic [15:0] x; bit [15:0] y; } struct_4_state_32; + typedef struct packed { logic [15:0] x; bit [16:0] y; } struct_4_state_33; + typedef struct packed { logic [31:0] x; bit [31:0] y; } struct_4_state_64; + typedef struct packed { logic [31:0] x; bit [32:0] y; } struct_4_state_65; + typedef struct packed { logic [63:0] x; bit [63:0] y; } struct_4_state_128; + + // 4-state packed unions of any size + typedef union packed { logic [ 0:0] x; bit y; } union_4_state_1; + typedef union packed { logic [ 1:0] x; bit y; } union_4_state_2; + typedef union packed { logic [ 7:0] x; bit y; } union_4_state_8; + typedef union packed { logic [ 8:0] x; bit y; } union_4_state_9; + typedef union packed { logic [ 15:0] x; bit y; } union_4_state_16; + typedef union packed { logic [ 16:0] x; bit y; } union_4_state_17; + typedef union packed { logic [ 31:0] x; bit y; } union_4_state_32; + typedef union packed { logic [ 32:0] x; bit y; } union_4_state_33; + typedef union packed { logic [ 63:0] x; bit y; } union_4_state_64; + typedef union packed { logic [ 64:0] x; bit y; } union_4_state_65; + typedef union packed { logic [127:0] x; bit y; } union_4_state_128; + + //====================================================================== + // Imports + //====================================================================== + + // 2-state packed arrays of width > 32 + import "DPI-C" function bit [ 32:0] i_array_2_state_33(); + import "DPI-C" function bit [ 63:0] i_array_2_state_64(); + import "DPI-C" function bit [ 64:0] i_array_2_state_65(); + import "DPI-C" function bit [127:0] i_array_2_state_128(); + + // 2-state packed arrays of width > 32 via typedef + import "DPI-C" function array_2_state_33_t i_array_2_state_33_t(); + import "DPI-C" function array_2_state_64_t i_array_2_state_64_t(); + import "DPI-C" function array_2_state_65_t i_array_2_state_65_t(); + import "DPI-C" function array_2_state_128_t i_array_2_state_128_t(); + + // 2-state packed structures of width > 32 + import "DPI-C" function struct_2_state_33 i_struct_2_state_33(); + import "DPI-C" function struct_2_state_64 i_struct_2_state_64(); + import "DPI-C" function struct_2_state_65 i_struct_2_state_65(); + import "DPI-C" function struct_2_state_128 i_struct_2_state_128(); + + // 2-state packed unions of width > 32 + import "DPI-C" function union_2_state_33 i_union_2_state_33(); + import "DPI-C" function union_2_state_64 i_union_2_state_64(); + import "DPI-C" function union_2_state_65 i_union_2_state_65(); + import "DPI-C" function union_2_state_128 i_union_2_state_128(); + + // 4-state basic types + import "DPI-C" function integer i_integer(); + + // 4-state packed arrays of any size + import "DPI-C" function logic [ 0:0] i_array_4_state_1(); + import "DPI-C" function logic [ 1:0] i_array_4_state_2(); + import "DPI-C" function logic [ 7:0] i_array_4_state_8(); + import "DPI-C" function logic [ 8:0] i_array_4_state_9(); + import "DPI-C" function logic [ 15:0] i_array_4_state_16(); + import "DPI-C" function logic [ 16:0] i_array_4_state_17(); + import "DPI-C" function logic [ 31:0] i_array_4_state_32(); + import "DPI-C" function logic [ 32:0] i_array_4_state_33(); + import "DPI-C" function logic [ 63:0] i_array_4_state_64(); + import "DPI-C" function logic [ 64:0] i_array_4_state_65(); + import "DPI-C" function logic [127:0] i_array_4_state_128(); + + // 4-state packed arrays of any size via typedef + import "DPI-C" function array_4_state_1_t i_array_4_state_1_t(); + import "DPI-C" function array_4_state_2_t i_array_4_state_2_t(); + import "DPI-C" function array_4_state_8_t i_array_4_state_8_t(); + import "DPI-C" function array_4_state_9_t i_array_4_state_9_t(); + import "DPI-C" function array_4_state_16_t i_array_4_state_16_t(); + import "DPI-C" function array_4_state_17_t i_array_4_state_17_t(); + import "DPI-C" function array_4_state_32_t i_array_4_state_32_t(); + import "DPI-C" function array_4_state_33_t i_array_4_state_33_t(); + import "DPI-C" function array_4_state_64_t i_array_4_state_64_t(); + import "DPI-C" function array_4_state_65_t i_array_4_state_65_t(); + import "DPI-C" function array_4_state_128_t i_array_4_state_128_t(); + + // 4-state packed structures of any size + import "DPI-C" function struct_4_state_1 i_struct_4_state_1(); + import "DPI-C" function struct_4_state_2 i_struct_4_state_2(); + import "DPI-C" function struct_4_state_8 i_struct_4_state_8(); + import "DPI-C" function struct_4_state_9 i_struct_4_state_9(); + import "DPI-C" function struct_4_state_16 i_struct_4_state_16(); + import "DPI-C" function struct_4_state_17 i_struct_4_state_17(); + import "DPI-C" function struct_4_state_32 i_struct_4_state_32(); + import "DPI-C" function struct_4_state_33 i_struct_4_state_33(); + import "DPI-C" function struct_4_state_64 i_struct_4_state_64(); + import "DPI-C" function struct_4_state_65 i_struct_4_state_65(); + import "DPI-C" function struct_4_state_128 i_struct_4_state_128(); + + // 4-state packed unions of any size + import "DPI-C" function union_4_state_1 i_union_4_state_1(); + import "DPI-C" function union_4_state_2 i_union_4_state_2(); + import "DPI-C" function union_4_state_8 i_union_4_state_8(); + import "DPI-C" function union_4_state_9 i_union_4_state_9(); + import "DPI-C" function union_4_state_16 i_union_4_state_16(); + import "DPI-C" function union_4_state_17 i_union_4_state_17(); + import "DPI-C" function union_4_state_32 i_union_4_state_32(); + import "DPI-C" function union_4_state_33 i_union_4_state_33(); + import "DPI-C" function union_4_state_64 i_union_4_state_64(); + import "DPI-C" function union_4_state_65 i_union_4_state_65(); + import "DPI-C" function union_4_state_128 i_union_4_state_128(); + + //====================================================================== + // Exports + //====================================================================== + + // 2-state packed arrays of width > 32 + export "DPI-C" function e_array_2_state_33; + export "DPI-C" function e_array_2_state_64; + export "DPI-C" function e_array_2_state_65; + export "DPI-C" function e_array_2_state_128; + + // 2-state packed arrays of width > 32 via typedef + export "DPI-C" function e_array_2_state_33_t; + export "DPI-C" function e_array_2_state_64_t; + export "DPI-C" function e_array_2_state_65_t; + export "DPI-C" function e_array_2_state_128_t; + + // 2-state packed structures of width > 32 + export "DPI-C" function e_struct_2_state_33; + export "DPI-C" function e_struct_2_state_64; + export "DPI-C" function e_struct_2_state_65; + export "DPI-C" function e_struct_2_state_128; + + // 2-state packed unions of width > 32 + export "DPI-C" function e_union_2_state_33; + export "DPI-C" function e_union_2_state_64; + export "DPI-C" function e_union_2_state_65; + export "DPI-C" function e_union_2_state_128; + + // 4-state basic types + export "DPI-C" function e_integer; + + // 4-state packed arrays of any size + export "DPI-C" function e_array_4_state_1; + export "DPI-C" function e_array_4_state_2; + export "DPI-C" function e_array_4_state_8; + export "DPI-C" function e_array_4_state_9; + export "DPI-C" function e_array_4_state_16; + export "DPI-C" function e_array_4_state_17; + export "DPI-C" function e_array_4_state_32; + export "DPI-C" function e_array_4_state_33; + export "DPI-C" function e_array_4_state_64; + export "DPI-C" function e_array_4_state_65; + export "DPI-C" function e_array_4_state_128; + + // 4-state packed arrays of any size via typedef + export "DPI-C" function e_array_4_state_1_t; + export "DPI-C" function e_array_4_state_2_t; + export "DPI-C" function e_array_4_state_8_t; + export "DPI-C" function e_array_4_state_9_t; + export "DPI-C" function e_array_4_state_16_t; + export "DPI-C" function e_array_4_state_17_t; + export "DPI-C" function e_array_4_state_32_t; + export "DPI-C" function e_array_4_state_33_t; + export "DPI-C" function e_array_4_state_64_t; + export "DPI-C" function e_array_4_state_65_t; + export "DPI-C" function e_array_4_state_128_t; + + // 4-state packed structures of any size + export "DPI-C" function e_struct_4_state_1; + export "DPI-C" function e_struct_4_state_2; + export "DPI-C" function e_struct_4_state_8; + export "DPI-C" function e_struct_4_state_9; + export "DPI-C" function e_struct_4_state_16; + export "DPI-C" function e_struct_4_state_17; + export "DPI-C" function e_struct_4_state_32; + export "DPI-C" function e_struct_4_state_33; + export "DPI-C" function e_struct_4_state_64; + export "DPI-C" function e_struct_4_state_65; + export "DPI-C" function e_struct_4_state_128; + + // 4-state packed unions of any size + export "DPI-C" function e_union_4_state_1; + export "DPI-C" function e_union_4_state_2; + export "DPI-C" function e_union_4_state_8; + export "DPI-C" function e_union_4_state_9; + export "DPI-C" function e_union_4_state_16; + export "DPI-C" function e_union_4_state_17; + export "DPI-C" function e_union_4_state_32; + export "DPI-C" function e_union_4_state_33; + export "DPI-C" function e_union_4_state_64; + export "DPI-C" function e_union_4_state_65; + export "DPI-C" function e_union_4_state_128; + + //====================================================================== + // Definitions of exported functions + //====================================================================== + + // 2-state packed arrays of width > 32 + function bit [ 32:0] e_array_2_state_33(); return 0; endfunction + function bit [ 63:0] e_array_2_state_64(); return 0; endfunction + function bit [ 64:0] e_array_2_state_65(); return 0; endfunction + function bit [127:0] e_array_2_state_128(); return 0; endfunction + + // 2-state packed arrays of width > 32 via typedef + function array_2_state_33_t e_array_2_state_33_t(); return 0; endfunction + function array_2_state_64_t e_array_2_state_64_t(); return 0; endfunction + function array_2_state_65_t e_array_2_state_65_t(); return 0; endfunction + function array_2_state_128_t e_array_2_state_128_t(); return 0; endfunction + + // 2-state packed structures of width > 32 + function struct_2_state_33 e_struct_2_state_33(); return 0; endfunction + function struct_2_state_64 e_struct_2_state_64(); return 0; endfunction + function struct_2_state_65 e_struct_2_state_65(); return 0; endfunction + function struct_2_state_128 e_struct_2_state_128(); return 0; endfunction + + // 2-state packed unions of width > 32 + function union_2_state_33 e_union_2_state_33(); return 0; endfunction + function union_2_state_64 e_union_2_state_64(); return 0; endfunction + function union_2_state_65 e_union_2_state_65(); return 0; endfunction + function union_2_state_128 e_union_2_state_128(); return 0; endfunction + + // 4-state basic types + function integer e_integer(); return 0; endfunction + + // 4-state packed arrays of any size + function logic [ 0:0] e_array_4_state_1(); return 0; endfunction + function logic [ 1:0] e_array_4_state_2(); return 0; endfunction + function logic [ 7:0] e_array_4_state_8(); return 0; endfunction + function logic [ 8:0] e_array_4_state_9(); return 0; endfunction + function logic [ 15:0] e_array_4_state_16(); return 0; endfunction + function logic [ 16:0] e_array_4_state_17(); return 0; endfunction + function logic [ 31:0] e_array_4_state_32(); return 0; endfunction + function logic [ 32:0] e_array_4_state_33(); return 0; endfunction + function logic [ 63:0] e_array_4_state_64(); return 0; endfunction + function logic [ 64:0] e_array_4_state_65(); return 0; endfunction + function logic [127:0] e_array_4_state_128(); return 0; endfunction + + // 4-state packed arrays of any size via typedef + function array_4_state_1_t e_array_4_state_1_t(); return 0; endfunction + function array_4_state_2_t e_array_4_state_2_t(); return 0; endfunction + function array_4_state_8_t e_array_4_state_8_t(); return 0; endfunction + function array_4_state_9_t e_array_4_state_9_t(); return 0; endfunction + function array_4_state_16_t e_array_4_state_16_t(); return 0; endfunction + function array_4_state_17_t e_array_4_state_17_t(); return 0; endfunction + function array_4_state_32_t e_array_4_state_32_t(); return 0; endfunction + function array_4_state_33_t e_array_4_state_33_t(); return 0; endfunction + function array_4_state_64_t e_array_4_state_64_t(); return 0; endfunction + function array_4_state_65_t e_array_4_state_65_t(); return 0; endfunction + function array_4_state_128_t e_array_4_state_128_t(); return 0; endfunction + + // 4-state packed structures of any size + function struct_4_state_1 e_struct_4_state_1(); return 0; endfunction + function struct_4_state_2 e_struct_4_state_2(); return 0; endfunction + function struct_4_state_8 e_struct_4_state_8(); return 0; endfunction + function struct_4_state_9 e_struct_4_state_9(); return 0; endfunction + function struct_4_state_16 e_struct_4_state_16(); return 0; endfunction + function struct_4_state_17 e_struct_4_state_17(); return 0; endfunction + function struct_4_state_32 e_struct_4_state_32(); return 0; endfunction + function struct_4_state_33 e_struct_4_state_33(); return 0; endfunction + function struct_4_state_64 e_struct_4_state_64(); return 0; endfunction + function struct_4_state_65 e_struct_4_state_65(); return 0; endfunction + function struct_4_state_128 e_struct_4_state_128(); return 0; endfunction + + // 4-state packed unions of any size + function union_4_state_1 e_union_4_state_1(); return 0; endfunction + function union_4_state_2 e_union_4_state_2(); return 0; endfunction + function union_4_state_8 e_union_4_state_8(); return 0; endfunction + function union_4_state_9 e_union_4_state_9(); return 0; endfunction + function union_4_state_16 e_union_4_state_16(); return 0; endfunction + function union_4_state_17 e_union_4_state_17(); return 0; endfunction + function union_4_state_32 e_union_4_state_32(); return 0; endfunction + function union_4_state_33 e_union_4_state_33(); return 0; endfunction + function union_4_state_64 e_union_4_state_64(); return 0; endfunction + function union_4_state_65 e_union_4_state_65(); return 0; endfunction + function union_4_state_128 e_union_4_state_128(); return 0; endfunction +endmodule diff --git a/test_regress/t/t_gen_missing_bad.out b/test_regress/t/t_gen_missing_bad.out index c482a7ec0..cf5330862 100644 --- a/test_regress/t/t_gen_missing_bad.out +++ b/test_regress/t/t_gen_missing_bad.out @@ -5,9 +5,6 @@ t/foo_not_needed t/foo_not_needed.v t/foo_not_needed.sv - obj_dir//foo_not_needed - obj_dir//foo_not_needed.v - obj_dir//foo_not_needed.sv ../include/foo_not_needed ../include/foo_not_needed.v ../include/foo_not_needed.sv diff --git a/test_regress/t/t_preproc_inc_notfound_bad.out b/test_regress/t/t_preproc_inc_notfound_bad.out index d2d6ba31d..9177274a2 100644 --- a/test_regress/t/t_preproc_inc_notfound_bad.out +++ b/test_regress/t/t_preproc_inc_notfound_bad.out @@ -5,9 +5,6 @@ t/this_file_is_not_found.vh t/this_file_is_not_found.vh.v t/this_file_is_not_found.vh.sv - obj_dir//this_file_is_not_found.vh - obj_dir//this_file_is_not_found.vh.v - obj_dir//this_file_is_not_found.vh.sv ../include/this_file_is_not_found.vh ../include/this_file_is_not_found.vh.v ../include/this_file_is_not_found.vh.sv From 914a6edd33b7963a83daadf76e04052468e658a8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 7 Apr 2020 19:58:17 -0400 Subject: [PATCH 028/127] Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. --- Changes | 2 ++ bin/verilator | 8 +++++--- include/verilated.h | 5 +++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 62bfc017b..c97291111 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Support $ferror, and $fflush without arguments, #1638. +**** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. + * Verilator 4.032 2020-04-04 diff --git a/bin/verilator b/bin/verilator index 2c544eeb0..2c8a4ee88 100755 --- a/bin/verilator +++ b/bin/verilator @@ -4819,10 +4819,12 @@ configured with --enable-prec11. This flag will be removed and C++11 compilers will be required for both compiling Verilator and compiling Verilated models no sooner than September 2020. -=item SystemC 2.1 and earlier support +=item SystemC 2.2 and earlier support -Support for SystemC versions 2.1 and earlier and the related sc_clock -variable attribute will be removed no sooner than July 2020. +Support for SystemC versions 2.2 and earlier including the related sc_clock +variable attribute will be removed no sooner than August 2020. The +supported versions will be SystemC 2.3.0 (SYSTEMC_VERSION 20111121) and +later (presently 2.3.0, 2.3.1, 2.3.2, 2.3.3). =item Configuration File -msg diff --git a/include/verilated.h b/include/verilated.h index 037f74121..8fff5a4d0 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -52,6 +52,11 @@ # define WAVES 1 // Set backward compatibility flag #endif +// Version check +#if defined(SYSTEMC_VERSION) && (SYSTEMC_VERSION < 20111121) +# warning "Verilator soon requires SystemC 2.3.*; see manual for deprecated other versions." +#endif + //========================================================================= // Basic types From 608d5a87d1e9804ebc83577f373a42021575b37b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 7 Apr 2020 20:55:47 -0400 Subject: [PATCH 029/127] tests: Avoid assuming a timescale. --- examples/make_tracing_sc/sc_main.cpp | 9 +++++---- test_regress/driver.pl | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/make_tracing_sc/sc_main.cpp b/examples/make_tracing_sc/sc_main.cpp index 31145a17f..30f47f2bc 100644 --- a/examples/make_tracing_sc/sc_main.cpp +++ b/examples/make_tracing_sc/sc_main.cpp @@ -90,7 +90,7 @@ int sc_main(int argc, char* argv[]) { // You must do one evaluation before enabling waves, in order to allow // SystemC to interconnect everything for testing. #if (SYSTEMC_VERSION>=20070314) - sc_start(1,SC_NS); + sc_start(1, SC_NS); #else sc_start(1); #endif @@ -118,15 +118,16 @@ int sc_main(int argc, char* argv[]) { #endif // Apply inputs - if (VL_TIME_Q() > 1 && VL_TIME_Q() < 10) { + if (sc_time_stamp() > sc_time(1, SC_NS) + && sc_time_stamp() < sc_time(10, SC_NS)) { reset_l = !1; // Assert reset - } else if (VL_TIME_Q() > 1) { + } else { reset_l = !0; // Deassert reset } // Simulate 1ns #if (SYSTEMC_VERSION>=20070314) - sc_start(1,SC_NS); + sc_start(1, SC_NS); #else sc_start(1); #endif diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 7b1f82649..2884f55b0 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1798,7 +1798,8 @@ sub _make_top_v { $self->_read_inputs_v(); - my $fh = IO::File->new(">$self->{top_shell_filename}") or die "%Error: $! $self->{top_shell_filename},"; + my $fh = IO::File->new(">$self->{top_shell_filename}") + or die "%Error: $! $self->{top_shell_filename},"; print $fh "module top;\n"; foreach my $inp (sort (keys %{$self->{inputs}})) { print $fh " reg ${inp};\n"; @@ -2007,6 +2008,7 @@ sub files_identical { $l1[$l] =~ s/\r/<#013>/mig; $l1[$l] =~ s/Command Failed[^\n]+/Command Failed/mig; $l1[$l] =~ s/Version: Verilator[^\n]+/Version: Verilator ###/mig; + $l1[$l] =~ s/CPU Time: +[0-9.]+ seconds[^\n]+/CPU Time: ###/mig; if ($l1[$l] =~ s/Exiting due to.*/Exiting due to/mig) { splice @l1, $l+1; # Trunc rest last; From 991d8b178b74028040fc08f78c45a2735d6b0a0e Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 8 Apr 2020 22:54:35 +0100 Subject: [PATCH 030/127] Fix FST tracing performance by removing std::map from hot path. (#2244) This patch eliminates a major piece of inefficiency in FST tracing support, by using an array to lookup fstHandle values corresponding to trace codes, instead of a tree based std::map. With this change, FST tracing is now only about 3x slower than VCD tracing. We do require more memory to store the symbol lookup table, but the size of that is still small, for the speed benefit. --- Changes | 2 ++ include/verilated_fst_c.cpp | 18 +++++++++++++++++- include/verilated_fst_c.h | 17 ++++++++--------- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/Changes b/Changes index c97291111..1860b60e3 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. +**** Improve FST dump performance, #2244. [Geza Lore] + * Verilator 4.032 2020-04-04 diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index b0776e468..360e9b811 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -77,10 +77,16 @@ VerilatedFst::VerilatedFst(void* fst) : m_fst(fst) , m_fullDump(true) , m_nextCode(1) - , m_scopeEscape('.') { + , m_scopeEscape('.') + , m_symbolp(NULL) { m_valueStrBuffer.reserve(64 + 1); // Need enough room for quad } +VerilatedFst::~VerilatedFst() { + if (m_fst) fstWriterClose(m_fst); + if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = NULL); +} + void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { m_assertOne.check(); m_fst = fstWriterCreate(filename, 1); @@ -104,6 +110,16 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { fstWriterSetUpscope(m_fst); it = m_curScope.erase(it); } + + // convert m_code2symbol into an array for fast lookup + if (!m_symbolp) { + m_symbolp = new fstHandle[m_nextCode + 10]; + for (Code2SymbolType::iterator it = m_code2symbol.begin(); it != m_code2symbol.end(); + ++it) { + m_symbolp[it->first] = it->second; + } + } + m_code2symbol.clear(); } void VerilatedFst::module(const std::string& name) { m_module = name; } diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index bd7e6a830..60516eb25 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -55,6 +55,7 @@ private: Code2SymbolType m_code2symbol; Local2FstDtype m_local2fstdtype; std::list m_curScope; + fstHandle* m_symbolp; ///< same as m_code2symbol, but as an array // CONSTRUCTORS VL_UNCOPYABLE(VerilatedFst); void declSymbol(vluint32_t code, const char* name, @@ -65,9 +66,7 @@ private: public: explicit VerilatedFst(void* fst = NULL); - ~VerilatedFst() { - if (m_fst == NULL) { fstWriterClose(m_fst); } - } + ~VerilatedFst(); void changeThread() { m_assertOne.changeThread(); } bool isOpen() const { return m_fst != NULL; } void open(const char* filename) VL_MT_UNSAFE; @@ -140,24 +139,24 @@ public: /// Inside dumping routines, dump one signal if it has changed void chgBit(vluint32_t code, const vluint32_t newval) { - fstWriterEmitValueChange(m_fst, m_code2symbol[code], newval ? "1" : "0"); + fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0"); } void chgBus(vluint32_t code, const vluint32_t newval, int bits) { - fstWriterEmitValueChange32(m_fst, m_code2symbol[code], bits, newval); + fstWriterEmitValueChange32(m_fst, m_symbolp[code], bits, newval); } void chgDouble(vluint32_t code, const double newval) { double val = newval; - fstWriterEmitValueChange(m_fst, m_code2symbol[code], &val); + fstWriterEmitValueChange(m_fst, m_symbolp[code], &val); } void chgFloat(vluint32_t code, const float newval) { double val = (double)newval; - fstWriterEmitValueChange(m_fst, m_code2symbol[code], &val); + fstWriterEmitValueChange(m_fst, m_symbolp[code], &val); } void chgQuad(vluint32_t code, const vluint64_t newval, int bits) { - fstWriterEmitValueChange64(m_fst, m_code2symbol[code], bits, newval); + fstWriterEmitValueChange64(m_fst, m_symbolp[code], bits, newval); } void chgArray(vluint32_t code, const vluint32_t* newval, int bits) { - fstWriterEmitValueChangeVec32(m_fst, m_code2symbol[code], bits, newval); + fstWriterEmitValueChangeVec32(m_fst, m_symbolp[code], bits, newval); } void fullBit(vluint32_t code, const vluint32_t newval) { chgBit(code, newval); } From 1e0b37f4bcb94c581aa1018b98a084d211073e4f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 8 Apr 2020 17:55:12 -0400 Subject: [PATCH 031/127] Commentary --- bin/verilator | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/verilator b/bin/verilator index 2c8a4ee88..235910133 100755 --- a/bin/verilator +++ b/bin/verilator @@ -515,6 +515,8 @@ unsized zero. Arguments to such functions will be parsed, but not otherwise checked. This prevents errors when linting in the presence of company specific PLI calls. +Using this argument will likely cause incorrect simulation. + =item --bbox-unsup Black box some unsupported language features, currently UDP tables, the @@ -522,6 +524,8 @@ cmos and tran gate primitives, deassign statements, and mixed edge errors. This may enable linting the rest of the design even when unsupported constructs are present. +Using this argument will likely cause incorrect simulation. + =item --bin I Rarely needed. Override the default filename for Verilator itself. When a From 0f617988d45b5f7e8b72d30d3f2f6469a4c2ec7f Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 9 Apr 2020 02:05:43 +0100 Subject: [PATCH 032/127] Compile fast tracing code with OPT_FAST in single compile mode. (#2245) When using the __ALL*.cpp based single compile mode (i.e.: without VM_PARALLEL_BUILDS), the fast path tracing code used to be included in __Allsup.cpp, which was compiled with OPT_SLOW, severely harming tracing performance. We now have __ALLfast.cpp and __ALLslow.cpp instead of __ALLcls.cpp and __ALLsup.cpp, so we can compile the fast support code with OPT_FAST as well. --- Changes | 2 ++ bin/verilator | 9 ++++----- include/verilated.mk.in | 19 ++++++++++--------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Changes b/Changes index 1860b60e3..8445f2f03 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Improve FST dump performance, #2244. [Geza Lore] +**** Fix build of fast path tracing code to use OPT_FAST, #2245. [Geza Lore] + * Verilator 4.032 2020-04-04 diff --git a/bin/verilator b/bin/verilator index 235910133..d198eb2a7 100755 --- a/bin/verilator +++ b/bin/verilator @@ -2110,9 +2110,8 @@ After running Make, the C++ compiler may produce the following: {mod_prefix}{misc}.o // Intermediate objects {prefix} // Final executable (w/--exe argument) {prefix}__ALL.a // Library of all Verilated objects - {prefix}__ALLboth.cpp // Include of classes for single compile - {prefix}__ALLcls.cpp // Include of user classes for single compile - {prefix}__ALLsup.cpp // Include of support files for single compile + {prefix}__ALLfast.cpp // Include of hot code for single compile + {prefix}__ALLslow.cpp // Include of slow code for single compile {prefix}{misc}.d // Intermediate dependencies {prefix}{misc}.o // Intermediate objects @@ -2689,8 +2688,8 @@ underneath NC: cd obj_dir ncsc_run \ sc_main.cpp \ - Vour__ALLcls.cpp \ - Vour__ALLsup.cpp \ + Vour__ALLfast.cpp \ + Vour__ALLslow.cpp \ verilated.cpp For larger designs you'll want to automate this using makefiles, which pull diff --git a/include/verilated.mk.in b/include/verilated.mk.in index f1fee71dc..833d185c1 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -163,10 +163,11 @@ LIBS += -lm -lstdc++ ####################################################################### # Overall Objects Linking -VK_CLASSES_H = $(addsuffix .h, $(VM_CLASSES)) -VK_CLASSES_CPP = $(addsuffix .cpp, $(VM_CLASSES)) +VK_CLASSES_FAST_CPP = $(addsuffix .cpp, $(VM_CLASSES_FAST)) +VK_CLASSES_SLOW_CPP = $(addsuffix .cpp, $(VM_CLASSES_SLOW)) -VK_SUPPORT_CPP = $(addsuffix .cpp, $(VM_SUPPORT)) +VK_SUPPORT_FAST_CPP = $(addsuffix .cpp, $(VM_SUPPORT_FAST)) +VK_SUPPORT_SLOW_CPP = $(addsuffix .cpp, $(VM_SUPPORT_SLOW)) VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES)) @@ -175,11 +176,11 @@ VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW)) ifneq ($(VM_PARALLEL_BUILDS),1) # Fast building, all .cpp's in one fell swoop # This saves about 5 sec per module, but can be slower if only a little changes - VK_OBJS += $(VM_PREFIX)__ALLcls.o $(VM_PREFIX)__ALLsup.o - all_cpp: $(VM_PREFIX)__ALLcls.cpp $(VM_PREFIX)__ALLsup.cpp - $(VM_PREFIX)__ALLcls.cpp: $(VK_CLASSES_CPP) + VK_OBJS += $(VM_PREFIX)__ALLfast.o $(VM_PREFIX)__ALLslow.o + all_cpp: $(VM_PREFIX)__ALLfast.cpp $(VM_PREFIX)__ALLslow.cpp + $(VM_PREFIX)__ALLfast.cpp: $(VK_CLASSES_FAST_CPP) $(VK_SUPPORT_FAST_CPP) $(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@ - $(VM_PREFIX)__ALLsup.cpp: $(VK_SUPPORT_CPP) + $(VM_PREFIX)__ALLslow.cpp: $(VK_CLASSES_SLOW_CPP) $(VK_SUPPORT_SLOW_CPP) $(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@ else #Slow way of building... Each .cpp file by itself @@ -194,10 +195,10 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) ### Compile rules ifneq ($(VM_DEFAULT_RULES),0) -$(VM_PREFIX)__ALLcls.o: $(VM_PREFIX)__ALLcls.cpp +$(VM_PREFIX)__ALLfast.o: $(VM_PREFIX)__ALLfast.cpp $(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $< -$(VM_PREFIX)__ALLsup.o: $(VM_PREFIX)__ALLsup.cpp +$(VM_PREFIX)__ALLslow.o: $(VM_PREFIX)__ALLslow.cpp $(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $< # VM_GLOBAL_FAST files including verilated.o use this rule From 05f213c2669b6c13ec347179e94a2aff4540278a Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 9 Apr 2020 13:19:26 +0100 Subject: [PATCH 033/127] VCD tracing speed improvements (#2246) * Don't inline VCD dump functions Improves model speed with tracing. Measured on SweRW cmark: - GCC 5.5 ~3% faster - Clang 6.0 ~12% faster (!) * Remove redundant test from VCD bit tracing. Improves model speed with tracing. Measured on SweRW cmark: - GCC 5.5 ~7.5% faster - Clang 6.0 ~1.5% faster --- Changes | 2 + include/verilated_fst_c.h | 3 +- include/verilated_vcd_c.cpp | 124 ++++++++++++++++++++++++++++++ include/verilated_vcd_c.h | 149 +++++------------------------------- 4 files changed, 146 insertions(+), 132 deletions(-) diff --git a/Changes b/Changes index 8445f2f03..cfa741af5 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix build of fast path tracing code to use OPT_FAST, #2245. [Geza Lore] +**** Improve VCD dump performance, ##2246. [Geza Lore] + * Verilator 4.032 2020-04-04 diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 60516eb25..1bcf9c5e7 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -179,7 +179,8 @@ public: void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri); void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits); void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits); - void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits); + void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, + int bits); void fullBitX(vluint32_t code); void fullBusX(vluint32_t code, int bits); void fullQuadX(vluint32_t code, int bits); diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 821f5311b..62b6c33cd 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -657,6 +657,112 @@ void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int //============================================================================= +void VerilatedVcd::fullBit(vluint32_t code, const vluint32_t newval) { + // Note the &1, so we don't require clean input -- makes more common no change case faster + m_sigs_oldvalp[code] = newval; + *m_writep++ = ('0' + static_cast(newval & 1)); + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} +void VerilatedVcd::fullBus(vluint32_t code, const vluint32_t newval, int bits) { + m_sigs_oldvalp[code] = newval; + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + *m_writep++ = ((newval & (1L << bit)) ? '1' : '0'); + } + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} +void VerilatedVcd::fullQuad(vluint32_t code, const vluint64_t newval, int bits) { + (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + *m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0'); + } + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} +void VerilatedVcd::fullArray(vluint32_t code, const vluint32_t* newval, int bits) { + for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { + m_sigs_oldvalp[code + word] = newval[word]; + } + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + *m_writep++ = ((newval[(bit / 32)] & (1L << (bit & 0x1f))) ? '1' : '0'); + } + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} +void VerilatedVcd::fullArray(vluint32_t code, const vluint64_t* newval, int bits) { + for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { + m_sigs_oldvalp[code + word] = newval[word]; + } + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + *m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0'); + } + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} +void VerilatedVcd::fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) { + m_sigs_oldvalp[code] = newval; + m_sigs_oldvalp[code + 1] = newtri; + *m_writep++ = "01zz"[m_sigs_oldvalp[code] | (m_sigs_oldvalp[code + 1] << 1)]; + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} +void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) { + m_sigs_oldvalp[code] = newval; + m_sigs_oldvalp[code + 1] = newtri; + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + *m_writep++ = "01zz"[((newval >> bit) & 1) | (((newtri >> bit) & 1) << 1)]; + } + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} +void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) { + (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; + (*(reinterpret_cast(&m_sigs_oldvalp[code + 1]))) = newtri; + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + *m_writep++ = "01zz"[((newval >> bit) & VL_ULL(1)) + | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))]; + } + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} +void VerilatedVcd::fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, + int bits) { + for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { + m_sigs_oldvalp[code + word * 2] = newvalp[word]; + m_sigs_oldvalp[code + word * 2 + 1] = newtrip[word]; + } + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + vluint32_t valbit = (newvalp[(bit / 32)] >> (bit & 0x1f)) & 1; + vluint32_t tribit = (newtrip[(bit / 32)] >> (bit & 0x1f)) & 1; + *m_writep++ = "01zz"[valbit | (tribit << 1)]; + } + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} void VerilatedVcd::fullDouble(vluint32_t code, const double newval) { // cppcheck-suppress invalidPointerCast (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; @@ -679,6 +785,24 @@ void VerilatedVcd::fullFloat(vluint32_t code, const float newval) { *m_writep++ = '\n'; bufferCheck(); } +void VerilatedVcd::fullBitX(vluint32_t code) { + *m_writep++ = 'x'; + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} +void VerilatedVcd::fullBusX(vluint32_t code, int bits) { + *m_writep++ = 'b'; + for (int bit = bits - 1; bit >= 0; --bit) { + *m_writep++ = 'x'; + } + *m_writep++ = ' '; + printCode(code); + *m_writep++ = '\n'; + bufferCheck(); +} +void VerilatedVcd::fullQuadX(vluint32_t code, int bits) { fullBusX(code, bits); } +void VerilatedVcd::fullArrayX(vluint32_t code, int bits) { fullBusX(code, bits); } //============================================================================= // Callbacks diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 359131a37..24257e5b6 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -216,113 +216,17 @@ public: void declFloat(vluint32_t code, const char* name, bool array, int arraynum); // ... other module_start for submodules (based on cell name) - /// Inside dumping routines, dump one signal - void fullBit(vluint32_t code, const vluint32_t newval) { - // Note the &1, so we don't require clean input -- makes more common no change case faster - m_sigs_oldvalp[code] = newval; - *m_writep++ = ('0' + static_cast(newval & 1)); - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } - void fullBus(vluint32_t code, const vluint32_t newval, int bits) { - m_sigs_oldvalp[code] = newval; - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = ((newval & (1L << bit)) ? '1' : '0'); - } - *m_writep++ = ' '; - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } - void fullQuad(vluint32_t code, const vluint64_t newval, int bits) { - (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0'); - } - *m_writep++ = ' '; - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } - void fullArray(vluint32_t code, const vluint32_t* newval, int bits) { - for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { - m_sigs_oldvalp[code + word] = newval[word]; - } - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = ((newval[(bit / 32)] & (1L << (bit & 0x1f))) ? '1' : '0'); - } - *m_writep++ = ' '; - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } - void fullArray(vluint32_t code, const vluint64_t* newval, int bits) { - for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { - m_sigs_oldvalp[code + word] = newval[word]; - } - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0'); - } - *m_writep++ = ' '; - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } - void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) { - m_sigs_oldvalp[code] = newval; - m_sigs_oldvalp[code + 1] = newtri; - *m_writep++ = "01zz"[m_sigs_oldvalp[code] | (m_sigs_oldvalp[code + 1] << 1)]; - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } - void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) { - m_sigs_oldvalp[code] = newval; - m_sigs_oldvalp[code + 1] = newtri; - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = "01zz"[((newval >> bit) & 1) | (((newtri >> bit) & 1) << 1)]; - } - *m_writep++ = ' '; - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } - void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) { - (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; - (*(reinterpret_cast(&m_sigs_oldvalp[code + 1]))) = newtri; - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = "01zz"[((newval >> bit) & VL_ULL(1)) - | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))]; - } - *m_writep++ = ' '; - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } - void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, - int bits) { - for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { - m_sigs_oldvalp[code + word * 2] = newvalp[word]; - m_sigs_oldvalp[code + word * 2 + 1] = newtrip[word]; - } - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - vluint32_t valbit = (newvalp[(bit / 32)] >> (bit & 0x1f)) & 1; - vluint32_t tribit = (newtrip[(bit / 32)] >> (bit & 0x1f)) & 1; - *m_writep++ = "01zz"[valbit | (tribit << 1)]; - } - *m_writep++ = ' '; - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } + /// Inside dumping routines, dump one signal, faster when not inlined + /// due to code size reduction. + void fullBit(vluint32_t code, const vluint32_t newval); + void fullBus(vluint32_t code, const vluint32_t newval, int bits); + void fullQuad(vluint32_t code, const vluint64_t newval, int bits); + void fullArray(vluint32_t code, const vluint32_t* newval, int bits); + void fullArray(vluint32_t code, const vluint64_t* newval, int bits); + void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri); + void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits); + void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits); + void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits); void fullDouble(vluint32_t code, const double newval); void fullFloat(vluint32_t code, const float newval); @@ -330,34 +234,17 @@ public: /// Presently this code doesn't change the oldval vector. /// Thus this is for special standalone applications that after calling /// fullBitX, must when then value goes non-X call fullBit. - inline void fullBitX(vluint32_t code) { - *m_writep++ = 'x'; - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } - inline void fullBusX(vluint32_t code, int bits) { - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = 'x'; - } - *m_writep++ = ' '; - printCode(code); - *m_writep++ = '\n'; - bufferCheck(); - } - inline void fullQuadX(vluint32_t code, int bits) { fullBusX(code, bits); } - inline void fullArrayX(vluint32_t code, int bits) { fullBusX(code, bits); } + void fullBitX(vluint32_t code); + void fullBusX(vluint32_t code, int bits); + void fullQuadX(vluint32_t code, int bits); + void fullArrayX(vluint32_t code, int bits); - /// Inside dumping routines, dump one signal if it has changed + /// Inside dumping routines, dump one signal if it has changed. + /// We do want to inline these to avoid calls when the value did not change. inline void chgBit(vluint32_t code, const vluint32_t newval) { vluint32_t diff = m_sigs_oldvalp[code] ^ newval; if (VL_UNLIKELY(diff)) { - // Verilator 3.510 and newer provide clean input, so the below - // is only for back compatibility - if (VL_UNLIKELY(diff & 1)) { // Change after clean? - fullBit(code, newval); - } + fullBit(code, newval); } } inline void chgBus(vluint32_t code, const vluint32_t newval, int bits) { From 4c1ae4701a27cd27a708800fcb0870a90e96706c Mon Sep 17 00:00:00 2001 From: Nathan Myers Date: Thu, 9 Apr 2020 19:00:27 -0400 Subject: [PATCH 034/127] Add assertion for monotonic dump times #2103 (#2237) --- docs/CONTRIBUTORS | 1 + include/verilated_fst_c.cpp | 7 +++++++ include/verilated_fst_c.h | 1 + 3 files changed, 9 insertions(+) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 4e1565764..4666f4728 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -28,6 +28,7 @@ Maciej Sobkowski Marco Widmer Matthew Ballance Mike Popoloski +Nathan Myers Patrick Stewart Peter Monsson Philipp Wagner diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 360e9b811..bdd2e5d61 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -76,6 +76,7 @@ protected: VerilatedFst::VerilatedFst(void* fst) : m_fst(fst) , m_fullDump(true) + , m_minNextDumpTime(0) , m_nextCode(1) , m_scopeEscape('.') , m_symbolp(NULL) { @@ -212,6 +213,12 @@ void VerilatedFst::addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallba void VerilatedFst::dump(vluint64_t timeui) { if (!isOpen()) return; + if (timeui < m_minNextDumpTime) { + VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64 "u\n", + m_minNextDumpTime - 1, timeui); + return; + } + m_minNextDumpTime = timeui + 1; if (VL_UNLIKELY(m_fullDump)) { m_fullDump = false; // No more need for next dump to be full for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 1bcf9c5e7..ffae20875 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -48,6 +48,7 @@ private: void* m_fst; VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread bool m_fullDump; + vluint64_t m_minNextDumpTime; vluint32_t m_nextCode; ///< Next code number to assign char m_scopeEscape; std::string m_module; From 343db78c03b1754ba4756440fcffc333adb39ccc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 9 Apr 2020 23:03:28 -0400 Subject: [PATCH 035/127] Fix including verilated_sc in Syms to fix compile order problem exposed in #2237. --- src/V3EmitC.cpp | 6 +++++- src/V3EmitCSyms.cpp | 24 +++++++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 1bf5cbc19..2e98bc6a4 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3110,7 +3110,11 @@ class EmitCTrace : EmitCStmts { cfilep->support(true); if (m_ofp) v3fatalSrc("Previous file not closed"); - m_ofp = new V3OutCFile(filename); + if (optSystemC()) { + m_ofp = new V3OutScFile(filename); + } else { + m_ofp = new V3OutCFile(filename); + } m_ofp->putsHeader(); m_ofp->puts("// DESCR" "IPTION: Verilator output: Tracing implementation internals\n"); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 51616453e..3a4534e7d 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -360,8 +360,12 @@ void EmitCSyms::emitSymHdr() { UINFO(6,__FUNCTION__<<": "<putsHeader(); puts("// DESCR" "IPTION: Verilator output: Symbol table internal header\n"); @@ -482,6 +486,7 @@ void EmitCSyms::emitSymHdr() { puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n"); ofp()->putsEndGuard(); + VL_DO_CLEAR(delete m_ofp, m_ofp = NULL); } void EmitCSyms::closeSplit() { @@ -502,7 +507,11 @@ void EmitCSyms::checkSplit(bool usesVfinal) { m_usesVfinal[m_funcNum] = usesVfinal; closeSplit(); - m_ofp = new V3OutCFile(filename); + if (v3Global.opt.systemC()) { + m_ofp = new V3OutScFile(filename); + } else { + m_ofp = new V3OutCFile(filename); + } m_ofpBase->puts(symClassName()+"_"+cvtToStr(m_funcNum)+"("); if (usesVfinal) { @@ -541,8 +550,13 @@ void EmitCSyms::emitSymImp() { string filename = v3Global.opt.makeDir()+"/"+symClassName()+".cpp"; AstCFile* cfilep = newCFile(filename, true/*slow*/, true/*source*/); cfilep->support(true); - V3OutCFile cf (filename); - m_ofp = &cf; + + if (v3Global.opt.systemC()) { + m_ofp = new V3OutScFile(filename); + } else { + m_ofp = new V3OutCFile(filename); + } + m_ofpBase = m_ofp; emitSymImpPreamble(); From 15b40a97d96a32f7fe2ffe7b0db584753439cf20 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 9 Apr 2020 23:26:03 -0400 Subject: [PATCH 036/127] Support `unconnected_drive --- src/V3Ast.h | 3 ++ src/V3Inline.cpp | 1 - src/V3Inst.cpp | 20 ++++++++++-- src/V3Options.h | 2 ++ src/V3ParseImp.h | 3 ++ src/V3Tristate.cpp | 6 ++-- src/verilog.l | 5 ++- src/verilog.y | 1 + test_regress/t/t_unconnected.pl | 21 +++++++++++++ test_regress/t/t_unconnected.v | 46 ++++++++++++++++++++++++++++ test_regress/t/t_unconnected_bad.out | 10 ++++++ test_regress/t/t_unconnected_bad.pl | 19 ++++++++++++ test_regress/t/t_unconnected_bad.v | 12 ++++++++ 13 files changed, 140 insertions(+), 9 deletions(-) create mode 100755 test_regress/t/t_unconnected.pl create mode 100644 test_regress/t/t_unconnected.v create mode 100644 test_regress/t/t_unconnected_bad.out create mode 100755 test_regress/t/t_unconnected_bad.pl create mode 100644 test_regress/t/t_unconnected_bad.v diff --git a/src/V3Ast.h b/src/V3Ast.h index f9797bc80..254935322 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2420,6 +2420,7 @@ private: int m_level; // 1=top module, 2=cell off top module, ... int m_varNum; // Incrementing variable number int m_typeNum; // Incrementing implicit type number + VOptionBool m_unconnectedDrive; // State of `unconnected_drive public: AstNodeModule(AstType t, FileLine* fl, const string& name) : AstNode(t, fl) @@ -2461,6 +2462,8 @@ public: bool recursive() const { return m_recursive; } void recursiveClone(bool flag) { m_recursiveClone = flag; } bool recursiveClone() const { return m_recursiveClone; } + void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } + VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } }; class AstNodeRange : public AstNode { diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 4525ee045..f1721588a 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -547,7 +547,6 @@ private: // we'll save work, and we can't call pinReconnectSimple in // this loop as it clone()s itself. for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { - if (!pinp->exprp()) continue; V3Inst::pinReconnectSimple(pinp, nodep, false); } diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index e3895e611..caa68d056 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -62,13 +62,15 @@ private: // PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input) // or ASSIGNW(expr,VARXREF(p)) (if sub's output) UINFO(4," PIN "<user1()) { + // Simplify it + V3Inst::pinReconnectSimple(nodep, m_cellp, false); + } if (!nodep->exprp()) return; // No-connect if (debug()>=9) nodep->dumpTree(cout, " Pin_oldb: "); V3Inst::checkOutputShort(nodep); // Use user1p on the PIN to indicate we created an assign for this pin if (!nodep->user1SetOnce()) { - // Simplify it - V3Inst::pinReconnectSimple(nodep, m_cellp, false); // Make an ASSIGNW (expr, pin) AstNode* exprp = nodep->exprp()->cloneTree(false); UASSERT_OBJ(exprp->width() == nodep->modVarp()->width(), nodep, @@ -481,8 +483,20 @@ public: // Else create a intermediate wire to perform the interconnect // Return the new assignment, if one was made // Note this module calles cloneTree() via new AstVar - AstVar* pinVarp = pinp->modVarp(); + if (!pinp->exprp()) { + // No-connect, perhaps promote based on `unconnected_drive, + // otherwise done + if (pinVarp->direction() == VDirection::INPUT + && cellp->modp()->unconnectedDrive().isSetTrue()) { + pinp->exprp(new AstConst(pinp->fileline(), AstConst::StringToParse(), "'1")); + } else if (pinVarp->direction() == VDirection::INPUT + && cellp->modp()->unconnectedDrive().isSetFalse()) { + pinp->exprp(new AstConst(pinp->fileline(), AstConst::StringToParse(), "'0")); + } else { + return NULL; + } + } AstVarRef* connectRefp = VN_CAST(pinp->exprp(), VarRef); AstVarXRef* connectXRefp = VN_CAST(pinp->exprp(), VarXRef); AstBasicDType* pinBasicp = VN_CAST(pinVarp->dtypep(), BasicDType); // Maybe NULL diff --git a/src/V3Options.h b/src/V3Options.h index 890395aba..dff2275e2 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -53,6 +53,8 @@ public: bool isDefault() const { return m_e == OPT_DEFAULT_FALSE || m_e == OPT_DEFAULT_TRUE; } bool isTrue() const { return m_e == OPT_TRUE || m_e == OPT_DEFAULT_TRUE; } bool isFalse() const { return m_e == OPT_FALSE || m_e == OPT_DEFAULT_FALSE; } + bool isSetTrue() const { return m_e == OPT_TRUE; } + bool isSetFalse() const { return m_e == OPT_FALSE; } void setTrueOrFalse(bool flag) { m_e = flag ? OPT_TRUE : OPT_FALSE; } const char* ascii() const { static const char* const names[] = { diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index f6560326e..7c2076f4e 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -109,6 +109,7 @@ class V3ParseImp { bool m_inLibrary; // Currently reading a library vs. regular file int m_inBeginKwd; // Inside a `begin_keywords int m_lastVerilogState; // Last LEX state in `begin_keywords + VOptionBool m_unconnectedDrive; // Last unconnected drive int m_prevLexToken; // previous parsed token (for lexer) bool m_ahead; // aheadval is valid @@ -199,6 +200,8 @@ public: bool inCellDefine() const { return m_inCellDefine; } void inCellDefine(bool flag) { m_inCellDefine = flag; } bool inLibrary() const { return m_inLibrary; } + VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } + void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } // Interactions with parser int bisonParse(); diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 362104e12..4886e99d6 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -1087,10 +1087,8 @@ class TristateVisitor : public TristateBaseVisitor { // Find child module's new variables. AstVar* enModVarp = static_cast(nodep->modVarp()->user1p()); if (!enModVarp) { - if (nodep->exprp()) { - // May have an output only that later connects to a tristate, so simplify now. - V3Inst::pinReconnectSimple(nodep, m_cellp, false); - } + // May have an output only that later connects to a tristate, so simplify now. + V3Inst::pinReconnectSimple(nodep, m_cellp, false); iteratePinGuts(nodep); return; // No __en signals on this pin } diff --git a/src/verilog.l b/src/verilog.l index 13a3229ef..9ab7bfdeb 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -966,7 +966,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "`noremove_gatenames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`noremove_netnames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`nosuppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility - "`nounconnected_drive" { FL_FWD; FL_BRK; } // Verilog-XL compatibility + "`nounconnected_drive" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_DEFAULT_FALSE); FL_BRK; } "`portcoerce" { FL_FWD; FL_BRK; } "`pragma"{ws}*[^\n\r]* { FL_FWD; FL_BRK; } // Verilog 2005 "`protect" { FL_FWD; FL_BRK; } @@ -976,6 +976,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} return yaT_RESETALL; } // Rest handled by preproc "`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`timescale"{ws}+[^\n\r]* { FL_FWD; FL_BRK; } // Verilog spec - not supported + "`unconnected_drive"{ws}+"pull0" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_FALSE); FL_BRK; } + "`unconnected_drive"{ws}+"pull1" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_TRUE); FL_BRK; } + "`unconnected_drive" { FL_FWD; yyerrorf("Bad `unconnected_drive syntax"); FL_BRK; } "`uselib"{ws}+[^\n\r]* { FL_FWD; FL_BRK; } // Verilog-XL compatibility /* See also setLanguage below */ diff --git a/src/verilog.y b/src/verilog.y index a830caba0..2fee40057 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -953,6 +953,7 @@ modFront: { $$ = new AstModule($3,*$3); $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); + $$->unconnectedDrive(PARSEP->unconnectedDrive()); PARSEP->rootp()->addModulep($$); SYMP->pushNew($$); } ; diff --git a/test_regress/t/t_unconnected.pl b/test_regress/t/t_unconnected.pl new file mode 100755 index 000000000..d89c3301f --- /dev/null +++ b/test_regress/t/t_unconnected.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2004 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_unconnected.v b/test_regress/t/t_unconnected.v new file mode 100644 index 000000000..4cce7be42 --- /dev/null +++ b/test_regress/t/t_unconnected.v @@ -0,0 +1,46 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + wire o_n; + wire o_0; + wire o_1; + + // verilator lint_off PINMISSING + sub_0 sub_0(.o_0); + sub_1 sub_1(.o_1); + sub_n sub_n(.o_n); + // verilator lint_on PINMISSING + + always @ (posedge clk) begin + if (o_0 !== 1'b0) $stop; + if (o_1 !== 1'b1) $stop; + //4-state if (o_n !== 1'bz) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule + +`unconnected_drive pull0 +module sub_0 (input i, output wire o_0); + assign o_0 = i; +endmodule + +`unconnected_drive pull1 +module sub_1 (input i, output wire o_1); + assign o_1 = i; +endmodule + +`nounconnected_drive +module sub_n (input i, output wire o_n); + assign o_n = i; +endmodule diff --git a/test_regress/t/t_unconnected_bad.out b/test_regress/t/t_unconnected_bad.out new file mode 100644 index 000000000..6ba09dcd1 --- /dev/null +++ b/test_regress/t/t_unconnected_bad.out @@ -0,0 +1,10 @@ +%Error: t/t_unconnected_bad.v:7:1: Bad `unconnected_drive syntax + 7 | `unconnected_drive + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_unconnected_bad.v:9:1: Bad `unconnected_drive syntax + 9 | `unconnected_drive pull2 + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_unconnected_bad.v:9:20: syntax error, unexpected IDENTIFIER + 9 | `unconnected_drive pull2 + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_unconnected_bad.pl b/test_regress/t/t_unconnected_bad.pl new file mode 100755 index 000000000..67a7abcb0 --- /dev/null +++ b/test_regress/t/t_unconnected_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_unconnected_bad.v b/test_regress/t/t_unconnected_bad.v new file mode 100644 index 000000000..46affd2f9 --- /dev/null +++ b/test_regress/t/t_unconnected_bad.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2018 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`unconnected_drive + +`unconnected_drive pull2 + +module t; +endmodule From 1a6c2fc55d206649d44e7c90f99fdcc4549a3615 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 10 Apr 2020 21:10:21 -0400 Subject: [PATCH 037/127] Fix class members getting misoptimized away. --- src/V3Ast.h | 7 ++++--- src/V3AstNodes.cpp | 1 - src/V3AstNodes.h | 5 +---- src/V3Dead.cpp | 1 + src/V3EmitC.cpp | 3 ++- src/V3LinkResolve.cpp | 2 +- src/V3Localize.cpp | 1 + 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 254935322..26c3d7d91 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -597,7 +597,8 @@ public: MODULETEMP, STMTTEMP, XTEMP, - IFACEREF // Used to link Interfaces between modules + IFACEREF, // Used to link Interfaces between modules + MEMBER }; enum en m_e; inline AstVarType() : m_e(UNKNOWN) {} @@ -612,7 +613,7 @@ public: "TRIWIRE", "TRI0", "TRI1", "PORT", "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", - "IFACEREF"}; + "IFACEREF", "MEMBER"}; return names[m_e]; } bool isSignal() const { return (m_e==WIRE || m_e==WREAL || m_e==IMPLICITWIRE @@ -632,7 +633,7 @@ public: return (m_e==GPARAM || m_e==LPARAM || m_e==GENVAR || m_e==VAR || m_e==BLOCKTEMP || m_e==MODULETEMP || m_e==STMTTEMP - || m_e==XTEMP || m_e==IFACEREF); + || m_e==XTEMP || m_e==IFACEREF || m_e==MEMBER); } bool isTemp() const { return (m_e==BLOCKTEMP || m_e==MODULETEMP || m_e==STMTTEMP || m_e==XTEMP); diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 0aa52a399..a46a7258d 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1307,7 +1307,6 @@ void AstVar::dump(std::ostream& str) const { if (attrClockEn()) str<<" [aCLKEN]"; if (attrIsolateAssign()) str<<" [aISO]"; if (attrFileDescr()) str<<" [aFD]"; - if (isClassMember()) str<<" [MEMBER]"; if (isFuncReturn()) str<<" [FUNCRTN]"; else if (isFuncLocal()) str<<" [FUNC]"; if (isDpiOpenArray()) str<<" [DPIOPENA]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 1e7118ad2..2ad684e6b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1575,7 +1575,6 @@ private: bool m_usedClock:1; // Signal used as a clock bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup) bool m_usedLoopIdx:1; // Variable subject of for unrolling - bool m_classMember:1; // Member variable for a class bool m_funcLocal:1; // Local variable for a function bool m_funcReturn:1; // Return variable for a function bool m_attrClockEn:1;// User clock enable attribute @@ -1603,7 +1602,6 @@ private: m_usedClock = false; m_usedParam = false; m_usedLoopIdx = false; m_sigPublic = false; m_sigModPublic = false; m_sigUserRdPublic = false; m_sigUserRWPublic = false; - m_classMember = false; m_funcLocal = false; m_funcReturn = false; m_attrClockEn = false; m_attrScBv = false; m_attrIsolateAssign = false; m_attrSFormat = false; m_attrSplitVar = false; @@ -1724,7 +1722,6 @@ public: void isConst(bool flag) { m_isConst = flag; } void isStatic(bool flag) { m_isStatic = flag; } void isIfaceParent(bool flag) { m_isIfaceParent = flag; } - void classMember(bool flag) { m_classMember = flag; } void funcLocal(bool flag) { m_funcLocal = flag; } void funcReturn(bool flag) { m_funcReturn = flag; } void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; } @@ -1756,6 +1753,7 @@ public: && (isIO() || isBitLogic()) // Wrapper would otherwise duplicate wrapped module's coverage && !isSc() && !isPrimaryIO() && !isConst()); } + bool isClassMember() const { return varType() == AstVarType::MEMBER; } bool isStatementTemp() const { return (varType()==AstVarType::STMTTEMP); } bool isMovableToBlock() const { return (varType()==AstVarType::BLOCKTEMP || isFuncLocal()); } bool isXTemp() const { return (varType()==AstVarType::XTEMP); } @@ -1779,7 +1777,6 @@ public: bool isTrace() const { return m_trace; } bool isConst() const { return m_isConst; } bool isStatic() const { return m_isStatic; } - bool isClassMember() const { return m_classMember; } bool isFuncLocal() const { return m_funcLocal; } bool isFuncReturn() const { return m_funcReturn; } bool isPullup() const { return m_isPullup; } diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 6b8e4de49..c90249700 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -328,6 +328,7 @@ private: bool mightElimVar(AstVar* nodep) { return (!nodep->isSigPublic() // Can't elim publics! && !nodep->isIO() + && !nodep->isClassMember() && ((nodep->isTemp() && !nodep->isTrace()) || (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly()) || m_elimUserVars)); // Post-Trace can kill most anything diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 2e98bc6a4..dd59d233b 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2513,7 +2513,8 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref bool doit = true; switch (which) { case EVL_CLASS_IO: doit = varp->isIO(); break; - case EVL_CLASS_SIG: doit = (varp->isSignal() && !varp->isIO()); break; + case EVL_CLASS_SIG: + doit = ((varp->isSignal() || varp->isClassMember()) && !varp->isIO()); break; case EVL_CLASS_TEMP: doit = (varp->isTemp() && !varp->isIO()); break; case EVL_CLASS_PAR: doit = (varp->isParam() && !VN_IS(varp->valuep(), Const)); break; case EVL_CLASS_ALL: doit = true; break; diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 3f5765881..6bea4587c 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -100,7 +100,7 @@ private: } virtual void visit(AstVar* nodep) VL_OVERRIDE { iterateChildren(nodep); - if (m_classp) nodep->classMember(true); + if (m_classp) nodep->varType(AstVarType::MEMBER); if (m_ftaskp) nodep->funcLocal(true); if (nodep->isSigModPublic()) { nodep->sigModPublic(false); // We're done with this attribute diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index 870c1f3fa..197a4b2fe 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -129,6 +129,7 @@ private: if ((nodep->isMovableToBlock() // Blocktemp || !flags.m_notStd) // Or used only in block && !flags.m_notOpt // Optimizable + && !nodep->isClassMember() && nodep->user1p()) { // Single cfunc // We don't need to test for tracing; it would be in the tracefunc if it was needed UINFO(4," ModVar->BlkVar "< Date: Sat, 11 Apr 2020 10:33:40 -0400 Subject: [PATCH 038/127] Make sure SystemC always included in -sc mode to prevent ordering issues. --- include/verilated.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/verilated.h b/include/verilated.h index 8fff5a4d0..7636eb71f 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -24,6 +24,9 @@ #define _VERILATED_H_ 1 ///< Header Guard #include "verilatedos.h" +#if VM_SC +# include "verilated_sc.h" // Get SYSTEMC_VERSION and time declarations +#endif #include #include From afa8e4c786edb71a83757c3e40be5977fcd5dcde Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 11 Apr 2020 10:54:42 -0400 Subject: [PATCH 039/127] Internals: Favor const_iterator. No functional change. --- src/V3AstNodes.h | 3 ++- src/V3EmitC.cpp | 2 +- src/V3LinkLevel.cpp | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 2ad684e6b..600c3779e 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2520,7 +2520,8 @@ public: AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl) { setOp1p(lhsp); setOp2p(rhsp); } ASTNODE_NODE_FUNCS(Dot) - static AstNode* newIfPkg(FileLine*fl, AstPackage* packagep, AstNode* rhsp) { // For parser, make only if non-null package + // For parser, make only if non-null package + static AstNode* newIfPkg(FileLine* fl, AstPackage* packagep, AstNode* rhsp) { if (!packagep) return rhsp; return new AstDot(fl, new AstPackageRef(fl, packagep), rhsp); } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index dd59d233b..742ec2f25 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1998,7 +1998,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, case 'e': displayArg(nodep, &elistp, isScan, vfmt, 'e'); break; case 'f': displayArg(nodep, &elistp, isScan, vfmt, 'f'); break; case 'g': displayArg(nodep, &elistp, isScan, vfmt, 'g'); break; - case '^': displayArg(nodep,&elistp,isScan, vfmt,'^'); break; // Realtime + case '^': displayArg(nodep, &elistp, isScan, vfmt, '^'); break; // Realtime case 'v': displayArg(nodep, &elistp, isScan, vfmt, 'v'); break; case 'm': { UASSERT_OBJ(scopenamep, nodep, "Display with %m but no AstScopeName"); diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index e51172c6e..062cfa44b 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -74,14 +74,14 @@ void V3LinkLevel::modSortByLevel() { // Reorder the netlist's modules to have modules in level sorted order stable_sort(mods.begin(), mods.end(), CmpLevel()); // Sort the vector UINFO(9,"modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666 - for (ModVec::iterator it = mods.begin(); it != mods.end(); ++it) { + for (ModVec::const_iterator it = mods.begin(); it != mods.end(); ++it) { AstNodeModule* nodep = *it; nodep->clearIter(); // Because we didn't iterate to find the node // pointers, may have a stale m_iterp() needing cleanup nodep->unlinkFrBack(); } UASSERT_OBJ(!v3Global.rootp()->modulesp(), v3Global.rootp(), "Unlink didn't work"); - for (ModVec::iterator it = mods.begin(); it != mods.end(); ++it) { + for (ModVec::const_iterator it = mods.begin(); it != mods.end(); ++it) { AstNodeModule* nodep = *it; v3Global.rootp()->addModulep(nodep); } From 8b2666cd048eacc4f69d264606aad8a1760c9b4f Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 11 Apr 2020 16:00:43 +0100 Subject: [PATCH 040/127] Fix to make trace code allocation dense. (#2250) This looks like a bits/bytes bug. The affected m_codeInc member determines how many 32-bit words to allocate in a buffer used to store previous values of the signal, but this was off by a factor of 8, so we used to use too much memory. SweRV VCD tracing speed +6.5% (excluding IO, clang 6.0), due mainly to reduced D cache misses. --- Changes | 4 ++-- src/V3AstNodes.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index cfa741af5..e49f180d7 100644 --- a/Changes +++ b/Changes @@ -15,11 +15,11 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. -**** Improve FST dump performance, #2244. [Geza Lore] +**** Improve FST dump performance, #2244, #2250. [Geza Lore] **** Fix build of fast path tracing code to use OPT_FAST, #2245. [Geza Lore] -**** Improve VCD dump performance, ##2246. [Geza Lore] +**** Improve VCD dump performance, #2246, #2250. [Geza Lore] * Verilator 4.032 2020-04-04 diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 600c3779e..dc4b9d8b8 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -4227,7 +4227,7 @@ public: m_code = 0; m_codeInc = ((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords() - * (VL_EDATASIZE / sizeof(uint32_t))); // A code is always 32-bits + * (VL_EDATASIZE / (8*sizeof(uint32_t)))); // A code is always 32-bits m_varType = varp->varType(); m_declKwd = varp->declKwd(); m_declDirection = varp->declDirection(); From 8e6674066ff814f4b95fdba054bec81dc18eb4d1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 11 Apr 2020 11:40:15 -0400 Subject: [PATCH 041/127] Tests: Clean before rerunning failing test. --- test_regress/driver.pl | 20 +++++++++++++++----- test_regress/t/t_a4_examples.pl | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 2884f55b0..3e4731613 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -192,11 +192,7 @@ if ($opt_rerun && $runner->fail_count) { skip_cnt => $orig_runner->{skip_cnt}, unsup_cnt => $orig_runner->{unsup_cnt}); foreach my $test (@{$orig_runner->{fail_tests}}) { - if (0) { # TBD if this is required - rare that intermediate results are bad - # Remove old results to force hard rebuild - system("rm", "-rf", "$test->{obj_dir}__fail1"); - system("mv", "$test->{obj_dir}", "$test->{obj_dir}__fail1"); - } + $test->clean; # Reschedule test $runner->one_test(pl_filename => $test->{pl_filename}, $test->{scenario} => 1); @@ -795,6 +791,20 @@ sub _read_status { #---------------------------------------------------------------------- # Methods invoked by tests +sub clean { + my $self = (ref $_[0] ? shift : $Self); + # Called on a rerun to cleanup files + if ($self->{clean_command}) { + system($self->{clean_command}); + } + if (1) { + # Prevents false-failures when switching compilers + # Remove old results to force hard rebuild + system("rm", "-rf", "$self->{obj_dir}__fail1"); + system("mv", "$self->{obj_dir}", "$self->{obj_dir}__fail1"); + } +} + sub compile_vlt_cmd { my $self = (ref $_[0]? shift : $Self); my %param = (%{$self}, @_); # Default arguments are from $self diff --git a/test_regress/t/t_a4_examples.pl b/test_regress/t/t_a4_examples.pl index 09c6958ca..a4b6bdcde 100755 --- a/test_regress/t/t_a4_examples.pl +++ b/test_regress/t/t_a4_examples.pl @@ -10,6 +10,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(dist => 1); +$Self->{clean_command} = 'rm -rf ../examples/*/build ../examples/*/obj*'; + my @examples = sort(glob("../examples/*")); for my $example (@examples) { run(cmd=>["make -C $example"]); From 152505e879adbaa4e14761e76de6f7f665c8f12c Mon Sep 17 00:00:00 2001 From: Nathan Kohagen Date: Sat, 11 Apr 2020 18:11:53 -0400 Subject: [PATCH 042/127] Fix make install/uninstall for examples/xml_py, #2252. --- Makefile.in | 3 ++- docs/CONTRIBUTORS | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index f9d9bffad..dfb5d3c0f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -336,6 +336,7 @@ installdata: $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib + $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/xml_py cd $(srcdir) \ ; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \ $(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \ @@ -370,8 +371,8 @@ uninstall: -rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c -rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc -rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib + -rmdir $(DESTDIR)$(pkgdatadir)/examples/xml_py -rmdir $(DESTDIR)$(pkgdatadir)/examples - -rmdir $(DESTDIR)$(pkgdatadir)/cmake -rmdir $(DESTDIR)$(pkgdatadir) -rmdir $(DESTDIR)$(pkgconfigdir) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 4666f4728..09209bf36 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -28,6 +28,7 @@ Maciej Sobkowski Marco Widmer Matthew Ballance Mike Popoloski +Nathan Kohagen Nathan Myers Patrick Stewart Peter Monsson From ea3acc2d3ad4f024deb8fcee8baee9554adf0e3c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 11 Apr 2020 20:22:57 -0400 Subject: [PATCH 043/127] Fix --skip-identical broke recent commit. --- src/V3EmitCSyms.cpp | 1 + src/Verilator.cpp | 17 +++++++++++------ test_regress/t/t_flag_skipidentical.pl | 5 ++++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 3a4534e7d..eb427a728 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -785,6 +785,7 @@ void EmitCSyms::emitSymImp() { m_ofpBase->puts("}\n"); closeSplit(); + VL_DO_CLEAR(delete m_ofp, m_ofp = NULL); } //###################################################################### diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 72d32d051..5cfbc3115 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -557,11 +557,16 @@ int main(int argc, char** argv, char** env) { // Can we skip doing everything if times are ok? V3File::addSrcDepend(v3Global.opt.bin()); if (v3Global.opt.skipIdentical().isTrue() - && V3File::checkTimes(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix() - +"__verFiles.dat", argString)) { + && V3File::checkTimes(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + + "__verFiles.dat", argString)) { UINFO(1,"--skip-identical: No change to any source files, exiting\n"); exit(0); } + // Undocumented debugging - cannot be a switch as then command line + // would mismatch forcing non-identicalness when we set it + if (!V3Os::getenvStr("VERILATOR_DEBUG_SKIP_IDENTICAL", "").empty()) { + v3fatalSrc("VERILATOR_DEBUG_SKIP_IDENTICAL w/ --skip-identical: Changes found\n"); + } //--FRONTEND------------------ @@ -597,13 +602,13 @@ int main(int argc, char** argv, char** env) { if (v3Global.opt.makeDepend().isTrue()) { V3File::writeDepend(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__ver.d"); } - if (v3Global.opt.skipIdentical().isTrue() || v3Global.opt.makeDepend().isTrue()) { - V3File::writeTimes(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix() - +"__verFiles.dat", argString); - } if (v3Global.opt.protectIds()) { VIdProtect::writeMapFile(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__idmap.xml"); } + if (v3Global.opt.skipIdentical().isTrue() || v3Global.opt.makeDepend().isTrue()) { + V3File::writeTimes(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__verFiles.dat", + argString); + } // Final writing shouldn't throw warnings, but... V3Error::abortIfWarnings(); diff --git a/test_regress/t/t_flag_skipidentical.pl b/test_regress/t/t_flag_skipidentical.pl index 93d5d8b3d..9ac3f346f 100755 --- a/test_regress/t/t_flag_skipidentical.pl +++ b/test_regress/t/t_flag_skipidentical.pl @@ -13,13 +13,16 @@ scenarios(vlt => 1); { compile(); + print "NOTE: use --debugi, as --debug in driver turns off skip-identical\n"; + my $outfile = "$Self->{obj_dir}/V".$Self->{name}.".cpp"; my @oldstats = stat($outfile); print "Old mtime=",$oldstats[9],"\n"; $oldstats[9] or error("No output file found: $outfile\n"); - sleep(1); # Or else it might take < 1 second to compile and see no diff. + sleep(2); # Or else it might take < 1 second to compile and see no diff. + $ENV{VERILATOR_DEBUG_SKIP_IDENTICAL} = 1; compile(); my @newstats = stat($outfile); From 1e2d73fc80f981d42fcbe8ed3406bc9b794a4f3d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 12 Apr 2020 08:26:14 -0400 Subject: [PATCH 044/127] Internals: clang-format and refactor taskref pin handling. --- src/V3Task.cpp | 60 +++++++++++++++++++++++------------------ src/V3Width.cpp | 71 ++++++++++++++++++++++++++++--------------------- 2 files changed, 75 insertions(+), 56 deletions(-) diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 3477d0591..91f02aaef 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1327,7 +1327,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) // Missing pin/expr? We return (pinvar, NULL) // Extra pin/expr? We clean it up - typedef std::map NameToIndex; + typedef std::map NameToIndex; NameToIndex nameToIndex; V3TaskConnects tconnects; UASSERT_OBJ(nodep->taskp(), nodep, "unlinked"); @@ -1335,16 +1335,18 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) // Find ports int tpinnum = 0; AstVar* sformatp = NULL; - for (AstNode* stmtp = taskStmtsp; stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = taskStmtsp; stmtp; stmtp = stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO()) { tconnects.push_back(make_pair(portp, static_cast(NULL))); - nameToIndex.insert(make_pair(portp->name(), tpinnum)); // For name based connections + nameToIndex.insert( + make_pair(portp->name(), tpinnum)); // For name based connections tpinnum++; if (portp->attrSFormat()) { sformatp = portp; } else if (sformatp) { - nodep->v3error("/*verilator sformat*/ can only be applied to last argument of a function"); + portp->v3error("/*verilator sformat*/ can only be applied to last argument of " + "a function"); } } } @@ -1353,7 +1355,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) // Find pins int ppinnum = 0; bool reorganize = false; - for (AstNode* nextp, *pinp = nodep->pinsp(); pinp; pinp=nextp) { + for (AstNode *nextp, *pinp = nodep->pinsp(); pinp; pinp = nextp) { nextp = pinp->nextp(); AstArg* argp = VN_CAST(pinp, Arg); UASSERT_OBJ(argp, pinp, "Non-arg under ftask reference"); @@ -1361,14 +1363,15 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) // By name NameToIndex::iterator it = nameToIndex.find(argp->name()); if (it == nameToIndex.end()) { - pinp->v3error("No such argument "<prettyNameQ() - <<" in function call to "<taskp()->prettyTypeName()); + pinp->v3error("No such argument " << argp->prettyNameQ() << " in function call to " + << nodep->taskp()->prettyTypeName()); // We'll just delete it; seems less error prone than making a false argument VL_DO_DANGLING(pinp->unlinkFrBack()->deleteTree(), pinp); } else { if (tconnects[it->second].second) { - pinp->v3error("Duplicate argument "<prettyNameQ() - <<" in function call to "<taskp()->prettyTypeName()); + pinp->v3error("Duplicate argument " << argp->prettyNameQ() + << " in function call to " + << nodep->taskp()->prettyTypeName()); } argp->name(""); // Can forget name as will add back in pin order tconnects[it->second].second = argp; @@ -1382,7 +1385,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) tpinnum++; } else { pinp->v3error("Too many arguments in function call to " - <taskp()->prettyTypeName()); + << nodep->taskp()->prettyTypeName()); // We'll just delete it; seems less error prone than making a false argument VL_DO_DANGLING(pinp->unlinkFrBack()->deleteTree(), pinp); } @@ -1394,13 +1397,14 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) } // Connect missing ones - for (int i=0; iexprp()) { AstNode* newvaluep = NULL; if (!portp->valuep()) { - nodep->v3error("Missing argument on non-defaulted argument "<prettyNameQ() - <<" in function call to "<taskp()->prettyTypeName()); + nodep->v3error("Missing argument on non-defaulted argument " + << portp->prettyNameQ() << " in function call to " + << nodep->taskp()->prettyTypeName()); newvaluep = new AstConst(nodep->fileline(), AstConst::Unsized32(), 0); } else if (!VN_IS(portp->valuep(), Const)) { // The default value for this port might be a constant @@ -1412,11 +1416,10 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) // call, or something else that only makes sense in the // domain of the function, not the callee. nodep->v3error("Unsupported: Non-constant default value in missing argument " - <prettyNameQ() - <<" in function call to "<taskp()->prettyTypeName()); + << portp->prettyNameQ() << " in function call to " + << nodep->taskp()->prettyTypeName()); newvaluep = new AstConst(nodep->fileline(), AstConst::Unsized32(), 0); - } - else { + } else { newvaluep = newvaluep->cloneTree(true); } } else { @@ -1424,7 +1427,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) } // To avoid problems with callee needing to know to deleteTree // or not, we make this into a pin - UINFO(9,"Default pin for "<fileline(), portp->name(), newvaluep); if (tconnects[i].second) { // Have a "NULL" pin already defined for it VL_DO_CLEAR(tconnects[i].second->unlinkFrBack()->deleteTree(), @@ -1433,25 +1436,30 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) tconnects[i].second = newp; reorganize = true; } - if (tconnects[i].second) { UINFO(9,"Connect "< "< NONE"< " << tconnects[i].second << endl); + } else { + UINFO(9, "Connect " << portp << " -> NONE" << endl); + } } if (reorganize) { // To simplify downstream, put argument list back into pure pinnumber ordering - while (nodep->pinsp()) nodep->pinsp()->unlinkFrBack(); // Must unlink each pin, not all pins linked together as one list - for (int i=0; ipinsp()) { + // Must unlink each pin, not all pins linked together as one list + nodep->pinsp()->unlinkFrBack(); + } + for (int i = 0; i < tpinnum; ++i) { AstArg* argp = tconnects[i].second; UASSERT_OBJ(argp, nodep, "Lost argument in func conversion"); nodep->addPinsp(argp); } } - if (debug()>=9) { + if (debug() >= 9) { nodep->dumpTree(cout, "-ftref-out: "); - for (int i=0; itaskp(), nodep, "Unlinked"); if (nodep->didWidth()) return; userIterate(nodep->taskp(), NULL); // // And do the arguments to the task/function too do { - reloop: + reloop: V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); - for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) { + for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { AstVar* portp = it->first; AstArg* argp = it->second; AstNode* pinp = argp->exprp(); @@ -3467,18 +3467,23 @@ private: // pointer, so need to iterate separately later if (portp->attrSFormat() && (!VN_IS(pinp, SFormatF) || pinp->nextp())) { // Not already done - UINFO(4," sformat via metacomment: "<unlinkFrBackWithNext(&handle); // Format + additional args, if any AstNode* argsp = NULL; while (AstArg* nextargp = VN_CAST(argp->nextp(), Arg)) { argsp = AstNode::addNext( - argsp, nextargp->exprp()->unlinkFrBackWithNext()); // Expression goes to SFormatF + argsp, nextargp->exprp() + ->unlinkFrBackWithNext()); // Expression goes to SFormatF nextargp->unlinkFrBack()->deleteTree(); // Remove the call's Arg wrapper } string format; - if (VN_IS(pinp, Const)) format = VN_CAST(pinp, Const)->num().toString(); - else pinp->v3error("Format to $display-like function must have constant format string"); + if (VN_IS(pinp, Const)) { + format = VN_CAST(pinp, Const)->num().toString(); + } else { + pinp->v3error( + "Format to $display-like function must have constant format string"); + } VL_DO_DANGLING(pushDeletep(argp), argp); AstSFormatF* newp = new AstSFormatF(nodep->fileline(), format, false, argsp); if (!newp->scopeNamep() && newp->formatScopeTracking()) { @@ -3487,13 +3492,15 @@ private: handle.relink(new AstArg(newp->fileline(), "", newp)); // Connection list is now incorrect (has extra args in it). goto reloop; // so exit early; next loop will correct it - } - else if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING + } // + else if (portp->basicp() + && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING && !VN_IS(pinp, CvtPackString) && !VN_IS(pinp, SFormatF) // Already generates a string && !(VN_IS(pinp, VarRef) - && VN_CAST(pinp, VarRef)->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) { - UINFO(4," Add CvtPackString: "<varp()->basicp()->keyword() + == AstBasicDTypeKwd::STRING)) { + UINFO(4, " Add CvtPackString: " << pinp << endl); AstNRelinker handle; pinp->unlinkFrBack(&handle); // No next, that's the next pin AstNode* newp = new AstCvtPackString(pinp->fileline(), pinp); @@ -3507,21 +3514,19 @@ private: // Stage 2 { V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); - for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) { + for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { AstVar* portp = it->first; AstArg* argp = it->second; AstNode* pinp = argp->exprp(); if (!pinp) continue; // Argument error we'll find later // Change data types based on above accept completion - if (portp->isDouble()) { - VL_DO_DANGLING(spliceCvtD(pinp), pinp); - } + if (portp->isDouble()) VL_DO_DANGLING(spliceCvtD(pinp), pinp); } } // Stage 3 { V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); - for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) { + for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { AstVar* portp = it->first; AstArg* argp = it->second; AstNode* pinp = argp->exprp(); @@ -3532,13 +3537,11 @@ private: } } // Cleanup any open arrays - if (markHasOpenArray(nodep->taskp())) { - makeOpenArrayShell(nodep); - } + if (markHasOpenArray(nodep->taskp())) makeOpenArrayShell(nodep); // Stage 4 { V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); - for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) { + for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { AstVar* portp = it->first; AstArg* argp = it->second; AstNode* pinp = argp->exprp(); @@ -3546,16 +3549,14 @@ private: if (portp->direction() == VDirection::REF && !similarDTypeRecurse(portp->dtypep(), pinp->dtypep())) { pinp->v3error("Ref argument requires matching types;" - <<" port "<prettyNameQ() - <<" requires "<prettyTypeName() - <<" but connection is "<prettyTypeName()<<"."); - } else if (portp->isWritable() - && pinp->width() != portp->width()) { + << " port " << portp->prettyNameQ() << " requires " + << portp->prettyTypeName() << " but connection is " + << pinp->prettyTypeName() << "."); + } else if (portp->isWritable() && pinp->width() != portp->width()) { pinp->v3error("Unsupported: Function output argument " - <prettyNameQ() - <<" requires "<width() - <<" bits, but connection's "<prettyTypeName() - <<" generates "<width()<<" bits."); + << portp->prettyNameQ() << " requires " << portp->width() + << " bits, but connection's " << pinp->prettyTypeName() + << " generates " << pinp->width() << " bits."); // otherwise would need some mess to force both sides to proper size // (get an ASSIGN with EXTEND on the lhs instead of rhs) } @@ -3566,6 +3567,16 @@ private: } } } + } + virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { + // For arguments, is assignment-like context; see IEEE rules in AstNodeAssign + // Function hasn't been widthed, so make it so. + UINFO(5, " FTASKREF " << nodep << endl); + UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked"); + if (nodep->didWidth()) return; + userIterate(nodep->taskp(), NULL); + // And do the arguments to the task/function too + processFTaskRefArgs(nodep); nodep->didWidth(true); } virtual void visit(AstInitial* nodep) VL_OVERRIDE { From d4b6e2b2b5ca904799d6f9f118de2dffa37c2a3d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 12 Apr 2020 14:53:10 -0400 Subject: [PATCH 045/127] Internals: NodeModule for packages. --- src/V3Ast.h | 12 ++++++------ src/V3AstNodes.h | 22 +++++++++++----------- src/V3LinkDot.cpp | 19 ++++++++++--------- src/V3Scope.cpp | 2 +- src/V3SymTable.h | 8 ++++---- 5 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 26c3d7d91..b73b1840e 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1962,7 +1962,7 @@ private: bool m_lvalue; // Left hand side assignment AstVar* m_varp; // [AfterLink] Pointer to variable itself AstVarScope* m_varScopep; // Varscope for hierarchy - AstPackage* m_packagep; // Package hierarchy + AstNodeModule* m_packagep; // Package hierarchy string m_name; // Name of variable string m_hiername; // Scope converted into name-> for emitting bool m_hierThis; // Hiername points to "this" function @@ -1997,8 +1997,8 @@ public: void hiername(const string& hn) { m_hiername = hn; } bool hierThis() const { return m_hierThis; } void hierThis(bool flag) { m_hierThis = flag; } - AstPackage* packagep() const { return m_packagep; } - void packagep(AstPackage* nodep) { m_packagep = nodep; } + AstNodeModule* packagep() const { return m_packagep; } + void packagep(AstNodeModule* nodep) { m_packagep = nodep; } // Know no children, and hot function, so skip iterator for speed // See checkTreeIter also that asserts no children // cppcheck-suppress functionConst @@ -2362,7 +2362,7 @@ private: string m_name; // Name of variable string m_dotted; // Dotted part of scope the name()ed task/func is under or "" string m_inlinedDots; // Dotted hierarchy flattened out - AstPackage* m_packagep; // Package hierarchy + AstNodeModule* m_packagep; // Package hierarchy public: AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) : AstNodeStmt(t, fl, statement) @@ -2390,8 +2390,8 @@ public: void taskp(AstNodeFTask* taskp) { m_taskp = taskp; } virtual void name(const string& name) { m_name = name; } void dotted(const string& name) { m_dotted = name; } - AstPackage* packagep() const { return m_packagep; } - void packagep(AstPackage* nodep) { m_packagep = nodep; } + AstNodeModule* packagep() const { return m_packagep; } + void packagep(AstNodeModule* nodep) { m_packagep = nodep; } // op1 = namep AstNode* namep() const { return op1p(); } // op2 = reserved for AstMethodCall diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index dc4b9d8b8..63437c0c5 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -826,7 +826,7 @@ class AstClassRefDType : public AstNodeDType { // Reference to a class private: AstClass* m_classp; // data type pointed to, BELOW the AstTypedef - AstPackage* m_packagep; // Package hierarchy + AstNodeModule* m_packagep; // Package hierarchy public: AstClassRefDType(FileLine* fl, AstClass* classp) : ASTGEN_SUPER(fl), m_classp(classp), m_packagep(NULL) { @@ -858,8 +858,8 @@ public: virtual AstNodeDType* virtRefDTypep() const { return NULL; } virtual void virtRefDTypep(AstNodeDType* nodep) {} virtual AstNodeDType* subDTypep() const { return NULL; } - AstPackage* packagep() const { return m_packagep; } - void packagep(AstPackage* nodep) { m_packagep = nodep; } + AstNodeModule* packagep() const { return m_packagep; } + void packagep(AstNodeModule* nodep) { m_packagep = nodep; } AstClass* classp() const { return m_classp; } void classp(AstClass* nodep) { m_classp = nodep; } }; @@ -972,7 +972,7 @@ class AstRefDType : public AstNodeDType { private: AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef string m_name; // Name of an AstTypedef - AstPackage* m_packagep; // Package hierarchy + AstNodeModule* m_packagep; // Package hierarchy public: AstRefDType(FileLine* fl, const string& name) : ASTGEN_SUPER(fl), m_refDTypep(NULL), m_name(name), m_packagep(NULL) {} @@ -1028,8 +1028,8 @@ public: virtual AstNodeDType* virtRefDTypep() const { return refDTypep(); } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } virtual AstNodeDType* subDTypep() const { return m_refDTypep; } - AstPackage* packagep() const { return m_packagep; } - void packagep(AstPackage* nodep) { m_packagep = nodep; } + AstNodeModule* packagep() const { return m_packagep; } + void packagep(AstNodeModule* nodep) { m_packagep = nodep; } AstNode* typeofp() const { return op2p(); } }; @@ -1156,10 +1156,10 @@ public: class AstEnumItemRef : public AstNodeMath { private: - AstEnumItem* m_itemp; // [AfterLink] Pointer to item - AstPackage* m_packagep; // Package hierarchy + AstEnumItem* m_itemp; // [AfterLink] Pointer to item + AstNodeModule* m_packagep; // Package hierarchy public: - AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstPackage* packagep) + AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* packagep) : ASTGEN_SUPER(fl), m_itemp(itemp), m_packagep(packagep) { dtypeFrom(m_itemp); } @@ -1176,8 +1176,8 @@ public: virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } - AstPackage* packagep() const { return m_packagep; } - void packagep(AstPackage* nodep) { m_packagep = nodep; } + AstNodeModule* packagep() const { return m_packagep; } + void packagep(AstNodeModule* nodep) { m_packagep = nodep; } }; class AstEnumDType : public AstNodeDType { diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 3044eca87..3737d094b 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -350,8 +350,8 @@ public: } return symp; } - VSymEnt* insertBlock(VSymEnt* abovep, const string& name, - AstNode* nodep, AstPackage* packagep) { + VSymEnt* insertBlock(VSymEnt* abovep, const string& name, AstNode* nodep, + AstNodeModule* packagep) { // A fake point in the hierarchy, corresponding to a begin or function/task block // After we remove begins these will go away // Note we fallback to the symbol table of the parent, as we want to find variables there @@ -371,8 +371,8 @@ public: abovep->reinsert(name, symp); return symp; } - VSymEnt* insertSym(VSymEnt* abovep, const string& name, - AstNode* nodep, AstPackage* packagep) { + VSymEnt* insertSym(VSymEnt* abovep, const string& name, AstNode* nodep, + AstNodeModule* packagep) { UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node"); VSymEnt* symp = new VSymEnt(&m_syms, nodep); UINFO(9," INSERTsym se"<stmtsp(); np; np = np->nextp()) { if (AstVar* varp = VN_CAST(np, Var)) { if (!varp->isIfaceParent() && !varp->isIfaceRef() @@ -164,7 +169,8 @@ void V3CCtors::cctorsAll() { if (v3Global.opt.coverage()) { V3CCtorsVisitor configure_coverage( modp, "_configure_coverage", - EmitCBaseVisitor::symClassVar() + ", bool first", "vlSymsp, first", + EmitCBaseVisitor::symClassVar() + ", bool first", + "vlSymsp, first", "if (false && vlSymsp && first) {} // Prevent unused\n"); for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { if (AstCoverDecl* coverp = VN_CAST(np, CoverDecl)) { @@ -175,14 +181,6 @@ void V3CCtors::cctorsAll() { } } } - if (VN_IS(modp, Class)) { - AstCFunc* funcp = new AstCFunc(modp->fileline(), "new", NULL, ""); - funcp->isConstructor(true); - funcp->isStatic(false); - funcp->slow(false); - modp->addStmtp(funcp); - funcp->addStmtsp(new AstCCall(varResetFuncp->fileline(), varResetFuncp)); - } if (VN_IS(modp, Class)) { AstCFunc* funcp = new AstCFunc(modp->fileline(), "~", NULL, ""); funcp->isDestructor(true); diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 44b3b2457..9ee147aed 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -223,6 +223,10 @@ private: virtual void visit(AstScopeName* nodep) VL_OVERRIDE { setClean(nodep, true); } + virtual void visit(AstCNew* nodep) VL_OVERRIDE { + iterateChildren(nodep); + setClean(nodep, true); + } virtual void visit(AstSel* nodep) VL_OVERRIDE { operandTriop(nodep); setClean(nodep, nodep->cleanOut()); diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 742ec2f25..46d6bd05e 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -850,8 +850,10 @@ public: puts(cvtToStr(nodep->fileline()->lineno())); puts(")"); } - virtual void visit(AstNew* nodep) VL_OVERRIDE { + virtual void visit(AstCNew* nodep) VL_OVERRIDE { puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">("); + puts("vlSymsp"); // TODO make this part of argsp, and eliminate when unnecessary + if (nodep->argsp()) puts(", "); iterateAndNextNull(nodep->argsp()); puts(")"); } diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index f8d108f9f..3d6ee4b17 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -67,7 +67,7 @@ class EmitCInlines : EmitCBaseVisitor { v3Global.needHeavy(true); iterateChildren(nodep); } - virtual void visit(AstNew* nodep) VL_OVERRIDE { + virtual void visit(AstCNew* nodep) VL_OVERRIDE { if (v3Global.opt.savable()) v3error("Unsupported: --savable with dynamic new"); iterateChildren(nodep); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 3737d094b..521d02786 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -643,10 +643,9 @@ public: VSymEnt* foundp = NULL; while (!foundp) { foundp = lookupSymp->findIdFallback(prefix + dotname); // Might be NULL - if (prefix == "") { - break; - } - prefix = removeLastInlineScope(prefix); + if (prefix.empty()) break; + string nextPrefix = removeLastInlineScope(prefix); + if (prefix == nextPrefix) break; } if (!foundp) baddot = dotname; return foundp; @@ -686,7 +685,8 @@ class LinkDotFindVisitor : public AstNVisitor { bool m_inRecursion; // Inside a recursive module int m_paramNum; // Parameter number, for position based connection int m_beginNum; // Begin block number, 0=none seen - int m_modBeginNum; // Begin block number in module, 0=none seen + bool m_explicitNew; // Hit a "new" function + int m_modBeginNum; // Begin block number in module, 0=none seen // METHODS int debug() { return LinkDotState::debug(); } @@ -723,6 +723,13 @@ class LinkDotFindVisitor : public AstNVisitor { } return NULL; } + void makeImplicitNew(AstClass* nodep) { + AstFunc* newp = new AstFunc(nodep->fileline(), "new", NULL, NULL); + newp->isConstructor(true); + nodep->addMembersp(newp); + UINFO(8, "Made implicit new for " << nodep->name() << ": " << nodep << endl); + m_statep->insertBlock(m_curSymp, newp->name(), newp, m_packagep); + } // VISITs virtual void visit(AstNetlist* nodep) VL_OVERRIDE { @@ -842,10 +849,13 @@ class LinkDotFindVisitor : public AstNVisitor { m_paramNum = 0; m_beginNum = 0; m_modBeginNum = 0; + m_explicitNew = false; // m_modSymp/m_curSymp for non-packages set by AstCell above this module // Iterate iterateChildren(nodep); nodep->user4(true); + // Implicit new needed? + if (!m_explicitNew && m_statep->forPrimary()) makeImplicitNew(nodep); } m_scope = oldscope; m_modSymp = oldModSymp; @@ -971,6 +981,7 @@ class LinkDotFindVisitor : public AstNVisitor { // NodeTask: Remember its name for later resolution UINFO(5," "<name() == "new") m_explicitNew = true; // Remember the existing symbol table scope VSymEnt* oldCurSymp = m_curSymp; { @@ -1232,6 +1243,7 @@ public: m_inRecursion = false; m_paramNum = 0; m_beginNum = 0; + m_explicitNew = false; m_modBeginNum = 0; // iterate(rootp); @@ -2423,6 +2435,8 @@ private: <prettyName() <<"'"<<" as a "<nodep()->typeName() <<" but expected a task/function"); + } else if (VN_IS(nodep, New) && m_statep->forPrearray()) { + // Resolved in V3Width } else if (nodep->dotted() == "") { string suggest = m_statep->suggestSymFallback( dotSymp, nodep->name(), LinkNodeMatcherFTask()); diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index 197a4b2fe..7a001ad43 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -126,6 +126,7 @@ private: if (nodep->valuep()) clearOptimizable(nodep, "HasInitValue"); if (!VarFlags(nodep).m_stdFuncAsn) clearStdOptimizable(nodep, "NoStdAssign"); VarFlags flags (nodep); + if ((nodep->isMovableToBlock() // Blocktemp || !flags.m_notStd) // Or used only in block && !flags.m_notOpt // Optimizable diff --git a/src/V3Name.cpp b/src/V3Name.cpp index 95ba18acc..c2dc0aa39 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -56,6 +56,7 @@ private: string newname = string("__PVT__")+nodep->name(); nodep->name(newname); nodep->editCountInc(); + } else if (VN_IS(nodep, CFunc) && VN_CAST(nodep, CFunc)->isConstructor()) { } else { string rsvd = m_words.isKeyword(nodep->name()); if (rsvd != "") { diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 729daca0f..fe0f9c057 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -501,6 +501,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { { m_contextp = nodep; AstNodeFTask* ftaskp = nodep->taskp(); + UASSERT_OBJ(ftaskp, nodep, "Unlinked"); // Iterate arguments of a function/task. for (AstNode *argp = nodep->pinsp(), *paramp = ftaskp->stmtsp(); argp; argp = argp->nextp(), paramp = paramp ? paramp->nextp() : NULL) { diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 91f02aaef..e92e97b21 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -186,7 +186,7 @@ private: m_assignwp = NULL; } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { - // Includes handling AstMethodCall + // Includes handling AstMethodCall, AstNew if (m_assignwp) { // Wire assigns must become always statements to deal with insertion // of multiple statements. Perhaps someday make all wassigns into always's? @@ -204,6 +204,7 @@ private: m_curVxp = getFTaskVertex(nodep); if (nodep->dpiImport()) m_curVxp->noInline(true); if (nodep->classMethod()) m_curVxp->noInline(true); // Until V3Task supports it + if (nodep->isConstructor()) m_curVxp->noInline(true); iterateChildren(nodep); m_curVxp = lastVxp; } @@ -474,7 +475,7 @@ private: } AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, const string& namePrefix, - AstVarScope* outvscp) { + AstVarScope* outvscp, AstCNew*& cnewpr) { // outvscp is the variable for functions only, if NULL, it's a task UASSERT_OBJ(refp->taskp(), refp, "Unlinked?"); AstCFunc* cfuncp = m_statep->ftaskCFuncp(refp->taskp()); @@ -483,12 +484,19 @@ private: AstNode* beginp = new AstComment(refp->fileline(), string("Function: ")+refp->name(), true); AstNodeCCall* ccallp; - if (AstMethodCall* mrefp = VN_CAST(refp, MethodCall)) { + if (AstNew* mrefp = VN_CAST(refp, New)) { + AstCNew* cnewp = new AstCNew(refp->fileline(), cfuncp); + cnewp->dtypep(refp->dtypep()); + ccallp = cnewp; + // Parent AstNew will replace with this CNew + cnewpr = cnewp; + } else if (AstMethodCall* mrefp = VN_CAST(refp, MethodCall)) { ccallp = new AstCMethodCall(refp->fileline(), mrefp->fromp()->unlinkFrBack(), cfuncp); + beginp->addNext(ccallp); } else { ccallp = new AstCCall(refp->fileline(), cfuncp); + beginp->addNext(ccallp); } - beginp->addNext(ccallp); // Convert complicated outputs to temp signals V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp()); @@ -988,8 +996,10 @@ private: // so make it unique now. string suffix; // So, make them unique if (!nodep->taskPublic()) suffix = "_"+m_scopep->nameDotless(); + string name = ((nodep->name() == "new") ? "new" + : prefix + nodep->name() + suffix); AstCFunc* cfuncp = new AstCFunc(nodep->fileline(), - prefix + nodep->name() + suffix, + name, m_scopep, ((nodep->taskPublic() && rtnvarp) ? rtnvarp->cPubArgType(true, true) @@ -1003,6 +1013,7 @@ private: cfuncp->dpiImportWrapper(nodep->dpiImport()); cfuncp->isStatic(!(nodep->dpiImport() || nodep->taskPublic() || nodep->classMethod())); cfuncp->pure(nodep->pure()); + cfuncp->isConstructor(nodep->name() == "new"); //cfuncp->dpiImport // Not set in the wrapper - the called function has it set if (cfuncp->dpiExport()) cfuncp->cname(nodep->cname()); @@ -1017,6 +1028,10 @@ private: } else { // Need symbol table cfuncp->argTypes(EmitCBaseVisitor::symClassVar()); + if (cfuncp->name() == "new") { + cfuncp->addInitsp( + new AstCStmt(nodep->fileline(), "_ctor_var_reset(vlSymsp);\n")); + } } } if (nodep->dpiContext()) { @@ -1157,6 +1172,7 @@ private: m_scopep = NULL; } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { + // Includes handling AstMethodCall, AstNew UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked?"); iterateIntoFTask(nodep->taskp()); // First, do hierarchical funcs UINFO(4," FTask REF "<ftaskNoInline(nodep->taskp())) { // This may share VarScope's with a public task, if any. Yuk. - beginp = createNonInlinedFTask(nodep, namePrefix, outvscp); + beginp = createNonInlinedFTask(nodep, namePrefix, outvscp, cnewp /*ref*/); } else { beginp = createInlinedFTask(nodep, namePrefix, outvscp); } // Replace the ref AstNode* visitp = NULL; - if (!nodep->isStatement()) { + if (VN_IS(nodep, New)) { + UASSERT_OBJ(!nodep->isStatement(), nodep, "new is non-stmt"); + UASSERT_OBJ(cnewp, nodep, "didn't create cnew for new"); + nodep->replaceWith(cnewp); + visitp = insertBeforeStmt(nodep, beginp); + } else if (!nodep->isStatement()) { UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function"); AstVarRef* outrefp = new AstVarRef(nodep->fileline(), outvscp, false); nodep->replaceWith(outrefp); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 8550c3c6c..4f30f2c50 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1895,7 +1895,7 @@ private: } virtual void visit(AstMethodCall* nodep) VL_OVERRIDE { - UINFO(5," METHODSEL "<didWidth()) return; if (debug()>=9) nodep->dumpTree("-mts-in: "); // Should check types the method requires, but at present we don't do much @@ -2431,12 +2431,20 @@ private: return; } nodep->dtypep(refp); - if (nodep->argsp()) { - nodep->v3error("Unsupported: new with arguments"); - pushDeletep(nodep->argsp()->unlinkFrBackWithNext()); - //TODO code similar to AstNodeFTaskRef - //userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); + + AstClass* classp = refp->classp(); + UASSERT_OBJ(classp, nodep, "Unlinked"); + if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember("new"), Func)) { + nodep->taskp(ftaskp); + nodep->packagep(classp); + } else { + // Either made explicitly or V3LinkDot made implicitly + classp->v3fatalSrc("Can't find class's new"); } + + userIterate(nodep->taskp(), NULL); + userIterateChildren(nodep, NULL); + processFTaskRefArgs(nodep); } virtual void visit(AstNewCopy* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; @@ -3406,7 +3414,6 @@ private: userIterateChildren(nodep, NULL); if (nodep->isConstructor()) { // Pretend it's void so less special casing needed when look at dtypes - nodep->v3error("Unsupported: new constructor"); nodep->dtypeSetVoid(); } else if (nodep->fvarp()) { m_funcp = VN_CAST(nodep, Func); diff --git a/test_regress/t/t_class_new.out b/test_regress/t/t_class_new.out deleted file mode 100644 index 6ddfd5636..000000000 --- a/test_regress/t/t_class_new.out +++ /dev/null @@ -1,13 +0,0 @@ -%Error: t/t_class_new.v:9:13: Unsupported: new constructor - : ... In instance t - 9 | function new(); - | ^~~ -%Error: t/t_class_new.v:16:13: Unsupported: new constructor - : ... In instance t - 16 | function new(int i); - | ^~~ -%Error: t/t_class_new.v:27:12: Unsupported: new with arguments - : ... In instance t - 27 | c2 = new(2); - | ^~~ -%Error: Exiting due to diff --git a/test_regress/t/t_class_new.pl b/test_regress/t/t_class_new.pl index 64b3d2dde..27b3049d2 100755 --- a/test_regress/t/t_class_new.pl +++ b/test_regress/t/t_class_new.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_class_new.v b/test_regress/t/t_class_new.v index 27a806465..e370e2e49 100644 --- a/test_regress/t/t_class_new.v +++ b/test_regress/t/t_class_new.v @@ -16,16 +16,22 @@ class ClsArg; function new(int i); imembera = i + 1; endfunction + function int geta; + return imembera; + endfunction endclass module t (/*AUTOARG*/); initial begin ClsNoArg c1; ClsArg c2; + c1 = new; if (c1.imembera != 5) $stop; + c2 = new(2); if (c2.imembera != 3) $stop; + if (c2.geta() != 3) $stop; $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_class_new_bad.out b/test_regress/t/t_class_new_bad.out index 293a4cd3f..ac1b98bf5 100644 --- a/test_regress/t/t_class_new_bad.out +++ b/test_regress/t/t_class_new_bad.out @@ -1,13 +1,12 @@ -%Error: t/t_class_new_bad.v:10:13: Unsupported: new constructor - : ... In instance t - 10 | function new(); - | ^~~ -%Error: t/t_class_new_bad.v:17:13: Unsupported: new constructor - : ... In instance t - 17 | function new(int i); - | ^~~ -%Error: t/t_class_new_bad.v:26:12: Unsupported: new with arguments - : ... In instance t - 26 | c1 = new(3); +%Error: t/t_class_new_bad.v:31:16: Too many arguments in function call to FUNC 'new' + 31 | c1 = new(3); + | ^ +%Error: t/t_class_new_bad.v:32:16: Too many arguments in function call to FUNC 'new' + 32 | c2 = new(3); + | ^ +%Error: t/t_class_new_bad.v:33:12: Missing argument on non-defaulted argument 'i' in function call to FUNC 'new' + 33 | c3 = new(); + | ^~~ +%Error: Internal Error: t/t_class_new_bad.v:33:12: ../V3Broken.cpp:#: Width != WidthMin + 33 | c3 = new(); | ^~~ -%Error: Exiting due to diff --git a/test_regress/t/t_class_new_bad.v b/test_regress/t/t_class_new_bad.v index 4e721bd61..5029ff0fd 100644 --- a/test_regress/t/t_class_new_bad.v +++ b/test_regress/t/t_class_new_bad.v @@ -12,6 +12,10 @@ class ClsNoArg; endfunction endclass +class ClsNoNew; + int imembera; +endclass + class ClsArg; int imembera; function new(int i); @@ -22,9 +26,11 @@ endclass module t (/*AUTOARG*/); initial begin ClsNoArg c1; - ClsArg c2; + ClsNoNew c2; + ClsArg c3; c1 = new(3); // Bad, called with arg - c2 = new(); // Bad, called without arg + c2 = new(3); // Bad, called with arg + c3 = new(); // Bad, called without arg $stop; end endmodule From 236e6baa76a3ffb81a3f0442f669403d053eaef2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 13 Apr 2020 17:44:19 -0400 Subject: [PATCH 047/127] clang-format: Loops allowed on single line. --- .clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 0fd60f7dd..5e66ff611 100644 --- a/.clang-format +++ b/.clang-format @@ -13,7 +13,7 @@ AllowShortBlocksOnASingleLine: true AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: true -AllowShortLoopsOnASingleLine: false +AllowShortLoopsOnASingleLine: true AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false From dc27a179e2bbeeeb8cd3b413d536f8e78987d7d0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 13 Apr 2020 19:07:56 -0400 Subject: [PATCH 048/127] Always define VL_SIG etc; conditional definitions were long removed SystemPerl. --- include/verilated.h | 63 +++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index 7636eb71f..31bbbb75b 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -239,55 +239,56 @@ public: //========================================================================= // Declare nets -#ifndef VL_SIG -# define VL_SIG8(name, msb,lsb) CData name ///< Declare signal, 1-8 bits -# define VL_SIG16(name, msb,lsb) SData name ///< Declare signal, 9-16 bits -# define VL_SIG64(name, msb,lsb) QData name ///< Declare signal, 33-64 bits -# define VL_SIG(name, msb,lsb) IData name ///< Declare signal, 17-32 bits -# define VL_SIGW(name, msb,lsb, words) WData name[words] ///< Declare signal, 65+ bits -# define VL_IN8(name, msb,lsb) CData name ///< Declare input signal, 1-8 bits -# define VL_IN16(name, msb,lsb) SData name ///< Declare input signal, 9-16 bits -# define VL_IN64(name, msb,lsb) QData name ///< Declare input signal, 33-64 bits -# define VL_IN(name, msb,lsb) IData name ///< Declare input signal, 17-32 bits -# define VL_INW(name, msb,lsb, words) WData name[words] ///< Declare input signal, 65+ bits -# define VL_INOUT8(name, msb,lsb) CData name ///< Declare bidir signal, 1-8 bits -# define VL_INOUT16(name, msb,lsb) SData name ///< Declare bidir signal, 9-16 bits -# define VL_INOUT64(name, msb,lsb) QData name ///< Declare bidir signal, 33-64 bits -# define VL_INOUT(name, msb,lsb) IData name ///< Declare bidir signal, 17-32 bits -# define VL_INOUTW(name, msb,lsb, words) WData name[words] ///< Declare bidir signal, 65+ bits -# define VL_OUT8(name, msb,lsb) CData name ///< Declare output signal, 1-8 bits -# define VL_OUT16(name, msb,lsb) SData name ///< Declare output signal, 9-16 bits -# define VL_OUT64(name, msb,lsb) QData name ///< Declare output signal, 33-64bits -# define VL_OUT(name, msb,lsb) IData name ///< Declare output signal, 17-32 bits -# define VL_OUTW(name, msb,lsb, words) WData name[words] ///< Declare output signal, 65+ bits +#define VL_SIG8(name, msb, lsb) CData name ///< Declare signal, 1-8 bits +#define VL_SIG16(name, msb, lsb) SData name ///< Declare signal, 9-16 bits +#define VL_SIG64(name, msb, lsb) QData name ///< Declare signal, 33-64 bits +#define VL_SIG(name, msb, lsb) IData name ///< Declare signal, 17-32 bits +#define VL_SIGW(name, msb, lsb, words) WData name[words] ///< Declare signal, 65+ bits +#define VL_IN8(name, msb, lsb) CData name ///< Declare input signal, 1-8 bits +#define VL_IN16(name, msb, lsb) SData name ///< Declare input signal, 9-16 bits +#define VL_IN64(name, msb, lsb) QData name ///< Declare input signal, 33-64 bits +#define VL_IN(name, msb, lsb) IData name ///< Declare input signal, 17-32 bits +#define VL_INW(name, msb, lsb, words) WData name[words] ///< Declare input signal, 65+ bits +#define VL_INOUT8(name, msb, lsb) CData name ///< Declare bidir signal, 1-8 bits +#define VL_INOUT16(name, msb, lsb) SData name ///< Declare bidir signal, 9-16 bits +#define VL_INOUT64(name, msb, lsb) QData name ///< Declare bidir signal, 33-64 bits +#define VL_INOUT(name, msb, lsb) IData name ///< Declare bidir signal, 17-32 bits +#define VL_INOUTW(name, msb, lsb, words) WData name[words] ///< Declare bidir signal, 65+ bits +#define VL_OUT8(name, msb, lsb) CData name ///< Declare output signal, 1-8 bits +#define VL_OUT16(name, msb, lsb) SData name ///< Declare output signal, 9-16 bits +#define VL_OUT64(name, msb, lsb) QData name ///< Declare output signal, 33-64bits +#define VL_OUT(name, msb, lsb) IData name ///< Declare output signal, 17-32 bits +#define VL_OUTW(name, msb, lsb, words) WData name[words] ///< Declare output signal, 65+ bits -# define VL_PIN_NOP(instname,pin,port) ///< Connect a pin, ala SP_PIN -# define VL_CELL(instname,type) ///< Declare a cell, ala SP_CELL +#define VL_PIN_NOP(instname, pin, port) ///< Connect a pin, ala SP_PIN +#define VL_CELL(instname, type) ///< Declare a cell, ala SP_CELL /// Declare a module, ala SC_MODULE -# define VL_MODULE(modname) class modname : public VerilatedModule +#define VL_MODULE(modname) class modname : public VerilatedModule /// Constructor, ala SC_CTOR -# define VL_CTOR(modname) modname(const char* __VCname="") +#define VL_CTOR(modname) modname(const char* __VCname = "") /// Constructor declaration for C++, ala SP_CTOR_IMPL -# define VL_CTOR_IMP(modname) modname::modname(const char* __VCname) : VerilatedModule(__VCname) +#define VL_CTOR_IMP(modname) \ + modname::modname(const char* __VCname) \ + : VerilatedModule(__VCname) /// Constructor declaration for SystemC, ala SP_CTOR_IMPL -# define VL_SC_CTOR_IMP(modname) modname::modname(sc_module_name) - -#endif +#define VL_SC_CTOR_IMP(modname) modname::modname(sc_module_name) //========================================================================= // Functions overridable by user defines // (Internals however must use VL_PRINTF_MT, which calls these.) +// clang-format off #ifndef VL_PRINTF -# define VL_PRINTF printf ///< Print ala printf, called from main thread; may redefine if desired +# define VL_PRINTF printf ///< Print ala printf, called from main thread; redefine if desired #endif #ifndef VL_VPRINTF -# define VL_VPRINTF vprintf ///< Print ala vprintf, called from main thread; may redefine if desired +# define VL_VPRINTF vprintf ///< Print ala vprintf, called from main thread; redefine if desired #endif +// clang-format on //=========================================================================== /// Verilator symbol table base class From dc5c259069f63b718ef3b7909724571c97beff53 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 14 Apr 2020 00:13:10 +0100 Subject: [PATCH 049/127] Improve tracing performance. (#2257) * Improve tracing performance. Various tactics used to improve performance of both VCD and FST tracing: - Both: Change tracing functions to templates to take variable widths as template parameters. For VCD, subsequently specialize these to the values used by Verilator. This avoids redundant instructions and hard to predict branches. - Both: Check for value changes via direct pointer access into the previous signal value buffer. This eliminates a lot of simple pointer arithmetic instructions form the tracing code. - Both: Verilator provides clean input, no need to mask out used bits. - VCD: pre-compute identifier codes and use memory copy instead of re-computing them every time a code is emitted. This saves a lot of instructions and hard to predict branches. The added D-cache misses are cheaper than the removed branches/instructions. - VCD: re-write the routines emitting the changes to be more efficient. - FST: Use previous signal value buffer the same way as the VCD tracing code, and only call the FST API when a change is detected. Performance as measured on SweRV EH1, with the pre-canned CoreMark benchmark running from DCCM/ICCM, clang 6.0.0, Intel i7-3770 @ 3.40GHz, and IO to ramdisk: +--------------+---------------+----------------------+ | VCD | FST | FST separate thread | | (--trace) | (--trace-fst) | (--trace-fst-thread) | ------------+-----------------------------------------------------+ Before | 30.2 s | 121.1 s | 69.8 s | ============+==============+===============+======================+ After | 24.7 s | 45.7 s | 32.4 s | ------------+--------------+---------------+----------------------+ Speedup | 22 % | 256 % | 215 % | ------------+--------------+---------------+----------------------+ Rel. to VCD | 1 x | 1.85 x | 1.31 x | ------------+--------------+---------------+----------------------+ In addition, FST trace size for the above reduced by 48%. --- Changes | 4 +- bin/verilator | 6 + include/verilated_fst_c.cpp | 17 +- include/verilated_fst_c.h | 156 +-- include/verilated_vcd_c.cpp | 371 +++++- include/verilated_vcd_c.h | 143 ++- src/V3EmitC.cpp | 47 +- test_regress/t/t_trace_complex_fst.out | 13 +- test_regress/t/t_trace_complex_old_api.pl | 38 + test_regress/t/t_trace_complex_params_fst.out | 13 +- .../t/t_trace_complex_structs_fst.out | 24 +- test_regress/t/t_trace_fst.out | 1067 +++++------------ test_regress/t/t_trace_packed_struct_fst.out | 3 +- 13 files changed, 920 insertions(+), 982 deletions(-) create mode 100755 test_regress/t/t_trace_complex_old_api.pl diff --git a/Changes b/Changes index e49f180d7..053cbda98 100644 --- a/Changes +++ b/Changes @@ -15,11 +15,11 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. -**** Improve FST dump performance, #2244, #2250. [Geza Lore] +**** Greatly improve FST dump performance, #2244, #2250, #2257. [Geza Lore] **** Fix build of fast path tracing code to use OPT_FAST, #2245. [Geza Lore] -**** Improve VCD dump performance, #2246, #2250. [Geza Lore] +**** Improve VCD dump performance, #2246, #2250, #2257. [Geza Lore] * Verilator 4.032 2020-04-04 diff --git a/bin/verilator b/bin/verilator index cd1bfb1e3..d49fc5e08 100755 --- a/bin/verilator +++ b/bin/verilator @@ -4987,6 +4987,12 @@ using the Verilator --exe flag. Note you can also call ->trace on multiple Verilated objects with the same trace file if you want all data to land in the same output file. +When using SystemC 2.3, the SystemC library must have been built with the +experiemntal simulation phase callback based tracing disabled. This is +disabled by default when building SystemC with its configure based build +system, but when building SystemC with CMake, you must pass +-DENABLE_PHASE_CALLBACKS_TRACING=OFF to disable this feature. + #include "verilated_vcd_sc.h" ... int main(int argc, char** argv, char** env) { diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index bdd2e5d61..5654cf9e8 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -17,6 +17,8 @@ //============================================================================= // SPDIFF_OFF +// clang-format off + #define __STDC_LIMIT_MACROS // UINT64_MAX #include "verilatedos.h" #include "verilated.h" @@ -49,6 +51,8 @@ # include #endif +// clang-format on + //============================================================================= class VerilatedFstCallInfo { @@ -79,13 +83,15 @@ VerilatedFst::VerilatedFst(void* fst) , m_minNextDumpTime(0) , m_nextCode(1) , m_scopeEscape('.') - , m_symbolp(NULL) { + , m_symbolp(NULL) + , m_sigs_oldvalp(NULL) { m_valueStrBuffer.reserve(64 + 1); // Need enough room for quad } VerilatedFst::~VerilatedFst() { if (m_fst) fstWriterClose(m_fst); if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = NULL); + if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL); } void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { @@ -121,6 +127,9 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { } } m_code2symbol.clear(); + + // Allocate space now we know the number of codes + if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[m_nextCode + 10]; } void VerilatedFst::module(const std::string& name) { m_module = name; } @@ -214,9 +223,9 @@ void VerilatedFst::addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallba void VerilatedFst::dump(vluint64_t timeui) { if (!isOpen()) return; if (timeui < m_minNextDumpTime) { - VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64 "u\n", - m_minNextDumpTime - 1, timeui); - return; + VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64 "u\n", + m_minNextDumpTime - 1, timeui); + return; } m_minNextDumpTime = timeui + 1; if (VL_UNLIKELY(m_fullDump)) { diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index ffae20875..341514adc 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -57,11 +57,11 @@ private: Local2FstDtype m_local2fstdtype; std::list m_curScope; fstHandle* m_symbolp; ///< same as m_code2symbol, but as an array + vluint32_t* m_sigs_oldvalp; // CONSTRUCTORS VL_UNCOPYABLE(VerilatedFst); - void declSymbol(vluint32_t code, const char* name, - int dtypenum, fstVarDir vardir, fstVarType vartype, - bool array, int arraynum, vluint32_t len, vluint32_t bits); + void declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum, vluint32_t len, vluint32_t bits); // helpers std::vector m_valueStrBuffer; @@ -94,102 +94,108 @@ public: void dump(vluint64_t timeui); /// Inside dumping routines, declare callbacks for tracings void addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb, - VerilatedFstCallback_t changecb, - void* userthis) VL_MT_UNSAFE_ONE; + VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE; /// Inside dumping routines, declare a module void module(const std::string& name); /// Inside dumping routines, declare a data type void declDTypeEnum(int dtypenum, const char* name, vluint32_t elements, - unsigned int minValbits, - const char** itemNamesp, const char** itemValuesp); + unsigned int minValbits, const char** itemNamesp, const char** itemValuesp); /// Inside dumping routines, declare a signal - void declBit(vluint32_t code, const char* name, - int dtypenum, fstVarDir vardir, fstVarType vartype, - bool array, int arraynum) { + void declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum) { declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1); } - void declBus(vluint32_t code, const char* name, - int dtypenum, fstVarDir vardir, fstVarType vartype, - bool array, int arraynum, int msb, int lsb) { + void declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum, int msb, int lsb) { declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, msb - lsb + 1); } - void declDouble(vluint32_t code, const char* name, - int dtypenum, fstVarDir vardir, fstVarType vartype, - bool array, int arraynum) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64); + void declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum, int msb, int lsb) { + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, + msb - lsb + 1); } - void declFloat(vluint32_t code, const char* name, - int dtypenum, fstVarDir vardir, fstVarType vartype, - bool array, int arraynum) { + void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum, int msb, int lsb) { + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, + msb - lsb + 1); + } + void declFloat(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum) { declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32); } - void declQuad(vluint32_t code, const char* name, - int dtypenum, fstVarDir vardir, fstVarType vartype, - bool array, int arraynum, int msb, int lsb) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, - msb - lsb + 1); - } - void declArray(vluint32_t code, const char* name, - int dtypenum, fstVarDir vardir, fstVarType vartype, - bool array, int arraynum, int msb, int lsb) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, - msb - lsb + 1); + void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum) { + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64); } - /// Inside dumping routines, dump one signal if it has changed - void chgBit(vluint32_t code, const vluint32_t newval) { - fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0"); + //========================================================================= + // Inside dumping routines used by Verilator + + vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; } + + //========================================================================= + // Write back to previous value buffer value and emit + + void fullBit(vluint32_t* oldp, vluint32_t newval) { + *oldp = newval; + fstWriterEmitValueChange(m_fst, m_symbolp[oldp - m_sigs_oldvalp], newval ? "1" : "0"); } - void chgBus(vluint32_t code, const vluint32_t newval, int bits) { - fstWriterEmitValueChange32(m_fst, m_symbolp[code], bits, newval); + template void fullBus(vluint32_t* oldp, vluint32_t newval) { + *oldp = newval; + fstWriterEmitValueChange32(m_fst, m_symbolp[oldp - m_sigs_oldvalp], T_Bits, newval); } - void chgDouble(vluint32_t code, const double newval) { - double val = newval; - fstWriterEmitValueChange(m_fst, m_symbolp[code], &val); + void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + *reinterpret_cast(oldp) = newval; + fstWriterEmitValueChange64(m_fst, m_symbolp[oldp - m_sigs_oldvalp], bits, newval); } - void chgFloat(vluint32_t code, const float newval) { - double val = (double)newval; - fstWriterEmitValueChange(m_fst, m_symbolp[code], &val); + void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + for (int i = 0; i < (bits + 31) / 32; ++i) oldp[i] = newvalp[i]; + fstWriterEmitValueChangeVec32(m_fst, m_symbolp[oldp - m_sigs_oldvalp], bits, newvalp); } - void chgQuad(vluint32_t code, const vluint64_t newval, int bits) { - fstWriterEmitValueChange64(m_fst, m_symbolp[code], bits, newval); + void fullFloat(vluint32_t* oldp, float newval) { + // cppcheck-suppress invalidPointerCast + *reinterpret_cast(oldp) = newval; + fstWriterEmitValueChange(m_fst, m_symbolp[oldp - m_sigs_oldvalp], oldp); } - void chgArray(vluint32_t code, const vluint32_t* newval, int bits) { - fstWriterEmitValueChangeVec32(m_fst, m_symbolp[code], bits, newval); + void fullDouble(vluint32_t* oldp, double newval) { + // cppcheck-suppress invalidPointerCast + *reinterpret_cast(oldp) = newval; + fstWriterEmitValueChange(m_fst, m_symbolp[oldp - m_sigs_oldvalp], oldp); } - void fullBit(vluint32_t code, const vluint32_t newval) { chgBit(code, newval); } - void fullBus(vluint32_t code, const vluint32_t newval, int bits) { - chgBus(code, newval, bits); - } - void fullDouble(vluint32_t code, const double newval) { chgDouble(code, newval); } - void fullFloat(vluint32_t code, const float newval) { chgFloat(code, newval); } - void fullQuad(vluint32_t code, const vluint64_t newval, int bits) { - chgQuad(code, newval, bits); - } - void fullArray(vluint32_t code, const vluint32_t* newval, int bits) { - chgArray(code, newval, bits); - } + //========================================================================= + // Check previous value and emit if changed - void declTriBit(vluint32_t code, const char* name, int arraynum); - void declTriBus(vluint32_t code, const char* name, int arraynum, int msb, int lsb); - void declTriQuad(vluint32_t code, const char* name, int arraynum, int msb, int lsb); - void declTriArray(vluint32_t code, const char* name, int arraynum, int msb, int lsb); - void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri); - void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits); - void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits); - void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, - int bits); - void fullBitX(vluint32_t code); - void fullBusX(vluint32_t code, int bits); - void fullQuadX(vluint32_t code, int bits); - void fullArrayX(vluint32_t code, int bits); - void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri); - void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits); - void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits); - void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits); + inline void chgBit(vluint32_t* oldp, vluint32_t newval) { + const vluint32_t diff = *oldp ^ newval; + if (VL_UNLIKELY(diff)) fullBit(oldp, newval); + } + template inline void chgBus(vluint32_t* oldp, vluint32_t newval) { + const vluint32_t diff = *oldp ^ newval; + if (VL_UNLIKELY(diff)) fullBus(oldp, newval); + } + inline void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + const vluint64_t diff = *reinterpret_cast(oldp) ^ newval; + if (VL_UNLIKELY(diff)) fullQuad(oldp, newval, bits); + } + inline void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + for (int i = 0; i < (bits + 31) / 32; ++i) { + if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) { + fullArray(oldp, newvalp, bits); + return; + } + } + } + inline void chgFloat(vluint32_t* oldp, float newval) { + // cppcheck-suppress invalidPointerCast + if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullFloat(oldp, newval); + } + inline void chgDouble(vluint32_t* oldp, double newval) { + // cppcheck-suppress invalidPointerCast + if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullDouble(oldp, newval); + } }; //============================================================================= diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 62b6c33cd..d5bde2a92 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -17,6 +17,8 @@ //============================================================================= // SPDIFF_OFF +// clang-format off + #include "verilatedos.h" #include "verilated.h" #include "verilated_vcd_c.h" @@ -45,6 +47,19 @@ # define O_CLOEXEC 0 #endif +// clang-format on + +// This size comes form VCD allowing use of printable ASCII characters between +// '!' and '~' inclusive, which are a total of 94 different values. Encoding a +// 32 bit code hence needs a maximum of ceil(log94(2**32-1)) == 5 bytes. +#define VL_TRACE_MAX_VCD_CODE_SIZE 5 ///< Maximum length of a VCD string code +// We use 8 bytes per code in a suffix buffer array. +// 1 byte optional separator + VL_TRACE_MAX_VCD_CODE_SIZE bytes for code +// + 1 byte '\n' + 1 byte suffix size. This luckily comes out to a power of 2, +// meaning the array can be aligned such that entries never straddle multiple +// cache-lines. +#define VL_TRACE_SUFFIX_ENTRY_SIZE 8 ///< Size of a suffix entry + //============================================================================= // VerilatedVcdImp /// Base class to hold some static state @@ -57,7 +72,10 @@ private: VerilatedMutex s_vcdMutex; ///< Protect the singleton VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces }; - static Singleton& singleton() { static Singleton s; return s; } + static Singleton& singleton() { + static Singleton s; + return s; + } public: static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) { @@ -152,6 +170,7 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) m_wrFlushp = m_wrBufp + m_wrChunkSize * 6; m_writep = m_wrBufp; m_wroteBytes = 0; + m_suffixesp = NULL; } void VerilatedVcd::open(const char* filename) { @@ -175,6 +194,9 @@ void VerilatedVcd::open(const char* filename) { // Allocate space now we know the number of codes if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[m_nextCode + 10]; + // Get the direct access pointer to the code strings + m_suffixesp = &m_suffixes[0]; // Note: C++11 m_suffixes.data(); + if (m_rolloverMB) { openNext(true); if (!isOpen()) return; @@ -191,10 +213,8 @@ void VerilatedVcd::openNext(bool incFilename) { std::string name = m_filename; size_t pos = name.rfind('.'); if (pos > 8 && 0 == strncmp("_cat", name.c_str() + pos - 8, 4) - && isdigit(name.c_str()[pos - 4]) - && isdigit(name.c_str()[pos - 3]) - && isdigit(name.c_str()[pos - 2]) - && isdigit(name.c_str()[pos - 1])) { + && isdigit(name.c_str()[pos - 4]) && isdigit(name.c_str()[pos - 3]) + && isdigit(name.c_str()[pos - 2]) && isdigit(name.c_str()[pos - 1])) { // Increment code. if ((++(name[pos - 1])) > '9') { name[pos - 1] = '0'; @@ -404,7 +424,8 @@ void VerilatedVcd::set_time_resolution(const char* unitp) { double VerilatedVcd::timescaleToDouble(const char* unitp) { char* endp; double value = strtod(unitp, &endp); - if (value == 0.0 && endp == unitp) value = 1; // On error so we allow just "ns" to return 1e-9. + // On error so we allow just "ns" to return 1e-9. + if (value == 0.0 && endp == unitp) value = 1; unitp = endp; for (; *unitp && isspace(*unitp); unitp++) {} switch (*unitp) { @@ -421,27 +442,41 @@ double VerilatedVcd::timescaleToDouble(const char* unitp) { std::string VerilatedVcd::doubleToTimescale(double value) { const char* suffixp = "s"; - if (value>=1e0) { suffixp="s"; value *= 1e0; } - else if (value>=1e-3 ) { suffixp="ms"; value *= 1e3; } - else if (value>=1e-6 ) { suffixp="us"; value *= 1e6; } - else if (value>=1e-9 ) { suffixp="ns"; value *= 1e9; } - else if (value>=1e-12) { suffixp="ps"; value *= 1e12; } - else if (value>=1e-15) { suffixp="fs"; value *= 1e15; } - else if (value>=1e-18) { suffixp="as"; value *= 1e18; } + // clang-format off + if (value >= 1e0) { suffixp = "s"; value *= 1e0; } + else if (value >= 1e-3 ) { suffixp = "ms"; value *= 1e3; } + else if (value >= 1e-6 ) { suffixp = "us"; value *= 1e6; } + else if (value >= 1e-9 ) { suffixp = "ns"; value *= 1e9; } + else if (value >= 1e-12) { suffixp = "ps"; value *= 1e12; } + else if (value >= 1e-15) { suffixp = "fs"; value *= 1e15; } + else if (value >= 1e-18) { suffixp = "as"; value *= 1e18; } + // clang-format on char valuestr[100]; sprintf(valuestr, "%3.0f%s", value, suffixp); return valuestr; // Gets converted to string, so no ref to stack } +//============================================================================= +// VCD string code + +char* VerilatedVcd::writeCode(char* writep, vluint32_t code) { + *writep++ = static_cast('!' + code % 94); + code /= 94; + while (code) { + code--; + *writep++ = static_cast('!' + code % 94); + code /= 94; + } + return writep; +} + //============================================================================= // Definitions void VerilatedVcd::printIndent(int level_change) { if (level_change < 0) m_modDepth += level_change; assert(m_modDepth >= 0); - for (int i = 0; i < m_modDepth; i++) { - printStr(" "); - } + for (int i = 0; i < m_modDepth; i++) printStr(" "); if (level_change > 0) m_modDepth += level_change; } @@ -539,8 +574,8 @@ void VerilatedVcd::module(const std::string& name) { m_modName = name; } -void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, - bool array, int arraynum, bool tri, bool bussed, int msb, int lsb) { +void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, bool array, + int arraynum, bool tri, bool bussed, int msb, int lsb) { if (!code) { VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal"); } @@ -554,6 +589,9 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, if (m_sigs.capacity() <= m_nextCode) { m_sigs.reserve(m_nextCode * 2); // Power-of-2 allocation speeds things up } + if (m_suffixes.size() <= m_nextCode * VL_TRACE_SUFFIX_ENTRY_SIZE) { + m_suffixes.resize(m_nextCode * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0); + } // Make sure write buffer is large enough (one character per bit), plus header bufferResize(bits + 1024); @@ -601,7 +639,21 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, sprintf(buf, "<%u", code); decl += buf; } else { - decl += stringCode(code); + // Add string code to decl + char* const endp = writeCode(buf, code); + *endp = '\0'; + decl += buf; + // Build suffix array entry + char* const entryp = &m_suffixes[code * VL_TRACE_SUFFIX_ENTRY_SIZE]; + const size_t length = endp - buf; + assert(length <= VL_TRACE_MAX_VCD_CODE_SIZE); + // 1 bit values don't have a ' ' separator between value and string code + const bool isBit = bits == 1; + entryp[0] = ' '; // Separator + std::strcpy(entryp + !isBit, buf); // Code (overwrite separator if isBit) + entryp[length + !isBit] = '\n'; // Replace '\0' with line termination '\n' + // Set length of suffix (used to increment write pointer) + entryp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1] = !isBit + length + 1; } decl += " "; decl += basename; @@ -633,6 +685,13 @@ void VerilatedVcd::declArray(vluint32_t code, const char* name, bool array, int int lsb) { declare(code, name, "wire", array, arraynum, false, true, msb, lsb); } +void VerilatedVcd::declFloat(vluint32_t code, const char* name, bool array, int arraynum) { + declare(code, name, "real", array, arraynum, false, false, 31, 0); +} +void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int arraynum) { + declare(code, name, "real", array, arraynum, false, false, 63, 0); +} +#ifndef VL_TRACE_VCD_OLD_API void VerilatedVcd::declTriBit(vluint32_t code, const char* name, bool array, int arraynum) { declare(code, name, "wire", array, arraynum, true, false, 0, 0); } @@ -648,20 +707,234 @@ void VerilatedVcd::declTriArray(vluint32_t code, const char* name, bool array, i int msb, int lsb) { declare(code, name, "wire", array, arraynum, true, true, msb, lsb); } -void VerilatedVcd::declFloat(vluint32_t code, const char* name, bool array, int arraynum) { - declare(code, name, "real", array, arraynum, false, false, 31, 0); -} -void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int arraynum) { - declare(code, name, "real", array, arraynum, false, false, 63, 0); -} +#endif // VL_TRACE_VCD_OLD_API //============================================================================= +// Trace recording routines + +#ifndef VL_TRACE_VCD_OLD_API + +//============================================================================= +// Pointer based variants used by Verilator + +// Emit suffix, write back write pointer, check buffer +void VerilatedVcd::finishLine(vluint32_t* oldp, char* writep) { + const vluint32_t code = oldp - m_sigs_oldvalp; + const char* const suffixp = m_suffixesp + code * VL_TRACE_SUFFIX_ENTRY_SIZE; + // Copy the whole suffix (this avoid having hard to predict branches which + // helps a lot). Note suffixp could be aligned, so could load it in one go, + // but then we would be endiannes dependent which we don't have a way to + // test right now and probably would make little difference... + // Note: The maximum length of the suffix is + // VL_TRACE_MAX_VCD_CODE_SIZE + 2 == 7, but we unroll this here for speed. + writep[0] = suffixp[0]; + writep[1] = suffixp[1]; + writep[2] = suffixp[2]; + writep[3] = suffixp[3]; + writep[4] = suffixp[4]; + writep[5] = suffixp[5]; + writep[6] = '\n'; // The 6th index is always '\n' if it's relevant, no need to fetch it. + // Now write back the write pointer incremented by the actual size of the + // suffix, which was stored in the last byte of the suffix buffer entry. + m_writep = writep + suffixp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1]; + bufferCheck(); +} + +void VerilatedVcd::fullBit(vluint32_t* oldp, vluint32_t newval) { + *oldp = newval; + char* wp = m_writep; + *wp++ = '0' | static_cast(newval); + finishLine(oldp, wp); +} + +// We do want these functions specialized for sizes to avoid hard to predict +// branches, but we don't want them inlined, so we explicitly create one +// specialization for each size used here here. + +// T_Bits is the number of used bits in the value +template void VerilatedVcd::fullBus(vluint32_t* oldp, vluint32_t newval) { + *oldp = newval; + char* wp = m_writep; + *wp++ = 'b'; + newval <<= 32 - T_Bits; + int bits = T_Bits; + do { + *wp++ = '0' | static_cast(newval >> 31); + newval <<= 1; + } while (--bits); + finishLine(oldp, wp); +} +// Note: No specialization for width 1, covered by 'fullBit' +template void VerilatedVcd::fullBus<2>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<3>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<4>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<5>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<6>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<7>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<8>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<9>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<10>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<11>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<12>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<13>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<14>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<15>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<16>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<17>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<18>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<19>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<20>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<21>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<22>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<23>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<24>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<25>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<26>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<27>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<28>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<29>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<30>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<31>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedVcd::fullBus<32>(vluint32_t* oldp, vluint32_t newval); + +// T_Bits is the number of used bits in the value +void VerilatedVcd::fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + *reinterpret_cast(oldp) = newval; + char* wp = m_writep; + *wp++ = 'b'; + newval <<= 64 - bits; + // Handle the top 32 bits within the 64 bit input + const int bitsInTopHalf = bits - 32; + wp += bitsInTopHalf; + // clang-format off + switch (bitsInTopHalf) { + case 32: wp[-32] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 31: wp[-31] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 30: wp[-30] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 29: wp[-29] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 28: wp[-28] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 27: wp[-27] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 26: wp[-26] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 25: wp[-25] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 24: wp[-24] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 23: wp[-23] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 22: wp[-22] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 21: wp[-21] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 20: wp[-20] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 19: wp[-19] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 18: wp[-18] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 17: wp[-17] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 16: wp[-16] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 15: wp[-15] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 14: wp[-14] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 13: wp[-13] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 12: wp[-12] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 11: wp[-11] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 10: wp[-10] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 9: wp[ -9] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 8: wp[ -8] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 7: wp[ -7] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 6: wp[ -6] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 5: wp[ -5] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 4: wp[ -4] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 3: wp[ -3] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 2: wp[ -2] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 1: wp[ -1] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + } + // clang-format on + // Handle the bottom 32 bits within the 64 bit input + int remaining = 32; + do { + *wp++ = '0' | static_cast(newval >> 63); + newval <<= 1; + } while (--remaining); + finishLine(oldp, wp); +} + +void VerilatedVcd::fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + int words = (bits + 31) / 32; + for (int i = 0; i < words; ++i) oldp[i] = newvalp[i]; + char* wp = m_writep; + *wp++ = 'b'; + // Handle the most significant word + const int bitsInMSW = bits % 32 == 0 ? 32 : bits % 32; + vluint32_t val = newvalp[--words] << (32 - bitsInMSW); + wp += bitsInMSW; + // clang-format off + switch (bitsInMSW) { + case 32: wp[-32] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 31: wp[-31] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 30: wp[-30] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 29: wp[-29] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 28: wp[-28] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 27: wp[-27] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 26: wp[-26] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 25: wp[-25] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 24: wp[-24] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 23: wp[-23] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 22: wp[-22] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 21: wp[-21] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 20: wp[-20] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 19: wp[-19] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 18: wp[-18] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 17: wp[-17] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 16: wp[-16] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 15: wp[-15] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 14: wp[-14] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 13: wp[-13] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 12: wp[-12] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 11: wp[-11] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 10: wp[-10] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 9: wp[ -9] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 8: wp[ -8] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 7: wp[ -7] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 6: wp[ -6] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 5: wp[ -5] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 4: wp[ -4] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 3: wp[ -3] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 2: wp[ -2] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 1: wp[ -1] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + } + // clang-format on + // Handle the remaining words + while (words > 0) { + vluint32_t val = newvalp[--words]; + int bits = 32; + do { + *wp++ = '0' | static_cast(val >> 31); + val <<= 1; + } while (--bits); + } + finishLine(oldp, wp); +} + +void VerilatedVcd::fullFloat(vluint32_t* oldp, float newval) { + // cppcheck-suppress invalidPointerCast + *reinterpret_cast(oldp) = newval; + char* wp = m_writep; + // Buffer can't overflow before sprintf; we sized during declaration + sprintf(wp, "r%.16g", static_cast(newval)); + wp += strlen(wp); + finishLine(oldp, wp); +} + +void VerilatedVcd::fullDouble(vluint32_t* oldp, double newval) { + // cppcheck-suppress invalidPointerCast + *reinterpret_cast(oldp) = newval; + char* wp = m_writep; + // Buffer can't overflow before sprintf; we sized during declaration + sprintf(wp, "r%.16g", newval); + wp += strlen(wp); + finishLine(oldp, wp); +} + +#else // VL_TRACE_VCD_OLD_API void VerilatedVcd::fullBit(vluint32_t code, const vluint32_t newval) { // Note the &1, so we don't require clean input -- makes more common no change case faster m_sigs_oldvalp[code] = newval; *m_writep++ = ('0' + static_cast(newval & 1)); - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } @@ -672,7 +945,7 @@ void VerilatedVcd::fullBus(vluint32_t code, const vluint32_t newval, int bits) { *m_writep++ = ((newval & (1L << bit)) ? '1' : '0'); } *m_writep++ = ' '; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } @@ -683,7 +956,7 @@ void VerilatedVcd::fullQuad(vluint32_t code, const vluint64_t newval, int bits) *m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0'); } *m_writep++ = ' '; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } @@ -696,7 +969,7 @@ void VerilatedVcd::fullArray(vluint32_t code, const vluint32_t* newval, int bits *m_writep++ = ((newval[(bit / 32)] & (1L << (bit & 0x1f))) ? '1' : '0'); } *m_writep++ = ' '; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } @@ -709,7 +982,7 @@ void VerilatedVcd::fullArray(vluint32_t code, const vluint64_t* newval, int bits *m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0'); } *m_writep++ = ' '; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } @@ -717,11 +990,12 @@ void VerilatedVcd::fullTriBit(vluint32_t code, const vluint32_t newval, const vl m_sigs_oldvalp[code] = newval; m_sigs_oldvalp[code + 1] = newtri; *m_writep++ = "01zz"[m_sigs_oldvalp[code] | (m_sigs_oldvalp[code + 1] << 1)]; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } -void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) { +void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, + int bits) { m_sigs_oldvalp[code] = newval; m_sigs_oldvalp[code + 1] = newtri; *m_writep++ = 'b'; @@ -729,25 +1003,26 @@ void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vl *m_writep++ = "01zz"[((newval >> bit) & 1) | (((newtri >> bit) & 1) << 1)]; } *m_writep++ = ' '; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } -void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) { +void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, + int bits) { (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; (*(reinterpret_cast(&m_sigs_oldvalp[code + 1]))) = newtri; *m_writep++ = 'b'; for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = "01zz"[((newval >> bit) & VL_ULL(1)) - | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))]; + *m_writep++ + = "01zz"[((newval >> bit) & VL_ULL(1)) | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))]; } *m_writep++ = ' '; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } -void VerilatedVcd::fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, - int bits) { +void VerilatedVcd::fullTriArray(vluint32_t code, const vluint32_t* newvalp, + const vluint32_t* newtrip, int bits) { for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { m_sigs_oldvalp[code + word * 2] = newvalp[word]; m_sigs_oldvalp[code + word * 2 + 1] = newtrip[word]; @@ -759,7 +1034,7 @@ void VerilatedVcd::fullTriArray(vluint32_t code, const vluint32_t* newvalp, cons *m_writep++ = "01zz"[valbit | (tribit << 1)]; } *m_writep++ = ' '; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } @@ -770,7 +1045,7 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) { sprintf(m_writep, "r%.16g", newval); m_writep += strlen(m_writep); *m_writep++ = ' '; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } @@ -781,29 +1056,29 @@ void VerilatedVcd::fullFloat(vluint32_t code, const float newval) { sprintf(m_writep, "r%.16g", static_cast(newval)); m_writep += strlen(m_writep); *m_writep++ = ' '; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } void VerilatedVcd::fullBitX(vluint32_t code) { *m_writep++ = 'x'; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } void VerilatedVcd::fullBusX(vluint32_t code, int bits) { *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = 'x'; - } + for (int bit = bits - 1; bit >= 0; --bit) *m_writep++ = 'x'; *m_writep++ = ' '; - printCode(code); + m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } void VerilatedVcd::fullQuadX(vluint32_t code, int bits) { fullBusX(code, bits); } void VerilatedVcd::fullArrayX(vluint32_t code, int bits) { fullBusX(code, bits); } +#endif // VL_TRACE_VCD_OLD_API + //============================================================================= // Callbacks @@ -867,6 +1142,8 @@ void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_a //====================================================================== //====================================================================== +// clang-format off + #ifdef VERILATED_VCD_TEST #include diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 24257e5b6..95128bba6 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -97,6 +97,9 @@ private: vluint64_t m_wrChunkSize; ///< Output buffer size vluint64_t m_wroteBytes; ///< Number of bytes written to this file + std::vector m_suffixes; ///< VCD line end string codes + metadata + const char* m_suffixesp; ///< Pointer to first element of above + vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values typedef std::vector SigVec; SigVec m_sigs; ///< Pointer to signal information @@ -131,26 +134,9 @@ private: void dumpFull(vluint64_t timeui); // cppcheck-suppress functionConst void dumpDone(); - inline void printCode(vluint32_t code) { - *m_writep++ = static_cast('!' + code % 94); - code /= 94; - while (code) { - code--; - *m_writep++ = static_cast('!' + code % 94); - code /= 94; - } - } - static std::string stringCode(vluint32_t code) VL_PURE { - std::string out; - out += static_cast('!' + code % 94); - code /= 94; - while (code) { - code--; - out += static_cast('!' + code % 94); - code /= 94; - } - return out; - } + char* writeCode(char* writep, vluint32_t code); + + void finishLine(vluint32_t* oldp, char* writep); // CONSTRUCTORS VL_UNCOPYABLE(VerilatedVcd); @@ -206,27 +192,116 @@ public: void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); + void declFloat(vluint32_t code, const char* name, bool array, int arraynum); + void declDouble(vluint32_t code, const char* name, bool array, int arraynum); +#ifndef VL_TRACE_VCD_OLD_API void declTriBit(vluint32_t code, const char* name, bool array, int arraynum); void declTriBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declTriQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declDouble(vluint32_t code, const char* name, bool array, int arraynum); - void declFloat(vluint32_t code, const char* name, bool array, int arraynum); +#endif // VL_TRACE_VCD_OLD_API // ... other module_start for submodules (based on cell name) + //========================================================================= + // Inside dumping routines used by Verilator + + vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; } + +#ifndef VL_TRACE_VCD_OLD_API + + //========================================================================= + // Write back to previous value buffer value and emit + + void fullBit(vluint32_t* oldp, vluint32_t newval); + template void fullBus(vluint32_t* oldp, vluint32_t newval); + void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits); + void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits); + void fullFloat(vluint32_t* oldp, float newval); + void fullDouble(vluint32_t* oldp, double newval); + + //========================================================================= + // Check previous value and emit if changed + + inline void chgBit(vluint32_t* oldp, vluint32_t newval) { + const vluint32_t diff = *oldp ^ newval; + if (VL_UNLIKELY(diff)) fullBit(oldp, newval); + } + template inline void chgBus(vluint32_t* oldp, vluint32_t newval) { + const vluint32_t diff = *oldp ^ newval; + if (VL_UNLIKELY(diff)) fullBus(oldp, newval); + } + inline void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + const vluint64_t diff = *reinterpret_cast(oldp) ^ newval; + if (VL_UNLIKELY(diff)) fullQuad(oldp, newval, bits); + } + inline void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + for (int i = 0; i < (bits + 31) / 32; ++i) { + if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) { + fullArray(oldp, newvalp, bits); + return; + } + } + } + inline void chgFloat(vluint32_t* oldp, float newval) { + // cppcheck-suppress invalidPointerCast + if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullFloat(oldp, newval); + } + inline void chgDouble(vluint32_t* oldp, double newval) { + // cppcheck-suppress invalidPointerCast + if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullDouble(oldp, newval); + } + +#else // VL_TRACE_VCD_OLD_API + + // Note: These are only for testing for backward compatibility. Verilator + // should use the more efficient versions above. + + //========================================================================= + // Write back to previous value buffer value and emit + + void fullBit(vluint32_t* oldp, vluint32_t newval) { fullBit(oldp - m_sigs_oldvalp, newval); } + template void fullBus(vluint32_t* oldp, vluint32_t newval) { + fullBus(oldp - m_sigs_oldvalp, newval, T_Bits); + } + void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + fullQuad(oldp - m_sigs_oldvalp, newval, bits); + } + void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + fullArray(oldp - m_sigs_oldvalp, newvalp, bits); + } + void fullFloat(vluint32_t* oldp, float newval) { fullFloat(oldp - m_sigs_oldvalp, newval); } + void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - m_sigs_oldvalp, newval); } + + //========================================================================= + // Check previous value and emit if changed + + void chgBit(vluint32_t* oldp, vluint32_t newval) { chgBit(oldp - m_sigs_oldvalp, newval); } + template void chgBus(vluint32_t* oldp, vluint32_t newval) { + chgBus(oldp - m_sigs_oldvalp, newval, T_Bits); + } + void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + chgQuad(oldp - m_sigs_oldvalp, newval, bits); + } + void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + chgArray(oldp - m_sigs_oldvalp, newvalp, bits); + } + void chgFloat(vluint32_t* oldp, float newval) { chgFloat(oldp - m_sigs_oldvalp, newval); } + void chgDouble(vluint32_t* oldp, double newval) { chgDouble(oldp - m_sigs_oldvalp, newval); } + /// Inside dumping routines, dump one signal, faster when not inlined /// due to code size reduction. void fullBit(vluint32_t code, const vluint32_t newval); void fullBus(vluint32_t code, const vluint32_t newval, int bits); void fullQuad(vluint32_t code, const vluint64_t newval, int bits); - void fullArray(vluint32_t code, const vluint32_t* newval, int bits); - void fullArray(vluint32_t code, const vluint64_t* newval, int bits); + void fullArray(vluint32_t code, const vluint32_t* newvalp, int bits); + void fullArray(vluint32_t code, const vluint64_t* newvalp, int bits); void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri); void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits); void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits); - void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits); + void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, + int bits); void fullDouble(vluint32_t code, const double newval); void fullFloat(vluint32_t code, const float newval); @@ -243,9 +318,7 @@ public: /// We do want to inline these to avoid calls when the value did not change. inline void chgBit(vluint32_t code, const vluint32_t newval) { vluint32_t diff = m_sigs_oldvalp[code] ^ newval; - if (VL_UNLIKELY(diff)) { - fullBit(code, newval); - } + if (VL_UNLIKELY(diff)) fullBit(code, newval); } inline void chgBus(vluint32_t code, const vluint32_t newval, int bits) { vluint32_t diff = m_sigs_oldvalp[code] ^ newval; @@ -263,18 +336,18 @@ public: } } } - inline void chgArray(vluint32_t code, const vluint32_t* newval, int bits) { + inline void chgArray(vluint32_t code, const vluint32_t* newvalp, int bits) { for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { - if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newval[word])) { - fullArray(code, newval, bits); + if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newvalp[word])) { + fullArray(code, newvalp, bits); return; } } } - inline void chgArray(vluint32_t code, const vluint64_t* newval, int bits) { + inline void chgArray(vluint32_t code, const vluint64_t* newvalp, int bits) { for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { - if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newval[word])) { - fullArray(code, newval, bits); + if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newvalp[word])) { + fullArray(code, newvalp, bits); return; } } @@ -332,6 +405,8 @@ public: } } +#endif // VL_TRACE_VCD_OLD_API + protected: // METHODS void evcd(bool flag) { m_evcd = flag; } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 46d6bd05e..a55d02d81 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3100,6 +3100,7 @@ class EmitCTrace : EmitCStmts { AstCFunc* m_funcp; // Function we're in now bool m_slow; // Making slow file int m_enumNum; // Enumeration number (whole netlist) + int m_baseCode; // Code of first AstTraceInc in this function // METHODS void newOutCFile(int filenum) { @@ -3380,28 +3381,24 @@ class EmitCTrace : EmitCStmts { ? "full":"chg"); bool emitWidth = false; if (nodep->dtypep()->basicp()->isDouble()) { - puts("vcdp->"+full+"Double"); + puts("vcdp->" + full + "Double"); } else if (nodep->isWide() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep)) { - puts("vcdp->"+full+"Array"); + puts("vcdp->" + full + "Array"); emitWidth = true; } else if (nodep->isQuad()) { - puts("vcdp->"+full+"Quad"); - emitWidth = true; - } else if (nodep->declp()->bitRange().ranged() - // 1 element smaller to use Bit dump - && nodep->declp()->bitRange().elements() != 1) { - puts("vcdp->"+full+"Bus"); + puts("vcdp->" + full + "Quad"); emitWidth = true; + } else if (nodep->declp()->widthMin() > 1) { + puts("vcdp->" + full + "Bus<" + cvtToStr(nodep->declp()->widthMin()) + ">"); } else { - puts("vcdp->"+full+"Bit"); + puts("vcdp->" + full + "Bit"); } - puts("(c+"+cvtToStr(nodep->declp()->code() - + ((arrayindex<0) ? 0 : (arrayindex*nodep->declp()->widthWords())))); - puts(","); + + const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords()); + const uint32_t code = nodep->declp()->code() + offset; + puts("(oldp+" + cvtToStr(code - m_baseCode) + ","); emitTraceValue(nodep, arrayindex); - if (emitWidth) { - puts(","+cvtToStr(nodep->declp()->widthMin())); - } + if (emitWidth) puts("," + cvtToStr(nodep->declp()->widthMin())); puts(");\n"); } void emitTraceValue(AstTraceInc* nodep, int arrayindex) { @@ -3460,8 +3457,24 @@ class EmitCTrace : EmitCStmts { if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign()+"\n"); - puts("int c = code;\n"); - puts("if (false && vcdp && c) {} // Prevent unused\n"); + m_baseCode = -1; + + if (nodep->funcType() == AstCFuncType::TRACE_FULL_SUB + || nodep->funcType() == AstCFuncType::TRACE_CHANGE_SUB) { + const AstTraceInc* const stmtp = VN_CAST_CONST(nodep->stmtsp(), TraceInc); + if (!stmtp) { + nodep->stmtsp()->v3fatalSrc("Trace sub function should contain AstTraceInc"); + } + m_baseCode = stmtp->declp()->code(); + puts("vluint32_t* oldp = vcdp->oldp(code+" + cvtToStr(m_baseCode) + ");\n"); + puts("if (false && vcdp && oldp) {} // Prevent unused\n"); + } else if (nodep->funcType() == AstCFuncType::TRACE_INIT_SUB) { + puts("int c = code;\n"); + puts("if (false && vcdp && c) {} // Prevent unused\n"); + } else { + puts("if (false && vcdp) {} // Prevent unused\n"); + } + if (nodep->funcType() == AstCFuncType::TRACE_INIT) { puts("vcdp->module(vlSymsp->name()); // Setup signal names\n"); } else if (nodep->funcType() == AstCFuncType::TRACE_INIT_SUB) { diff --git a/test_regress/t/t_trace_complex_fst.out b/test_regress/t/t_trace_complex_fst.out index 57e86c1b7..7ceb73591 100644 --- a/test_regress/t/t_trace_complex_fst.out +++ b/test_regress/t/t_trace_complex_fst.out @@ -1,5 +1,5 @@ $date - Tue Jan 21 18:08:49 2020 + Sun Apr 12 20:15:55 2020 $end $version @@ -101,7 +101,6 @@ b00000000000000000000000000000011 A #10 b00000000000000000000000000000101 ? b00000000000000000000000000000101 > -b000000 : b111 9 b00000000000000000000000000000010 8 b00000000000000000000000000000001 7 @@ -144,14 +143,10 @@ b00000000000000000000000000000010 7 b00000000000000000000000000000100 8 b110 9 b111111 : -b00000000000000000000000000000101 > -b00000000000000000000000000000101 ? #25 0! #30 1! -b00000000000000000000000000000101 ? -b00000000000000000000000000000101 > b110110 : b101 9 b00000000000000000000000000000110 8 @@ -194,14 +189,10 @@ b00000000000000000000000000000100 7 b00000000000000000000000000001000 8 b100 9 b101101 : -b00000000000000000000000000000101 > -b00000000000000000000000000000101 ? #45 0! #50 1! -b00000000000000000000000000000101 ? -b00000000000000000000000000000101 > b100100 : b011 9 b00000000000000000000000000001010 8 @@ -244,5 +235,3 @@ b00000000000000000000000000000110 7 b00000000000000000000000000001100 8 b010 9 b011011 : -b00000000000000000000000000000101 > -b00000000000000000000000000000101 ? diff --git a/test_regress/t/t_trace_complex_old_api.pl b/test_regress/t/t_trace_complex_old_api.pl new file mode 100755 index 000000000..6041f09c2 --- /dev/null +++ b/test_regress/t/t_trace_complex_old_api.pl @@ -0,0 +1,38 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +# Same test as t_trace_complex, but exercising the old VCD tracing API + +scenarios(simulator => 1); + +top_filename("t/t_trace_complex.v"); + +compile( + verilator_flags2 => ['--cc --trace -CFLAGS -DVL_TRACE_VCD_OLD_API'], + ); + +execute( + check_finished => 1, + ); + +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_strp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_strp_strp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp_arrp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp_strp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru\(/); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arru\(/); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arrp\(/); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_strp\(/); + +vcd_identical ("$Self->{obj_dir}/simx.vcd", "t/t_trace_complex.out"); + +ok(1); +1; diff --git a/test_regress/t/t_trace_complex_params_fst.out b/test_regress/t/t_trace_complex_params_fst.out index 1dc90cb57..63f837f52 100644 --- a/test_regress/t/t_trace_complex_params_fst.out +++ b/test_regress/t/t_trace_complex_params_fst.out @@ -1,5 +1,5 @@ $date - Tue Jan 21 18:15:28 2020 + Sun Apr 12 20:17:15 2020 $end $version @@ -101,7 +101,6 @@ b00000000000000000000000000000011 A #10 b00000000000000000000000000000101 ? b00000000000000000000000000000101 > -b000000 : b111 9 b00000000000000000000000000000010 8 b00000000000000000000000000000001 7 @@ -144,14 +143,10 @@ b00000000000000000000000000000010 7 b00000000000000000000000000000100 8 b110 9 b111111 : -b00000000000000000000000000000101 > -b00000000000000000000000000000101 ? #25 0! #30 1! -b00000000000000000000000000000101 ? -b00000000000000000000000000000101 > b110110 : b101 9 b00000000000000000000000000000110 8 @@ -194,14 +189,10 @@ b00000000000000000000000000000100 7 b00000000000000000000000000001000 8 b100 9 b101101 : -b00000000000000000000000000000101 > -b00000000000000000000000000000101 ? #45 0! #50 1! -b00000000000000000000000000000101 ? -b00000000000000000000000000000101 > b100100 : b011 9 b00000000000000000000000000001010 8 @@ -244,5 +235,3 @@ b00000000000000000000000000000110 7 b00000000000000000000000000001100 8 b010 9 b011011 : -b00000000000000000000000000000101 > -b00000000000000000000000000000101 ? diff --git a/test_regress/t/t_trace_complex_structs_fst.out b/test_regress/t/t_trace_complex_structs_fst.out index fd26fc14c..8319f05a6 100644 --- a/test_regress/t/t_trace_complex_structs_fst.out +++ b/test_regress/t/t_trace_complex_structs_fst.out @@ -1,5 +1,5 @@ $date - Tue Jan 21 18:55:14 2020 + Sun Apr 12 20:14:19 2020 $end $version @@ -151,8 +151,6 @@ b00000000000000000000000000000000 L #10 b00000000000000000000000000000101 L b00000000000000000000000000000101 K -b000 G -b000 F b111 E b00000000000000000000000000000010 D b00000000000000000000000000000001 C @@ -218,18 +216,14 @@ b00000000000000000000000000000010 B b00000000000000000000000000000010 C b00000000000000000000000000000100 D b110 E -b111 F b111 G -b00000000000000000000000000000101 K -b00000000000000000000000000000101 L +b111 F #25 0! #30 1! -b00000000000000000000000000000101 L -b00000000000000000000000000000101 K -b110 G b110 F +b110 G b101 E b00000000000000000000000000000110 D b00000000000000000000000000000011 C @@ -294,18 +288,14 @@ b00000000000000000000000000000100 B b00000000000000000000000000000100 C b00000000000000000000000000001000 D b100 E -b101 F b101 G -b00000000000000000000000000000101 K -b00000000000000000000000000000101 L +b101 F #45 0! #50 1! -b00000000000000000000000000000101 L -b00000000000000000000000000000101 K -b100 G b100 F +b100 G b011 E b00000000000000000000000000001010 D b00000000000000000000000000000101 C @@ -370,7 +360,5 @@ b00000000000000000000000000000110 B b00000000000000000000000000000110 C b00000000000000000000000000001100 D b010 E -b011 F b011 G -b00000000000000000000000000000101 K -b00000000000000000000000000000101 L +b011 F diff --git a/test_regress/t/t_trace_fst.out b/test_regress/t/t_trace_fst.out index d6453e931..0a3805543 100644 --- a/test_regress/t/t_trace_fst.out +++ b/test_regress/t/t_trace_fst.out @@ -1,5 +1,5 @@ $date - Tue Nov 5 20:18:53 2019 + Sun Apr 12 20:17:58 2020 $end $version @@ -82,1398 +82,947 @@ b00000000000000000000000000000000 : b00000000000000000000000000000000 ; #10 b00000000000000000000000000000011 ; -b00000000000000000000000000000000 : b00001 9 b00001 8 b00001 7 b10100 6 -0$ b00000000000000000000000000000001 # b00001 " 1! #15 0! -b00001 " #20 -b00001 " 1! b00000000000000000000000000000010 # -0$ -b10100 6 -b00001 7 -b00001 8 -b00001 9 -b00000000000000000000000000000000 : -b00000000000000000000000000000011 ; #25 0! -b00001 " #30 -b00001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000000 : -b00001 9 -b00001 8 -b00001 7 -b10100 6 -0$ b00000000000000000000000000000011 # #35 0! -b00001 " #40 -b00001 " 1! b00000000000000000000000000000100 # -0$ -b10100 6 -b00001 7 -b00001 8 -b00001 9 -b00000000000000000000000000000000 : -b00000000000000000000000000000011 ; #45 0! -b00001 " #50 -b00001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000000 : -b00001 9 -b00001 8 -b00001 7 -b10100 6 -0$ b00000000000000000000000000000101 # #55 0! -b00001 " #60 -b00001 " 1! b00000000000000000000000000000110 # -0$ -b10100 6 -b00001 7 -b00001 8 -b00001 9 -b00000000000000000000000000000000 : -b00000000000000000000000000000011 ; #65 0! -b00001 " #70 -b00001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000000 : -b00001 9 -b00001 8 -b00001 7 -b10100 6 -0$ b00000000000000000000000000000111 # #75 0! -b00001 " #80 -b00001 " 1! b00000000000000000000000000001000 # -0$ -b10100 6 -b00001 7 -b00001 8 -b00001 9 -b00000000000000000000000000000000 : -b00000000000000000000000000000011 ; #85 0! -b00001 " #90 -b00001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000000 : -b00001 9 -b00001 8 -b00001 7 -b10100 6 -0$ b00000000000000000000000000001001 # #95 0! -b00001 " #100 -b00001 " 1! b00000000000000000000000000001010 # -0$ -b10100 6 -b00001 7 -b00001 8 -b00001 9 -b00000000000000000000000000000000 : -b00000000000000000000000000000011 ; #105 0! -b00001 " #110 -b00001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000000 : -b00001 9 -b00001 8 -b00001 7 -b10100 6 -1$ b00000000000000000000000000001011 # +1$ #115 0! -b00001 " #120 -b00001 " 1! b00000000000000000000000000001100 # -1$ b01010 6 -b00001 7 -b00001 8 b10100 9 b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; #125 0! -b00001 " #130 -b00001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : b01010 9 -b10100 8 -b00001 7 b00101 6 -1$ b00000000000000000000000000001101 # +b10100 8 #135 0! -b00001 " #140 -b10100 " 1! -b00000000000000000000000000001110 # -1$ -b10110 6 -b10100 7 b01010 8 +b00000000000000000000000000001110 # +b10110 6 b00101 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10100 " +b10100 7 #145 0! -b10100 " #150 -b01010 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10110 9 -b00101 8 b01010 7 +b01010 " +b10110 9 b01011 6 -1$ b00000000000000000000000000001111 # +b00101 8 #155 0! -b01010 " #160 -b00101 " 1! -b00000000000000000000000000010000 # -1$ -b10001 6 -b00101 7 b10110 8 +b00000000000000000000000000010000 # +b10001 6 b01011 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b00101 " +b00101 7 #165 0! -b00101 " #170 -b10110 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10001 9 -b01011 8 b10110 7 +b10110 " +b10001 9 b11100 6 -1$ b00000000000000000000000000010001 # +b01011 8 #175 0! -b10110 " #180 -b01011 " 1! -b00000000000000000000000000010010 # -1$ -b01110 6 -b01011 7 b10001 8 +b00000000000000000000000000010010 # +b01110 6 b11100 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b01011 " +b01011 7 #185 0! -b01011 " #190 -b10001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01110 9 -b11100 8 b10001 7 +b10001 " +b01110 9 b00111 6 -1$ b00000000000000000000000000010011 # +b11100 8 #195 0! -b10001 " #200 -b11100 " 1! -b00000000000000000000000000010100 # -1$ -b10111 6 -b11100 7 b01110 8 +b00000000000000000000000000010100 # +b10111 6 b00111 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11100 " +b11100 7 #205 0! -b11100 " #210 -b01110 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10111 9 -b00111 8 b01110 7 +b01110 " +b10111 9 b11111 6 -1$ b00000000000000000000000000010101 # +b00111 8 #215 0! -b01110 " #220 -b00111 " 1! -b00000000000000000000000000010110 # -1$ -b11011 6 -b00111 7 b10111 8 +b00000000000000000000000000010110 # +b11011 6 b11111 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b00111 " +b00111 7 #225 0! -b00111 " #230 -b10111 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11011 9 -b11111 8 b10111 7 +b10111 " +b11011 9 b11001 6 -1$ b00000000000000000000000000010111 # +b11111 8 #235 0! -b10111 " #240 -b11111 " 1! -b00000000000000000000000000011000 # -1$ -b11000 6 -b11111 7 b11011 8 +b00000000000000000000000000011000 # +b11000 6 b11001 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11111 " +b11111 7 #245 0! -b11111 " #250 -b11011 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11000 9 -b11001 8 b11011 7 +b11011 " +b11000 9 b01100 6 -1$ b00000000000000000000000000011001 # +b11001 8 #255 0! -b11011 " #260 -b11001 " 1! -b00000000000000000000000000011010 # -1$ -b00110 6 -b11001 7 b11000 8 +b00000000000000000000000000011010 # +b00110 6 b01100 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11001 " +b11001 7 #265 0! -b11001 " #270 -b11000 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b00110 9 -b01100 8 b11000 7 +b11000 " +b00110 9 b00011 6 -1$ b00000000000000000000000000011011 # +b01100 8 #275 0! -b11000 " #280 -b01100 " 1! -b00000000000000000000000000011100 # -1$ -b10101 6 -b01100 7 b00110 8 +b00000000000000000000000000011100 # +b10101 6 b00011 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b01100 " +b01100 7 #285 0! -b01100 " #290 -b00110 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10101 9 -b00011 8 b00110 7 +b00110 " +b10101 9 b11110 6 -1$ b00000000000000000000000000011101 # +b00011 8 #295 0! -b00110 " #300 -b00011 " 1! -b00000000000000000000000000011110 # -1$ -b01111 6 -b00011 7 b10101 8 +b00000000000000000000000000011110 # +b01111 6 b11110 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b00011 " +b00011 7 #305 0! -b00011 " #310 -b10101 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01111 9 -b11110 8 b10101 7 +b10101 " +b01111 9 b10011 6 -1$ b00000000000000000000000000011111 # +b11110 8 #315 0! -b10101 " #320 -b11110 " 1! -b00000000000000000000000000100000 # -1$ -b11101 6 -b11110 7 b01111 8 +b00000000000000000000000000100000 # +b11101 6 b10011 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11110 " +b11110 7 #325 0! -b11110 " #330 -b01111 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11101 9 -b10011 8 b01111 7 +b01111 " +b11101 9 b11010 6 -1$ b00000000000000000000000000100001 # +b10011 8 #335 0! -b01111 " #340 -b10011 " 1! -b00000000000000000000000000100010 # -1$ -b01101 6 -b10011 7 b11101 8 +b00000000000000000000000000100010 # +b01101 6 b11010 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10011 " +b10011 7 #345 0! -b10011 " #350 -b11101 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01101 9 -b11010 8 b11101 7 +b11101 " +b01101 9 b10010 6 -1$ b00000000000000000000000000100011 # +b11010 8 #355 0! -b11101 " #360 -b11010 " 1! -b00000000000000000000000000100100 # -1$ -b01001 6 -b11010 7 b01101 8 +b00000000000000000000000000100100 # +b01001 6 b10010 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11010 " +b11010 7 #365 0! -b11010 " #370 -b01101 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01001 9 -b10010 8 b01101 7 +b01101 " +b01001 9 b10000 6 -1$ b00000000000000000000000000100101 # +b10010 8 #375 0! -b01101 " #380 -b10010 " 1! -b00000000000000000000000000100110 # -1$ -b01000 6 -b10010 7 b01001 8 +b00000000000000000000000000100110 # +b01000 6 b10000 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10010 " +b10010 7 #385 0! -b10010 " #390 -b01001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01000 9 -b10000 8 b01001 7 +b01001 " +b01000 9 b00100 6 -1$ b00000000000000000000000000100111 # +b10000 8 #395 0! -b01001 " #400 -b10000 " 1! -b00000000000000000000000000101000 # -1$ -b00010 6 -b10000 7 b01000 8 +b00000000000000000000000000101000 # +b00010 6 b00100 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10000 " +b10000 7 #405 0! -b10000 " #410 -b01000 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b00010 9 -b00100 8 b01000 7 +b01000 " +b00010 9 b00001 6 -1$ b00000000000000000000000000101001 # +b00100 8 #415 0! -b01000 " #420 -b00100 " 1! -b00000000000000000000000000101010 # -1$ -b10100 6 -b00100 7 b00010 8 +b00000000000000000000000000101010 # +b10100 6 b00001 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b00100 " +b00100 7 #425 0! -b00100 " #430 -b00010 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10100 9 -b00001 8 b00010 7 +b00010 " +b10100 9 b01010 6 -1$ b00000000000000000000000000101011 # +b00001 8 #435 0! -b00010 " #440 -b00001 " 1! -b00000000000000000000000000101100 # -1$ -b00101 6 -b00001 7 b10100 8 +b00000000000000000000000000101100 # +b00101 6 b01010 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b00001 " +b00001 7 #445 0! -b00001 " #450 -b10100 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b00101 9 -b01010 8 b10100 7 +b10100 " +b00101 9 b10110 6 -1$ b00000000000000000000000000101101 # +b01010 8 #455 0! -b10100 " #460 -b01010 " 1! -b00000000000000000000000000101110 # -1$ -b01011 6 -b01010 7 b00101 8 +b00000000000000000000000000101110 # +b01011 6 b10110 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b01010 " +b01010 7 #465 0! -b01010 " #470 -b00101 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01011 9 -b10110 8 b00101 7 +b00101 " +b01011 9 b10001 6 -1$ b00000000000000000000000000101111 # +b10110 8 #475 0! -b00101 " #480 -b10110 " 1! -b00000000000000000000000000110000 # -1$ -b11100 6 -b10110 7 b01011 8 +b00000000000000000000000000110000 # +b11100 6 b10001 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10110 " +b10110 7 #485 0! -b10110 " #490 -b01011 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11100 9 -b10001 8 b01011 7 +b01011 " +b11100 9 b01110 6 -1$ b00000000000000000000000000110001 # +b10001 8 #495 0! -b01011 " #500 -b10001 " 1! -b00000000000000000000000000110010 # -1$ -b00111 6 -b10001 7 b11100 8 +b00000000000000000000000000110010 # +b00111 6 b01110 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10001 " +b10001 7 #505 0! -b10001 " #510 -b11100 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b00111 9 -b01110 8 b11100 7 +b11100 " +b00111 9 b10111 6 -1$ b00000000000000000000000000110011 # +b01110 8 #515 0! -b11100 " #520 -b01110 " 1! -b00000000000000000000000000110100 # -1$ -b11111 6 -b01110 7 b00111 8 +b00000000000000000000000000110100 # +b11111 6 b10111 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b01110 " +b01110 7 #525 0! -b01110 " #530 -b00111 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11111 9 -b10111 8 b00111 7 +b00111 " +b11111 9 b11011 6 -1$ b00000000000000000000000000110101 # +b10111 8 #535 0! -b00111 " #540 -b10111 " 1! -b00000000000000000000000000110110 # -1$ -b11001 6 -b10111 7 b11111 8 +b00000000000000000000000000110110 # +b11001 6 b11011 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10111 " +b10111 7 #545 0! -b10111 " #550 -b11111 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11001 9 -b11011 8 b11111 7 +b11111 " +b11001 9 b11000 6 -1$ b00000000000000000000000000110111 # +b11011 8 #555 0! -b11111 " #560 -b11011 " 1! -b00000000000000000000000000111000 # -1$ -b01100 6 -b11011 7 b11001 8 +b00000000000000000000000000111000 # +b01100 6 b11000 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11011 " +b11011 7 #565 0! -b11011 " #570 -b11001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01100 9 -b11000 8 b11001 7 +b11001 " +b01100 9 b00110 6 -1$ b00000000000000000000000000111001 # +b11000 8 #575 0! -b11001 " #580 -b11000 " 1! -b00000000000000000000000000111010 # -1$ -b00011 6 -b11000 7 b01100 8 +b00000000000000000000000000111010 # +b00011 6 b00110 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11000 " +b11000 7 #585 0! -b11000 " #590 -b01100 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b00011 9 -b00110 8 b01100 7 +b01100 " +b00011 9 b10101 6 -1$ b00000000000000000000000000111011 # +b00110 8 #595 0! -b01100 " #600 -b00110 " 1! -b00000000000000000000000000111100 # -1$ -b11110 6 -b00110 7 b00011 8 +b00000000000000000000000000111100 # +b11110 6 b10101 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b00110 " +b00110 7 #605 0! -b00110 " #610 -b00011 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11110 9 -b10101 8 b00011 7 +b00011 " +b11110 9 b01111 6 -1$ b00000000000000000000000000111101 # +b10101 8 #615 0! -b00011 " #620 -b10101 " 1! -b00000000000000000000000000111110 # -1$ -b10011 6 -b10101 7 b11110 8 +b00000000000000000000000000111110 # +b10011 6 b01111 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10101 " +b10101 7 #625 0! -b10101 " #630 -b11110 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10011 9 -b01111 8 b11110 7 +b11110 " +b10011 9 b11101 6 -1$ b00000000000000000000000000111111 # +b01111 8 #635 0! -b11110 " #640 -b01111 " 1! -b00000000000000000000000001000000 # -1$ -b11010 6 -b01111 7 b10011 8 +b00000000000000000000000001000000 # +b11010 6 b11101 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b01111 " +b01111 7 #645 0! -b01111 " #650 -b10011 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11010 9 -b11101 8 b10011 7 +b10011 " +b11010 9 b01101 6 -1$ b00000000000000000000000001000001 # +b11101 8 #655 0! -b10011 " #660 -b11101 " 1! -b00000000000000000000000001000010 # -1$ -b10010 6 -b11101 7 b11010 8 +b00000000000000000000000001000010 # +b10010 6 b01101 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11101 " +b11101 7 #665 0! -b11101 " #670 -b11010 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10010 9 -b01101 8 b11010 7 +b11010 " +b10010 9 b01001 6 -1$ b00000000000000000000000001000011 # +b01101 8 #675 0! -b11010 " #680 -b01101 " 1! -b00000000000000000000000001000100 # -1$ -b10000 6 -b01101 7 b10010 8 +b00000000000000000000000001000100 # +b10000 6 b01001 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b01101 " +b01101 7 #685 0! -b01101 " #690 -b10010 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10000 9 -b01001 8 b10010 7 +b10010 " +b10000 9 b01000 6 -1$ b00000000000000000000000001000101 # +b01001 8 #695 0! -b10010 " #700 -b01001 " 1! -b00000000000000000000000001000110 # -1$ -b00100 6 -b01001 7 b10000 8 +b00000000000000000000000001000110 # +b00100 6 b01000 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b01001 " +b01001 7 #705 0! -b01001 " #710 -b10000 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b00100 9 -b01000 8 b10000 7 +b10000 " +b00100 9 b00010 6 -1$ b00000000000000000000000001000111 # +b01000 8 #715 0! -b10000 " #720 -b01000 " 1! -b00000000000000000000000001001000 # -1$ -b00001 6 -b01000 7 b00100 8 +b00000000000000000000000001001000 # +b00001 6 b00010 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b01000 " +b01000 7 #725 0! -b01000 " #730 -b00100 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b00001 9 -b00010 8 b00100 7 +b00100 " +b00001 9 b10100 6 -1$ b00000000000000000000000001001001 # +b00010 8 #735 0! -b00100 " #740 -b00010 " 1! -b00000000000000000000000001001010 # -1$ -b01010 6 -b00010 7 b00001 8 +b00000000000000000000000001001010 # +b01010 6 b10100 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b00010 " +b00010 7 #745 0! -b00010 " #750 -b00001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01010 9 -b10100 8 b00001 7 +b00001 " +b01010 9 b00101 6 -1$ b00000000000000000000000001001011 # +b10100 8 #755 0! -b00001 " #760 -b10100 " 1! -b00000000000000000000000001001100 # -1$ -b10110 6 -b10100 7 b01010 8 +b00000000000000000000000001001100 # +b10110 6 b00101 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10100 " +b10100 7 #765 0! -b10100 " #770 -b01010 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10110 9 -b00101 8 b01010 7 +b01010 " +b10110 9 b01011 6 -1$ b00000000000000000000000001001101 # +b00101 8 #775 0! -b01010 " #780 -b00101 " 1! -b00000000000000000000000001001110 # -1$ -b10001 6 -b00101 7 b10110 8 +b00000000000000000000000001001110 # +b10001 6 b01011 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b00101 " +b00101 7 #785 0! -b00101 " #790 -b10110 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10001 9 -b01011 8 b10110 7 +b10110 " +b10001 9 b11100 6 -1$ b00000000000000000000000001001111 # +b01011 8 #795 0! -b10110 " #800 -b01011 " 1! -b00000000000000000000000001010000 # -1$ -b01110 6 -b01011 7 b10001 8 +b00000000000000000000000001010000 # +b01110 6 b11100 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b01011 " +b01011 7 #805 0! -b01011 " #810 -b10001 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01110 9 -b11100 8 b10001 7 +b10001 " +b01110 9 b00111 6 -1$ b00000000000000000000000001010001 # +b11100 8 #815 0! -b10001 " #820 -b11100 " 1! -b00000000000000000000000001010010 # -1$ -b10111 6 -b11100 7 b01110 8 +b00000000000000000000000001010010 # +b10111 6 b00111 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11100 " +b11100 7 #825 0! -b11100 " #830 -b01110 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10111 9 -b00111 8 b01110 7 +b01110 " +b10111 9 b11111 6 -1$ b00000000000000000000000001010011 # +b00111 8 #835 0! -b01110 " #840 -b00111 " 1! -b00000000000000000000000001010100 # -1$ -b11011 6 -b00111 7 b10111 8 +b00000000000000000000000001010100 # +b11011 6 b11111 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b00111 " +b00111 7 #845 0! -b00111 " #850 -b10111 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11011 9 -b11111 8 b10111 7 +b10111 " +b11011 9 b11001 6 -1$ b00000000000000000000000001010101 # +b11111 8 #855 0! -b10111 " #860 -b11111 " 1! -b00000000000000000000000001010110 # -1$ -b11000 6 -b11111 7 b11011 8 +b00000000000000000000000001010110 # +b11000 6 b11001 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11111 " +b11111 7 #865 0! -b11111 " #870 -b11011 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11000 9 -b11001 8 b11011 7 +b11011 " +b11000 9 b01100 6 -1$ b00000000000000000000000001010111 # +b11001 8 #875 0! -b11011 " #880 -b11001 " 1! -b00000000000000000000000001011000 # -1$ -b00110 6 -b11001 7 b11000 8 +b00000000000000000000000001011000 # +b00110 6 b01100 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11001 " +b11001 7 #885 0! -b11001 " #890 -b11000 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b00110 9 -b01100 8 b11000 7 +b11000 " +b00110 9 b00011 6 -1$ b00000000000000000000000001011001 # +b01100 8 #895 0! -b11000 " #900 -b01100 " 1! -b00000000000000000000000001011010 # -1$ -b10101 6 -b01100 7 b00110 8 +b00000000000000000000000001011010 # +b10101 6 b00011 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b01100 " +b01100 7 #905 0! -b01100 " #910 -b00110 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b10101 9 -b00011 8 b00110 7 +b00110 " +b10101 9 b11110 6 -1$ b00000000000000000000000001011011 # +b00011 8 #915 0! -b00110 " #920 -b00011 " 1! -b00000000000000000000000001011100 # -1$ -b01111 6 -b00011 7 b10101 8 +b00000000000000000000000001011100 # +b01111 6 b11110 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b00011 " +b00011 7 #925 0! -b00011 " #930 -b10101 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01111 9 -b11110 8 b10101 7 +b10101 " +b01111 9 b10011 6 -1$ b00000000000000000000000001011101 # +b11110 8 #935 0! -b10101 " #940 -b11110 " 1! -b00000000000000000000000001011110 # -1$ -b11101 6 -b11110 7 b01111 8 +b00000000000000000000000001011110 # +b11101 6 b10011 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11110 " +b11110 7 #945 0! -b11110 " #950 -b01111 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b11101 9 -b10011 8 b01111 7 +b01111 " +b11101 9 b11010 6 -1$ b00000000000000000000000001011111 # +b10011 8 #955 0! -b01111 " #960 -b10011 " 1! -b00000000000000000000000001100000 # -1$ -b01101 6 -b10011 7 b11101 8 +b00000000000000000000000001100000 # +b01101 6 b11010 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10011 " +b10011 7 #965 0! -b10011 " #970 -b11101 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01101 9 -b11010 8 b11101 7 +b11101 " +b01101 9 b10010 6 -1$ b00000000000000000000000001100001 # +b11010 8 #975 0! -b11101 " #980 -b11010 " 1! -b00000000000000000000000001100010 # -1$ -b01001 6 -b11010 7 b01101 8 +b00000000000000000000000001100010 # +b01001 6 b10010 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b11010 " +b11010 7 #985 0! -b11010 " #990 -b01101 " 1! -b00000000000000000000000000000011 ; -b00000000000000000000000000000010 : -b01001 9 -b10010 8 b01101 7 +b01101 " +b01001 9 b10000 6 -1$ b00000000000000000000000001100011 # +b10010 8 #995 0! -b01101 " #1000 -b10010 " 1! -b00000000000000000000000001100100 # -1$ -b01000 6 -b10010 7 b01001 8 +b00000000000000000000000001100100 # +b01000 6 b10000 9 -b00000000000000000000000000000010 : -b00000000000000000000000000000011 ; +b10010 " +b10010 7 diff --git a/test_regress/t/t_trace_packed_struct_fst.out b/test_regress/t/t_trace_packed_struct_fst.out index f976eb4d8..6335f7b24 100644 --- a/test_regress/t/t_trace_packed_struct_fst.out +++ b/test_regress/t/t_trace_packed_struct_fst.out @@ -1,5 +1,5 @@ $date - Sun Oct 21 21:56:54 2018 + Sun Apr 12 20:19:35 2020 $end $version @@ -42,4 +42,3 @@ b00000000000000000000000000000011 " 0! #40 1! -b00000000000000000000000000000011 " From 5c966ec510ba6b13801002d36734456f56acb56e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 13 Apr 2020 22:51:35 -0400 Subject: [PATCH 050/127] clang-format many files. No functional change. Use nodist/clang_formatter to reformat files that are now clean. --- docs/clang-format.txt | 150 --- examples/make_hello_sc/sc_main.cpp | 8 +- examples/make_protect_lib/sim_main.cpp | 14 +- examples/make_tracing_c/sim_main.cpp | 9 +- examples/make_tracing_sc/sc_main.cpp | 47 +- include/verilated.cpp | 827 +++++++++-------- include/verilated.h | 1168 +++++++++++++----------- include/verilated_config.h.in | 5 +- include/verilated_cov.cpp | 235 ++--- include/verilated_cov.h | 40 +- include/verilated_cov_key.h | 2 + include/verilated_dpi.cpp | 532 ++++++----- include/verilated_dpi.h | 32 +- include/verilated_heavy.h | 6 +- include/verilated_imp.h | 110 ++- include/verilated_save.cpp | 10 +- include/verilated_save.h | 6 +- include/verilated_sym_props.h | 106 ++- include/verilated_threads.cpp | 12 +- include/verilated_threads.h | 21 +- include/verilated_unordered_set_map.h | 159 ++-- include/verilated_vcd_sc.cpp | 46 +- include/verilated_vcd_sc.h | 69 +- include/verilated_vpi.cpp | 684 +++++++------- include/verilatedos.h | 248 ++--- nodist/clang_formatter | 260 ++++++ src/V3Active.cpp | 126 ++- src/V3ActiveTop.cpp | 35 +- src/V3Assert.cpp | 127 +-- src/V3AssertPre.cpp | 35 +- src/V3AstConstOnly.h | 12 +- src/V3Branch.cpp | 22 +- src/V3Class.cpp | 20 +- src/V3Config.cpp | 6 +- src/V3Coverage.cpp | 244 +++-- src/V3CoverageJoin.cpp | 30 +- src/V3Depth.cpp | 41 +- src/V3DepthBlock.cpp | 28 +- src/V3Descope.cpp | 13 +- src/V3EmitCInlines.cpp | 10 +- src/V3EmitV.h | 7 +- src/V3Global.cpp | 4 +- src/V3Global.h | 33 +- src/V3Graph.h | 137 +-- src/V3GraphDfa.cpp | 228 ++--- src/V3GraphDfa.h | 36 +- src/V3GraphPathChecker.cpp | 47 +- src/V3GraphStream.h | 32 +- src/V3Hashed.h | 15 +- src/V3Inst.h | 4 +- src/V3InstrCount.cpp | 39 +- src/V3LangCode.h | 28 +- src/V3LanguageWords.h | 19 +- src/V3LinkDot.h | 17 +- src/V3LinkLValue.cpp | 31 +- src/V3List.h | 37 +- src/V3Localize.cpp | 61 +- src/V3Name.cpp | 42 +- src/V3Number_test.cpp | 126 ++- src/V3OrderGraph.h | 201 ++-- src/V3Os.h | 17 +- src/V3ParseLex.cpp | 13 +- src/V3ParseSym.h | 52 +- src/V3Partition.h | 7 +- src/V3PartitionGraph.h | 55 +- src/V3PreLex.h | 76 +- src/V3PreProc.h | 26 +- src/V3PreShell.cpp | 43 +- src/V3Reloop.cpp | 123 +-- src/V3Scoreboard.cpp | 16 +- src/V3Scoreboard.h | 81 +- src/V3SenTree.h | 23 +- src/V3Stats.cpp | 103 ++- src/V3Stats.h | 69 +- src/V3StatsReport.cpp | 123 ++- src/V3String.cpp | 183 ++-- src/V3String.h | 79 +- src/V3SymTable.h | 132 +-- src/V3TSP.h | 38 +- src/V3Task.h | 2 +- src/V3Trace.cpp | 264 +++--- src/V3TraceDecl.cpp | 144 ++- src/V3WidthCommit.h | 34 +- src/VlcBucket.h | 4 +- src/VlcMain.cpp | 4 +- src/VlcOptions.h | 2 + src/VlcPoint.h | 6 +- src/VlcSource.h | 4 +- src/VlcTest.h | 4 +- src/VlcTop.cpp | 8 +- src/config_build.h.in | 2 + 91 files changed, 4413 insertions(+), 4023 deletions(-) delete mode 100644 docs/clang-format.txt create mode 100755 nodist/clang_formatter diff --git a/docs/clang-format.txt b/docs/clang-format.txt deleted file mode 100644 index d21358c90..000000000 --- a/docs/clang-format.txt +++ /dev/null @@ -1,150 +0,0 @@ -clang-format is used to standardize the indentation of the internal C++ -code. - -For the most part clang-format changes provide good consistency, the two -main exceptions being the indentation of preprocessor directives, and -tables of statements. - -Reformatting is generally performed only before other large changes are to -be made to a file. The following files are not yet clang-format clean: - -clang-format -i include/verilated.h -clang-format -i include/verilated_dpi.h -clang-format -i include/verilated_imp.h -clang-format -i include/verilated_unordered_set_map.h -clang-format -i include/verilatedos.h - -clang-format -i include/verilated.cpp -clang-format -i include/verilated_cov.cpp -clang-format -i include/verilated_dpi.cpp -clang-format -i include/verilated_vpi.cpp - -clang-format -i src/V3Ast.h -clang-format -i src/V3AstNodes.h -clang-format -i src/V3EmitCBase.h -clang-format -i src/V3Error.h -clang-format -i src/V3File.h -clang-format -i src/V3FileLine.h -clang-format -i src/V3Global.h -clang-format -i src/V3Graph.h -clang-format -i src/V3GraphDfa.h -clang-format -i src/V3GraphStream.h -clang-format -i src/V3Hashed.h -clang-format -i src/V3LanguageWords.h -clang-format -i src/V3LinkDot.h -clang-format -i src/V3List.h -clang-format -i src/V3Number.h -clang-format -i src/V3Options.h -clang-format -i src/V3OrderGraph.h -clang-format -i src/V3Os.h -clang-format -i src/V3ParseImp.h -clang-format -i src/V3ParseSym.h -clang-format -i src/V3Partition.h -clang-format -i src/V3PartitionGraph.h -clang-format -i src/V3PreLex.h -clang-format -i src/V3PreProc.h -clang-format -i src/V3Scoreboard.h -clang-format -i src/V3SenTree.h -clang-format -i src/V3Simulate.h -clang-format -i src/V3Stats.h -clang-format -i src/V3String.h -clang-format -i src/V3SymTable.h -clang-format -i src/V3TSP.h -clang-format -i src/V3Task.h -clang-format -i src/V3WidthCommit.h - -clang-format -i src/V3Active.cpp -clang-format -i src/V3ActiveTop.cpp -clang-format -i src/V3Assert.cpp -clang-format -i src/V3AssertPre.cpp -clang-format -i src/V3Ast.cpp -clang-format -i src/V3AstNodes.cpp -clang-format -i src/V3Begin.cpp -clang-format -i src/V3Branch.cpp -clang-format -i src/V3Broken.cpp -clang-format -i src/V3CCtors.cpp -clang-format -i src/V3Case.cpp -clang-format -i src/V3Cast.cpp -clang-format -i src/V3Cdc.cpp -clang-format -i src/V3Changed.cpp -clang-format -i src/V3Clean.cpp -clang-format -i src/V3Clock.cpp -clang-format -i src/V3Combine.cpp -clang-format -i src/V3Const.cpp -clang-format -i src/V3Coverage.cpp -clang-format -i src/V3CoverageJoin.cpp -clang-format -i src/V3Dead.cpp -clang-format -i src/V3Delayed.cpp -clang-format -i src/V3Depth.cpp -clang-format -i src/V3DepthBlock.cpp -clang-format -i src/V3EmitC.cpp -clang-format -i src/V3EmitCInlines.cpp -clang-format -i src/V3EmitCMake.cpp -clang-format -i src/V3EmitCSyms.cpp -clang-format -i src/V3EmitMk.cpp -clang-format -i src/V3EmitV.cpp -clang-format -i src/V3EmitXml.cpp -clang-format -i src/V3Error.cpp -clang-format -i src/V3Expand.cpp -clang-format -i src/V3File.cpp -clang-format -i src/V3FileLine.cpp -clang-format -i src/V3Gate.cpp -clang-format -i src/V3GenClk.cpp -clang-format -i src/V3Graph.cpp -clang-format -i src/V3GraphAcyc.cpp -clang-format -i src/V3GraphAlg.cpp -clang-format -i src/V3GraphDfa.cpp -clang-format -i src/V3GraphPathChecker.cpp -clang-format -i src/V3GraphTest.cpp -clang-format -i src/V3Hashed.cpp -clang-format -i src/V3Inline.cpp -clang-format -i src/V3Inst.cpp -clang-format -i src/V3InstrCount.cpp -clang-format -i src/V3Life.cpp -clang-format -i src/V3LifePost.cpp -clang-format -i src/V3LinkCells.cpp -clang-format -i src/V3LinkDot.cpp -clang-format -i src/V3LinkJump.cpp -clang-format -i src/V3LinkLValue.cpp -clang-format -i src/V3LinkLevel.cpp -clang-format -i src/V3LinkParse.cpp -clang-format -i src/V3LinkResolve.cpp -clang-format -i src/V3Localize.cpp -clang-format -i src/V3Name.cpp -clang-format -i src/V3Number.cpp -clang-format -i src/V3Number_test.cpp -clang-format -i src/V3Options.cpp -clang-format -i src/V3Order.cpp -clang-format -i src/V3Os.cpp -clang-format -i src/V3Param.cpp -clang-format -i src/V3ParseGrammar.cpp -clang-format -i src/V3ParseImp.cpp -clang-format -i src/V3ParseLex.cpp -clang-format -i src/V3Partition.cpp -clang-format -i src/V3PreProc.cpp -clang-format -i src/V3PreShell.cpp -clang-format -i src/V3Premit.cpp -clang-format -i src/V3ProtectLib.cpp -clang-format -i src/V3Reloop.cpp -clang-format -i src/V3Scope.cpp -clang-format -i src/V3Scoreboard.cpp -clang-format -i src/V3Slice.cpp -clang-format -i src/V3Split.cpp -clang-format -i src/V3SplitAs.cpp -clang-format -i src/V3SplitVar.cpp -clang-format -i src/V3Stats.cpp -clang-format -i src/V3StatsReport.cpp -clang-format -i src/V3String.cpp -clang-format -i src/V3Subst.cpp -clang-format -i src/V3TSP.cpp -clang-format -i src/V3Table.cpp -clang-format -i src/V3Task.cpp -clang-format -i src/V3Trace.cpp -clang-format -i src/V3TraceDecl.cpp -clang-format -i src/V3Tristate.cpp -clang-format -i src/V3Undriven.cpp -clang-format -i src/V3Unknown.cpp -clang-format -i src/V3Unroll.cpp -clang-format -i src/V3Width.cpp -clang-format -i src/V3WidthSel.cpp -clang-format -i src/Verilator.cpp diff --git a/examples/make_hello_sc/sc_main.cpp b/examples/make_hello_sc/sc_main.cpp index 12848e35b..131527f5f 100644 --- a/examples/make_hello_sc/sc_main.cpp +++ b/examples/make_hello_sc/sc_main.cpp @@ -29,16 +29,16 @@ int sc_main(int argc, char* argv[]) { Vtop* top = new Vtop("top"); // Initialize SC model -#if (SYSTEMC_VERSION>=20070314) - sc_start(1,SC_NS); +#if (SYSTEMC_VERSION >= 20070314) + sc_start(1, SC_NS); #else sc_start(1); #endif // Simulate until $finish while (!Verilated::gotFinish()) { -#if (SYSTEMC_VERSION>=20070314) - sc_start(1,SC_NS); +#if (SYSTEMC_VERSION >= 20070314) + sc_start(1, SC_NS); #else sc_start(1); #endif diff --git a/examples/make_protect_lib/sim_main.cpp b/examples/make_protect_lib/sim_main.cpp index 3244f0a69..e329019b5 100644 --- a/examples/make_protect_lib/sim_main.cpp +++ b/examples/make_protect_lib/sim_main.cpp @@ -17,9 +17,7 @@ #endif vluint64_t main_time = 0; -double sc_time_stamp() { - return main_time; -} +double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { if (0 && argc && argv && env) {} @@ -35,7 +33,7 @@ int main(int argc, char** argv, char** env) { // When tracing, the contents of the secret module will not be seen VerilatedVcdC* tfp = NULL; const char* flag = Verilated::commandArgsPlusMatch("trace"); - if (flag && 0==strcmp(flag, "+trace")) { + if (flag && 0 == strcmp(flag, "+trace")) { Verilated::traceEverOn(true); VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n"); tfp = new VerilatedVcdC; @@ -62,11 +60,15 @@ int main(int argc, char** argv, char** env) { // Close trace if opened #if VM_TRACE - if (tfp) { tfp->close(); tfp = NULL; } + if (tfp) { + tfp->close(); + tfp = NULL; + } #endif // Destroy model - delete top; top = NULL; + delete top; + top = NULL; // Fin exit(0); diff --git a/examples/make_tracing_c/sim_main.cpp b/examples/make_tracing_c/sim_main.cpp index 6ff878731..8da3fee7a 100644 --- a/examples/make_tracing_c/sim_main.cpp +++ b/examples/make_tracing_c/sim_main.cpp @@ -83,9 +83,9 @@ int main(int argc, char** argv, char** env) { // Read outputs VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x" - " -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n", - main_time, top->clk, top->reset_l, top->in_quad, - top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]); + " -> oquad=%" VL_PRI64 "x owide=%x_%08x_%08x\n", + main_time, top->clk, top->reset_l, top->in_quad, top->out_quad, top->out_wide[2], + top->out_wide[1], top->out_wide[0]); } // Final model cleanup @@ -98,7 +98,8 @@ int main(int argc, char** argv, char** env) { #endif // Destroy model - delete top; top = NULL; + delete top; + top = NULL; // Fin exit(0); diff --git a/examples/make_tracing_sc/sc_main.cpp b/examples/make_tracing_sc/sc_main.cpp index 30f47f2bc..8ec598d0b 100644 --- a/examples/make_tracing_sc/sc_main.cpp +++ b/examples/make_tracing_sc/sc_main.cpp @@ -45,19 +45,19 @@ int sc_main(int argc, char* argv[]) { ios::sync_with_stdio(); // Defaults time -#if (SYSTEMC_VERSION>20011000) +#if (SYSTEMC_VERSION > 20011000) #else sc_time dut(1.0, sc_ns); sc_set_default_time_unit(dut); #endif // Define clocks -#if (SYSTEMC_VERSION>=20070314) - sc_clock clk ("clk", 10,SC_NS, 0.5, 3,SC_NS, true); - sc_clock fastclk ("fastclk", 2,SC_NS, 0.5, 2,SC_NS, true); +#if (SYSTEMC_VERSION >= 20070314) + sc_clock clk("clk", 10, SC_NS, 0.5, 3, SC_NS, true); + sc_clock fastclk("fastclk", 2, SC_NS, 0.5, 2, SC_NS, true); #else - sc_clock clk ("clk", 10, 0.5, 3, true); - sc_clock fastclk ("fastclk", 2, 0.5, 2, true); + sc_clock clk("clk", 10, 0.5, 3, true); + sc_clock fastclk("fastclk", 2, 0.5, 2, true); #endif // Define interconnect @@ -72,15 +72,15 @@ int sc_main(int argc, char* argv[]) { // Construct the Verilated model, from inside Vtop.h Vtop* top = new Vtop("top"); // Attach signals to the model - top->clk (clk); - top->fastclk (fastclk); - top->reset_l (reset_l); - top->in_small (in_small); - top->in_quad (in_quad); - top->in_wide (in_wide); - top->out_small (out_small); - top->out_quad (out_quad); - top->out_wide (out_wide); + top->clk(clk); + top->fastclk(fastclk); + top->reset_l(reset_l); + top->in_small(in_small); + top->in_quad(in_quad); + top->in_wide(in_wide); + top->out_small(out_small); + top->out_quad(out_quad); + top->out_wide(out_wide); #if VM_TRACE // Before any evaluation, need to know to calculate those signals only used for tracing @@ -89,7 +89,7 @@ int sc_main(int argc, char* argv[]) { // You must do one evaluation before enabling waves, in order to allow // SystemC to interconnect everything for testing. -#if (SYSTEMC_VERSION>=20070314) +#if (SYSTEMC_VERSION >= 20070314) sc_start(1, SC_NS); #else sc_start(1); @@ -100,7 +100,7 @@ int sc_main(int argc, char* argv[]) { // and if at run time passed the +trace argument, turn on tracing VerilatedVcdSc* tfp = NULL; const char* flag = Verilated::commandArgsPlusMatch("trace"); - if (flag && 0==strcmp(flag, "+trace")) { + if (flag && 0 == strcmp(flag, "+trace")) { cout << "Enabling waves into logs/vlt_dump.vcd...\n"; tfp = new VerilatedVcdSc; top->trace(tfp, 99); // Trace 99 levels of hierarchy @@ -118,15 +118,14 @@ int sc_main(int argc, char* argv[]) { #endif // Apply inputs - if (sc_time_stamp() > sc_time(1, SC_NS) - && sc_time_stamp() < sc_time(10, SC_NS)) { + if (sc_time_stamp() > sc_time(1, SC_NS) && sc_time_stamp() < sc_time(10, SC_NS)) { reset_l = !1; // Assert reset } else { reset_l = !0; // Deassert reset } // Simulate 1ns -#if (SYSTEMC_VERSION>=20070314) +#if (SYSTEMC_VERSION >= 20070314) sc_start(1, SC_NS); #else sc_start(1); @@ -138,7 +137,10 @@ int sc_main(int argc, char* argv[]) { // Close trace if opened #if VM_TRACE - if (tfp) { tfp->close(); tfp = NULL; } + if (tfp) { + tfp->close(); + tfp = NULL; + } #endif // Coverage analysis (since test passed) @@ -148,7 +150,8 @@ int sc_main(int argc, char* argv[]) { #endif // Destroy model - delete top; top = NULL; + delete top; + top = NULL; // Fin return 0; diff --git a/include/verilated.cpp b/include/verilated.cpp index 94b7ed6b7..8dd0b39b3 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -31,9 +31,11 @@ #include #include // mkdir +// clang-format off #if defined(_WIN32) || defined(__MINGW32__) # include // mkdir #endif +// clang-format on #define VL_VALUE_STRING_MAX_WIDTH 8192 ///< Max static char array for VL_VALUE_STRING @@ -42,13 +44,13 @@ typedef union { // cppcheck-suppress unusedStructMember // Unused as is assertion - char vluint8_incorrect[(sizeof(vluint8_t) == 1) ? 1:-1]; + char vluint8_incorrect[(sizeof(vluint8_t) == 1) ? 1 : -1]; // cppcheck-suppress unusedStructMember // Unused as is assertion - char vluint16_incorrect[(sizeof(vluint16_t) == 2) ? 1:-1]; + char vluint16_incorrect[(sizeof(vluint16_t) == 2) ? 1 : -1]; // cppcheck-suppress unusedStructMember // Unused as is assertion - char vluint32_incorrect[(sizeof(vluint32_t) == 4) ? 1:-1]; + char vluint32_incorrect[(sizeof(vluint32_t) == 4) ? 1 : -1]; // cppcheck-suppress unusedStructMember // Unused as is assertion - char vluint64_incorrect[(sizeof(vluint64_t) == 8) ? 1:-1]; + char vluint64_incorrect[(sizeof(vluint64_t) == 8) ? 1 : -1]; } vl_static_checks_t; //=========================================================================== @@ -114,7 +116,8 @@ void vl_stop_maybe(const char* filename, int linenum, const char* hier, bool may Verilated::errorCountInc(); if (maybe && Verilated::errorCount() < Verilated::errorLimit()) { VL_PRINTF( // Not VL_PRINTF_MT, already on main thread - "-Info: %s:%d: %s\n", filename, linenum, "Verilog $stop, ignored due to +verilator+error+limit"); + "-Info: %s:%d: %s\n", filename, linenum, + "Verilog $stop, ignored due to +verilator+error+limit"); } else { vl_stop(filename, linenum, hier); } @@ -126,9 +129,9 @@ void vl_stop_maybe(const char* filename, int linenum, const char* hier, bool may void VL_FINISH_MT(const char* filename, int linenum, const char* hier) VL_MT_SAFE { #ifdef VL_THREADED - VerilatedThreadMsgQueue::post(VerilatedMsg([=](){ - vl_finish(filename, linenum, hier); - })); + VerilatedThreadMsgQueue::post(VerilatedMsg([=]() { // + vl_finish(filename, linenum, hier); + })); #else vl_finish(filename, linenum, hier); #endif @@ -136,9 +139,9 @@ void VL_FINISH_MT(const char* filename, int linenum, const char* hier) VL_MT_SAF void VL_STOP_MT(const char* filename, int linenum, const char* hier, bool maybe) VL_MT_SAFE { #ifdef VL_THREADED - VerilatedThreadMsgQueue::post(VerilatedMsg([=](){ - vl_stop_maybe(filename, linenum, hier, maybe); - })); + VerilatedThreadMsgQueue::post(VerilatedMsg([=]() { // + vl_stop_maybe(filename, linenum, hier, maybe); + })); #else vl_stop_maybe(filename, linenum, hier, maybe); #endif @@ -146,9 +149,9 @@ void VL_STOP_MT(const char* filename, int linenum, const char* hier, bool maybe) void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_SAFE { #ifdef VL_THREADED - VerilatedThreadMsgQueue::post(VerilatedMsg([=](){ - vl_fatal(filename, linenum, hier, msg); - })); + VerilatedThreadMsgQueue::post(VerilatedMsg([=]() { // + vl_fatal(filename, linenum, hier, msg); + })); #else vl_fatal(filename, linenum, hier, msg); #endif @@ -163,12 +166,10 @@ std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE { va_copy(aq, ap); int len = VL_VSNPRINTF(NULL, 0, formatp, aq); va_end(aq); - if (VL_UNLIKELY(len < 1)) { - return ""; - } + if (VL_UNLIKELY(len < 1)) return ""; - char* bufp = new char[len+1]; - VL_VSNPRINTF(bufp, len+1, formatp, ap); + char* bufp = new char[len + 1]; + VL_VSNPRINTF(bufp, len + 1, formatp, ap); std::string out = std::string(bufp, len); delete[] bufp; @@ -203,7 +204,8 @@ void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE { 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()); + // printf("-imm-V{t%d,%" VL_PRI64 "d}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), + // out.c_str()); // Using VL_PRINTF not VL_PRINTF_MT so that we can call VL_DBG_MSGF // from within the guts of the thread execution machinery (and it goes @@ -217,9 +219,9 @@ void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE { va_start(ap, formatp); std::string out = _vl_string_vprintf(formatp, ap); va_end(ap); - VerilatedThreadMsgQueue::post(VerilatedMsg([=](){ - VL_PRINTF("%s", out.c_str()); - })); + VerilatedThreadMsgQueue::post(VerilatedMsg([=]() { // + VL_PRINTF("%s", out.c_str()); + })); } #endif @@ -258,9 +260,9 @@ static vluint32_t vl_sys_rand32() VL_MT_UNSAFE { // Used only to construct seed for Verilator's PNRG. #if defined(_WIN32) && !defined(__CYGWIN__) // Windows doesn't have lrand48(), although Cygwin does. - return (rand()<<16) ^ rand(); + return (rand() << 16) ^ rand(); #else - return (lrand48()<<16) ^ lrand48(); + return (lrand48() << 16) ^ lrand48(); #endif } @@ -292,22 +294,17 @@ vluint64_t vl_rand64() VL_MT_SAFE { // Xoroshiro128+ algorithm vluint64_t result = t_state[0] + t_state[1]; t_state[1] ^= t_state[0]; - t_state[0] = (((t_state[0] << 55) | (t_state[0] >> 9)) - ^ t_state[1] ^ (t_state[1] << 14)); + t_state[0] = (((t_state[0] << 55) | (t_state[0] >> 9)) ^ t_state[1] ^ (t_state[1] << 14)); t_state[1] = (t_state[1] << 36) | (t_state[1] >> 28); return result; } -IData VL_RANDOM_I(int obits) VL_MT_SAFE { - return vl_rand64() & VL_MASK_I(obits); -} -QData VL_RANDOM_Q(int obits) VL_MT_SAFE { - return vl_rand64() & VL_MASK_Q(obits); -} +IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); } +QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); } // VL_RANDOM_W currently unused as $random always 32 bits WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE { - for (int i=0; i= 0; --i) { - VL_PRINTF_MT("%08x ", iwp[i]); - } + for (int i = VL_WORDS_I(lbits) - 1; i >= 0; --i) VL_PRINTF_MT("%08x ", iwp[i]); VL_PRINTF_MT("\n"); } @@ -371,12 +366,12 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, // for debug see V3Number version // Requires clean input int words = VL_WORDS_I(lbits); - for (int i=0; i= 0; --j) { - vluint64_t unw64 = ((k<(lwp[j])); + for (int j = uw - 1; j >= 0; --j) { + vluint64_t unw64 = ((k << VL_ULL(32)) + static_cast(lwp[j])); owp[j] = unw64 / static_cast(rwp[0]); - k = unw64 - static_cast(owp[j])*static_cast(rwp[0]); + k = unw64 - static_cast(owp[j]) * static_cast(rwp[0]); } if (is_modulus) { owp[0] = k; - for (int i=1; i> 32 won't mask the value - for (int i = vw-1; i>0; --i) { - vn[i] = (rwp[i] << s) | (shift_mask & (rwp[i-1] >> (32-s))); + for (int i = vw - 1; i > 0; --i) { + vn[i] = (rwp[i] << s) | (shift_mask & (rwp[i - 1] >> (32 - s))); } vn[0] = rwp[0] << s; // Copy and shift dividend by same amount; may set new upper word - if (s) un[uw] = lwp[uw-1] >> (32-s); - else un[uw] = 0; - for (int i=uw-1; i>0; --i) { - un[i] = (lwp[i] << s) | (shift_mask & (lwp[i-1] >> (32-s))); + if (s) { + un[uw] = lwp[uw - 1] >> (32 - s); + } else { + un[uw] = 0; + } + for (int i = uw - 1; i > 0; --i) { + un[i] = (lwp[i] << s) | (shift_mask & (lwp[i - 1] >> (32 - s))); } un[0] = lwp[0] << s; // Main loop for (int j = uw - vw; j >= 0; --j) { // Estimate - vluint64_t unw64 = (static_cast(un[j+vw])<(un[j+vw-1])); - vluint64_t qhat = unw64 / static_cast(vn[vw-1]); - vluint64_t rhat = unw64 - qhat*static_cast(vn[vw-1]); + vluint64_t unw64 = (static_cast(un[j + vw]) << VL_ULL(32) + | static_cast(un[j + vw - 1])); + vluint64_t qhat = unw64 / static_cast(vn[vw - 1]); + vluint64_t rhat = unw64 - qhat * static_cast(vn[vw - 1]); - again: + again: if (qhat >= VL_ULL(0x100000000) - || ((qhat*vn[vw-2]) > ((rhat< ((rhat << VL_ULL(32)) + un[j + vw - 2]))) { qhat = qhat - 1; - rhat = rhat + vn[vw-1]; + rhat = rhat + vn[vw - 1]; if (rhat < VL_ULL(0x100000000)) goto again; } vlsint64_t t = 0; // Must be signed vluint64_t k = 0; - for (int i=0; i> VL_ULL(32)) - (t >> VL_ULL(32)); } - t = un[j+vw] - k; - un[j+vw] = t; + t = un[j + vw] - k; + un[j + vw] = t; owp[j] = qhat; // Save quotient digit if (t < 0) { // Over subtracted; correct by adding back owp[j]--; k = 0; - for (int i=0; i(un[i+j]) + static_cast(vn[i]) + k; - un[i+j] = t; + for (int i = 0; i < vw; ++i) { + t = static_cast(un[i + j]) + static_cast(vn[i]) + k; + un[i + j] = t; k = t >> VL_ULL(32); } - un[j+vw] = un[j+vw] + k; + un[j + vw] = un[j + vw] + k; } } if (is_modulus) { // modulus // Need to reverse normalization on copy to output - for (int i=0; i> s) | (shift_mask & (un[i+1] << (32-s))); + for (int i = 0; i < vw; ++i) { + owp[i] = (un[i] >> s) | (shift_mask & (un[i + 1] << (32 - s))); } - for (int i=vw; i0) { // power = power*power + for (int bit = 0; bit < rbits; bit++) { + if (bit > 0) { // power = power*power VL_ASSIGN_W(obits, lastpowstore, powstore); VL_MUL_W(VL_WORDS_I(obits), powstore, lastpowstore, lastpowstore); } @@ -498,18 +496,19 @@ WDataOutP VL_POW_WWW(int obits, int, int rbits, } return owp; } -WDataOutP VL_POW_WWQ(int obits, int lbits, int rbits, - WDataOutP owp, WDataInP lwp, QData rhs) VL_MT_SAFE { - WData rhsw[VL_WQ_WORDS_E]; VL_SET_WQ(rhsw, rhs); +WDataOutP VL_POW_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp, + QData rhs) VL_MT_SAFE { + WData rhsw[VL_WQ_WORDS_E]; + 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) VL_MT_SAFE { // Skip check for rhs == 0, as short-circuit doesn't save time - if (VL_UNLIKELY(lhs==0)) return 0; + if (VL_UNLIKELY(lhs == 0)) return 0; QData power = lhs; QData out = VL_ULL(1); - for (int bit=0; bit0) power = power*power; + for (int bit = 0; bit < rbits; ++bit) { + if (bit > 0) power = power * power; if (VL_BITISSET_W(rwp, bit)) out *= power; } return out; @@ -522,35 +521,45 @@ WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, W int words = VL_WORDS_I(obits); VL_ZERO_W(obits, owp); EData lor = 0; // 0=all zeros, ~0=all ones, else mix - for (int i=1; i < (words-1); ++i) { - lor |= lwp[i]; - } - lor |= ( (lwp[words-1] == VL_MASK_E(rbits)) ? ~VL_EUL(0) : 0); - if (lor==0 && lwp[0]==0) { return owp; } // "X" so return 0 - else if (lor==0 && lwp[0]==1) { owp[0] = 1; return owp; } // 1 - else if (lsign && lor == ~VL_EUL(0) && lwp[0] == ~VL_EUL(0)) { // -1 - if (rwp[0] & 1) { return VL_ALLONES_W(obits, owp); } // -1^odd=-1 - else { owp[0] = 1; return owp; } // -1^even=1 + for (int i = 1; i < (words - 1); ++i) { lor |= lwp[i]; } + lor |= ((lwp[words - 1] == VL_MASK_E(rbits)) ? ~VL_EUL(0) : 0); + if (lor == 0 && lwp[0] == 0) { // "X" so return 0 + return owp; + } else if (lor == 0 && lwp[0] == 1) { // 1 + owp[0] = 1; + return owp; + } else if (lsign && lor == ~VL_EUL(0) && lwp[0] == ~VL_EUL(0)) { // -1 + if (rwp[0] & 1) { // -1^odd=-1 + return VL_ALLONES_W(obits, owp); + } else { // -1^even=1 + owp[0] = 1; + return owp; + } } return 0; } 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, +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[VL_WQ_WORDS_E]; VL_SET_WQ(rhsw, rhs); + WData rhsw[VL_WQ_WORDS_E]; + 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) VL_MT_SAFE { +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" - else if (lhs == 1) return 1; - else if (lsign && lhs == VL_MASK_Q(obits)) { // -1 - if (rwp[0] & 1) return VL_MASK_Q(obits); // -1^odd=-1 - else return 1; // -1^even=1 + if (lhs == 0) { + return 0; // "X" + } else if (lhs == 1) { + return 1; + } else if (lsign && lhs == VL_MASK_Q(obits)) { // -1 + if (rwp[0] & 1) { + return VL_MASK_Q(obits); // -1^odd=-1 + } else { + return 1; // -1^even=1 + } } return 0; } @@ -562,19 +571,19 @@ QData VL_POWSS_QQW(int obits, int, int rbits, /// Output a string representation of a wide number std::string VL_DECIMAL_NW(int width, WDataInP lwp) VL_MT_SAFE { - int maxdecwidth = (width+3)*4/3; + int maxdecwidth = (width + 3) * 4 / 3; // Or (maxdecwidth+7)/8], but can't have more than 4 BCD bits per word - WData bcd[VL_VALUE_STRING_MAX_WIDTH/4+2]; + WData bcd[VL_VALUE_STRING_MAX_WIDTH / 4 + 2]; VL_ZERO_RESET_W(maxdecwidth, bcd); - WData tmp[VL_VALUE_STRING_MAX_WIDTH/4+2]; - WData tmp2[VL_VALUE_STRING_MAX_WIDTH/4+2]; - int from_bit = width-1; + WData tmp[VL_VALUE_STRING_MAX_WIDTH / 4 + 2]; + WData tmp2[VL_VALUE_STRING_MAX_WIDTH / 4 + 2]; + int from_bit = width - 1; // Skip all leading zeros - for (; from_bit >= 0 && !(VL_BITRSHIFT_W(lwp, from_bit) & 1); --from_bit); + for (; from_bit >= 0 && !(VL_BITRSHIFT_W(lwp, from_bit) & 1); --from_bit) {} // Double-dabble algorithm for (; from_bit >= 0; --from_bit) { // Any digits >= 5 need an add 3 (via tmp) - for (int nibble_bit = 0; nibble_bit < maxdecwidth; nibble_bit+=4) { + for (int nibble_bit = 0; nibble_bit < maxdecwidth; nibble_bit += 4) { if ((VL_BITRSHIFT_W(bcd, nibble_bit) & 0xf) >= 5) { VL_ZERO_RESET_W(maxdecwidth, tmp2); tmp2[VL_BITWORD_E(nibble_bit)] |= VL_EUL(0x3) << VL_BITBIT_E(nibble_bit); @@ -589,11 +598,11 @@ std::string VL_DECIMAL_NW(int width, WDataInP lwp) VL_MT_SAFE { if (VL_BITISSET_W(lwp, from_bit)) bcd[0] |= 1; } std::string output; - int lsb = (maxdecwidth-1) & ~3; - for (; lsb>0; lsb-=4) { // Skip leading zeros + int lsb = (maxdecwidth - 1) & ~3; + for (; lsb > 0; lsb -= 4) { // Skip leading zeros if (VL_BITRSHIFT_W(bcd, lsb) & 0xf) break; } - for (; lsb>=0; lsb-=4) { + for (; lsb >= 0; lsb -= 4) { output += ('0' + (VL_BITRSHIFT_W(bcd, lsb) & 0xf)); // 0..9 } return output; @@ -617,7 +626,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA bool left = false; size_t width = 0; for (const char* pos = formatp; *pos; ++pos) { - if (!inPct && pos[0]=='%') { + if (!inPct && pos[0] == '%') { pctp = pos; inPct = true; widthSet = false; @@ -625,20 +634,19 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } else if (!inPct) { // Normal text // Fast-forward to next escape and add to output const char* ep = pos; - while (ep[0] && ep[0]!='%') ep++; + while (ep[0] && ep[0] != '%') ep++; if (ep != pos) { - output.append(pos, ep-pos); - pos += ep-pos-1; + output.append(pos, ep - pos); + pos += ep - pos - 1; } } else { // Format character inPct = false; char fmt = pos[0]; switch (fmt) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': + case '0' ... '9': inPct = true; // Get more digits widthSet = true; - width = width*10 + (fmt - '0'); + width = width * 10 + (fmt - '0'); break; case '-': left = true; @@ -647,12 +655,15 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA case '.': inPct = true; // Get more digits break; - case '%': + case '%': // output += '%'; break; case 'N': { // "C" string with name of module, add . if needed const char* cstrp = va_arg(ap, const char*); - if (VL_LIKELY(*cstrp)) { output += cstrp; output += '.'; } + if (VL_LIKELY(*cstrp)) { + output += cstrp; + output += '.'; + } break; } case 'S': { // "C" string @@ -677,9 +688,9 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA if (lbits) {} // UNUSED - always 64 switch (fmt) { case '^': { // Realtime - int digits = sprintf(tmp, "%g", d/VL_TIME_MULTIPLIER); - int needmore = width-digits; - if (needmore>0) output.append(needmore, ' '); // Pre-pad spaces + int digits = sprintf(tmp, "%g", d / VL_TIME_MULTIPLIER); + int needmore = width - digits; + if (needmore > 0) output.append(needmore, ' '); // Pre-pad spaces output += tmp; break; } @@ -688,7 +699,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA sprintf(tmp, fmt.c_str(), d); output += tmp; break; - } + } // break; } // switch break; @@ -707,8 +718,10 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA lwp = va_arg(ap, WDataInP); ld = lwp[0]; } - int lsb=lbits-1; - if (widthSet && width==0) while (lsb && !VL_BITISSET_W(lwp, lsb)) --lsb; + int lsb = lbits - 1; + if (widthSet && width == 0) { + while (lsb && !VL_BITISSET_W(lwp, lsb)) --lsb; + } switch (fmt) { case 'c': { IData charval = ld & 0xff; @@ -717,10 +730,10 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } case 's': { std::string field; - for (; lsb>=0; --lsb) { + for (; lsb >= 0; --lsb) { lsb = (lsb / 8) * 8; // Next digit IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff; - field += (charval==0)?' ':charval; + field += (charval == 0) ? ' ' : charval; } std::string padding; if (width > field.size()) padding.append(width - field.size(), ' '); @@ -736,7 +749,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA append = tmp; } else { if (VL_SIGN_E(lbits, lwp[VL_WORDS_I(lbits) - 1])) { - WData neg[VL_VALUE_STRING_MAX_WIDTH/4+2]; + WData neg[VL_VALUE_STRING_MAX_WIDTH / 4 + 2]; VL_NEGATE_W(VL_WORDS_I(lbits), neg, lwp); append = std::string("-") + VL_DECIMAL_NW(lbits, neg); } else { @@ -744,10 +757,10 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } digits = append.length(); } - int needmore = width-digits; + int needmore = width - digits; std::string padding; - if (needmore>0) { - if (pctp && pctp[0] && pctp[1]=='0') { // %0 + if (needmore > 0) { + if (pctp && pctp[0] && pctp[1] == '0') { // %0 padding.append(needmore, '0'); // Pre-pad zero } else { padding.append(needmore, ' '); // Pre-pad spaces @@ -766,10 +779,10 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA append = VL_DECIMAL_NW(lbits, lwp); digits = append.length(); } - int needmore = width-digits; + int needmore = width - digits; std::string padding; - if (needmore>0) { - if (pctp && pctp[0] && pctp[1]=='0') { // %0 + if (needmore > 0) { + if (pctp && pctp[0] && pctp[1] == '0') { // %0 padding.append(needmore, '0'); // Pre-pad zero } else { padding.append(needmore, ' '); // Pre-pad spaces @@ -780,51 +793,48 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } case 't': { // Time int digits; - if (VL_TIME_MULTIPLIER==1) { - digits=sprintf(tmp, "%" VL_PRI64 "u", ld); - } else if (VL_TIME_MULTIPLIER==1000) { - digits=sprintf(tmp, "%" VL_PRI64 "u.%03" VL_PRI64 "u", - static_cast(ld/VL_TIME_MULTIPLIER), - static_cast(ld%VL_TIME_MULTIPLIER)); + if (VL_TIME_MULTIPLIER == 1) { + digits = sprintf(tmp, "%" VL_PRI64 "u", ld); + } else if (VL_TIME_MULTIPLIER == 1000) { + digits = sprintf(tmp, "%" VL_PRI64 "u.%03" VL_PRI64 "u", + static_cast(ld / VL_TIME_MULTIPLIER), + static_cast(ld % VL_TIME_MULTIPLIER)); } else { VL_FATAL_MT(__FILE__, __LINE__, "", "Unsupported VL_TIME_MULTIPLIER"); } - int needmore = width-digits; + int needmore = width - digits; std::string padding; - if (needmore>0) padding.append(needmore, ' '); // Pad with spaces + if (needmore > 0) padding.append(needmore, ' '); // Pad with spaces output += left ? (tmp + padding) : (padding + tmp); break; } case 'b': - for (; lsb>=0; --lsb) { - output += (VL_BITRSHIFT_W(lwp, lsb) & 1) + '0'; - } + for (; lsb >= 0; --lsb) output += (VL_BITRSHIFT_W(lwp, lsb) & 1) + '0'; break; case 'o': - for (; lsb>=0; --lsb) { + for (; lsb >= 0; --lsb) { lsb = (lsb / 3) * 3; // Next digit // Octal numbers may span more than one wide word, // so we need to grab each bit separately and check for overrun // Octal is rare, so we'll do it a slow simple way - output += ('0' - + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+0)) ? 1 : 0) - + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+1)) ? 2 : 0) - + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+2)) ? 4 : 0)); + output += ('0' + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 0)) ? 1 : 0) + + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 1)) ? 2 : 0) + + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 2)) ? 4 : 0)); } break; case 'u': // Packed 2-state - output.reserve(output.size() + 4*VL_WORDS_I(lbits)); - for (int i=0; i((lwp[i] ) & 0xff); + output.reserve(output.size() + 4 * VL_WORDS_I(lbits)); + for (int i = 0; i < VL_WORDS_I(lbits); ++i) { + output += static_cast((lwp[i]) & 0xff); output += static_cast((lwp[i] >> 8) & 0xff); output += static_cast((lwp[i] >> 16) & 0xff); output += static_cast((lwp[i] >> 24) & 0xff); } break; case 'z': // Packed 4-state - output.reserve(output.size() + 8*VL_WORDS_I(lbits)); - for (int i=0; i((lwp[i] ) & 0xff); + output.reserve(output.size() + 8 * VL_WORDS_I(lbits)); + for (int i = 0; i < VL_WORDS_I(lbits); ++i) { + output += static_cast((lwp[i]) & 0xff); output += static_cast((lwp[i] >> 8) & 0xff); output += static_cast((lwp[i] >> 16) & 0xff); output += static_cast((lwp[i] >> 24) & 0xff); @@ -832,20 +842,23 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } break; case 'v': // Strength; assume always strong - for (lsb=lbits-1; lsb>=0; --lsb) { - if (VL_BITRSHIFT_W(lwp, lsb) & 1) output += "St1 "; - else output += "St0 "; + for (lsb = lbits - 1; lsb >= 0; --lsb) { + if (VL_BITRSHIFT_W(lwp, lsb) & 1) { + output += "St1 "; + } else { + output += "St0 "; + } } break; case 'x': - for (; lsb>=0; --lsb) { + for (; lsb >= 0; --lsb) { lsb = (lsb / 4) * 4; // Next digit IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xf; output += "0123456789abcdef"[charval]; } break; default: - std::string msg = std::string("Unknown _vl_vsformat code: ")+pos[0]; + std::string msg = std::string("Unknown _vl_vsformat code: ") + pos[0]; VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); break; } // switch @@ -863,11 +876,14 @@ static inline bool _vl_vsss_eof(FILE* fp, int floc) VL_MT_SAFE { } } static inline void _vl_vsss_advance(FILE* fp, int& floc) VL_MT_SAFE { - if (fp) fgetc(fp); - else floc -= 8; + if (fp) { + fgetc(fp); + } else { + floc -= 8; + } } -static inline int _vl_vsss_peek(FILE* fp, int& floc, WDataInP fromp, - const std::string& fstr) VL_MT_SAFE { +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); @@ -878,17 +894,17 @@ static inline int _vl_vsss_peek(FILE* fp, int& floc, WDataInP fromp, if (floc < 0) return EOF; floc = floc & ~7; // Align to closest character if (fromp == NULL) { - return fstr[fstr.length()-1 - (floc>>3)]; + return fstr[fstr.length() - 1 - (floc >> 3)]; } else { return VL_BITRSHIFT_W(fromp, floc) & 0xff; } } } -static inline void _vl_vsss_skipspace(FILE* fp, int& floc, - WDataInP fromp, const std::string& fstr) VL_MT_SAFE { +static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp, + const std::string& fstr) VL_MT_SAFE { while (true) { int c = _vl_vsss_peek(fp, floc, fromp, fstr); - if (c==EOF || !isspace(c)) return; + if (c == EOF || !isspace(c)) return; _vl_vsss_advance(fp, floc); } } @@ -898,49 +914,49 @@ static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std: char* cp = tmpp; while (true) { int c = _vl_vsss_peek(fp, floc, fromp, fstr); - if (c==EOF || isspace(c)) break; - if (acceptp // String - allow anything - && NULL==strchr(acceptp, c)) break; + if (c == EOF || isspace(c)) break; + if (acceptp && NULL == strchr(acceptp, c)) break; // String - allow anything if (acceptp) c = tolower(c); // Non-strings we'll simplify *cp++ = c; _vl_vsss_advance(fp, floc); } *cp++ = '\0'; - //VL_DBG_MSGF(" _read got='"<>=1) { +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, +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) { + for (int i = 0, pos = static_cast(posend) - 1; + i < obits && pos >= static_cast(posstart); --pos) { + // clang-format off switch (tolower (strp[pos])) { case 'x': case 'z': case '?': // FALLTHRU case '0': lsb += baseLog2; break; - case '1': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 1); lsb+=baseLog2; break; - case '2': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 2); lsb+=baseLog2; break; - case '3': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 3); lsb+=baseLog2; break; - case '4': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 4); lsb+=baseLog2; break; - case '5': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 5); lsb+=baseLog2; break; - case '6': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 6); lsb+=baseLog2; break; - case '7': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 7); lsb+=baseLog2; break; - case '8': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 8); lsb+=baseLog2; break; - case '9': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 9); lsb+=baseLog2; break; - case 'a': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 10); lsb+=baseLog2; break; - case 'b': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 11); lsb+=baseLog2; break; - case 'c': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 12); lsb+=baseLog2; break; - case 'd': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 13); lsb+=baseLog2; break; - case 'e': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 14); lsb+=baseLog2; break; - case 'f': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 15); lsb+=baseLog2; break; + case '1': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 1); lsb += baseLog2; break; + case '2': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 2); lsb += baseLog2; break; + case '3': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 3); lsb += baseLog2; break; + case '4': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 4); lsb += baseLog2; break; + case '5': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 5); lsb += baseLog2; break; + case '6': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 6); lsb += baseLog2; break; + case '7': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 7); lsb += baseLog2; break; + case '8': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 8); lsb += baseLog2; break; + case '9': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 9); lsb += baseLog2; break; + case 'a': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 10); lsb += baseLog2; break; + case 'b': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 11); lsb += baseLog2; break; + case 'c': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 12); lsb += baseLog2; break; + case 'd': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 13); lsb += baseLog2; break; + case 'e': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 14); lsb += baseLog2; break; + case 'f': _vl_vsss_setbit(owp, obits, lsb, baseLog2, 15); lsb += baseLog2; break; case '_': break; } + // clang-format on } } @@ -957,8 +973,9 @@ 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_MSGF("_vlscan fmt='"< VL_QUADSIZE) { - owp = va_arg(ap, WDataOutP); - } - for (int i=0; i VL_QUADSIZE) owp = va_arg(ap, WDataOutP); + for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0; switch (fmt) { case 'c': { int c = _vl_vsss_peek(fp, floc, fromp, fstr); - if (c==EOF) goto done; - else _vl_vsss_advance(fp, floc); + if (c == EOF) goto done; + _vl_vsss_advance(fp, floc); owp[0] = c; break; } @@ -1001,10 +1017,11 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf _vl_vsss_skipspace(fp, floc, fromp, fstr); _vl_vsss_read(fp, floc, fromp, fstr, tmp, NULL); if (!tmp[0]) goto done; - int lpos = (static_cast(strlen(tmp)))-1; + int lpos = (static_cast(strlen(tmp))) - 1; int lsb = 0; - for (int i=0; i=0; --lpos) { - _vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]); lsb+=8; + for (int i = 0; i < obits && lpos >= 0; --lpos) { + _vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]); + lsb += 8; } break; } @@ -1013,7 +1030,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf _vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_"); if (!tmp[0]) goto done; vlsint64_t ld; - sscanf(tmp, "%30" VL_PRI64 "d",&ld); + sscanf(tmp, "%30" VL_PRI64 "d", &ld); VL_SET_WQ(owp, ld); break; } @@ -1024,7 +1041,10 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf _vl_vsss_read(fp, floc, fromp, fstr, tmp, "+-.0123456789eE"); if (!tmp[0]) goto done; // cppcheck-suppress unusedStructMember // It's used - union { double r; vlsint64_t ld; } u; + union { + double r; + vlsint64_t ld; + } u; u.r = strtod(tmp, NULL); VL_SET_WQ(owp, u.ld); break; @@ -1035,7 +1055,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf _vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_"); if (!tmp[0]) goto done; QData ld; - sscanf(tmp, "%30" VL_PRI64 "u",&ld); + sscanf(tmp, "%30" VL_PRI64 "u", &ld); VL_SET_WQ(owp, ld); break; } @@ -1061,7 +1081,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf break; } default: - std::string msg = std::string("Unknown _vl_vsscanf code: ")+pos[0]; + std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0]; VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); break; } // switch @@ -1069,45 +1089,48 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf got++; // Reload data if non-wide (if wide, we put it in the right place directly) if (obits <= VL_BYTESIZE) { - CData* p = va_arg(ap, CData*); *p = owp[0]; + CData* p = va_arg(ap, CData*); + *p = owp[0]; } else if (obits <= VL_SHORTSIZE) { - SData* p = va_arg(ap, SData*); *p = owp[0]; + SData* p = va_arg(ap, SData*); + *p = owp[0]; } else if (obits <= VL_IDATASIZE) { - IData* p = va_arg(ap, IData*); *p = owp[0]; + IData* p = va_arg(ap, IData*); + *p = owp[0]; } else if (obits <= VL_QUADSIZE) { - QData* p = va_arg(ap, QData*); *p = VL_SET_QW(owp); + QData* p = va_arg(ap, QData*); + *p = VL_SET_QW(owp); } } } // switch } } - done: +done: return got; } //=========================================================================== // File I/O -FILE* VL_CVT_I_FP(IData lhs) VL_MT_SAFE { - return VerilatedImp::fdToFp(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) VL_MT_SAFE { // See also VL_DATA_TO_STRING_NW - int lsb=obits-1; - bool start=true; + int lsb = obits - 1; + bool start = true; char* destp = destoutp; - for (; lsb>=0; --lsb) { + for (; lsb >= 0; --lsb) { lsb = (lsb / 8) * 8; // Next digit IData charval = VL_BITRSHIFT_W(sourcep, lsb) & 0xff; if (!start || charval) { - *destp++ = (charval==0)?' ':charval; + *destp++ = (charval == 0) ? ' ' : charval; start = false; // Drop leading 0s } } *destp = '\0'; // Terminate - // Drop trailing spaces - if (!start) while (isspace(*(destp-1)) && destp>destoutp) *--destp = '\0'; + if (!start) { // Drop trailing spaces + while (isspace(*(destp - 1)) && destp > destoutp) *--destp = '\0'; + } } void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp) VL_MT_SAFE { @@ -1116,8 +1139,8 @@ void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp) char* op = reinterpret_cast(destp); if (srclen > bytes) srclen = bytes; // Don't overflow destination size_t i; - for (i=0; i(memp))[entry]; if (shift == start_shift) { *datap = 0; } - *datap |= ((static_cast(c) << static_cast(shift)) - & VL_MASK_Q(width)); + *datap |= ((static_cast(c) << static_cast(shift)) & VL_MASK_Q(width)); } else { WDataOutP datap = &(reinterpret_cast(memp))[entry * VL_WORDS_I(width)]; - if (shift == start_shift) { VL_ZERO_RESET_W(width, datap); } + if (shift == start_shift) VL_ZERO_RESET_W(width, datap); datap[VL_BITWORD_E(shift)] |= (static_cast(c) << VL_BITBIT_E(shift)); } // Prep for next @@ -1393,7 +1417,8 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, } IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE { - WData lhsw[VL_WQ_WORDS_E]; VL_SET_WQ(lhsw, lhs); + WData lhsw[VL_WQ_WORDS_E]; + VL_SET_WQ(lhsw, lhs); return VL_SYSTEM_IW(VL_WQ_WORDS_E, lhsw); } IData VL_SYSTEM_IW(int lhswords, WDataInP lhsp) VL_MT_SAFE { @@ -1405,8 +1430,7 @@ IData VL_SYSTEM_IW(int lhswords, WDataInP lhsp) VL_MT_SAFE { IData VL_TESTPLUSARGS_I(const char* formatp) VL_MT_SAFE { const std::string& match = VerilatedImp::argPlusMatch(formatp); - if (match.empty()) return 0; - else return 1; + return match.empty() ? 0 : 1; } IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE { @@ -1415,7 +1439,7 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M bool done = false; char fmt = ' '; for (const char* posp = ld.c_str(); !done && *posp; ++posp) { - if (!inPct && posp[0]=='%') { + if (!inPct && posp[0] == '%') { inPct = true; } else if (!inPct) { // Normal text prefix += *posp; @@ -1441,22 +1465,18 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M switch (tolower(fmt)) { case 'd': vlsint64_t lld; - sscanf(dp, "%30" VL_PRI64 "d",&lld); + sscanf(dp, "%30" VL_PRI64 "d", &lld); VL_SET_WQ(rwp, lld); break; - case 'b': - _vl_vsss_based(rwp, rbits, 1, dp, 0, strlen(dp)); - break; - case 'o': - _vl_vsss_based(rwp, rbits, 3, dp, 0, strlen(dp)); - break; + case 'b': _vl_vsss_based(rwp, rbits, 1, dp, 0, strlen(dp)); break; + case 'o': _vl_vsss_based(rwp, rbits, 3, dp, 0, strlen(dp)); break; case 'h': // FALLTHRU - case 'x': - _vl_vsss_based(rwp, rbits, 4, dp, 0, strlen(dp)); - break; + case 'x': _vl_vsss_based(rwp, rbits, 4, dp, 0, strlen(dp)); break; case 's': // string/no conversion - for (int i=0, lsb=0, posp=static_cast(strlen(dp))-1; i=0; --posp) { - _vl_vsss_setbit(rwp, rbits, lsb, 8, dp[posp]); lsb+=8; + for (int i = 0, lsb = 0, posp = static_cast(strlen(dp)) - 1; i < rbits && posp >= 0; + --posp) { + _vl_vsss_setbit(rwp, rbits, lsb, 8, dp[posp]); + lsb += 8; } break; case 'e': { @@ -1488,7 +1508,7 @@ IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_S bool inPct = false; bool done = false; for (const char* posp = ld.c_str(); !done && *posp; ++posp) { - if (!inPct && posp[0]=='%') { + if (!inPct && posp[0] == '%') { inPct = true; } else if (!inPct) { // Normal text prefix += *posp; @@ -1498,7 +1518,7 @@ IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_S prefix += *posp; inPct = false; break; - default: + default: // done = true; break; } @@ -1524,34 +1544,22 @@ const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE { //=========================================================================== // Heavy string functions -std::string VL_TO_STRING(CData lhs) { - return VL_SFORMATF_NX("'h%0x", 8, lhs); -} -std::string VL_TO_STRING(SData lhs) { - return VL_SFORMATF_NX("'h%0x", 16, lhs); -} -std::string VL_TO_STRING(IData lhs) { - return VL_SFORMATF_NX("'h%0x", 32, lhs); -} -std::string VL_TO_STRING(QData lhs) { - return VL_SFORMATF_NX("'h%0x", 64, lhs); -} +std::string VL_TO_STRING(CData lhs) { return VL_SFORMATF_NX("'h%0x", 8, lhs); } +std::string VL_TO_STRING(SData lhs) { return VL_SFORMATF_NX("'h%0x", 16, lhs); } +std::string VL_TO_STRING(IData lhs) { return VL_SFORMATF_NX("'h%0x", 32, lhs); } +std::string VL_TO_STRING(QData lhs) { return VL_SFORMATF_NX("'h%0x", 64, lhs); } std::string VL_TO_STRING_W(int words, WDataInP obj) { return VL_SFORMATF_NX("'h%0x", words * VL_EDATASIZE, obj); } std::string VL_TOLOWER_NN(const std::string& ld) VL_MT_SAFE { std::string out = ld; - for (std::string::iterator it = out.begin(); it != out.end(); ++it) { - *it = tolower(*it); - } + for (std::string::iterator it = out.begin(); it != out.end(); ++it) *it = tolower(*it); return out; } std::string VL_TOUPPER_NN(const std::string& ld) VL_MT_SAFE { std::string out = ld; - for (std::string::iterator it = out.begin(); it != out.end(); ++it) { - *it = toupper(*it); - } + for (std::string::iterator it = out.begin(); it != out.end(); ++it) *it = toupper(*it); return out; } @@ -1559,15 +1567,15 @@ 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_EDATASIZE + 1]; int obits = lwords * VL_EDATASIZE; - int lsb=obits-1; - bool start=true; + int lsb = obits - 1; + bool start = true; char* destp = destout; int len = 0; - for (; lsb>=0; --lsb) { + for (; lsb >= 0; --lsb) { lsb = (lsb / 8) * 8; // Next digit IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff; if (!start || charval) { - *destp++ = (charval==0)?' ':charval; + *destp++ = (charval == 0) ? ' ' : charval; len++; start = false; // Drop leading 0s } @@ -1667,7 +1675,10 @@ VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData star } } VlReadMem::~VlReadMem() { - if (m_fp) { fclose(m_fp); m_fp = NULL; } + if (m_fp) { + fclose(m_fp); + m_fp = NULL; + } } bool VlReadMem::get(QData& addrr, std::string& valuer) { if (VL_UNLIKELY(!m_fp)) return false; @@ -1697,7 +1708,8 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) { } // Parse line if (c == '\n') { - ++m_linenum; ignore_to_eol = false; + ++m_linenum; + ignore_to_eol = false; reading_addr = false; } else if (c == '\t' || c == ' ' || c == '\r' || c == '\f') { reading_addr = false; @@ -1707,15 +1719,22 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) { ignore_to_cmt = false; reading_addr = false; } else if (!ignore_to_eol && !ignore_to_cmt) { - if (lastc == '/' && c == '*') { ignore_to_cmt = true; } - else if (lastc == '/' && c == '/') { ignore_to_eol = true; } - else if (c == '/') {} // Part of /* or // - else if (c == '#') { ignore_to_eol = true; } - else if (c == '@') { reading_addr = true; m_addr = 0; } + if (lastc == '/' && c == '*') { + ignore_to_cmt = true; + } else if (lastc == '/' && c == '/') { + ignore_to_eol = true; + } else if (c == '/') { // Part of /* or // + } else if (c == '#') { + ignore_to_eol = true; + } else if (c == '@') { + reading_addr = true; + m_addr = 0; + } // Check for hex or binary digits as file format requests else if (isxdigit(c) || (!reading_addr && (c == 'x' || c == 'X'))) { c = tolower(c); - int value = (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c-'a'+10)) : (c-'0')); + int value + = (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c - 'a' + 10)) : (c - '0')); if (reading_addr) { // Decode @ addresses m_addr = (m_addr << 4) + value; @@ -1768,7 +1787,7 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) { & VL_MASK_Q(m_bits); } else { WDataOutP datap = reinterpret_cast(valuep); - if (!innum) { VL_ZERO_RESET_W(m_bits, datap); } + if (!innum) VL_ZERO_RESET_W(m_bits, datap); _VL_SHIFTL_INPLACE_W(m_bits, datap, static_cast(shift)); datap[0] |= value; } @@ -1798,7 +1817,10 @@ VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData st } } VlWriteMem::~VlWriteMem() { - if (m_fp) { fclose(m_fp); m_fp = NULL; } + if (m_fp) { + fclose(m_fp); + m_fp = NULL; + } } void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) { if (VL_UNLIKELY(!m_fp)) return; @@ -1866,7 +1888,7 @@ void VL_READMEM_N(bool hex, // Hex format, else binary while (true) { QData addr; std::string value; - if (rmem.get(addr /*ref*/, value/*ref*/)) { + if (rmem.get(addr /*ref*/, value /*ref*/)) { if (VL_UNLIKELY(addr < static_cast(array_lsb) || addr >= static_cast(array_lsb + depth))) { VL_FATAL_MT(filename.c_str(), rmem.linenum(), "", @@ -1886,8 +1908,8 @@ void VL_READMEM_N(bool hex, // Hex format, else binary QData* datap = &(reinterpret_cast(memp))[entry]; rmem.setData(datap, value); } else { - WDataOutP datap = &(reinterpret_cast(memp)) - [ entry*VL_WORDS_I(bits) ]; + WDataOutP datap + = &(reinterpret_cast(memp))[entry * VL_WORDS_I(bits)]; rmem.setData(datap, value); } } @@ -1945,7 +1967,10 @@ int VL_TIME_STR_CONVERT(const char* strp) { int scale = 0; if (!strp) return 0; if (*strp++ != '1') return 0; - while (*strp == '0') { scale++; strp++; } + while (*strp == '0') { + scale++; + strp++; + } switch (*strp++) { case 's': break; case 'm': scale -= 3; break; @@ -1966,13 +1991,15 @@ int VL_TIME_STR_CONVERT(const char* strp) { Verilated::ThreadLocal::ThreadLocal() : #ifdef VL_THREADED - t_mtaskId(0), - t_endOfEvalReqd(0), + t_mtaskId(0) + , t_endOfEvalReqd(0) + , #endif - t_dpiScopep(NULL), t_dpiFilename(0), t_dpiLineno(0) { -} -Verilated::ThreadLocal::~ThreadLocal() { + t_dpiScopep(NULL) + , t_dpiFilename(0) + , t_dpiLineno(0) { } +Verilated::ThreadLocal::~ThreadLocal() {} void Verilated::debug(int level) VL_MT_SAFE { VerilatedLockGuard lock(m_mutex); @@ -2038,15 +2065,14 @@ void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE { s_ns.s_profThreadsFilenamep = strdup(flagp); } - const char* Verilated::catName(const char* n1, const char* n2, const char* delimiter) VL_MT_SAFE { // Returns new'ed data // Used by symbol table creation to make module names static VL_THREAD_LOCAL char* strp = NULL; - static VL_THREAD_LOCAL size_t len = 0; - size_t newlen = strlen(n1)+strlen(n2)+strlen(delimiter)+1; + static VL_THREAD_LOCAL size_t len = 0; + size_t newlen = strlen(n1) + strlen(n2) + strlen(delimiter) + 1; if (!strp || newlen > len) { - if (strp) delete [] strp; + if (strp) delete[] strp; strp = new char[newlen]; len = newlen; } @@ -2058,9 +2084,10 @@ const char* Verilated::catName(const char* n1, const char* n2, const char* delim void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE { VerilatedLockGuard lock(m_mutex); - if (s_flushCb == cb) {} // Ok - don't duplicate - else if (!s_flushCb) { s_flushCb=cb; } - else { // LCOV_EXCL_LINE + if (s_flushCb == cb) { // Ok - don't duplicate + } else if (!s_flushCb) { + s_flushCb = cb; + } else { // LCOV_EXCL_LINE // Someday we may allow multiple callbacks ala atexit(), but until then VL_FATAL_MT("unknown", 0, "", // LCOV_EXCL_LINE "Verilated::flushCb called twice with different callbacks"); @@ -2074,12 +2101,8 @@ void Verilated::flushCall() VL_MT_SAFE { fflush(stdout); } -const char* Verilated::productName() VL_PURE { - return VERILATOR_PRODUCT; -} -const char* Verilated::productVersion() VL_PURE { - return VERILATOR_VERSION; -} +const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; } +const char* Verilated::productVersion() VL_PURE { return VERILATOR_VERSION; } void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE { VerilatedLockGuard lock(s_args.m_argMutex); @@ -2105,8 +2128,7 @@ void Verilated::nullPointerError(const char* filename, int linenum) VL_MT_SAFE { void Verilated::overWidthError(const char* signame) VL_MT_SAFE { // Slowpath - Called only when signal sets too high of a bit - std::string msg = (std::string("Testbench C set input '") - + signame + std::string msg = (std::string("Testbench C set input '") + signame + "' to value that overflows what the signal's width can fit"); VL_FATAL_MT("unknown", 0, "", msg.c_str()); VL_UNREACHABLE @@ -2127,13 +2149,9 @@ void Verilated::quiesce() VL_MT_SAFE { #endif } -void Verilated::internalsDump() VL_MT_SAFE { - VerilatedImp::internalsDump(); -} +void Verilated::internalsDump() VL_MT_SAFE { VerilatedImp::internalsDump(); } -void Verilated::scopesDump() VL_MT_SAFE { - VerilatedImp::scopesDump(); -} +void Verilated::scopesDump() VL_MT_SAFE { VerilatedImp::scopesDump(); } const VerilatedScope* Verilated::scopeFind(const char* namep) VL_MT_SAFE { return VerilatedImp::scopeFind(namep); @@ -2167,7 +2185,7 @@ void VerilatedImp::internalsDump() VL_MT_SAFE { VL_PRINTF_MT("internalsDump:\n"); versionDump(); VL_PRINTF_MT(" Argv:"); - for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) { + for (ArgVec::const_iterator it = s_s.m_argVec.begin(); it != s_s.m_argVec.end(); ++it) { VL_PRINTF_MT(" %s", it->c_str()); } VL_PRINTF_MT("\n"); @@ -2176,8 +2194,7 @@ void VerilatedImp::internalsDump() VL_MT_SAFE { userDump(); } void VerilatedImp::versionDump() VL_MT_SAFE { - VL_PRINTF_MT(" Version: %s %s\n", - Verilated::productName(), Verilated::productVersion()); + VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion()); } void VerilatedImp::commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) { @@ -2191,7 +2208,7 @@ void VerilatedImp::commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m } void VerilatedImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex) { if (!s_s.m_argVecLoaded) s_s.m_argVec.clear(); - for (int i=0; i m_udims || dim > 3)) return NULL; + if (VL_UNLIKELY(dim <= 0 || dim > m_udims || dim > 3)) return NULL; if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return NULL; int indxAdj = indx - low(dim); vluint8_t* bytep = reinterpret_cast(datap); // If on index 1 of a 2 index array, then each index 1 is index2sz*entsz size_t slicesz = entSize(); - for (int d=dim+1; d<=m_udims; ++d) slicesz *= elements(d); - bytep += indxAdj*slicesz; + for (int d = dim + 1; d <= m_udims; ++d) slicesz *= elements(d); + bytep += indxAdj * slicesz; return bytep; } @@ -2339,20 +2342,19 @@ VerilatedScope::VerilatedScope() { VerilatedScope::~VerilatedScope() { // Memory cleanup - not called during normal operation VerilatedImp::scopeErase(this); - if (m_namep) VL_DO_CLEAR(delete [] m_namep, m_namep = NULL); - if (m_callbacksp) VL_DO_CLEAR(delete [] m_callbacksp, m_callbacksp = NULL); + if (m_namep) VL_DO_CLEAR(delete[] m_namep, m_namep = NULL); + if (m_callbacksp) VL_DO_CLEAR(delete[] m_callbacksp, m_callbacksp = NULL); if (m_varsp) VL_DO_CLEAR(delete m_varsp, m_varsp = NULL); m_funcnumMax = 0; // Force callback table to empty } -void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, - const char* suffixp, const char* identifier, - const Type type) VL_MT_UNSAFE { +void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp, + const char* identifier, const Type type) 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; m_type = type; - char* namep = new char[strlen(prefixp)+strlen(suffixp)+2]; + char* namep = new char[strlen(prefixp) + strlen(suffixp) + 2]; strcpy(namep, prefixp); if (*prefixp && *suffixp) strcat(namep, "."); strcat(namep, suffixp); @@ -2368,15 +2370,15 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_ if (!finalize) { // Need two passes so we know array size to create // Alternative is to dynamically stretch the array, which is more code, and slower. - if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum+1; } + if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum + 1; } } else { if (VL_UNCOVERABLE(funcnum >= m_funcnumMax)) { VL_FATAL_MT(__FILE__, __LINE__, "", // LCOV_EXCL_LINE "Internal: Bad funcnum vs. pre-finalize maximum"); } if (VL_UNLIKELY(!m_callbacksp)) { // First allocation - m_callbacksp = new void* [m_funcnumMax]; - memset(m_callbacksp, 0, m_funcnumMax*sizeof(void*)); + m_callbacksp = new void*[m_funcnumMax]; + memset(m_callbacksp, 0, m_funcnumMax * sizeof(void*)); } m_callbacksp[funcnum] = cb; } @@ -2394,21 +2396,21 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, va_list ap; va_start(ap, dims); - for (int i=0; i=1 && i<=3) { - var.m_unpacked[i-1].m_left = msb; - var.m_unpacked[i-1].m_right = lsb; + } else if (i >= 1 && i <= 3) { + var.m_unpacked[i - 1].m_left = msb; + var.m_unpacked[i - 1].m_right = lsb; } else { // We could have a linked list of ranges, but really this whole thing needs // to be generalized to support structs and unions, etc. - VL_FATAL_MT(__FILE__, __LINE__, "", - (std::string("Unsupported multi-dimensional public varInsert: ") - + namep).c_str()); + VL_FATAL_MT( + __FILE__, __LINE__, "", + (std::string("Unsupported multi-dimensional public varInsert: ") + namep).c_str()); } } va_end(ap); @@ -2420,9 +2422,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, 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())) { - return &(it->second); - } + if (VL_LIKELY(it != m_varsp->end())) return &(it->second); } return NULL; } @@ -2438,25 +2438,23 @@ void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE { void* VerilatedScope::exportFindError(int funcnum) const { // Slowpath - Called only when find has failed - std::string msg = (std::string("Testbench C called '") - +VerilatedImp::exportName(funcnum) - +"' but this DPI export function exists only in other scopes, not scope '" - +name()+"'"); + std::string msg = (std::string("Testbench C called '") + VerilatedImp::exportName(funcnum) + + "' but this DPI export function exists only in other scopes, not scope '" + + name() + "'"); VL_FATAL_MT("unknown", 0, "", msg.c_str()); return NULL; } void VerilatedScope::scopeDump() const { VL_PRINTF_MT(" SCOPE %p: %s\n", this, name()); - for (int i=0; ivarsp()) { - for (VerilatedVarNameMap::const_iterator it = varsp->begin(); - it != varsp->end(); ++it) { + for (VerilatedVarNameMap::const_iterator it = varsp->begin(); it != varsp->end(); ++it) { VL_PRINTF_MT(" VAR %p: %s\n", &(it->second), it->first); } } @@ -2471,7 +2469,8 @@ void VerilatedHierarchy::add(VerilatedScope* fromp, VerilatedScope* top) { #if defined(VL_THREADED) && defined(VL_DEBUG) void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE { - VL_FATAL_MT(__FILE__, __LINE__, "", "Routine called that is single threaded, but called from" + VL_FATAL_MT(__FILE__, __LINE__, "", + "Routine called that is single threaded, but called from" " a different thread then the expected constructing thread"); } #endif diff --git a/include/verilated.h b/include/verilated.h index 31bbbb75b..217911eb0 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -23,6 +23,7 @@ #ifndef _VERILATED_H_ #define _VERILATED_H_ 1 ///< Header Guard +// clang-format off #include "verilatedos.h" #if VM_SC # include "verilated_sc.h" // Get SYSTEMC_VERSION and time declarations @@ -47,10 +48,12 @@ #ifdef VL_VERILATED_INCLUDE # include VL_VERILATED_INCLUDE #endif +// clang-format on //============================================================================= // Switches +// clang-format off #if VM_TRACE // Verilator tracing requested # define WAVES 1 // Set backward compatibility flag #endif @@ -59,10 +62,12 @@ #if defined(SYSTEMC_VERSION) && (SYSTEMC_VERSION < 20111121) # warning "Verilator soon requires SystemC 2.3.*; see manual for deprecated other versions." #endif +// clang-format on //========================================================================= // Basic types +// clang-format off // P // Packed data of bit type (C/S/I/Q/W) typedef vluint8_t CData; ///< Verilated pack data, 1-8 bits typedef vluint16_t SData; ///< Verilated pack data, 9-16 bits @@ -73,6 +78,7 @@ typedef EData WData; ///< Verilated pack data, >64 bits, as an array // float F // No typedef needed; Verilator uses float // double D // No typedef needed; Verilator uses double // string N // No typedef needed; Verilator uses string +// clang-format on typedef const WData* WDataInP; ///< Array input to a function typedef WData* WDataOutP; ///< Array output from a function @@ -92,27 +98,27 @@ class VerilatedFst; class VerilatedFstC; enum VerilatedVarType { - VLVT_UNKNOWN=0, - VLVT_PTR, // Pointer to something - VLVT_UINT8, // AKA CData - VLVT_UINT16, // AKA SData - VLVT_UINT32, // AKA IData - VLVT_UINT64, // AKA QData - VLVT_WDATA, // AKA WData - VLVT_STRING // C++ string + VLVT_UNKNOWN = 0, + VLVT_PTR, // Pointer to something + VLVT_UINT8, // AKA CData + VLVT_UINT16, // AKA SData + VLVT_UINT32, // AKA IData + VLVT_UINT64, // AKA QData + VLVT_WDATA, // AKA WData + VLVT_STRING // C++ string }; enum VerilatedVarFlags { - VLVD_0 = 0, // None - VLVD_IN = 1, // == vpiInput - VLVD_OUT = 2, // == vpiOutput - VLVD_INOUT = 3, // == vpiInOut - VLVD_NODIR = 5, // == vpiNoDirection + VLVD_0 = 0, // None + VLVD_IN = 1, // == vpiInput + VLVD_OUT = 2, // == vpiOutput + VLVD_INOUT = 3, // == vpiInOut + VLVD_NODIR = 5, // == vpiNoDirection VLVF_MASK_DIR = 7, // Bit mask for above directions // Flags - VLVF_PUB_RD = (1<<8), // Public readable - VLVF_PUB_RW = (1<<9), // Public writable - VLVF_DPI_CLAY = (1<<10) // DPI compatible C standard layout + VLVF_PUB_RD = (1 << 8), // Public readable + VLVF_PUB_RW = (1 << 9), // Public writable + VLVF_DPI_CLAY = (1 << 10) // DPI compatible C standard layout }; //========================================================================= @@ -127,9 +133,9 @@ extern vluint32_t VL_THREAD_ID() VL_MT_SAFE; /// Mutex, wrapped to allow -fthread_safety checks class VL_CAPABILITY("mutex") VerilatedMutex { - private: +private: std::mutex m_mutex; // Mutex - public: +public: VerilatedMutex() {} ~VerilatedMutex() {} const VerilatedMutex& operator!() const { return *this; } // For -fthread_safety @@ -154,16 +160,16 @@ class VL_CAPABILITY("mutex") VerilatedMutex { /// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks class VL_SCOPED_CAPABILITY VerilatedLockGuard { VL_UNCOPYABLE(VerilatedLockGuard); - private: + +private: VerilatedMutex& m_mutexr; - public: + +public: explicit VerilatedLockGuard(VerilatedMutex& mutexr) VL_ACQUIRE(mutexr) : m_mutexr(mutexr) { m_mutexr.lock(); } - ~VerilatedLockGuard() VL_RELEASE() { - m_mutexr.unlock(); - } + ~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); } void lock() VL_ACQUIRE() { m_mutexr.lock(); } void unlock() VL_RELEASE() { m_mutexr.unlock(); } }; @@ -180,6 +186,7 @@ public: /// Empty non-threaded lock guard to avoid #ifdefs in consuming code class VerilatedLockGuard { VL_UNCOPYABLE(VerilatedLockGuard); + public: explicit VerilatedLockGuard(VerilatedMutex&) {} ~VerilatedLockGuard() {} @@ -228,6 +235,7 @@ class VerilatedScope; class VerilatedModule { VL_UNCOPYABLE(VerilatedModule); + private: const char* m_namep; ///< Module name public: @@ -309,18 +317,19 @@ public: // But for internal use only class VerilatedScope { public: typedef enum { - SCOPE_MODULE, SCOPE_OTHER + SCOPE_MODULE, + SCOPE_OTHER } Type; // Type of a scope, currently module is only interesting private: // Fastpath: - VerilatedSyms* m_symsp; ///< Symbol table - void** m_callbacksp; ///< Callback table pointer (Fastpath) - int m_funcnumMax; ///< Maxium function number stored (Fastpath) + VerilatedSyms* m_symsp; ///< Symbol table + void** m_callbacksp; ///< Callback table pointer (Fastpath) + int m_funcnumMax; ///< Maxium function number stored (Fastpath) // 4 bytes padding (on -m64), for rent. - VerilatedVarNameMap* m_varsp; ///< Variable map - const char* m_namep; ///< Scope name (Slowpath) - const char* m_identifierp; ///< Identifier of scope (with escapes removed) - Type m_type; ///< Type of the scope + VerilatedVarNameMap* m_varsp; ///< Variable map + const char* m_namep; ///< Scope name (Slowpath) + const char* m_identifierp; ///< Identifier of scope (with escapes removed) + Type m_type; ///< Type of the scope public: // But internals only - called from VerilatedModule's VerilatedScope(); @@ -328,8 +337,8 @@ public: // But internals only - called from VerilatedModule's void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp, const char* identifier, const Type type) VL_MT_UNSAFE; void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE; - void varInsert(int finalize, const char* namep, void* datap, - VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE; + void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype, + int vlflags, int dims, ...) VL_MT_UNSAFE; // ACCESSORS const char* name() const { return m_namep; } const char* identifier() const { return m_identifierp; } @@ -368,11 +377,11 @@ class Verilated { static struct Serialized { // All these members serialized/deserialized // Fast path - int s_debug; ///< See accessors... only when VL_DEBUG set - bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated - bool s_gotFinish; ///< A $finish statement executed - bool s_assertOn; ///< Assertions are enabled - bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported + int s_debug; ///< See accessors... only when VL_DEBUG set + bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated + bool s_gotFinish; ///< A $finish statement executed + bool s_assertOn; ///< Assertions are enabled + bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported // Slow path int s_errorCount; ///< Number of errors int s_errorLimit; ///< Stop on error number @@ -399,7 +408,9 @@ class Verilated { VerilatedMutex m_argMutex; ///< Mutex for s_args members, when VL_THREADED int argc; const char** argv; - CommandArgValues() : argc(0), argv(NULL) {} + CommandArgValues() + : argc(0) + , argv(NULL) {} ~CommandArgValues() {} } s_args; @@ -442,12 +453,14 @@ public: /// changing the level (no mutex) static inline int debug() VL_MT_SAFE { return s_s.s_debug; } #else - static inline int debug() VL_PURE { return 0; } ///< Return constant 0 debug level, so C++'s optimizer rips up + /// Return constant 0 debug level, so C++'s optimizer rips up + static inline int debug() VL_PURE { return 0; } #endif /// Enable calculation of unused signals static void calcUnusedSigs(bool flag) VL_MT_SAFE; static bool calcUnusedSigs() VL_MT_SAFE { ///< Return calcUnusedSigs value - return s_s.s_calcUnusedSigs; } + return s_s.s_calcUnusedSigs; + } /// Current number of errors/assertions static void errorCount(int val) VL_MT_SAFE; static void errorCountInc() VL_MT_SAFE; @@ -485,7 +498,8 @@ public: /// This should be called before the first model is created. static void commandArgs(int argc, const char** argv) VL_MT_SAFE; static void commandArgs(int argc, char** argv) VL_MT_SAFE { - commandArgs(argc, const_cast(argv)); } + commandArgs(argc, const_cast(argv)); + } static void commandArgsAdd(int argc, const char** argv); static CommandArgValues* getCommandArgs() VL_MT_SAFE { return &s_args; } /// Match plusargs with a given prefix. Returns static char* valid only for a single call @@ -529,8 +543,12 @@ public: // Internal: Get and set DPI context static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; } static void dpiScope(const VerilatedScope* scopep) VL_MT_SAFE { t_s.t_dpiScopep = scopep; } - static void dpiContext(const VerilatedScope* scopep, const char* filenamep, int lineno) VL_MT_SAFE { - t_s.t_dpiScopep = scopep; t_s.t_dpiFilename = filenamep; t_s.t_dpiLineno = lineno; } + static void dpiContext(const VerilatedScope* scopep, const char* filenamep, + int lineno) VL_MT_SAFE { + t_s.t_dpiScopep = scopep; + t_s.t_dpiFilename = filenamep; + t_s.t_dpiLineno = lineno; + } static void dpiClearContext() VL_MT_SAFE { t_s.t_dpiScopep = NULL; } static bool dpiInContext() VL_MT_SAFE { return t_s.t_dpiScopep != NULL; } static const char* dpiFilenamep() VL_MT_SAFE { return t_s.t_dpiFilename; } @@ -586,8 +604,7 @@ extern void vl_stop(const char* filename, int linenum, const char* hier); /// 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); +extern void vl_fatal(const char* filename, int linenum, const char* hier, const char* msg); //========================================================================= // Extern functions -- Slow path @@ -601,12 +618,15 @@ extern void VL_STOP_MT(const char* filename, int linenum, const char* hier, extern void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_SAFE; +// clang-format off /// Print a string, multithread safe. Eventually VL_PRINTF will get called. #ifdef VL_THREADED extern void VL_PRINTF_MT(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE; #else # define VL_PRINTF_MT VL_PRINTF // The following parens will take care of themselves #endif +// clang-format on + /// Print a debug message from internals with standard prefix, with printf style format extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE; @@ -618,16 +638,21 @@ extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp); ///< Randomize a sign extern IData VL_RAND_RESET_I(int obits); ///< Random reset a signal extern QData VL_RAND_RESET_Q(int obits); ///< Random reset a signal extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp); ///< Random reset a signal -extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); ///< Zero reset a signal (slow - else use VL_ZERO_W) +/// Zero reset a signal (slow - else use VL_ZERO_W) +extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); #if VL_THREADED /// Return high-precision counter for profiling, or 0x0 if not available -inline QData VL_RDTSC_Q() { vluint64_t val; VL_RDTSC(val); return val; } +inline QData VL_RDTSC_Q() { + vluint64_t val; + VL_RDTSC(val); + return val; +} #endif /// Math -extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, - WDataInP lwp, WDataInP rwp, bool is_modulus); +extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, + bool is_modulus); /// File I/O extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi); @@ -636,12 +661,13 @@ extern IData VL_FOPEN_S(const char* filenamep, const char* modep); extern IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode); extern IData VL_FOPEN_QI(QData filename, IData mode); inline IData VL_FOPEN_II(IData filename, IData mode) VL_MT_SAFE { - return VL_FOPEN_QI(filename, mode); } + return VL_FOPEN_QI(filename, mode); +} extern void VL_FCLOSE_I(IData fdi); -extern IData VL_FREAD_I(int width, int array_lsb, int array_size, - void* memp, IData fpi, IData start, IData count); +extern IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi, + IData start, IData count); extern void VL_WRITEF(const char* formatp, ...); extern void VL_FWRITEF(IData fpi, const char* formatp, ...); @@ -668,41 +694,64 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish // Base macros /// Return true if data[bit] set; not 0/1 return, but 0/non-zero return. -#define VL_BITISSET_I(data,bit) ((data) & (VL_UL(1) << VL_BITBIT_I(bit))) -#define VL_BITISSET_Q(data,bit) ((data) & (VL_ULL(1) << VL_BITBIT_Q(bit))) -#define VL_BITISSET_E(data,bit) ((data) & (VL_EUL(1) << VL_BITBIT_E(bit))) -#define VL_BITISSET_W(data,bit) ((data)[VL_BITWORD_E(bit)] & (VL_EUL(1) << VL_BITBIT_E(bit))) -#define VL_BITISSETLIMIT_W(data,width,bit) (((bit) < (width)) && VL_BITISSET_W(data,bit)) +#define VL_BITISSET_I(data, bit) ((data) & (VL_UL(1) << VL_BITBIT_I(bit))) +#define VL_BITISSET_Q(data, bit) ((data) & (VL_ULL(1) << VL_BITBIT_Q(bit))) +#define VL_BITISSET_E(data, bit) ((data) & (VL_EUL(1) << VL_BITBIT_E(bit))) +#define VL_BITISSET_W(data, bit) ((data)[VL_BITWORD_E(bit)] & (VL_EUL(1) << VL_BITBIT_E(bit))) +#define VL_BITISSETLIMIT_W(data, width, bit) (((bit) < (width)) && VL_BITISSET_W(data, bit)) /// Shift appropriate word by bit. Does not account for wrapping between two words -#define VL_BITRSHIFT_W(data,bit) ((data)[VL_BITWORD_E(bit)] >> VL_BITBIT_E(bit)) +#define VL_BITRSHIFT_W(data, bit) ((data)[VL_BITWORD_E(bit)] >> VL_BITBIT_E(bit)) /// Create two 32-bit words from quadword /// WData is always at least 2 words; does not clean upper bits -#define VL_SET_WQ(owp,data) { (owp)[0] = static_cast(data); \ - (owp)[1] = static_cast((data) >> VL_EDATASIZE); } -#define VL_SET_WI(owp,data) { (owp)[0] = static_cast(data); (owp)[1] = 0; } +#define VL_SET_WQ(owp, data) \ + { \ + (owp)[0] = static_cast(data); \ + (owp)[1] = static_cast((data) >> VL_EDATASIZE); \ + } +#define VL_SET_WI(owp, data) \ + { \ + (owp)[0] = static_cast(data); \ + (owp)[1] = 0; \ + } #define VL_SET_QW(lwp) \ - ( (static_cast((lwp)[0])) \ - | (static_cast((lwp)[1]) << (static_cast(VL_EDATASIZE)) )) -#define _VL_SET_QII(ld,rd) ((static_cast(ld)<(rd)) + ((static_cast((lwp)[0])) \ + | (static_cast((lwp)[1]) << (static_cast(VL_EDATASIZE)))) +#define _VL_SET_QII(ld, rd) ((static_cast(ld) << VL_ULL(32)) | static_cast(rd)) /// Return FILE* from IData -extern FILE* VL_CVT_I_FP(IData lhs); +extern FILE* VL_CVT_I_FP(IData lhs); +// clang-format off // Use a union to avoid cast-to-different-size warnings /// Return void* from QData -static inline void* VL_CVT_Q_VP(QData lhs) VL_PURE { - 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) VL_PURE { - 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) VL_PURE { - union { double d; QData q; } u; u.q=lhs; return u.d; } + 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) VL_PURE { - 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; +} +// clang-format on + /// Return double from QData (numeric) static inline double VL_ITOR_D_I(IData lhs) VL_PURE { return static_cast(static_cast(lhs)); @@ -714,19 +763,21 @@ static inline IData VL_RTOI_I_D(double lhs) VL_PURE { // Sign extend such that if MSB set, we get ffff_ffff, else 0s // (Requires clean input) -#define VL_SIGN_I(nbits,lhs) ((lhs) >> VL_BITBIT_I((nbits) - VL_UL(1))) -#define VL_SIGN_Q(nbits,lhs) ((lhs) >> VL_BITBIT_Q((nbits) - VL_ULL(1))) -#define VL_SIGN_E(nbits,lhs) ((lhs) >> VL_BITBIT_E((nbits) - VL_EUL(1))) -#define VL_SIGN_W(nbits,rwp) \ - ((rwp)[VL_BITWORD_E((nbits) - VL_EUL(1))] >> VL_BITBIT_E((nbits) - VL_EUL(1))) +#define VL_SIGN_I(nbits, lhs) ((lhs) >> VL_BITBIT_I((nbits)-VL_UL(1))) +#define VL_SIGN_Q(nbits, lhs) ((lhs) >> VL_BITBIT_Q((nbits)-VL_ULL(1))) +#define VL_SIGN_E(nbits, lhs) ((lhs) >> VL_BITBIT_E((nbits)-VL_EUL(1))) +#define VL_SIGN_W(nbits, rwp) \ + ((rwp)[VL_BITWORD_E((nbits)-VL_EUL(1))] >> VL_BITBIT_E((nbits)-VL_EUL(1))) #define VL_SIGNONES_E(nbits, lhs) (-(VL_SIGN_E(nbits, lhs))) // Sign bit extended up to MSB, doesn't include unsigned portion // Optimization bug in GCC 3.3 returns different bitmasks to later states for static inline IData VL_EXTENDSIGN_I(int lbits, IData lhs) VL_PURE { - return (-((lhs)&(VL_UL(1)<<(lbits-1)))); } + return (-((lhs) & (VL_UL(1) << (lbits - 1)))); +} static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) VL_PURE { - return (-((lhs)&(VL_ULL(1)<<(lbits-1)))); } + return (-((lhs) & (VL_ULL(1) << (lbits - 1)))); +} // Debugging prints extern void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp); @@ -736,6 +787,7 @@ extern void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp); extern int VL_TIME_STR_CONVERT(const char* strp) VL_PURE; +// clang-format off #ifndef VL_TIME_PRECISION # ifdef VL_TIME_PRECISION_STR # define VL_TIME_PRECISION VL_TIME_STR_CONVERT(VL_STRINGIFY(VL_TIME_PRECISION_STR)) @@ -777,7 +829,7 @@ extern double sc_time_stamp(); #ifndef SP_AUTO_COVER3 # define SP_AUTO_COVER3(what,file,line) #endif - +// clang-format on //========================================================================= // Functional macros/routines @@ -793,31 +845,31 @@ extern double sc_time_stamp(); // Output clean // EMIT_RULE: VL_CLEAN: oclean=clean; obits=lbits; -#define VL_CLEAN_II(obits,lbits,lhs) ((lhs) & VL_MASK_I(obits)) -#define VL_CLEAN_QQ(obits,lbits,lhs) ((lhs) & VL_MASK_Q(obits)) +#define VL_CLEAN_II(obits, lbits, lhs) ((lhs)&VL_MASK_I(obits)) +#define VL_CLEAN_QQ(obits, lbits, lhs) ((lhs)&VL_MASK_Q(obits)) // EMIT_RULE: VL_ASSIGNCLEAN: oclean=clean; obits==lbits; -#define VL_ASSIGNCLEAN_W(obits,owp,lwp) VL_CLEAN_WW((obits), (obits), (owp), (lwp)) +#define VL_ASSIGNCLEAN_W(obits, owp, lwp) VL_CLEAN_WW((obits), (obits), (owp), (lwp)) static inline WDataOutP _VL_CLEAN_INPLACE_W(int obits, WDataOutP owp) VL_MT_SAFE { int words = VL_WORDS_I(obits); - owp[words-1] &= VL_MASK_E(obits); + owp[words - 1] &= VL_MASK_E(obits); return owp; } static inline WDataOutP VL_CLEAN_WW(int obits, int, WDataOutP 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_E(obits); + for (int i = 0; (i < (words - 1)); ++i) owp[i] = lwp[i]; + owp[words - 1] = lwp[words - 1] & VL_MASK_E(obits); return owp; } static inline WDataOutP VL_ZERO_W(int obits, WDataOutP owp) VL_MT_SAFE { int words = VL_WORDS_I(obits); - for (int i=0; i < words; ++i) owp[i] = 0; + for (int i = 0; i < words; ++i) owp[i] = 0; return owp; } static inline WDataOutP VL_ALLONES_W(int obits, WDataOutP owp) VL_MT_SAFE { int words = VL_WORDS_I(obits); for (int i = 0; i < (words - 1); ++i) owp[i] = ~VL_EUL(0); - owp[words-1] = VL_MASK_E(obits); + owp[words - 1] = VL_MASK_E(obits); return owp; } @@ -826,25 +878,22 @@ static inline WDataOutP VL_ALLONES_W(int obits, WDataOutP owp) VL_MT_SAFE { // Note: If a ASSIGN isn't clean, use VL_ASSIGNCLEAN instead to do the same thing. static inline WDataOutP VL_ASSIGN_W(int obits, WDataOutP owp, WDataInP lwp) VL_MT_SAFE { int words = VL_WORDS_I(obits); - for (int i=0; i < words; ++i) owp[i] = lwp[i]; + for (int i = 0; i < words; ++i) owp[i] = lwp[i]; return owp; } // EMIT_RULE: VL_ASSIGNBIT: rclean=clean; static inline void VL_ASSIGNBIT_II(int, int bit, CData& lhsr, IData rhs) VL_PURE { - lhsr = ((lhsr & ~(VL_UL(1)<(rhs) << VL_BITBIT_Q(bit))); } static inline void VL_ASSIGNBIT_WI(int, int bit, WDataOutP owp, IData rhs) VL_MT_SAFE { @@ -875,71 +924,87 @@ static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) VL_MT_SAF // Copying verilog format to systemc integers and bit vectors. // Get a SystemC variable -#define VL_ASSIGN_ISI(obits,vvar,svar) { (vvar) = VL_CLEAN_II((obits), (obits), (svar).read()); } -#define VL_ASSIGN_QSQ(obits,vvar,svar) { (vvar) = VL_CLEAN_QQ((obits), (obits), (svar).read()); } +#define VL_ASSIGN_ISI(obits, vvar, svar) \ + { (vvar) = VL_CLEAN_II((obits), (obits), (svar).read()); } +#define VL_ASSIGN_QSQ(obits, vvar, svar) \ + { (vvar) = VL_CLEAN_QQ((obits), (obits), (svar).read()); } -#define VL_ASSIGN_ISW(obits,od,svar) { \ - (od) = ((svar).read().get_word(0)) & VL_MASK_I(obits); \ +#define VL_ASSIGN_ISW(obits, od, svar) \ + { (od) = ((svar).read().get_word(0)) & VL_MASK_I(obits); } +#define VL_ASSIGN_QSW(obits, od, svar) \ + { \ + (od) = ((static_cast((svar).read().get_word(1))) << VL_IDATASIZE \ + | (svar).read().get_word(0)) \ + & VL_MASK_Q(obits); \ } -#define VL_ASSIGN_QSW(obits,od,svar) { \ - (od) = ((static_cast((svar).read().get_word(1)))< _butemp = (svar).read(); \ - for (int i=0; i < words; ++i) { \ - int msb = ((i + 1) * VL_IDATASIZE) - 1; \ - msb = (msb >= (obits)) ? ((obits)-1) : msb; \ - (owp)[i] = _butemp.range(msb, i * VL_IDATASIZE).to_uint(); \ - } \ - (owp)[words-1] &= VL_MASK_E(obits); \ +#define VL_ASSIGN_ISU(obits, vvar, svar) \ + { (vvar) = VL_CLEAN_II((obits), (obits), (svar).read().to_uint()); } +#define VL_ASSIGN_QSU(obits, vvar, svar) \ + { (vvar) = VL_CLEAN_QQ((obits), (obits), (svar).read().to_uint64()); } +#define VL_ASSIGN_WSB(obits, owp, svar) \ + { \ + int words = VL_WORDS_I(obits); \ + sc_biguint<(obits)> _butemp = (svar).read(); \ + for (int i = 0; i < words; ++i) { \ + int msb = ((i + 1) * VL_IDATASIZE) - 1; \ + msb = (msb >= (obits)) ? ((obits)-1) : msb; \ + (owp)[i] = _butemp.range(msb, i * VL_IDATASIZE).to_uint(); \ + } \ + (owp)[words - 1] &= VL_MASK_E(obits); \ } // Copying verilog format from systemc integers and bit vectors. // Set a SystemC variable -#define VL_ASSIGN_SII(obits,svar,vvar) { (svar).write(vvar); } -#define VL_ASSIGN_SQQ(obits,svar,vvar) { (svar).write(vvar); } +#define VL_ASSIGN_SII(obits, svar, vvar) \ + { (svar).write(vvar); } +#define VL_ASSIGN_SQQ(obits, svar, vvar) \ + { (svar).write(vvar); } -#define VL_ASSIGN_SWI(obits,svar,rd) { \ - sc_bv<(obits)> _bvtemp; \ - _bvtemp.set_word(0, (rd)); \ - (svar).write(_bvtemp); \ +#define VL_ASSIGN_SWI(obits, svar, rd) \ + { \ + sc_bv<(obits)> _bvtemp; \ + _bvtemp.set_word(0, (rd)); \ + (svar).write(_bvtemp); \ } -#define VL_ASSIGN_SWQ(obits,svar,rd) { \ - sc_bv<(obits)> _bvtemp; \ - _bvtemp.set_word(0, static_cast(rd)); \ - _bvtemp.set_word(1, static_cast((rd) >> VL_IDATASIZE)); \ - (svar).write(_bvtemp); \ +#define VL_ASSIGN_SWQ(obits, svar, rd) \ + { \ + sc_bv<(obits)> _bvtemp; \ + _bvtemp.set_word(0, static_cast(rd)); \ + _bvtemp.set_word(1, static_cast((rd) >> VL_IDATASIZE)); \ + (svar).write(_bvtemp); \ } -#define VL_ASSIGN_SWW(obits,svar,rwp) { \ - sc_bv<(obits)> _bvtemp; \ - for (int i=0; i < VL_WORDS_I(obits); ++i) _bvtemp.set_word(i, (rwp)[i]); \ - (svar).write(_bvtemp); \ +#define VL_ASSIGN_SWW(obits, svar, rwp) \ + { \ + sc_bv<(obits)> _bvtemp; \ + for (int i = 0; i < VL_WORDS_I(obits); ++i) _bvtemp.set_word(i, (rwp)[i]); \ + (svar).write(_bvtemp); \ } -#define VL_ASSIGN_SUI(obits,svar,rd) { (svar).write(rd); } -#define VL_ASSIGN_SUQ(obits,svar,rd) { (svar).write(rd); } -#define VL_ASSIGN_SBI(obits,svar,rd) { (svar).write(rd); } -#define VL_ASSIGN_SBQ(obits,svar,rd) { (svar).write(rd); } -#define VL_ASSIGN_SBW(obits,svar,rwp) { \ - sc_biguint<(obits)> _butemp; \ - for (int i=0; i < VL_WORDS_I(obits); ++i) { \ - int msb = ((i + 1) * VL_IDATASIZE) - 1; \ - msb = (msb >= (obits)) ? ((obits)-1) : msb; \ - _butemp.range(msb, i * VL_IDATASIZE) = (rwp)[i]; \ - } \ - (svar).write(_butemp); \ +#define VL_ASSIGN_SUI(obits, svar, rd) \ + { (svar).write(rd); } +#define VL_ASSIGN_SUQ(obits, svar, rd) \ + { (svar).write(rd); } +#define VL_ASSIGN_SBI(obits, svar, rd) \ + { (svar).write(rd); } +#define VL_ASSIGN_SBQ(obits, svar, rd) \ + { (svar).write(rd); } +#define VL_ASSIGN_SBW(obits, svar, rwp) \ + { \ + sc_biguint<(obits)> _butemp; \ + for (int i = 0; i < VL_WORDS_I(obits); ++i) { \ + int msb = ((i + 1) * VL_IDATASIZE) - 1; \ + msb = (msb >= (obits)) ? ((obits)-1) : msb; \ + _butemp.range(msb, i* VL_IDATASIZE) = (rwp)[i]; \ + } \ + (svar).write(_butemp); \ } //=================================================================== @@ -949,9 +1014,9 @@ static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) VL_MT_SAF // Right must be clean because otherwise size increase would pick up bad bits // EMIT_RULE: VL_EXTEND: oclean=clean; rclean==clean; -#define VL_EXTEND_II(obits,lbits,lhs) ((lhs)) -#define VL_EXTEND_QI(obits,lbits,lhs) (static_cast(lhs)) -#define VL_EXTEND_QQ(obits,lbits,lhs) ((lhs)) +#define VL_EXTEND_II(obits, lbits, lhs) ((lhs)) +#define VL_EXTEND_QI(obits, lbits, lhs) (static_cast(lhs)) +#define VL_EXTEND_QQ(obits, lbits, lhs) ((lhs)) static inline WDataOutP VL_EXTEND_WI(int obits, int, WDataOutP owp, IData ld) VL_MT_SAFE { // Note for extracts that obits != lbits @@ -964,7 +1029,8 @@ static inline WDataOutP VL_EXTEND_WQ(int obits, int, WDataOutP owp, QData ld) VL for (int i = VL_WQ_WORDS_E; 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) VL_MT_SAFE { +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; @@ -975,7 +1041,7 @@ static inline WDataOutP VL_EXTEND_WW(int obits, int lbits, WDataOutP owp, WDataI 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*/) VL_PURE { +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) VL_PURE { @@ -995,8 +1061,9 @@ static inline WDataOutP VL_EXTENDS_WQ(int obits, int lbits, WDataOutP owp, QData for (int i = VL_WQ_WORDS_E; 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) VL_MT_SAFE { - for (int i = 0; i < VL_WORDS_I(lbits)-1; ++i) owp[i] = lwp[i]; +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; EData sign = VL_SIGNONES_E(lbits, lwp[lmsw]); owp[lmsw] = lwp[lmsw] | (sign & ~VL_MASK_E(lbits)); @@ -1008,36 +1075,37 @@ static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp, WData // REDUCTION OPERATORS // 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)) +#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) VL_MT_SAFE { int words = VL_WORDS_I(lbits); EData combine = lwp[0]; for (int i = 1; i < words - 1; ++i) combine &= lwp[i]; - combine &= ~VL_MASK_E(lbits) | lwp[words-1]; - return ((~combine)==0); + combine &= ~VL_MASK_E(lbits) | lwp[words - 1]; + return ((~combine) == 0); } // EMIT_RULE: VL_REDOR: oclean=clean; lclean==clean; obits=1; -#define VL_REDOR_I(lhs) ((lhs)!=0) -#define VL_REDOR_Q(lhs) ((lhs)!=0) +#define VL_REDOR_I(lhs) ((lhs) != 0) +#define VL_REDOR_Q(lhs) ((lhs) != 0) static inline IData VL_REDOR_W(int words, WDataInP lwp) VL_MT_SAFE { EData equal = 0; - for (int i=0; i < words; ++i) equal |= lwp[i]; + 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) VL_PURE { // Experiments show VL_REDXOR_2 is faster than __builtin_parityl - r=(r^(r>>1)); + r = (r ^ (r >> 1)); return 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 - r=(r^(r>>1)); r=(r^(r>>2)); + r = (r ^ (r >> 1)); + r = (r ^ (r >> 2)); return r; #endif } @@ -1045,7 +1113,9 @@ static inline IData VL_REDXOR_8(IData r) VL_PURE { #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) return __builtin_parityl(r); #else - r=(r^(r>>1)); r=(r^(r>>2)); r=(r^(r>>4)); + r = (r ^ (r >> 1)); + r = (r ^ (r >> 2)); + r = (r ^ (r >> 4)); return r; #endif } @@ -1053,7 +1123,10 @@ static inline IData VL_REDXOR_16(IData r) VL_PURE { #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) return __builtin_parityl(r); #else - r=(r^(r>>1)); r=(r^(r>>2)); r=(r^(r>>4)); r=(r^(r>>8)); + r = (r ^ (r >> 1)); + r = (r ^ (r >> 2)); + r = (r ^ (r >> 4)); + r = (r ^ (r >> 8)); return r; #endif } @@ -1061,7 +1134,11 @@ static inline IData VL_REDXOR_32(IData r) VL_PURE { #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) return __builtin_parityl(r); #else - r=(r^(r>>1)); r=(r^(r>>2)); r=(r^(r>>4)); r=(r^(r>>8)); r=(r^(r>>16)); + r = (r ^ (r >> 1)); + r = (r ^ (r >> 2)); + r = (r ^ (r >> 4)); + r = (r ^ (r >> 8)); + r = (r ^ (r >> 16)); return r; #endif } @@ -1069,13 +1146,18 @@ static inline IData VL_REDXOR_64(QData r) VL_PURE { #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) return __builtin_parityll(r); #else - r=(r^(r>>1)); r=(r^(r>>2)); r=(r^(r>>4)); r=(r^(r>>8)); r=(r^(r>>16)); r=(r^(r>>32)); + r = (r ^ (r >> 1)); + r = (r ^ (r >> 2)); + r = (r ^ (r >> 4)); + r = (r ^ (r >> 8)); + r = (r ^ (r >> 16)); + r = (r ^ (r >> 32)); return static_cast(r); #endif } static inline IData VL_REDXOR_W(int words, WDataInP lwp) VL_MT_SAFE { EData r = lwp[0]; - for (int i=1; i < words; ++i) r ^= lwp[i]; + for (int i = 1; i < words; ++i) r ^= lwp[i]; return VL_REDXOR_32(r); } @@ -1083,13 +1165,13 @@ static inline IData VL_REDXOR_W(int words, WDataInP lwp) VL_MT_SAFE { 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; - r = (r + (r>>6)); - r = (r + (r>>12) + (r>>24)) & 077; + r = (r + (r >> 3)) & 030707070707; + r = (r + (r >> 6)); + r = (r + (r >> 12) + (r >> 24)) & 077; return r; } static inline IData VL_COUNTONES_Q(QData lhs) VL_PURE { - return VL_COUNTONES_I(static_cast(lhs)) + VL_COUNTONES_I(static_cast(lhs>>32)); + return VL_COUNTONES_I(static_cast(lhs)) + VL_COUNTONES_I(static_cast(lhs >> 32)); } #define VL_COUNTONES_E VL_COUNTONES_I static inline IData VL_COUNTONES_W(int words, WDataInP lwp) VL_MT_SAFE { @@ -1099,36 +1181,32 @@ static inline IData VL_COUNTONES_W(int words, WDataInP lwp) VL_MT_SAFE { } static inline IData VL_ONEHOT_I(IData lhs) VL_PURE { - return (((lhs & (lhs-1))==0) & (lhs!=0)); + return (((lhs & (lhs - 1)) == 0) & (lhs != 0)); } static inline IData VL_ONEHOT_Q(QData lhs) VL_PURE { - return (((lhs & (lhs-1))==0) & (lhs!=0)); + return (((lhs & (lhs - 1)) == 0) & (lhs != 0)); } static inline IData VL_ONEHOT_W(int words, WDataInP lwp) VL_MT_SAFE { EData one = 0; - for (int i=0; (i < words); ++i) { + for (int i = 0; (i < words); ++i) { if (lwp[i]) { if (one) return 0; one = 1; - if (lwp[i] & (lwp[i]-1)) return 0; + if (lwp[i] & (lwp[i] - 1)) return 0; } } return one; } -static inline IData VL_ONEHOT0_I(IData lhs) VL_PURE { - return ((lhs & (lhs-1))==0); -} -static inline IData VL_ONEHOT0_Q(QData lhs) VL_PURE { - return ((lhs & (lhs-1))==0); -} +static inline IData VL_ONEHOT0_I(IData lhs) VL_PURE { return ((lhs & (lhs - 1)) == 0); } +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) VL_MT_SAFE { bool one = false; - for (int i=0; (i < words); ++i) { + for (int i = 0; (i < words); ++i) { if (lwp[i]) { if (one) return 0; one = true; - if (lwp[i] & (lwp[i]-1)) return 0; + if (lwp[i] & (lwp[i] - 1)) return 0; } } return 1; @@ -1139,19 +1217,19 @@ static inline IData VL_CLOG2_I(IData lhs) VL_PURE { if (VL_UNLIKELY(!lhs)) return 0; lhs--; int shifts = 0; - for (; lhs!=0; ++shifts) lhs = lhs >> 1; + for (; lhs != 0; ++shifts) lhs = lhs >> 1; return shifts; } 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); + for (; lhs != 0; ++shifts) lhs = lhs >> VL_ULL(1); return shifts; } static inline IData VL_CLOG2_W(int words, WDataInP lwp) VL_MT_SAFE { EData adjust = (VL_COUNTONES_W(words, lwp) == 1) ? 0 : 1; - for (int i=words-1; i>=0; --i) { + for (int i = words - 1; i >= 0; --i) { if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) { if (VL_UNLIKELY(VL_BITISSET_E(lwp[i], bit))) { @@ -1166,12 +1244,10 @@ static inline IData VL_CLOG2_W(int words, WDataInP lwp) VL_MT_SAFE { 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) { + for (int i = words - 1; i >= 0; --i) { if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) { - if (VL_UNLIKELY(VL_BITISSET_E(lwp[i], bit))) { - return i * VL_EDATASIZE + bit + 1; - } + if (VL_UNLIKELY(VL_BITISSET_E(lwp[i], bit))) { return i * VL_EDATASIZE + bit + 1; } } // Can't get here - one bit must be set } @@ -1184,33 +1260,34 @@ static inline IData VL_MOSTSETBITP1_W(int words, WDataInP lwp) VL_MT_SAFE { // 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) VL_MT_SAFE { - for (int i=0; (i < words); ++i) owp[i] = (lwp[i] & rwp[i]); + 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) VL_MT_SAFE { - for (int i=0; (i < words); ++i) owp[i] = (lwp[i] | rwp[i]); + 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) VL_MT_SAFE { IData od = 0; - for (int i=0; (i < words); ++i) od |= (lwp[i] ^ rwp[i]); - return(od); + 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) VL_MT_SAFE { - for (int i=0; (i < words); ++i) owp[i] = (lwp[i] ^ rwp[i]); + 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) VL_MT_SAFE { - for (int i=0; (i < words); ++i) owp[i] = (lwp[i] ^ ~rwp[i]); +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) VL_MT_SAFE { - for (int i=0; i < words; ++i) owp[i] = ~(lwp[i]); + for (int i = 0; i < words; ++i) owp[i] = ~(lwp[i]); return owp; } @@ -1223,32 +1300,32 @@ static inline WDataOutP VL_NOT_W(int words, WDataOutP owp, WDataInP lwp) VL_MT_S // EMIT_RULE: VL_GT: oclean=clean; lclean==clean; rclean==clean; obits=1; lbits==rbits; // EMIT_RULE: VL_GTE: oclean=clean; lclean==clean; rclean==clean; obits=1; lbits==rbits; // EMIT_RULE: VL_LTE: oclean=clean; lclean==clean; rclean==clean; obits=1; lbits==rbits; -#define VL_NEQ_W(words,lwp,rwp) (!VL_EQ_W(words,lwp,rwp)) -#define VL_LT_W(words,lwp,rwp) (_VL_CMP_W(words,lwp,rwp)<0) -#define VL_LTE_W(words,lwp,rwp) (_VL_CMP_W(words,lwp,rwp)<=0) -#define VL_GT_W(words,lwp,rwp) (_VL_CMP_W(words,lwp,rwp)>0) -#define VL_GTE_W(words,lwp,rwp) (_VL_CMP_W(words,lwp,rwp)>=0) +#define VL_NEQ_W(words, lwp, rwp) (!VL_EQ_W(words, lwp, rwp)) +#define VL_LT_W(words, lwp, rwp) (_VL_CMP_W(words, lwp, rwp) < 0) +#define VL_LTE_W(words, lwp, rwp) (_VL_CMP_W(words, lwp, rwp) <= 0) +#define VL_GT_W(words, lwp, rwp) (_VL_CMP_W(words, lwp, rwp) > 0) +#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) VL_MT_SAFE { EData nequal = 0; - for (int i=0; (i < words); ++i) nequal |= (lwp[i] ^ rwp[i]); - return (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) VL_MT_SAFE { - for (int i=words-1; i>=0; --i) { + for (int i = words - 1; i >= 0; --i) { if (lwp[i] > rwp[i]) return 1; if (lwp[i] < rwp[i]) return -1; } - return(0); // == + return 0; // == } -#define VL_LTS_IWW(obits,lbits,rbbits,lwp,rwp) (_VL_CMPS_W(lbits,lwp,rwp)<0) -#define VL_LTES_IWW(obits,lbits,rbits,lwp,rwp) (_VL_CMPS_W(lbits,lwp,rwp)<=0) -#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) +#define VL_LTS_IWW(obits, lbits, rbbits, lwp, rwp) (_VL_CMPS_W(lbits, lwp, rwp) < 0) +#define VL_LTES_IWW(obits, lbits, rbits, lwp, rwp) (_VL_CMPS_W(lbits, lwp, rwp) <= 0) +#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) VL_PURE { // For lbits==32, this becomes just a single instruction, otherwise ~5. @@ -1298,17 +1375,17 @@ static inline IData VL_LTES_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PU 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; + int i = words - 1; // We need to flip sense if negative comparison EData lsign = VL_SIGN_E(lbits, lwp[i]); EData rsign = VL_SIGN_E(lbits, rwp[i]); - if (!lsign && rsign) return 1; // + > - + if (!lsign && rsign) return 1; // + > - if (lsign && !rsign) return -1; // - < + - for (; i>=0; --i) { + for (; i >= 0; --i) { if (lwp[i] > rwp[i]) return 1; if (lwp[i] < rwp[i]) return -1; } - return(0); // == + return 0; // == } //========================================================================= @@ -1341,12 +1418,12 @@ static void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE { // EMIT_RULE: VL_MUL: oclean=dirty; lclean==clean; rclean==clean; // EMIT_RULE: VL_DIV: oclean=dirty; lclean==clean; rclean==clean; // EMIT_RULE: VL_MODDIV: oclean=dirty; lclean==clean; rclean==clean; -#define VL_DIV_III(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)/(rhs)) -#define VL_DIV_QQQ(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)/(rhs)) -#define VL_DIV_WWW(lbits,owp,lwp,rwp) (_vl_moddiv_w(lbits,owp,lwp,rwp,0)) -#define VL_MODDIV_III(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)%(rhs)) -#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)) +#define VL_DIV_III(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) / (rhs)) +#define VL_DIV_QQQ(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) / (rhs)) +#define VL_DIV_WWW(lbits, owp, lwp, rwp) (_vl_moddiv_w(lbits, owp, lwp, rwp, 0)) +#define VL_MODDIV_III(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) % (rhs)) +#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) VL_MT_SAFE { QData carry = 0; @@ -1373,11 +1450,11 @@ static inline WDataOutP VL_SUB_W(int words, WDataOutP owp, WDataInP lwp, WDataIn } static inline WDataOutP VL_MUL_W(int words, WDataOutP owp, WDataInP lwp, WDataInP rwp) VL_MT_SAFE { - for (int i=0; i(lwp[lword]) * static_cast(rwp[rword]); - for (int qword=lword+rword; qword(owp[qword]); owp[qword] = (mul & VL_ULL(0xffffffff)); mul = (mul >> VL_ULL(32)) & VL_ULL(0xffffffff); @@ -1399,8 +1476,8 @@ static inline QData VL_MULS_QQQ(int, int lbits, int, QData lhs, QData rhs) VL_PU return lhs_signed * rhs_signed; } -static inline WDataOutP VL_MULS_WWW(int, int lbits, int, - WDataOutP owp, WDataInP lwp, WDataInP rwp) VL_MT_SAFE { +static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP lwp, + WDataInP rwp) VL_MT_SAFE { int words = VL_WORDS_I(lbits); // cppcheck-suppress variableScope WData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here @@ -1539,51 +1616,60 @@ WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDa WDataOutP VL_POW_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, QData rhs); QData VL_POW_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp); -#define VL_POWSS_IIQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) \ - VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) -#define VL_POWSS_IIQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) \ - VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) -#define VL_POWSS_IIW(obits,lbits,rbits,lhs,rwp,lsign,rsign) \ - VL_POWSS_QQW(obits,lbits,rbits,lhs,rwp,lsign,rsign) -#define VL_POWSS_QQI(obits,lbits,rbits,lhs,rhs,lsign,rsign) \ - VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) -#define VL_POWSS_WWI(obits,lbits,rbits,owp,lwp,rhs,lsign,rsign) \ - VL_POWSS_WWQ(obits,lbits,rbits,owp,lwp,rhs,lsign,rsign) +#define VL_POWSS_IIQ(obits, lbits, rbits, lhs, rhs, lsign, rsign) \ + VL_POWSS_QQQ(obits, lbits, rbits, lhs, rhs, lsign, rsign) +#define VL_POWSS_IIQ(obits, lbits, rbits, lhs, rhs, lsign, rsign) \ + VL_POWSS_QQQ(obits, lbits, rbits, lhs, rhs, lsign, rsign) +#define VL_POWSS_IIW(obits, lbits, rbits, lhs, rwp, lsign, rsign) \ + VL_POWSS_QQW(obits, lbits, rbits, lhs, rwp, lsign, rsign) +#define VL_POWSS_QQI(obits, lbits, rbits, lhs, rhs, lsign, rsign) \ + VL_POWSS_QQQ(obits, lbits, rbits, lhs, rhs, lsign, rsign) +#define VL_POWSS_WWI(obits, lbits, rbits, owp, lwp, rhs, lsign, rsign) \ + VL_POWSS_WWQ(obits, lbits, rbits, owp, lwp, rhs, lsign, rsign) -static inline IData VL_POWSS_III(int obits, int, int rbits, - IData lhs, IData rhs, bool lsign, bool rsign) VL_MT_SAFE { +static inline IData VL_POWSS_III(int obits, int, int rbits, IData lhs, IData rhs, bool lsign, + bool rsign) VL_MT_SAFE { if (VL_UNLIKELY(rhs == 0)) return 1; if (rsign && VL_SIGN_I(rbits, rhs)) { - if (lhs == 0) return 0; // "X" - else if (lhs == 1) return 1; - else if (lsign && lhs == VL_MASK_I(obits)) { // -1 - if (rhs & 1) return VL_MASK_I(obits); // -1^odd=-1 - else return 1; // -1^even=1 + if (lhs == 0) { + return 0; // "X" + } else if (lhs == 1) { + return 1; + } else if (lsign && lhs == VL_MASK_I(obits)) { // -1 + if (rhs & 1) { + return VL_MASK_I(obits); // -1^odd=-1 + } else { + return 1; // -1^even=1 + } } return 0; } return VL_POW_III(obits, rbits, rbits, lhs, rhs); } -static inline QData VL_POWSS_QQQ(int obits, int, int rbits, - QData lhs, QData rhs, bool lsign, bool rsign) VL_MT_SAFE { +static inline QData VL_POWSS_QQQ(int obits, int, int rbits, QData lhs, QData rhs, bool lsign, + bool rsign) VL_MT_SAFE { if (VL_UNLIKELY(rhs == 0)) return 1; if (rsign && VL_SIGN_Q(rbits, rhs)) { - if (lhs == 0) return 0; // "X" - else if (lhs == 1) return 1; - else if (lsign && lhs == VL_MASK_Q(obits)) { // -1 - if (rhs & 1) return VL_MASK_Q(obits); // -1^odd=-1 - else return 1; // -1^even=1 + if (lhs == 0) { + return 0; // "X" + } else if (lhs == 1) { + return 1; + } else if (lsign && lhs == VL_MASK_Q(obits)) { // -1 + if (rhs & 1) { + return VL_MASK_Q(obits); // -1^odd=-1 + } else { + return 1; // -1^even=1 + } } return 0; } return VL_POW_QQQ(obits, rbits, rbits, lhs, rhs); } -WDataOutP VL_POWSS_WWW(int obits, int, int rbits, - WDataOutP owp, WDataInP lwp, WDataInP rwp, bool lsign, bool rsign); -WDataOutP VL_POWSS_WWQ(int obits, int, int rbits, - WDataOutP owp, WDataInP lwp, QData rhs, bool lsign, bool rsign); -QData VL_POWSS_QQW(int obits, int, int rbits, - QData lhs, 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); +WDataOutP VL_POWSS_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, QData rhs, + bool lsign, bool rsign); +QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsign, bool rsign); //=================================================================== // Concat/replication @@ -1638,29 +1724,23 @@ static inline void _VL_INSERT_WW(int, WDataOutP owp, WDataInP lwp, int hbit, int int words = VL_WORDS_I(hbit - lbit + 1); if (hoffset == VL_SIZEBITS_E && loffset == 0) { // Fast and common case, word based insertion - for (int i=0; i> nbitsonright; EData od = (d & ~linsmask) | (owp[oword] & linsmask); @@ -1685,19 +1765,21 @@ static inline void _VL_INSERT_WW(int, WDataOutP owp, WDataInP lwp, int hbit, int } } -static inline void _VL_INSERT_WQ(int obits, WDataOutP owp, QData ld, int hbit, int lbit) VL_MT_SAFE { - WData lwp[VL_WQ_WORDS_E]; VL_SET_WQ(lwp, ld); +static inline void _VL_INSERT_WQ(int obits, WDataOutP owp, QData ld, int hbit, + int lbit) VL_MT_SAFE { + WData lwp[VL_WQ_WORDS_E]; + VL_SET_WQ(lwp, ld); _VL_INSERT_WW(obits, owp, lwp, hbit, lbit); } // EMIT_RULE: VL_REPLICATE: oclean=clean>width32, dirty<=width32; lclean=clean; rclean==clean; // RHS MUST BE CLEAN CONSTANT. -#define VL_REPLICATE_IOI(obits,lbits,rbits, ld, rep) (-(ld)) // Iff lbits==1 -#define VL_REPLICATE_QOI(obits,lbits,rbits, ld, rep) (-(static_cast(ld))) // Iff lbits==1 +#define VL_REPLICATE_IOI(obits, lbits, rbits, ld, rep) (-(ld)) // Iff lbits==1 +#define VL_REPLICATE_QOI(obits, lbits, rbits, ld, rep) (-(static_cast(ld))) // Iff lbits==1 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){ + for (unsigned i = 1; i < rep; ++i) { returndata = returndata << lbits; returndata |= ld; } @@ -1705,33 +1787,33 @@ static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) V } 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){ + for (unsigned i = 1; i < rep; ++i) { returndata = returndata << lbits; returndata |= static_cast(ld); } return returndata; } -static inline WDataOutP VL_REPLICATE_WII(int obits, int lbits, int, - WDataOutP owp, IData ld, IData rep) VL_MT_SAFE { +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); + 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) VL_MT_SAFE { +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); + 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) 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); +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); } return owp; } @@ -1768,20 +1850,11 @@ static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_ ret = (ret & ~msbMask) | ((ret & msbMask) << ((VL_UL(1) << rd_log2) - lbitsRem)); } switch (rd_log2) { - case 0: - ret = ((ret >> 1) & VL_UL(0x55555555)) - | ((ret & VL_UL(0x55555555)) << 1); // FALLTHRU - case 1: - ret = ((ret >> 2) & VL_UL(0x33333333)) - | ((ret & VL_UL(0x33333333)) << 2); // FALLTHRU - case 2: - ret = ((ret >> 4) & VL_UL(0x0f0f0f0f)) - | ((ret & VL_UL(0x0f0f0f0f)) << 4); // FALLTHRU - case 3: - ret = ((ret >> 8) & VL_UL(0x00ff00ff)) - | ((ret & VL_UL(0x00ff00ff)) << 8); // FALLTHRU - case 4: - ret = ((ret >> 16) | (ret << 16)); + case 0: ret = ((ret >> 1) & VL_UL(0x55555555)) | ((ret & VL_UL(0x55555555)) << 1); // FALLTHRU + case 1: ret = ((ret >> 2) & VL_UL(0x33333333)) | ((ret & VL_UL(0x33333333)) << 2); // FALLTHRU + case 2: ret = ((ret >> 4) & VL_UL(0x0f0f0f0f)) | ((ret & VL_UL(0x0f0f0f0f)) << 4); // FALLTHRU + case 3: ret = ((ret >> 8) & VL_UL(0x00ff00ff)) | ((ret & VL_UL(0x00ff00ff)) << 8); // FALLTHRU + case 4: ret = ((ret >> 16) | (ret << 16)); } return ret >> (VL_IDATASIZE - lbits); } @@ -1796,23 +1869,22 @@ static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_ ret = (ret & ~msbMask) | ((ret & msbMask) << ((VL_ULL(1) << rd_log2) - lbitsRem)); } switch (rd_log2) { - case 0: - ret = (((ret >> 1) & VL_ULL(0x5555555555555555)) - | ((ret & VL_ULL(0x5555555555555555)) << 1)); // FALLTHRU - case 1: - ret = (((ret >> 2) & VL_ULL(0x3333333333333333)) - | ((ret & VL_ULL(0x3333333333333333)) << 2)); // FALLTHRU - case 2: - ret = (((ret >> 4) & VL_ULL(0x0f0f0f0f0f0f0f0f)) - | ((ret & VL_ULL(0x0f0f0f0f0f0f0f0f)) << 4)); // FALLTHRU - case 3: - ret = (((ret >> 8) & VL_ULL(0x00ff00ff00ff00ff)) - | ((ret & VL_ULL(0x00ff00ff00ff00ff)) << 8)); // FALLTHRU - case 4: - ret = (((ret >> 16) & VL_ULL(0x0000ffff0000ffff)) - | ((ret & VL_ULL(0x0000ffff0000ffff)) << 16)); // FALLTHRU - case 5: - ret = ((ret >> 32) | (ret << 32)); + case 0: + ret = (((ret >> 1) & VL_ULL(0x5555555555555555)) + | ((ret & VL_ULL(0x5555555555555555)) << 1)); // FALLTHRU + case 1: + ret = (((ret >> 2) & VL_ULL(0x3333333333333333)) + | ((ret & VL_ULL(0x3333333333333333)) << 2)); // FALLTHRU + case 2: + ret = (((ret >> 4) & VL_ULL(0x0f0f0f0f0f0f0f0f)) + | ((ret & VL_ULL(0x0f0f0f0f0f0f0f0f)) << 4)); // FALLTHRU + case 3: + ret = (((ret >> 8) & VL_ULL(0x00ff00ff00ff00ff)) + | ((ret & VL_ULL(0x00ff00ff00ff00ff)) << 8)); // FALLTHRU + case 4: + ret = (((ret >> 16) & VL_ULL(0x0000ffff0000ffff)) + | ((ret & VL_ULL(0x0000ffff0000ffff)) << 16)); // FALLTHRU + case 5: ret = ((ret >> 32) | (ret << 32)); } return ret >> (VL_QUADSIZE - lbits); } @@ -1834,23 +1906,23 @@ static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) VL_P QData ret = 0; // Slice size should never exceed the lhs width QData mask = VL_MASK_Q(rd); - for (int istart=0; istart 0 ? ostart : 0; ret |= ((ld >> istart) & mask) << ostart; } return ret; } -static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, - WDataOutP owp, WDataInP lwp, IData rd) VL_MT_SAFE { +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)); - for (int istart=0; istart 0 ? ostart : 0; - for (int sbit=0; sbit(ld)<<(rbits) | static_cast(rd)) -#define VL_CONCAT_QII(obits,lbits,rbits,ld,rd) \ - (static_cast(ld)<<(rbits) | static_cast(rd)) -#define VL_CONCAT_QIQ(obits,lbits,rbits,ld,rd) \ - (static_cast(ld)<<(rbits) | static_cast(rd)) -#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)) +#define VL_CONCAT_III(obits, lbits, rbits, ld, rd) \ + (static_cast(ld) << (rbits) | static_cast(rd)) +#define VL_CONCAT_QII(obits, lbits, rbits, ld, rd) \ + (static_cast(ld) << (rbits) | static_cast(rd)) +#define VL_CONCAT_QIQ(obits, lbits, rbits, ld, rd) \ + (static_cast(ld) << (rbits) | static_cast(rd)) +#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) VL_MT_SAFE { +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); + 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) VL_MT_SAFE { +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); + 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) 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); +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) VL_MT_SAFE { +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 = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0; - _VL_INSERT_WI(obits, owp, ld, rbits+lbits-1, rbits); + _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) VL_MT_SAFE { +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); + 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) VL_MT_SAFE { +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 = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0; - _VL_INSERT_WQ(obits, owp, ld, rbits+lbits-1, rbits); + _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) VL_MT_SAFE { +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 = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0; - _VL_INSERT_WW(obits, owp, lwp, rbits+lbits-1, rbits); + _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) 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); +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) 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); +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); return owp; } @@ -1944,37 +2016,39 @@ static inline WDataOutP VL_CONCAT_WWW(int obits, int lbits, int rbits, // 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*/) VL_MT_SAFE { +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); EData linsmask = VL_MASK_E(rd); - for (int i=words-1; i>=1; --i) { - iowp[i] = ((iowp[i]<> (VL_EDATASIZE - rd)) & linsmask); + for (int i = words - 1; i >= 1; --i) { + iowp[i] + = ((iowp[i] << rd) & ~linsmask) | ((iowp[i - 1] >> (VL_EDATASIZE - rd)) & linsmask); } - iowp[0] = ((iowp[0]<= static_cast(obits)) { // rd may be huge with MSB set - for (int i=0; i < VL_WORDS_I(obits); ++i) owp[i] = 0; - } else if (bit_shift==0) { // Aligned word shift (<<0,<<32,<<64 etc) - for (int i=0; i < word_shift; ++i) owp[i] = 0; - for (int i=word_shift; i < VL_WORDS_I(obits); ++i) owp[i] = lwp[i-word_shift]; + for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0; + } else if (bit_shift == 0) { // Aligned word shift (<<0,<<32,<<64 etc) + for (int i = 0; i < word_shift; ++i) owp[i] = 0; + for (int i = word_shift; i < VL_WORDS_I(obits); ++i) owp[i] = lwp[i - word_shift]; } else { - for (int i=0; i < VL_WORDS_I(obits); ++i) owp[i] = 0; - _VL_INSERT_WW(obits, owp, lwp, obits-1, rd); + for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0; + _VL_INSERT_WW(obits, owp, lwp, obits - 1, rd); } return owp; } -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) { +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); } @@ -1982,64 +2056,63 @@ static inline WDataOutP VL_SHIFTL_WWW(int obits, int lbits, int rbits, 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) VL_MT_SAFE { - for (int i=1; i < VL_WORDS_I(rbits); ++i) { + for (int i = 1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more return 0; } } - return VL_CLEAN_II(obits, obits, lhs<>32 or more return 0; } } // Above checks rwp[1]==0 so not needed in below shift - return VL_CLEAN_QQ(obits, obits, lhs<<(static_cast(rwp[0]))); + return VL_CLEAN_QQ(obits, obits, lhs << (static_cast(rwp[0]))); } // 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) VL_MT_SAFE { +static inline WDataOutP VL_SHIFTR_WWI(int obits, int, int, WDataOutP owp, WDataInP lwp, + IData rd) VL_MT_SAFE { int word_shift = VL_BITWORD_E(rd); // Maybe 0 int bit_shift = VL_BITBIT_E(rd); if (rd >= static_cast(obits)) { // rd may be huge with MSB set - for (int i=0; i < VL_WORDS_I(obits); ++i) owp[i] = 0; - } else if (bit_shift==0) { // Aligned word shift (>>0,>>32,>>64 etc) - int copy_words = (VL_WORDS_I(obits)-word_shift); - for (int i=0; i < copy_words; ++i) owp[i] = lwp[i+word_shift]; - for (int i=copy_words; i < VL_WORDS_I(obits); ++i) owp[i] = 0; + for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0; + } else if (bit_shift == 0) { // Aligned word shift (>>0,>>32,>>64 etc) + int copy_words = (VL_WORDS_I(obits) - word_shift); + for (int i = 0; i < copy_words; ++i) owp[i] = lwp[i + word_shift]; + for (int i = copy_words; i < VL_WORDS_I(obits); ++i) owp[i] = 0; } else { int loffset = rd & VL_SIZEBITS_E; int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword (know loffset!=0) // Middle words - int words = VL_WORDS_I(obits-rd); - for (int i=0; i>loffset; - int upperword = i+word_shift+1; - if (upperword < VL_WORDS_I(obits)) { - owp[i] |= lwp[upperword]<< nbitsonright; - } + int words = VL_WORDS_I(obits - rd); + for (int i = 0; i < words; ++i) { + owp[i] = lwp[i + word_shift] >> loffset; + int upperword = i + word_shift + 1; + if (upperword < VL_WORDS_I(obits)) owp[i] |= lwp[upperword] << nbitsonright; } - for (int i=words; i>32 or more return VL_ZERO_W(obits, owp); } } return VL_SHIFTR_WWI(obits, lbits, 32, owp, lwp, rwp[0]); } -static inline WDataOutP VL_SHIFTR_WWQ(int obits, int lbits, int rbits, - WDataOutP owp, WDataInP lwp, QData rd) VL_MT_SAFE { - WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rd); +static inline WDataOutP VL_SHIFTR_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp, + QData rd) VL_MT_SAFE { + WData rwp[VL_WQ_WORDS_E]; + VL_SET_WQ(rwp, rd); return VL_SHIFTR_WWW(obits, lbits, rbits, owp, lwp, rwp); } @@ -2067,31 +2140,30 @@ static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData r // IEEE says signed if output signed, but bit position from lbits; // must use lbits for sign; lbits might != obits, // an EXTEND(SHIFTRS(...)) can became a SHIFTRS(...) within same 32/64 bit word length - IData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative + IData sign = -(lhs >> (lbits - 1)); // ffff_ffff if negative 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) VL_PURE { - QData sign = -(lhs >> (lbits-1)); + 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) VL_PURE { +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) VL_MT_SAFE { +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_E(rd); int bit_shift = VL_BITBIT_E(rd); - int lmsw = VL_WORDS_I(obits)-1; + int lmsw = VL_WORDS_I(obits) - 1; EData sign = VL_SIGNONES_E(lbits, lwp[lmsw]); if (rd >= static_cast(obits)) { // Shifting past end, sign in all of lbits - for (int i=0; i <= lmsw; ++i) owp[i] = sign; + for (int i = 0; i <= lmsw; ++i) owp[i] = sign; owp[lmsw] &= VL_MASK_E(lbits); - } else if (bit_shift==0) { // Aligned word shift (>>0,>>32,>>64 etc) - int copy_words = (VL_WORDS_I(obits)-word_shift); - for (int i=0; i < copy_words; ++i) owp[i] = lwp[i+word_shift]; + } else if (bit_shift == 0) { // Aligned word shift (>>0,>>32,>>64 etc) + int copy_words = (VL_WORDS_I(obits) - word_shift); + for (int i = 0; i < copy_words; ++i) owp[i] = lwp[i + word_shift]; if (copy_words >= 0) owp[copy_words - 1] |= ~VL_MASK_E(obits) & sign; for (int i = copy_words; i < VL_WORDS_I(obits); ++i) owp[i] = sign; owp[lmsw] &= VL_MASK_E(lbits); @@ -2099,13 +2171,11 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits, int lbits, int, int loffset = rd & VL_SIZEBITS_E; int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword (know loffset!=0) // Middle words - int words = VL_WORDS_I(obits-rd); - for (int i=0; i>loffset; - int upperword = i+word_shift+1; - if (upperword < VL_WORDS_I(obits)) { - owp[i] |= lwp[upperword]<< nbitsonright; - } + int words = VL_WORDS_I(obits - rd); + for (int i = 0; i < words; ++i) { + owp[i] = lwp[i + word_shift] >> loffset; + int upperword = i + word_shift + 1; + if (upperword < VL_WORDS_I(obits)) owp[i] |= lwp[upperword] << nbitsonright; } if (words) owp[words - 1] |= sign & ~VL_MASK_E(obits - loffset); for (int i = words; i < VL_WORDS_I(obits); ++i) owp[i] = sign; @@ -2113,12 +2183,10 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits, int lbits, int, } return owp; } -static inline WDataOutP VL_SHIFTRS_WWW(int obits, int lbits, int rbits, - WDataOutP owp, WDataInP lwp, WDataInP rwp) VL_MT_SAFE { +static inline WDataOutP VL_SHIFTRS_WWW(int obits, int lbits, int rbits, WDataOutP owp, + WDataInP lwp, WDataInP rwp) VL_MT_SAFE { EData overshift = 0; // Huge shift 1>>32 or more - for (int i = 1; i < VL_WORDS_I(rbits); ++i) { - overshift |= rwp[i]; - } + for (int i = 1; i < VL_WORDS_I(rbits); ++i) overshift |= rwp[i]; if (VL_UNLIKELY(overshift)) { int lmsw = VL_WORDS_I(obits) - 1; EData sign = VL_SIGNONES_E(lbits, lwp[lmsw]); @@ -2128,41 +2196,40 @@ static inline WDataOutP VL_SHIFTRS_WWW(int obits, int lbits, int rbits, } return VL_SHIFTRS_WWI(obits, lbits, 32, owp, lwp, rwp[0]); } -static inline WDataOutP VL_SHIFTRS_WWQ(int obits, int lbits, int rbits, - WDataOutP owp, WDataInP lwp, QData rd) VL_MT_SAFE { - WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rd); +static inline WDataOutP VL_SHIFTRS_WWQ(int obits, int lbits, int rbits, WDataOutP owp, + WDataInP lwp, QData rd) VL_MT_SAFE { + WData rwp[VL_WQ_WORDS_E]; + VL_SET_WQ(rwp, rd); return VL_SHIFTRS_WWW(obits, lbits, rbits, owp, lwp, rwp); } -static inline IData VL_SHIFTRS_IIW(int obits, int lbits, int rbits, - IData lhs, WDataInP rwp) VL_MT_SAFE { +static inline IData VL_SHIFTRS_IIW(int obits, int lbits, int rbits, IData lhs, + WDataInP rwp) VL_MT_SAFE { EData overshift = 0; // Huge shift 1>>32 or more - for (int i = 1; i < VL_WORDS_I(rbits); ++i) { - overshift |= rwp[i]; - } + for (int i = 1; i < VL_WORDS_I(rbits); ++i) overshift |= rwp[i]; if (VL_UNLIKELY(overshift)) { - IData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative + IData sign = -(lhs >> (lbits - 1)); // ffff_ffff if negative return VL_CLEAN_II(obits, obits, sign); } 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) VL_MT_SAFE { +static inline QData VL_SHIFTRS_QQW(int obits, int lbits, int rbits, QData lhs, + WDataInP rwp) VL_MT_SAFE { EData overshift = 0; // Huge shift 1>>32 or more - for (int i = 1; i < VL_WORDS_I(rbits); ++i) { - overshift |= rwp[i]; - } + for (int i = 1; i < VL_WORDS_I(rbits); ++i) overshift |= rwp[i]; if (VL_UNLIKELY(overshift)) { - QData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative + QData sign = -(lhs >> (lbits - 1)); // ffff_ffff if negative return VL_CLEAN_QQ(obits, obits, sign); } 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) VL_PURE { - WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rhs); + WData rwp[VL_WQ_WORDS_E]; + 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) VL_PURE { - WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rhs); + WData rwp[VL_WQ_WORDS_E]; + VL_SET_WQ(rwp, rhs); return VL_SHIFTRS_QQW(obits, lbits, rbits, lhs, rwp); } @@ -2170,10 +2237,10 @@ static inline QData VL_SHIFTRS_QQQ(int obits, int lbits, int rbits, QData lhs, Q // Bit selection // EMIT_RULE: VL_BITSEL: oclean=dirty; rclean==clean; -#define VL_BITSEL_IIII(obits,lbits,rbits,zbits,lhs,rhs) ((lhs)>>(rhs)) -#define VL_BITSEL_QIII(obits,lbits,rbits,zbits,lhs,rhs) ((lhs)>>(rhs)) -#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))) +#define VL_BITSEL_IIII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs)) +#define VL_BITSEL_QIII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs)) +#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) VL_MT_SAFE { int word = VL_BITWORD_E(rd); @@ -2187,29 +2254,29 @@ static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData // EMIT_RULE: VL_RANGE: oclean=lclean; out=dirty // & MUST BE CLEAN (currently constant) -#define VL_SEL_IIII(obits,lbits,rbits,tbits,lhs,lsb,width) ((lhs)>>(lsb)) -#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))) +#define VL_SEL_IIII(obits, lbits, rbits, tbits, lhs, lsb, width) ((lhs) >> (lsb)) +#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) VL_MT_SAFE { - int msb = lsb+width-1; - if (VL_UNLIKELY(msb>lbits)) { +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. } else if (VL_BITWORD_E(msb) == VL_BITWORD_E(static_cast(lsb))) { return VL_BITRSHIFT_W(lwp, lsb); } else { // 32 bit extraction may span two words int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb); // bits that come from low word - return ((lwp[VL_BITWORD_E(msb)] << nbitsfromlow) - | VL_BITRSHIFT_W(lwp, lsb)); + return ((lwp[VL_BITWORD_E(msb)] << nbitsfromlow) | VL_BITRSHIFT_W(lwp, lsb)); } } -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)) { +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. } else if (VL_BITWORD_E(msb) == VL_BITWORD_E(static_cast(lsb))) { return VL_BITRSHIFT_W(lwp, lsb); @@ -2228,31 +2295,30 @@ static inline QData VL_SEL_QWII(int, int lbits, int, int, } } -static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int, - WDataOutP owp, WDataInP lwp, +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 msb = lsb + width - 1; int word_shift = VL_BITWORD_E(lsb); - if (VL_UNLIKELY(msb>lbits)) { // Outside bounds, - for (int i=0; i lbits)) { // Outside bounds, + for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) owp[i] = ~0; owp[VL_WORDS_I(obits) - 1] = VL_MASK_E(obits); } else if (VL_BITBIT_E(lsb) == 0) { // Just a word extract - for (int i=0; i>loffset; - int upperword = i+word_shift+1; + int words = VL_WORDS_I(msb - lsb + 1); + for (int i = 0; i < words; ++i) { + owp[i] = lwp[i + word_shift] >> loffset; + int upperword = i + word_shift + 1; if (upperword <= static_cast(VL_BITWORD_E(msb))) { owp[i] |= lwp[upperword] << nbitsfromlow; } } - for (int i=words; i= rhs width 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); + _VL_INSERT_WI(obits, owp, rhs, lsb + obits - 1, lsb); } 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); + _VL_INSERT_WQ(obits, owp, rhs, lsb + obits - 1, lsb); } 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); + _VL_INSERT_WW(obits, owp, rwp, lsb + obits - 1, lsb); } //====================================================================== // Triops -static inline WDataOutP VL_COND_WIWW(int obits, int, int, int, - WDataOutP owp, int cond, +static inline WDataOutP VL_COND_WIWW(int obits, int, int, int, 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]; + for (int i = 0; i < words; ++i) owp[i] = cond ? w1p[i] : w2p[i]; return owp; } @@ -2354,91 +2419,114 @@ static inline WDataOutP VL_COND_WIWW(int obits, int, int, int, // hence all upper words must be zeroed. // If changing the number of functions here, also change EMITCINLINES_NUM_CONSTW -#define _END(obits,wordsSet) \ - for(int i=(wordsSet);i class VerilatedCoverItemSpec : public VerilatedCovImpItem { private: // MEMBERS - T* m_countp; ///< Count value + T* m_countp; ///< Count value public: // METHODS // cppcheck-suppress truncLongCastReturn @@ -74,7 +74,10 @@ public: virtual void zero() const VL_OVERRIDE { *m_countp = 0; } // CONSTRUCTORS // cppcheck-suppress noExplicitConstructor - explicit VerilatedCoverItemSpec(T* countp) : m_countp(countp) { *m_countp = 0; } + explicit VerilatedCoverItemSpec(T* countp) + : m_countp(countp) { + *m_countp = 0; + } virtual ~VerilatedCoverItemSpec() VL_OVERRIDE {} }; @@ -87,20 +90,20 @@ public: class VerilatedCovImp : VerilatedCovImpBase { private: // TYPES - typedef std::map ValueIndexMap; - typedef std::map IndexValueMap; + typedef std::map ValueIndexMap; + typedef std::map IndexValueMap; typedef std::deque ItemList; private: // MEMBERS - VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it. - ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value - IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value - ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items + VerilatedMutex m_mutex; ///< Protects all members + ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for values + IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for keys + ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex); ///< Item about to insert - const char* m_insertFilenamep VL_GUARDED_BY(m_mutex); ///< Filename about to insert - int m_insertLineno VL_GUARDED_BY(m_mutex); ///< Line number about to insert + const char* m_insertFilenamep VL_GUARDED_BY(m_mutex); ///< Filename about to insert + int m_insertLineno VL_GUARDED_BY(m_mutex); ///< Line number about to insert // CONSTRUCTORS VerilatedCovImp() { @@ -109,6 +112,7 @@ private: m_insertLineno = 0; } VL_UNCOPYABLE(VerilatedCovImp); + public: ~VerilatedCovImp() { clearGuts(); } static VerilatedCovImp& imp() VL_MT_SAFE { @@ -119,10 +123,11 @@ public: private: // PRIVATE METHODS int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) { - static int nextIndex = KEY_UNDEF+1; + static int nextIndex = KEY_UNDEF + 1; ValueIndexMap::iterator iter = m_valueIndexes.find(value); if (iter != m_valueIndexes.end()) return iter->second; - nextIndex++; assert(nextIndex>0); + nextIndex++; + assert(nextIndex > 0); // Didn't rollover m_valueIndexes.insert(std::make_pair(value, nextIndex)); m_indexValues.insert(std::make_pair(nextIndex, value)); return nextIndex; @@ -131,8 +136,9 @@ private: // Quote any special characters std::string rtn; for (const char* pos = text.c_str(); *pos; ++pos) { - if (!isprint(*pos) || *pos=='%' || *pos=='"') { - char hex[10]; sprintf(hex, "%%%02X", pos[0]); + if (!isprint(*pos) || *pos == '%' || *pos == '"') { + char hex[10]; + sprintf(hex, "%%%02X", pos[0]); rtn += hex; } else { rtn += *pos; @@ -145,18 +151,19 @@ private: // don't want applications to either get confused if they use // a letter differently, nor want them to rely on our compression... // (Considered using numeric keys, but will remain back compatible.) - if (key.length()<2) return false; - if (key.length()==2 && isdigit(key[1])) return false; + if (key.length() < 2) return false; + if (key.length() == 2 && isdigit(key[1])) return false; return true; } - static std::string keyValueFormatter(const std::string& key, const std::string& value) VL_PURE { + 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; + if (key.length() == 1 && isalpha(key[0])) { + name += std::string("\001") + key; } else { - name += std::string("\001")+dequote(key); + name += std::string("\001") + dequote(key); } - name += std::string("\002")+dequote(value); + name += std::string("\002") + dequote(value); return name; } static std::string combineHier(const std::string& old, const std::string& add) VL_PURE { @@ -173,28 +180,35 @@ private: // Scan forward to first mismatch const char* apre = a; const char* bpre = b; - while (*apre == *bpre) { apre++; bpre++; } + while (*apre == *bpre) { + apre++; + bpre++; + } // We used to backup and split on only .'s but it seems better to be verbose // and not assume . is the separator - std::string prefix = std::string(a, apre-a); + std::string prefix = std::string(a, apre - a); // Scan backward to last mismatch - const char* apost = a+strlen(a)-1; - const char* bpost = b+strlen(b)-1; - while (*apost == *bpost - && apost>apre && bpost>bpre) { apost--; bpost--; } + const char* apost = a + strlen(a) - 1; + const char* bpost = b + strlen(b) - 1; + while (*apost == *bpost && apost > apre && bpost > bpre) { + apost--; + bpost--; + } // Forward to . so we have a whole word - std::string suffix = *bpost ? std::string(bpost+1) : ""; + std::string suffix = *bpost ? std::string(bpost + 1) : ""; - std::string out = prefix+"*"+suffix; + std::string out = prefix + "*" + suffix; - //cout << "\nch pre="<zero(); } } @@ -268,33 +288,33 @@ public: m_insertFilenamep = filenamep; m_insertLineno = lineno; } - void insertp(const char* ckeyps[MAX_KEYS], - const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) { + void insertp(const char* ckeyps[MAX_KEYS], const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) { VerilatedLockGuard lock(m_mutex); assert(m_insertp); // First two key/vals are filename - ckeyps[0]="filename"; valps[0]=m_insertFilenamep; + ckeyps[0] = "filename"; + valps[0] = m_insertFilenamep; std::string linestr = vlCovCvtToStr(m_insertLineno); - ckeyps[1]="lineno"; valps[1]=linestr.c_str(); + ckeyps[1] = "lineno"; + valps[1] = linestr.c_str(); // Default page if not specified const char* fnstartp = m_insertFilenamep; - while (const char* foundp = strchr(fnstartp,'/')) fnstartp = foundp+1; + while (const char* foundp = strchr(fnstartp, '/')) fnstartp = foundp + 1; const char* fnendp = fnstartp; - while (*fnendp && *fnendp!='.') fnendp++; - std::string page_default = "sp_user/"+std::string(fnstartp, fnendp-fnstartp); - ckeyps[2]="page"; valps[2]=page_default.c_str(); + for (; *fnendp && *fnendp != '.'; fnendp++) {} + std::string page_default = "sp_user/" + std::string(fnstartp, fnendp - fnstartp); + ckeyps[2] = "page"; + valps[2] = page_default.c_str(); // Keys -> strings std::string keys[MAX_KEYS]; - for (int i=0; i > EventMap; + typedef std::map > EventMap; EventMap eventCounts; - for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) { + for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) { VerilatedCovImpItem* itemp = *(it); std::string name; std::string hier; bool per_instance = false; - for (int i=0; im_keys[i] != KEY_UNDEF) { std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]); std::string val = m_indexValues[itemp->m_vals[i]]; @@ -380,19 +400,19 @@ public: if (cit != eventCounts.end()) { const std::string& oldhier = cit->second.first; cit->second.second += itemp->count(); - cit->second.first = combineHier(oldhier, hier); + cit->second.first = combineHier(oldhier, hier); } else { eventCounts.insert(std::make_pair(name, make_pair(hier, itemp->count()))); } } // Output body - for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) { - os<<"C '"<first; - if (!it->second.first.empty()) os<second.first); - os<<"' "<second.second; - os<first; + if (!it->second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, it->second.first); + os << "' " << it->second.second; + os << std::endl; } } }; @@ -400,15 +420,11 @@ public: //============================================================================= // VerilatedCov -void VerilatedCov::clear() VL_MT_SAFE { - VerilatedCovImp::imp().clear(); -} +void VerilatedCov::clear() VL_MT_SAFE { VerilatedCovImp::imp().clear(); } void VerilatedCov::clearNonMatch(const char* matchp) VL_MT_SAFE { VerilatedCovImp::imp().clearNonMatch(matchp); } -void VerilatedCov::zero() VL_MT_SAFE { - VerilatedCovImp::imp().zero(); -} +void VerilatedCov::zero() VL_MT_SAFE { VerilatedCovImp::imp().zero(); } void VerilatedCov::write(const char* filenamep) VL_MT_SAFE { VerilatedCovImp::imp().write(filenamep); } @@ -422,48 +438,49 @@ void VerilatedCov::_insertf(const char* filename, int lineno) VL_MT_SAFE { VerilatedCovImp::imp().insertf(filename, lineno); } -#define K(n) const char* key ## n -#define A(n) const char* key ## n, const char* valp ## n // Argument list -#define C(n) key ## n, valp ## n // Calling argument list -#define N(n) "","" // Null argument list -void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9), - A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19), - A(20),A(21),A(22),A(23),A(24),A(25),A(26),A(27),A(28),A(29)) VL_MT_SAFE { +#define K(n) const char* key##n +#define A(n) const char *key##n, const char *valp##n // Argument list +#define C(n) key##n, valp##n // Calling argument list +#define N(n) "", "" // Null argument list +void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), + A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18), A(19), A(20), + A(21), A(22), A(23), A(24), A(25), A(26), A(27), A(28), + A(29)) VL_MT_SAFE { const char* keyps[VerilatedCovImpBase::MAX_KEYS] - = {NULL,NULL,NULL, // filename,lineno,page - key0,key1,key2,key3,key4,key5,key6,key7,key8,key9, - key10,key11,key12,key13,key14,key15,key16,key17,key18,key19, - key20,key21,key22,key23,key24,key25,key26,key27,key28,key29}; + = {NULL, NULL, NULL, // filename,lineno,page + key0, key1, key2, key3, key4, key5, key6, key7, key8, key9, + key10, key11, key12, key13, key14, key15, key16, key17, key18, key19, + key20, key21, key22, key23, key24, key25, key26, key27, key28, key29}; const char* valps[VerilatedCovImpBase::MAX_KEYS] - = {NULL,NULL,NULL, // filename,lineno,page - valp0,valp1,valp2,valp3,valp4,valp5,valp6,valp7,valp8,valp9, - valp10,valp11,valp12,valp13,valp14,valp15,valp16,valp17,valp18,valp19, - valp20,valp21,valp22,valp23,valp24,valp25,valp26,valp27,valp28,valp29}; + = {NULL, NULL, NULL, // filename,lineno,page + valp0, valp1, valp2, valp3, valp4, valp5, valp6, valp7, valp8, valp9, + valp10, valp11, valp12, valp13, valp14, valp15, valp16, valp17, valp18, valp19, + valp20, valp21, valp22, valp23, valp24, valp25, valp26, valp27, valp28, valp29}; VerilatedCovImp::imp().insertp(keyps, valps); } // And versions with fewer arguments (oh for a language with named parameters!) -void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) VL_MT_SAFE { - _insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9), - N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19), - N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29)); +void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), + A(9)) VL_MT_SAFE { + _insertp(C(0), C(1), C(2), C(3), C(4), C(5), C(6), C(7), C(8), C(9), N(10), N(11), N(12), + N(13), N(14), N(15), N(16), N(17), N(18), N(19), N(20), N(21), N(22), N(23), N(24), + N(25), N(26), N(27), N(28), N(29)); } -void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9), - A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) VL_MT_SAFE { - _insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9), - C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19), - N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29)); +void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), + A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18), + A(19)) VL_MT_SAFE { + _insertp(C(0), C(1), C(2), C(3), C(4), C(5), C(6), C(7), C(8), C(9), C(10), C(11), C(12), + C(13), C(14), C(15), C(16), C(17), C(18), C(19), N(20), N(21), N(22), N(23), N(24), + N(25), N(26), N(27), N(28), N(29)); } // Backward compatibility for Verilator -void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3, - K(4),const std::string& val4, A(5),A(6)) VL_MT_SAFE { +void VerilatedCov::_insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), + const std::string& val4, A(5), A(6)) VL_MT_SAFE { std::string val2str = vlCovCvtToStr(val2); std::string val3str = vlCovCvtToStr(val3); - _insertp(C(0),C(1), - key2,val2str.c_str(), key3,val3str.c_str(), key4, val4.c_str(), - C(5),C(6),N(7),N(8),N(9), - N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19), - N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29)); + _insertp(C(0), C(1), key2, val2str.c_str(), key3, val3str.c_str(), key4, val4.c_str(), C(5), + C(6), N(7), N(8), N(9), N(10), N(11), N(12), N(13), N(14), N(15), N(16), N(17), N(18), + N(19), N(20), N(21), N(22), N(23), N(24), N(25), N(26), N(27), N(28), N(29)); } #undef A #undef C diff --git a/include/verilated_cov.h b/include/verilated_cov.h index 5aa11a2d7..a7efa51cd 100644 --- a/include/verilated_cov.h +++ b/include/verilated_cov.h @@ -28,17 +28,17 @@ //============================================================================= /// Conditionally compile coverage code +// clang-format off #ifdef VM_COVERAGE # define VL_IF_COVER(stmts) \ - do { \ - stmts; \ - } while (false) + do { stmts; } while (false) #else # define VL_IF_COVER(stmts) \ do { \ if (false) { stmts; } \ } while (false) #endif +// clang-format on //============================================================================= /// Insert a item for coverage analysis. @@ -68,16 +68,17 @@ /// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i)); /// } -#define VL_COVER_INSERT(countp,...) \ - VL_IF_COVER(VerilatedCov::_inserti(countp); \ - VerilatedCov::_insertf(__FILE__, __LINE__); \ +#define VL_COVER_INSERT(countp, ...) \ + VL_IF_COVER(VerilatedCov::_inserti(countp); VerilatedCov::_insertf(__FILE__, __LINE__); \ VerilatedCov::_insertp("hier", name(), __VA_ARGS__)) //============================================================================= /// Convert VL_COVER_INSERT value arguments to strings -template< class T> std::string vlCovCvtToStr(const T& t) VL_PURE { - std::ostringstream os; os< std::string vlCovCvtToStr(const T& t) VL_PURE { + std::ostringstream os; + os << t; + return os.str(); } //============================================================================= @@ -89,6 +90,7 @@ template< class T> std::string vlCovCvtToStr(const T& t) VL_PURE { class VerilatedCov { VL_UNCOPYABLE(VerilatedCov); + public: // GLOBAL METHODS /// Return default filename @@ -108,18 +110,18 @@ public: // We could have just the maximum argument version, but this compiles // much slower (nearly 2x) than having smaller versions also. However // there's not much more gain in having a version for each number of args. -#define K(n) const char* key ## n -#define A(n) const char* key ## n, const char* valp ## n // Argument list -#define D(n) const char* key ## n = NULL, const char* valp ## n = NULL // Argument list - static void _insertp(D(0),D(1),D(2),D(3),D(4),D(5),D(6),D(7),D(8),D(9)); - static void _insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9) - ,A(10),D(11),D(12),D(13),D(14),D(15),D(16),D(17),D(18),D(19)); - static void _insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9) - ,A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19) - ,A(20),D(21),D(22),D(23),D(24),D(25),D(26),D(27),D(28),D(29)); +#define K(n) const char* key##n +#define A(n) const char *key##n, const char *valp##n // Argument list +#define D(n) const char *key##n = NULL, const char *valp##n = NULL // Argument list + static void _insertp(D(0), D(1), D(2), D(3), D(4), D(5), D(6), D(7), D(8), D(9)); + static void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), D(11), + D(12), D(13), D(14), D(15), D(16), D(17), D(18), D(19)); + static void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), A(11), + A(12), A(13), A(14), A(15), A(16), A(17), A(18), A(19), A(20), D(21), + D(22), D(23), D(24), D(25), D(26), D(27), D(28), D(29)); // Backward compatibility for Verilator - static void _insertp(A(0), A(1), K(2),int val2, K(3),int val3, - K(4),const std::string& val4, A(5),A(6)); + static void _insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), const std::string& val4, + A(5), A(6)); #undef K #undef A diff --git a/include/verilated_cov_key.h b/include/verilated_cov_key.h index fdb0600e2..a2807eb5d 100644 --- a/include/verilated_cov_key.h +++ b/include/verilated_cov_key.h @@ -28,6 +28,7 @@ #define VLCOVGEN_ITEM(string_parsed_by_vlcovgen) +// clang-format off VLCOVGEN_ITEM("name=>'col0_name', short=>'C0', group=>1, default=>undef, descr=>'The column title for the header line of this column'") VLCOVGEN_ITEM("name=>'col1_name', short=>'C1', group=>1, default=>undef, ") VLCOVGEN_ITEM("name=>'col2_name', short=>'C2', group=>1, default=>undef, ") @@ -59,6 +60,7 @@ VLCOVGEN_ITEM("name=>'row1', short=>'r1', group=>0, default=>undef, ") 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'") +// clang-format on // VLCOVGEN_CIK_AUTO_EDIT_BEGIN #define VL_CIK_COL0 "c0" diff --git a/include/verilated_dpi.cpp b/include/verilated_dpi.cpp index 7b4678ea1..6c6d99a63 100644 --- a/include/verilated_dpi.cpp +++ b/include/verilated_dpi.cpp @@ -40,88 +40,80 @@ // Not supported yet #define _VL_SVDPI_UNIMP() \ VL_FATAL_MT(__FILE__, __LINE__, "", \ - (std::string("%%Error: Unsupported DPI function: ")+VL_FUNC).c_str()) + (std::string("%%Error: Unsupported DPI function: ") + VL_FUNC).c_str()) -#define _VL_SVDPI_WARN(...) \ - VL_PRINTF_MT(__VA_ARGS__) +#define _VL_SVDPI_WARN(...) VL_PRINTF_MT(__VA_ARGS__) // Function requires a "context" in the import declaration #define _VL_SVDPI_CONTEXT_WARN() \ - _VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword.\n"); + _VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing " \ + "'context' keyword.\n"); //====================================================================== //====================================================================== //====================================================================== // DPI ROUTINES -const char* svDpiVersion() { - return "1800-2005"; -} +const char* svDpiVersion() { return "1800-2005"; } //====================================================================== // Bit-select utility functions. -svBit svGetBitselBit(const svBitVecVal* sp, int bit) { - return VL_BITRSHIFT_W(sp,bit) & 1; -} +svBit svGetBitselBit(const svBitVecVal* sp, int bit) { return VL_BITRSHIFT_W(sp, bit) & 1; } svLogic svGetBitselLogic(const svLogicVecVal* sp, int bit) { // Not VL_BITRSHIFT_W as sp is a different structure type // Verilator doesn't support X/Z so only aval return (((sp[VL_BITWORD_I(bit)].aval >> VL_BITBIT_I(bit)) & 1) - | (((sp[VL_BITWORD_I(bit)].bval >> VL_BITBIT_I(bit)) & 1)<<1)); + | (((sp[VL_BITWORD_I(bit)].bval >> VL_BITBIT_I(bit)) & 1) << 1)); } -void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { - VL_ASSIGNBIT_WI(32, bit, dp, s); -} +void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { VL_ASSIGNBIT_WI(32, bit, dp, s); } void svPutBitselLogic(svLogicVecVal* dp, int bit, svLogic s) { // Verilator doesn't support X/Z so only aval - dp[VL_BITWORD_I(bit)].aval - = ((dp[VL_BITWORD_I(bit)].aval & ~(VL_UL(1)<>1<> 1 << VL_BITBIT_I(bit))); } void svGetPartselBit(svBitVecVal* dp, const svBitVecVal* sp, int lsb, int width) { // See also VL_SEL_WWI - int msb = lsb+width-1; + int msb = lsb + width - 1; int word_shift = VL_BITWORD_I(lsb); - if (VL_BITBIT_I(lsb)==0) { + if (VL_BITBIT_I(lsb) == 0) { // Just a word extract - for (int i=0; i>loffset; - int upperword = i+word_shift+1; + int words = VL_WORDS_I(msb - lsb + 1); + for (int i = 0; i < words; ++i) { + dp[i] = sp[i + word_shift] >> loffset; + int upperword = i + word_shift + 1; if (upperword <= static_cast(VL_BITWORD_I(msb))) { dp[i] |= sp[upperword] << nbitsfromlow; } } } // Clean result - dp[VL_WORDS_I(width)-1] &= VL_MASK_I(width); + dp[VL_WORDS_I(width) - 1] &= VL_MASK_I(width); } void svGetPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int lsb, int width) { - int msb = lsb+width-1; + int msb = lsb + width - 1; int word_shift = VL_BITWORD_I(lsb); - if (VL_BITBIT_I(lsb)==0) { + if (VL_BITBIT_I(lsb) == 0) { // Just a word extract - for (int i=0; i> loffset; - dp[i].bval = sp[i+word_shift].bval >> loffset; - int upperword = i+word_shift+1; + int words = VL_WORDS_I(msb - lsb + 1); + for (int i = 0; i < words; ++i) { + dp[i].aval = sp[i + word_shift].aval >> loffset; + dp[i].bval = sp[i + word_shift].bval >> loffset; + int upperword = i + word_shift + 1; if (upperword <= static_cast(VL_BITWORD_I(msb))) { dp[i].aval |= sp[upperword].aval << nbitsfromlow; dp[i].bval |= sp[upperword].bval << nbitsfromlow; @@ -129,58 +121,56 @@ void svGetPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int lsb, int } } // Clean result - dp[VL_WORDS_I(width)-1].aval &= VL_MASK_I(width); - dp[VL_WORDS_I(width)-1].bval &= VL_MASK_I(width); + dp[VL_WORDS_I(width) - 1].aval &= VL_MASK_I(width); + dp[VL_WORDS_I(width) - 1].bval &= VL_MASK_I(width); } void svPutPartselBit(svBitVecVal* dp, const svBitVecVal s, int lbit, int width) { // See also _VL_INSERT_WI - int hbit = lbit+width-1; + int hbit = lbit + width - 1; int hoffset = VL_BITBIT_I(hbit); int loffset = VL_BITBIT_I(lbit); - if (hoffset==VL_SIZEBITS_I && loffset==0) { + if (hoffset == VL_SIZEBITS_I && loffset == 0) { // Fast and common case, word based insertion dp[VL_BITWORD_I(lbit)] = s; - } - else { + } else { int hword = VL_BITWORD_I(hbit); int lword = VL_BITWORD_I(lbit); - if (hword==lword) { // know < 32 bits because above checks it - IData insmask = (VL_MASK_I(hoffset-loffset+1))<>nbitsonright) & hinsmask); + IData hinsmask = (VL_MASK_I(hoffset - 0 + 1)) << 0; + IData linsmask = (VL_MASK_I(31 - loffset + 1)) << loffset; + int nbitsonright = 32 - loffset; // bits that end up in lword + dp[lword] = (dp[lword] & ~linsmask) | ((s << loffset) & linsmask); + dp[hword] = (dp[hword] & ~hinsmask) | ((s >> nbitsonright) & hinsmask); } } } // cppcheck-suppress passedByValue void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int width) { - int hbit = lbit+width-1; + int hbit = lbit + width - 1; int hoffset = VL_BITBIT_I(hbit); int loffset = VL_BITBIT_I(lbit); - if (hoffset==VL_SIZEBITS_I && loffset==0) { + if (hoffset == VL_SIZEBITS_I && loffset == 0) { // Fast and common case, word based insertion dp[VL_BITWORD_I(lbit)].aval = s.aval; dp[VL_BITWORD_I(lbit)].bval = s.bval; - } - else { + } else { int hword = VL_BITWORD_I(hbit); int lword = VL_BITWORD_I(lbit); - if (hword==lword) { // know < 32 bits because above checks it - IData insmask = (VL_MASK_I(hoffset-loffset+1))<>nbitsonright) & hinsmask); - dp[hword].bval = (dp[hword].bval & ~hinsmask) | ((s.bval>>nbitsonright) & hinsmask); + IData hinsmask = (VL_MASK_I(hoffset - 0 + 1)) << 0; + IData linsmask = (VL_MASK_I(31 - loffset + 1)) << loffset; + int nbitsonright = 32 - loffset; // bits that end up in lword + dp[lword].aval = (dp[lword].aval & ~linsmask) | ((s.aval << loffset) & linsmask); + dp[lword].bval = (dp[lword].bval & ~linsmask) | ((s.bval << loffset) & linsmask); + dp[hword].aval = (dp[hword].aval & ~hinsmask) | ((s.aval >> nbitsonright) & hinsmask); + dp[hword].bval = (dp[hword].bval & ~hinsmask) | ((s.bval >> nbitsonright) & hinsmask); } } } @@ -204,27 +194,14 @@ static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHa //====================================================================== // Open array querying functions -int svLeft(const svOpenArrayHandle h, int d) { - return _vl_openhandle_varp(h)->left(d); -} -int svRight(const svOpenArrayHandle h, int d) { - return _vl_openhandle_varp(h)->right(d); -} -int svLow(const svOpenArrayHandle h, int d) { - return _vl_openhandle_varp(h)->low(d); -} -int svHigh(const svOpenArrayHandle h, int d) { - return _vl_openhandle_varp(h)->high(d); -} -int svIncrement(const svOpenArrayHandle h, int d) { - return _vl_openhandle_varp(h)->increment(d); -} -int svSize(const svOpenArrayHandle h, int d) { - return _vl_openhandle_varp(h)->elements(d); -} -int svDimensions(const svOpenArrayHandle h) { - return _vl_openhandle_varp(h)->udims(); -} +int svLeft(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->left(d); } +int svRight(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->right(d); } +int svLow(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->low(d); } +int svHigh(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->high(d); } +int svIncrement(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->increment(d); } +int svSize(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->elements(d); } +int svDimensions(const svOpenArrayHandle h) { return _vl_openhandle_varp(h)->udims(); } + /// Return pointer to open array data, or NULL if not in IEEE standard C layout void* svGetArrayPtr(const svOpenArrayHandle h) { const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h); @@ -242,8 +219,8 @@ int svSizeOfArray(const svOpenArrayHandle h) { //====================================================================== // Open array access internals -static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, - int nargs, int indx1, int indx2, int indx3) { +static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, int indx1, + int indx2, int indx3) { void* datap = varp->datap(); if (VL_UNLIKELY(nargs != varp->udims())) { _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function called on" @@ -251,26 +228,29 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, varp->udims(), nargs); return NULL; } - if (nargs>=1) { + if (nargs >= 1) { datap = varp->datapAdjustIndex(datap, 1, indx1); if (VL_UNLIKELY(!datap)) { - _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 1 out of bounds; %d outside [%d:%d].\n", + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 1 " + "out of bounds; %d outside [%d:%d].\n", indx1, varp->left(1), varp->right(1)); return NULL; } } - if (nargs>=2) { + if (nargs >= 2) { datap = varp->datapAdjustIndex(datap, 2, indx2); if (VL_UNLIKELY(!datap)) { - _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 2 out of bounds; %d outside [%d:%d].\n", + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 2 " + "out of bounds; %d outside [%d:%d].\n", indx2, varp->left(2), varp->right(2)); return NULL; } } - if (nargs>=3) { + if (nargs >= 3) { datap = varp->datapAdjustIndex(datap, 3, indx3); if (VL_UNLIKELY(!datap)) { - _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 3 out of bounds; %d outside [%d:%d].\n", + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 3 " + "out of bounds; %d outside [%d:%d].\n", indx1, varp->left(3), varp->right(3)); return NULL; } @@ -280,7 +260,8 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, static int _vl_sv_adjusted_bit(const VerilatedDpiOpenVar* varp, int indx) { if (VL_UNLIKELY(indx < varp->low(0) || indx > varp->high(0))) { - _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function packed index out of bounds; %d outside [%d:%d].\n", + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function packed index out of bounds; %d " + "outside [%d:%d].\n", indx, varp->left(0), varp->right(0)); return 0; } @@ -288,8 +269,8 @@ static int _vl_sv_adjusted_bit(const VerilatedDpiOpenVar* varp, int indx) { } /// Return pointer to simulator open array element, or NULL if outside range -static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h, - int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE { +static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h, int nargs, int indx1, int indx2, + int indx3) VL_MT_SAFE { const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h); if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL; void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); @@ -297,23 +278,25 @@ static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h, } /// Copy to user bit array from simulator open array -static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, - int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE { +static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int nargs, + int indx1, int indx2, int indx3) VL_MT_SAFE { const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); if (VL_UNLIKELY(!datap)) return; switch (varp->vltype()) { - case VLVT_UINT8: d[0] = *(reinterpret_cast(datap)); return; + case VLVT_UINT8: d[0] = *(reinterpret_cast(datap)); return; case VLVT_UINT16: d[0] = *(reinterpret_cast(datap)); return; case VLVT_UINT32: d[0] = *(reinterpret_cast(datap)); return; case VLVT_UINT64: { - WData lwp[2]; VL_SET_WQ(lwp, *(reinterpret_cast(datap))); - d[0] = lwp[0]; d[1] = lwp[1]; + WData lwp[2]; + VL_SET_WQ(lwp, *(reinterpret_cast(datap))); + d[0] = lwp[0]; + d[1] = lwp[1]; break; } case VLVT_WDATA: { WDataOutP wdatap = (reinterpret_cast(datap)); - for (int i=0; ipacked().elements()); ++i) d[i] = wdatap[i]; + for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) d[i] = wdatap[i]; return; } default: @@ -323,25 +306,38 @@ static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, } } /// Copy to user logic array from simulator open array -static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, - int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE { +static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int nargs, + int indx1, int indx2, int indx3) VL_MT_SAFE { const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); if (VL_UNLIKELY(!datap)) return; switch (varp->vltype()) { - case VLVT_UINT8: d[0].aval = *(reinterpret_cast(datap)); d[0].bval=0; return; - case VLVT_UINT16: d[0].aval = *(reinterpret_cast(datap)); d[0].bval=0; return; - case VLVT_UINT32: d[0].aval = *(reinterpret_cast(datap)); d[0].bval=0; return; + case VLVT_UINT8: + d[0].aval = *(reinterpret_cast(datap)); + d[0].bval = 0; + return; + case VLVT_UINT16: + d[0].aval = *(reinterpret_cast(datap)); + d[0].bval = 0; + return; + case VLVT_UINT32: + d[0].aval = *(reinterpret_cast(datap)); + d[0].bval = 0; + return; case VLVT_UINT64: { - WData lwp[2]; VL_SET_WQ(lwp, *(reinterpret_cast(datap))); - d[0].aval = lwp[0]; d[0].bval=0; - d[1].aval = lwp[1]; d[0].bval=0; + WData lwp[2]; + VL_SET_WQ(lwp, *(reinterpret_cast(datap))); + d[0].aval = lwp[0]; + d[0].bval = 0; + d[1].aval = lwp[1]; + d[0].bval = 0; break; } case VLVT_WDATA: { WDataOutP wdatap = (reinterpret_cast(datap)); - for (int i=0; ipacked().elements()); ++i) { - d[i].aval = wdatap[i]; d[i].bval = 0; + for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) { + d[i].aval = wdatap[i]; + d[i].bval = 0; } return; } @@ -353,19 +349,19 @@ static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandl } /// Copy to simulator open array from from user bit array -static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, - int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE { +static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int nargs, + int indx1, int indx2, int indx3) VL_MT_SAFE { const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); if (VL_UNLIKELY(!datap)) return; switch (varp->vltype()) { - case VLVT_UINT8: *(reinterpret_cast(datap)) = s[0]; return; + case VLVT_UINT8: *(reinterpret_cast(datap)) = s[0]; return; case VLVT_UINT16: *(reinterpret_cast(datap)) = s[0]; return; case VLVT_UINT32: *(reinterpret_cast(datap)) = s[0]; return; case VLVT_UINT64: *(reinterpret_cast(datap)) = _VL_SET_QII(s[1], s[0]); break; case VLVT_WDATA: { WDataOutP wdatap = (reinterpret_cast(datap)); - for (int i=0; ipacked().elements()); ++i) wdatap[i] = s[i]; + for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i]; return; } default: @@ -381,80 +377,82 @@ static void _vl_svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogic void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); if (VL_UNLIKELY(!datap)) return; switch (varp->vltype()) { - case VLVT_UINT8: *(reinterpret_cast(datap)) = s[0].aval; return; + case VLVT_UINT8: *(reinterpret_cast(datap)) = s[0].aval; return; case VLVT_UINT16: *(reinterpret_cast(datap)) = s[0].aval; return; case VLVT_UINT32: *(reinterpret_cast(datap)) = s[0].aval; return; - case VLVT_UINT64: *(reinterpret_cast(datap)) = _VL_SET_QII(s[1].aval, s[0].aval); break; + case VLVT_UINT64: + *(reinterpret_cast(datap)) = _VL_SET_QII(s[1].aval, s[0].aval); + break; case VLVT_WDATA: { WDataOutP wdatap = (reinterpret_cast(datap)); - for (int i=0; ipacked().elements()); ++i) wdatap[i] = s[i].aval; + for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i].aval; return; } default: - _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype()); + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", + varp->vltype()); return; } } /// Return bit from simulator open array -static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s, - int nargs, int indx1, int indx2, int indx3, int indx4) VL_MT_SAFE { +static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s, int nargs, int indx1, int indx2, + int indx3, int indx4) VL_MT_SAFE { // One extra index supported, as need bit number const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); void* datap; int lsb; if (varp->packed().elements()) { - datap = _vl_sv_adjusted_datap(varp, nargs-1, indx1, indx2, indx3); - lsb = _vl_sv_adjusted_bit(varp, ((nargs==1) ? indx1 - : (nargs==2) ? indx2 - : (nargs==3) ? indx3 - : indx4)); + datap = _vl_sv_adjusted_datap(varp, nargs - 1, indx1, indx2, indx3); + lsb = _vl_sv_adjusted_bit( + varp, ((nargs == 1) ? indx1 : (nargs == 2) ? indx2 : (nargs == 3) ? indx3 : indx4)); } else { datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); lsb = 0; } if (VL_UNLIKELY(!datap)) return 0; switch (varp->vltype()) { - case VLVT_UINT8: return (*(reinterpret_cast(datap)) >> lsb) & 1; + case VLVT_UINT8: return (*(reinterpret_cast(datap)) >> lsb) & 1; case VLVT_UINT16: return (*(reinterpret_cast(datap)) >> lsb) & 1; case VLVT_UINT32: return (*(reinterpret_cast(datap)) >> lsb) & 1; - case VLVT_UINT64: return (*(reinterpret_cast(datap)) >> static_cast(lsb)) & VL_ULL(1); + case VLVT_UINT64: + return (*(reinterpret_cast(datap)) >> static_cast(lsb)) & VL_ULL(1); case VLVT_WDATA: { WDataOutP wdatap = (reinterpret_cast(datap)); return VL_BITRSHIFT_W(wdatap, lsb) & 1; } default: - _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype()); + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", + varp->vltype()); return 0; } } /// Update simulator open array from bit -static void _vl_svPutBitArrElem(const svOpenArrayHandle d, svBit value, - int nargs, int indx1, int indx2, int indx3, int indx4) VL_MT_SAFE { +static void _vl_svPutBitArrElem(const svOpenArrayHandle d, svBit value, int nargs, int indx1, + int indx2, int indx3, int indx4) VL_MT_SAFE { // One extra index supported, as need bit number value &= 1; // Make sure clean const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); void* datap; int lsb; if (varp->packed().elements()) { - datap = _vl_sv_adjusted_datap(varp, nargs-1, indx1, indx2, indx3); - lsb = _vl_sv_adjusted_bit(varp, ((nargs==1) ? indx1 - : (nargs==2) ? indx2 - : (nargs==3) ? indx3 - : indx4)); + datap = _vl_sv_adjusted_datap(varp, nargs - 1, indx1, indx2, indx3); + lsb = _vl_sv_adjusted_bit( + varp, ((nargs == 1) ? indx1 : (nargs == 2) ? indx2 : (nargs == 3) ? indx3 : indx4)); } else { datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); lsb = 0; } if (VL_UNLIKELY(!datap)) return; switch (varp->vltype()) { - case VLVT_UINT8: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast(datap)), value); return; + case VLVT_UINT8: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast(datap)), value); return; case VLVT_UINT16: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast(datap)), value); return; case VLVT_UINT32: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast(datap)), value); return; case VLVT_UINT64: VL_ASSIGNBIT_QI(-1, lsb, *(reinterpret_cast(datap)), value); return; - case VLVT_WDATA: VL_ASSIGNBIT_WI(-1, lsb, (reinterpret_cast(datap)), value); return; + case VLVT_WDATA: VL_ASSIGNBIT_WI(-1, lsb, (reinterpret_cast(datap)), value); return; default: - _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype()); + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", + varp->vltype()); return; } } @@ -470,10 +468,17 @@ void* svGetArrElemPtr(const svOpenArrayHandle h, int indx1, ...) { // va_arg is a macro, so need temporaries as used below switch (varp->udims()) { case 1: datap = _vl_svGetArrElemPtr(h, 1, indx1, 0, 0); break; - case 2: { int indx2=va_arg(ap,int); - datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0); break; } - case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); - datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3); break; } + case 2: { + int indx2 = va_arg(ap, int); + datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0); + break; + } + case 3: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3); + break; + } default: datap = _vl_svGetArrElemPtr(h, -1, 0, 0, 0); break; // Will error } va_end(ap); @@ -489,116 +494,134 @@ void* svGetArrElemPtr3(const svOpenArrayHandle h, int indx1, int indx2, int indx return _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3); } -void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, - int indx1, ...) { +void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, ...) { const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); va_list ap; va_start(ap, indx1); switch (varp->udims()) { case 1: _vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0); break; - case 2: { int indx2=va_arg(ap,int); - _vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0); break; } - case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); - _vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; } + case 2: { + int indx2 = va_arg(ap, int); + _vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0); + break; + } + case 3: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + _vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); + break; + } default: _vl_svPutBitArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error } va_end(ap); } -void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s, - int indx1) { +void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1) { _vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0); } -void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s, - int indx1, int indx2) { +void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, + int indx2) { _vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0); } -void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s, - int indx1, int indx2, int indx3) { +void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, int indx2, + int indx3) { _vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); } -void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s, - int indx1, ...) { +void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, ...) { const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); va_list ap; va_start(ap, indx1); switch (varp->udims()) { case 1: _vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break; - case 2: { int indx2=va_arg(ap,int); - _vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); break; } - case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); - _vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; } + case 2: { + int indx2 = va_arg(ap, int); + _vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); + break; + } + case 3: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + _vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); + break; + } default: _vl_svPutLogicArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error } va_end(ap); } -void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, - int indx1) { +void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1) { _vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0); } -void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, - int indx1, int indx2) { +void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, + int indx2) { _vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); } -void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, - int indx1, int indx2, int indx3) { +void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, + int indx2, int indx3) { _vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); } //====================================================================== // From simulator storage into user space -void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, - int indx1, ...) { +void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, ...) { const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); va_list ap; va_start(ap, indx1); switch (varp->udims()) { case 1: _vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0); break; - case 2: { int indx2=va_arg(ap,int); - _vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0); break; } - case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); - _vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; } + case 2: { + int indx2 = va_arg(ap, int); + _vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0); + break; + } + case 3: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + _vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); + break; + } default: _vl_svGetBitArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error } va_end(ap); } -void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s, - int indx1) { +void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1) { _vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0); } -void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s, - int indx1, int indx2) { +void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2) { _vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0); } -void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s, - int indx1, int indx2, int indx3) { +void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2, + int indx3) { _vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); } -void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, - int indx1, ...) { +void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, ...) { const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); va_list ap; va_start(ap, indx1); switch (varp->udims()) { case 1: _vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break; - case 2: { int indx2=va_arg(ap,int); - _vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); break; } - case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); - _vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; } + case 2: { + int indx2 = va_arg(ap, int); + _vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); + break; + } + case 3: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + _vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); + break; + } default: _vl_svGetLogicArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error } va_end(ap); } -void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s, - int indx1) { +void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1) { _vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0); } -void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s, - int indx1, int indx2) { +void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2) { _vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); } -void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s, - int indx1, int indx2, int indx3) { +void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2, + int indx3) { _vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); } @@ -609,12 +632,24 @@ svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...) { va_start(ap, indx1); switch (varp->udims()) { case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break; - case 2: { int indx2=va_arg(ap,int); - out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); break; } - case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); - out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); break; } - case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int); - out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4); break; } + case 2: { + int indx2 = va_arg(ap, int); + out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); + break; + } + case 3: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); + break; + } + case 4: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + int indx4 = va_arg(ap, int); + out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4); + break; + } default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break; // Will error } va_end(ap); @@ -637,12 +672,24 @@ svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...) { va_start(ap, indx1); switch (varp->udims()) { case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break; - case 2: { int indx2=va_arg(ap,int); - out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); break; } - case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); - out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); break; } - case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int); - out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4); break; } + case 2: { + int indx2 = va_arg(ap, int); + out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); + break; + } + case 3: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); + break; + } + case 4: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + int indx4 = va_arg(ap, int); + out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4); + break; + } default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break; // Will error } va_end(ap); @@ -667,12 +714,24 @@ void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...) { va_start(ap, indx1); switch (varp->udims()) { case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break; - case 2: { int indx2=va_arg(ap,int); - _vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); break; } - case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); - _vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); break; } - case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int); - _vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4); break; } + case 2: { + int indx2 = va_arg(ap, int); + _vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); + break; + } + case 3: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + _vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); + break; + } + case 4: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + int indx4 = va_arg(ap, int); + _vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4); + break; + } default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break; // Will error } va_end(ap); @@ -693,12 +752,24 @@ void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...) va_start(ap, indx1); switch (varp->udims()) { case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break; - case 2: { int indx2=va_arg(ap,int); - _vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); break; } - case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); - _vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); break; } - case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int); - _vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4); break; } + case 2: { + int indx2 = va_arg(ap, int); + _vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); + break; + } + case 3: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + _vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); + break; + } + case 4: { + int indx2 = va_arg(ap, int); + int indx3 = va_arg(ap, int); + int indx4 = va_arg(ap, int); + _vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4); + break; + } default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break; // Will error } va_end(ap); @@ -707,13 +778,12 @@ void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) { // Verilator doesn't support X/Z so can just call Bit version svPutBitArrElem1(d, value, indx1); } -void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, - int indx1, int indx2) { +void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2) { // Verilator doesn't support X/Z so can just call Bit version svPutBitArrElem2(d, value, indx1, indx2); } -void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, - int indx1, int indx2, int indx3) { +void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2, + int indx3) { // Verilator doesn't support X/Z so can just call Bit version svPutBitArrElem3(d, value, indx1, indx2, indx3); } @@ -722,7 +792,10 @@ void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, // Functions for working with DPI context svScope svGetScope() { - if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return NULL; } + if (VL_UNLIKELY(!Verilated::dpiInContext())) { + _VL_SVDPI_CONTEXT_WARN(); + return NULL; + } // NOLINTNEXTLINE(google-readability-casting) return (svScope)(Verilated::dpiScope()); } @@ -746,16 +819,19 @@ svScope svGetScopeFromName(const char* scopeName) { } int svPutUserData(const svScope scope, void* userKey, void* userData) { - VerilatedImp::userInsert(scope,userKey,userData); + VerilatedImp::userInsert(scope, userKey, userData); return 0; } void* svGetUserData(const svScope scope, void* userKey) { - return VerilatedImp::userFind(scope,userKey); + return VerilatedImp::userFind(scope, userKey); } -int svGetCallerInfo(const char** fileNamepp, int *lineNumberp) { - if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return false; } +int svGetCallerInfo(const char** fileNamepp, int* lineNumberp) { + if (VL_UNLIKELY(!Verilated::dpiInContext())) { + _VL_SVDPI_CONTEXT_WARN(); + return false; + } if (VL_LIKELY(fileNamepp)) *fileNamepp = Verilated::dpiFilenamep(); // thread local if (VL_LIKELY(lineNumberp)) *lineNumberp = Verilated::dpiLineno(); // thread local return true; diff --git a/include/verilated_dpi.h b/include/verilated_dpi.h index b15527fb3..ff20f7360 100644 --- a/include/verilated_dpi.h +++ b/include/verilated_dpi.h @@ -35,29 +35,21 @@ /// Convert svBitVecVal to Verilator internal data static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, const svBitVecVal* lwp) VL_MT_SAFE { int words = VL_WORDS_I(obits); - for (int i = 0; i < words - 1; ++i) { - owp[i] = lwp[i]; - } + for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i]; owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits); } static inline QData VL_SET_Q_SVBV(const svBitVecVal* lwp) VL_MT_SAFE { return _VL_SET_QII(lwp[1], lwp[0]); } -static inline IData VL_SET_I_SVBV(const svBitVecVal* lwp) VL_MT_SAFE { - return lwp[0]; -} +static inline IData VL_SET_I_SVBV(const svBitVecVal* lwp) VL_MT_SAFE { return lwp[0]; } /// Convert Verilator internal data to svBitVecVal 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]; - } + 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_I(int, svBitVecVal* owp, IData ld) VL_MT_SAFE { - owp[0] = ld; -} +static inline void VL_SET_SVBV_I(int, svBitVecVal* owp, IData ld) VL_MT_SAFE { owp[0] = ld; } static inline void VL_SET_SVBV_Q(int, svBitVecVal* owp, QData ld) VL_MT_SAFE { VL_SET_WQ(owp, ld); } @@ -66,28 +58,20 @@ static inline void VL_SET_SVBV_Q(int, svBitVecVal* owp, QData ld) VL_MT_SAFE { /// Note these functions ignore X/Z in svLogicVecVal static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, const svLogicVecVal* lwp) VL_MT_SAFE { int words = VL_WORDS_I(obits); - for (int i = 0; i < words - 1; ++i) { - owp[i] = lwp[i].aval; - } + 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 QData VL_SET_Q_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE { return _VL_SET_QII(lwp[1].aval, lwp[0].aval); } -static inline IData VL_SET_I_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE { - return lwp[0].aval; -} +static inline IData VL_SET_I_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE { return lwp[0].aval; } /// Convert Verilator internal data to svLogicVecVal /// Note these functions never create X/Z in svLogicVecVal static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) VL_MT_SAFE { int words = VL_WORDS_I(obits); - for (int i = 0; i < words; ++i) { - owp[i].bval = 0; - } - for (int i = 0; i < words - 1; ++i) { - owp[i].aval = lwp[i]; - } + for (int i = 0; i < words; ++i) owp[i].bval = 0; + for (int i = 0; i < words - 1; ++i) owp[i].aval = lwp[i]; owp[words - 1].aval = lwp[words - 1] & VL_MASK_I(obits); } static inline void VL_SET_SVLV_I(int, svLogicVecVal* owp, IData ld) VL_MT_SAFE { diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 557ad45f3..2a92390aa 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -379,11 +379,13 @@ template std::string VL_TO_STRING(const VlQueue& obj) { // be protected by other means // +// clang-format off #if (defined(_MSC_VER) && _MSC_VER >= 1900) || (__cplusplus >= 201103L) # define VlClassRef std::shared_ptr #else # define VlClassRef VlClassRef__SystemVerilog_class_support_requires_a_C11_or_newer_compiler #endif +// clang-format on template // T typically of type VlClassRef inline T VL_NULL_CHECK(T t, const char* filename, int linenum) { @@ -412,9 +414,7 @@ inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs 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; - } + 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, diff --git a/include/verilated_imp.h b/include/verilated_imp.h index ac580ec1a..7d8f23a4e 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -19,6 +19,7 @@ #ifndef _VERILATED_IMP_H_ #define _VERILATED_IMP_H_ 1 ///< Header Guard +// clang-format off #if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_) && !defined(_VERILATED_VPI_CPP_) # error "verilated_imp.h only to be included by verilated*.cpp internals" #endif @@ -35,6 +36,7 @@ # include # include #endif +// clang-format on class VerilatedScope; @@ -47,9 +49,11 @@ class VerilatedMsg { public: // TYPES struct Cmp { - bool operator() (const VerilatedMsg& a, const VerilatedMsg& b) const { - return a.mtaskId() < b.mtaskId(); } + bool operator()(const VerilatedMsg& a, const VerilatedMsg& b) const { + return a.mtaskId() < b.mtaskId(); + } }; + private: // MEMBERS vluint32_t m_mtaskId; ///< MTask that did enqueue @@ -86,6 +90,7 @@ public: private: VL_UNCOPYABLE(VerilatedEvalMsgQueue); + public: // METHODS //// Add message to queue (called by producer) @@ -122,6 +127,7 @@ public: /// Each thread has a local queue to build up messages until the end of the eval() call class VerilatedThreadMsgQueue { std::queue m_queue; + public: // CONSTRUCTORS VerilatedThreadMsgQueue() {} @@ -129,6 +135,7 @@ public: // The only call of this with a non-empty queue is a fatal error. // So this does not flush the queue, as the destination queue is not known to this class. } + private: VL_UNCOPYABLE(VerilatedThreadMsgQueue); // METHODS @@ -136,6 +143,7 @@ private: static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s; return t_s; } + public: /// Add message to queue, called by producer static void post(const VerilatedMsg& msg) VL_MT_SAFE { @@ -176,28 +184,33 @@ class VerilatedImp { // Nothing here is save-restored; users expected to re-register appropriately - VerilatedMutex m_argMutex; ///< Protect m_argVec, m_argVecLoaded - ArgVec m_argVec VL_GUARDED_BY(m_argMutex); ///< Argument list (NOT save-restored, may want different results) - bool m_argVecLoaded VL_GUARDED_BY(m_argMutex); ///< Ever loaded argument list + VerilatedMutex m_argMutex; ///< Protect m_argVec, m_argVecLoaded + /// Argument list (NOT save-restored, may want different results) + ArgVec m_argVec VL_GUARDED_BY(m_argMutex); + bool m_argVecLoaded VL_GUARDED_BY(m_argMutex); ///< Ever loaded argument list - VerilatedMutex m_userMapMutex; ///< Protect m_userMap - UserMap m_userMap VL_GUARDED_BY(m_userMapMutex); ///< Map of <(scope,userkey), userData> + VerilatedMutex m_userMapMutex; ///< Protect m_userMap + UserMap m_userMap VL_GUARDED_BY(m_userMapMutex); ///< Map of <(scope,userkey), userData> - VerilatedMutex m_nameMutex; ///< Protect m_nameMap - VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex); ///< Map of + VerilatedMutex m_nameMutex; ///< Protect m_nameMap + /// Map of + VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex); - VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap - VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex); ///< Map the represents scope hierarchy + VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap + /// Map the represents scope hierarchy + VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex); // Slow - somewhat static: - VerilatedMutex m_exportMutex; ///< Protect m_nameMap - ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex); ///< Map of - int m_exportNext VL_GUARDED_BY(m_exportMutex); ///< Next export funcnum + VerilatedMutex m_exportMutex; ///< Protect m_nameMap + /// Map of + ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex); + int m_exportNext VL_GUARDED_BY(m_exportMutex); ///< Next export funcnum // File I/O - VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree - std::vector m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors - std::deque m_fdFree VL_GUARDED_BY(m_fdMutex); ///< List of free descriptors (SLOW - FOPEN/CLOSE only) + VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree + std::vector m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors + /// List of free descriptors (SLOW - FOPEN/CLOSE only) + std::deque m_fdFree VL_GUARDED_BY(m_fdMutex); public: // But only for verilated*.cpp // CONSTRUCTORS @@ -210,8 +223,10 @@ public: // But only for verilated*.cpp m_fdps[2] = stderr; } ~VerilatedImp() {} + private: VL_UNCOPYABLE(VerilatedImp); + public: // METHODS - debug static void internalsDump() VL_MT_SAFE; @@ -238,11 +253,12 @@ public: } return ""; } + private: static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex); static void commandArgVl(const std::string& arg); - static bool commandArgVlValue(const std::string& arg, - const std::string& prefix, std::string& valuer); + static bool commandArgVlValue(const std::string& arg, const std::string& prefix, + std::string& valuer); public: // METHODS - user scope tracking @@ -252,16 +268,19 @@ public: static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE { VerilatedLockGuard lock(s_s.m_userMapMutex); UserMap::iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey)); - if (it != s_s.m_userMap.end()) it->second = userData; - // When we support VL_THREADs, we need a lock around this insert, as it's runtime - else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData)); + if (it != s_s.m_userMap.end()) { + it->second = userData; + } else { + s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData)); + } } static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE { VerilatedLockGuard lock(s_s.m_userMapMutex); - UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep, userKey)); - if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second; - else return NULL; + UserMap::const_iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey)); + if (VL_UNLIKELY(it == s_s.m_userMap.end())) return NULL; + return it->second; } + private: /// Symbol table destruction cleans up the entries for each scope. static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE { @@ -278,10 +297,13 @@ private: static void userDump() VL_MT_SAFE { VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump bool first = true; - for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) { - if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; } - VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n", - it->first.first, it->first.second, it->second); + for (UserMap::const_iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end(); ++it) { + if (first) { + VL_PRINTF_MT(" userDump:\n"); + first = false; + } + VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n", it->first.first, + it->first.second, it->second); } } @@ -298,9 +320,9 @@ public: // But only for verilated*.cpp static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE { VerilatedLockGuard lock(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT - VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep); - if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second; - else return NULL; + VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.find(namep); + if (VL_UNLIKELY(it == s_s.m_nameMap.end())) return NULL; + return it->second; } static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE { // Slow ok - called once/scope at destruction @@ -360,8 +382,8 @@ public: // But only for verilated*.cpp VerilatedLockGuard lock(s_s.m_exportMutex); ExportNameMap::const_iterator it = s_s.m_exportMap.find(namep); if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second; - std::string msg = (std::string("%Error: Testbench C called ")+namep - +" but no such DPI export function name exists in ANY model"); + std::string msg = (std::string("%Error: Testbench C called ") + namep + + " but no such DPI export function name exists in ANY model"); VL_FATAL_MT("unknown", 0, "", msg.c_str()); return -1; } @@ -377,9 +399,12 @@ public: // But only for verilated*.cpp static void exportsDump() VL_MT_SAFE { VerilatedLockGuard lock(s_s.m_exportMutex); bool first = true; - for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); - it!=s_s.m_exportMap.end(); ++it) { - if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; } + for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin(); + it != s_s.m_exportMap.end(); ++it) { + if (first) { + VL_PRINTF_MT(" exportDump:\n"); + first = false; + } VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first); } } @@ -395,12 +420,15 @@ public: // But only for verilated*.cpp if (s_s.m_fdFree.empty()) { // Need to create more space in m_fdps and m_fdFree size_t start = s_s.m_fdps.size(); - s_s.m_fdps.resize(start*2); - for (size_t i=start; i(i)); + s_s.m_fdps.resize(start * 2); + for (size_t i = start; i < start * 2; ++i) { + s_s.m_fdFree.push_back(static_cast(i)); + } } - IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back(); + IData idx = s_s.m_fdFree.back(); + s_s.m_fdFree.pop_back(); s_s.m_fdps[idx] = fp; - return (idx | (1UL<<31)); // bit 31 indicates not MCD + return (idx | (1UL << 31)); // bit 31 indicates not MCD } static void fdDelete(IData fdi) VL_MT_SAFE { IData idx = VL_MASK_I(31) & fdi; diff --git a/include/verilated_save.cpp b/include/verilated_save.cpp index fde2a5190..2c91e384e 100644 --- a/include/verilated_save.cpp +++ b/include/verilated_save.cpp @@ -23,6 +23,7 @@ #include #include +// clang-format off #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) # include #else @@ -38,6 +39,7 @@ #ifndef O_CLOEXEC # define O_CLOEXEC 0 #endif +// clang-format on // CONSTANTS static const char* const VLTSAVE_HEADER_STR @@ -54,9 +56,7 @@ bool VerilatedDeserialize::readDiffers(const void* __restrict datap, bufferCheck(); const vluint8_t* __restrict dp = static_cast(datap); vluint8_t miss = 0; - while (size--) { - miss |= (*dp++ ^ *m_cp++); - } + while (size--) miss |= (*dp++ ^ *m_cp++); return (miss != 0); } @@ -232,9 +232,7 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE { } else { // got==0, EOF // Fill buffer from here to end with NULLs so reader's don't // need to check eof each character. - while (m_endp < m_bufp + bufferSize()) { - *m_endp++ = '\0'; - } + while (m_endp < m_bufp + bufferSize()) *m_endp++ = '\0'; break; } } diff --git a/include/verilated_save.h b/include/verilated_save.h index 7652e0750..74ea32d83 100644 --- a/include/verilated_save.h +++ b/include/verilated_save.h @@ -132,7 +132,7 @@ public: size_t blk = size; if (blk > bufferInsertSize()) blk = bufferInsertSize(); const vluint8_t* __restrict maxp = dp + blk; - for (; dp < maxp; *dp++ = *m_cp++); + for (; dp < maxp; *dp++ = *m_cp++) {} size -= blk; } return *this; // For function chaining @@ -257,8 +257,8 @@ VerilatedSerialize& operator<<(VerilatedSerialize& os, VlAssocArray::const_iterator it = rhs.begin(); - it != rhs.end(); ++it) { + for (typename VlAssocArray::const_iterator it = rhs.begin(); it != rhs.end(); + ++it) { T_Key index = it->first; // Copy to get around const_iterator T_Value value = it->second; os << index << value; diff --git a/include/verilated_sym_props.h b/include/verilated_sym_props.h index 47846c8ec..bc1dfdd94 100644 --- a/include/verilated_sym_props.h +++ b/include/verilated_sym_props.h @@ -41,8 +41,12 @@ class VerilatedRange { protected: friend class VerilatedVarProps; friend class VerilatedScope; - VerilatedRange() : m_left(0), m_right(0) {} - VerilatedRange(int left, int right) : m_left(left), m_right(right) {} + VerilatedRange() + : m_left(0) + , m_right(0) {} + VerilatedRange(int left, int right) + : m_left(left) + , m_right(right) {} void init(int left, int right) { m_left = left; m_right = right; @@ -78,63 +82,89 @@ class VerilatedVarProps { // CONSTRUCTORS protected: friend class VerilatedScope; - VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, - int pdims, int udims) - : m_magic(MAGIC), m_vltype(vltype), m_vlflags(vlflags), m_pdims(pdims), m_udims(udims) {} + VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int pdims, int udims) + : m_magic(MAGIC) + , m_vltype(vltype) + , m_vlflags(vlflags) + , m_pdims(pdims) + , m_udims(udims) {} public: class Unpacked {}; // Without packed VerilatedVarProps(VerilatedVarType vltype, int vlflags) - : m_magic(MAGIC), m_vltype(vltype), - m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(0) {} - VerilatedVarProps(VerilatedVarType vltype, int vlflags, - Unpacked, int u0l, int u0r) - : m_magic(MAGIC), m_vltype(vltype), - m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(1) { + : m_magic(MAGIC) + , m_vltype(vltype) + , m_vlflags(VerilatedVarFlags(vlflags)) + , m_pdims(0) + , m_udims(0) {} + VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r) + : m_magic(MAGIC) + , m_vltype(vltype) + , m_vlflags(VerilatedVarFlags(vlflags)) + , m_pdims(0) + , m_udims(1) { m_unpacked[0].init(u0l, u0r); } - VerilatedVarProps(VerilatedVarType vltype, int vlflags, - Unpacked, int u0l, int u0r, int u1l, int u1r) - : m_magic(MAGIC), m_vltype(vltype), - m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(2) { + VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l, + int u1r) + : m_magic(MAGIC) + , m_vltype(vltype) + , m_vlflags(VerilatedVarFlags(vlflags)) + , m_pdims(0) + , m_udims(2) { m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); } - VerilatedVarProps(VerilatedVarType vltype, int vlflags, - Unpacked, int u0l, int u0r, int u1l, int u1r, int u2l, int u2r) - : m_magic(MAGIC), m_vltype(vltype), - m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(3) { + VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l, + int u1r, int u2l, int u2r) + : m_magic(MAGIC) + , m_vltype(vltype) + , m_vlflags(VerilatedVarFlags(vlflags)) + , m_pdims(0) + , m_udims(3) { m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); m_unpacked[2].init(u2l, u2r); } // With packed class Packed {}; - VerilatedVarProps(VerilatedVarType vltype, int vlflags, - Packed, int pl, int pr) - : m_magic(MAGIC), m_vltype(vltype), - m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(0), m_packed(pl,pr) {} - VerilatedVarProps(VerilatedVarType vltype, int vlflags, - Packed, int pl, int pr, - Unpacked, int u0l, int u0r) - : m_magic(MAGIC), m_vltype(vltype), - m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(1), m_packed(pl,pr) { + VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr) + : m_magic(MAGIC) + , m_vltype(vltype) + , m_vlflags(VerilatedVarFlags(vlflags)) + , m_pdims(1) + , m_udims(0) + , m_packed(pl, pr) {} + VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked, + int u0l, int u0r) + : m_magic(MAGIC) + , m_vltype(vltype) + , m_vlflags(VerilatedVarFlags(vlflags)) + , m_pdims(1) + , m_udims(1) + , m_packed(pl, pr) { m_unpacked[0].init(u0l, u0r); } - VerilatedVarProps(VerilatedVarType vltype, int vlflags, - Packed, int pl, int pr, - Unpacked, int u0l, int u0r, int u1l, int u1r) - : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), - m_pdims(1), m_udims(2), m_packed(pl,pr) { + VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked, + int u0l, int u0r, int u1l, int u1r) + : m_magic(MAGIC) + , m_vltype(vltype) + , m_vlflags(VerilatedVarFlags(vlflags)) + , m_pdims(1) + , m_udims(2) + , m_packed(pl, pr) { m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); } - VerilatedVarProps(VerilatedVarType vltype, int vlflags, - Packed, int pl, int pr, - Unpacked, int u0l, int u0r, int u1l, int u1r, int u2l, int u2r) - : m_magic(MAGIC), m_vltype(vltype), - m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(3), m_packed(pl,pr) { + VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked, + int u0l, int u0r, int u1l, int u1r, int u2l, int u2r) + : m_magic(MAGIC) + , m_vltype(vltype) + , m_vlflags(VerilatedVarFlags(vlflags)) + , m_pdims(1) + , m_udims(3) + , m_packed(pl, pr) { m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); m_unpacked[2].init(u2l, u2r); diff --git a/include/verilated_threads.cpp b/include/verilated_threads.cpp index f4f23149f..0ac6cee74 100644 --- a/include/verilated_threads.cpp +++ b/include/verilated_threads.cpp @@ -61,8 +61,7 @@ void VlWorkerThread::workerLoop() { if (VL_LIKELY(!work.m_fnp)) dequeWork(&work); // Do this here, not above, to avoid a race with the destructor. - if (VL_UNLIKELY(m_exiting.load(std::memory_order_acquire))) - break; + if (VL_UNLIKELY(m_exiting.load(std::memory_order_acquire))) break; if (VL_LIKELY(work.m_fnp)) { work.m_fnp(work.m_evenCycle, work.m_sym); @@ -128,8 +127,7 @@ void VlThreadPool::setupProfilingClientThread() { void VlThreadPool::profileAppendAll(const VlProfileRec& rec) { VerilatedLockGuard lk(m_mutex); - for (ProfileSet::iterator it = m_allProfiles.begin(); - it != m_allProfiles.end(); ++it) { + for (ProfileSet::iterator it = m_allProfiles.begin(); it != m_allProfiles.end(); ++it) { // Every thread's profile trace gets a copy of rec. (*it)->emplace_back(rec); } @@ -156,14 +154,14 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) { fprintf(fp, "VLPROF stat yields %" VL_PRI64 "u\n", VlMTaskVertex::yields()); vluint32_t thread_id = 0; - for (ProfileSet::const_iterator pit = m_allProfiles.begin(); - pit != m_allProfiles.end(); ++pit) { + for (ProfileSet::const_iterator pit = m_allProfiles.begin(); pit != m_allProfiles.end(); + ++pit) { ++thread_id; bool printing = false; // False while in warmup phase for (ProfileTrace::const_iterator eit = (*pit)->begin(); eit != (*pit)->end(); ++eit) { switch (eit->m_type) { - case VlProfileRec::TYPE_BARRIER: + case VlProfileRec::TYPE_BARRIER: // printing = true; break; case VlProfileRec::TYPE_MTASK_RUN: diff --git a/include/verilated_threads.h b/include/verilated_threads.h index 19d7af2c2..b1e5a4fd9 100644 --- a/include/verilated_threads.h +++ b/include/verilated_threads.h @@ -25,12 +25,15 @@ #include #include #include + +// clang-format off #if defined(__linux) -#include // For sched_getcpu() +# include // For sched_getcpu() #endif #if defined(__APPLE__) # include // For __cpuid_count() #endif +// clang-format on // VlMTaskVertex and VlThreadpool will work with multiple symbol table types. // Since the type is opaque to VlMTaskVertex and VlThreadPool, represent it @@ -115,10 +118,7 @@ public: class VlProfileRec { protected: friend class VlThreadPool; - enum VlProfileE { - TYPE_MTASK_RUN, - TYPE_BARRIER - }; + enum VlProfileE { TYPE_MTASK_RUN, TYPE_BARRIER }; VlProfileE m_type; // Record type vluint32_t m_mtaskId; // Mtask we're logging vluint32_t m_predictTime; // How long scheduler predicted would take @@ -173,9 +173,14 @@ private: VlExecFnp m_fnp; // Function to execute VlThrSymTab m_sym; // Symbol table to execute bool m_evenCycle; // Even/odd for flag alternation - ExecRec() : m_fnp(NULL), m_sym(NULL), m_evenCycle(false) {} + ExecRec() + : m_fnp(NULL) + , m_sym(NULL) + , m_evenCycle(false) {} ExecRec(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym) - : m_fnp(fnp), m_sym(sym), m_evenCycle(evenCycle) {} + : m_fnp(fnp) + , m_sym(sym) + , m_evenCycle(evenCycle) {} }; // MEMBERS @@ -208,7 +213,7 @@ public: inline void dequeWork(ExecRec* workp) { // Spin for a while, waiting for new data for (int i = 0; i < VL_LOCK_SPINS; ++i) { - if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) { + if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) { // break; } VL_CPU_RELAX(); diff --git a/include/verilated_unordered_set_map.h b/include/verilated_unordered_set_map.h index 9800b39a1..ce5ee4357 100644 --- a/include/verilated_unordered_set_map.h +++ b/include/verilated_unordered_set_map.h @@ -41,13 +41,9 @@ #include // Abstract 'vl_hash' and 'vl_equal_to' templates. -template struct vl_hash { - size_t operator()(const T& k) const; -}; +template struct vl_hash { size_t operator()(const T& k) const; }; -template struct vl_equal_to { - bool operator()(const T& a, const T& b) const; -}; +template struct vl_equal_to { bool operator()(const T& a, const T& b) const; }; // Specializations of 'vl_hash' and 'vl_equal_to'. inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) { @@ -59,60 +55,50 @@ inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) { return hash; } -template <> inline size_t -vl_hash::operator()(const unsigned int& k) const { +template <> inline size_t vl_hash::operator()(const unsigned int& k) const { return k; } -template <> inline bool -vl_equal_to::operator()(const unsigned int& a, - const unsigned int& b) const { +template <> +inline bool vl_equal_to::operator()(const unsigned int& a, + const unsigned int& b) const { return a == b; } -template <> inline size_t -vl_hash::operator()(const std::string& k) const { +template <> inline size_t vl_hash::operator()(const std::string& k) const { return vl_hash_bytes(k.data(), k.size()); } -template <> inline bool -vl_equal_to::operator()(const std::string& a, - const std::string& b) const { +template <> +inline bool vl_equal_to::operator()(const std::string& a, + const std::string& b) const { // Don't scan the strings if the sizes are different. - if (a.size() != b.size()) { - return false; - } + if (a.size() != b.size()) return false; return (0 == a.compare(b)); // Must scan. } template struct vl_hash { size_t operator()(T* kp) const { - return ((sizeof(size_t) == sizeof(kp)) - ? reinterpret_cast(kp) - : vl_hash_bytes(&kp, sizeof(kp))); + return ((sizeof(size_t) == sizeof(kp)) ? reinterpret_cast(kp) + : vl_hash_bytes(&kp, sizeof(kp))); } }; template struct vl_equal_to { - bool operator()(T* ap, T* bp) const { - return ap == bp; - } + bool operator()(T* ap, T* bp) const { return ap == bp; } }; //=================================================================== // /// Functional clone of the std::unordered_set hash table. -template , - class T_Equal = vl_equal_to > +template , class T_Equal = vl_equal_to > class vl_unordered_set { public: // TYPES typedef std::list Bucket; enum RehashType { GROW, SHRINK }; - template friend class vl_unordered_map; + template friend class vl_unordered_map; class iterator { protected: @@ -123,29 +109,23 @@ public: public: // CONSTRUCTORS - iterator(size_t bucketIdx, typename Bucket::iterator bit, - const vl_unordered_set* setp) - : m_bucketIdx(bucketIdx), m_bit(bit), m_setp(setp) {} + iterator(size_t bucketIdx, typename Bucket::iterator bit, const vl_unordered_set* setp) + : m_bucketIdx(bucketIdx) + , m_bit(bit) + , m_setp(setp) {} // METHODS - const T_Key& operator*() const { - return *m_bit; - } + const T_Key& operator*() const { return *m_bit; } // This should really be 'const T_Key*' type for unordered_set, // however this iterator is shared with unordered_map whose // operator-> returns a non-const ValueType*, so keep this // non-const to avoid having to define a whole separate iterator // for unordered_map. - T_Key* operator->() const { - return &(*m_bit); - } + T_Key* operator->() const { return &(*m_bit); } bool operator==(const iterator& other) const { - return ((m_bucketIdx == other.m_bucketIdx) - && (m_bit == other.m_bit)); - } - bool operator!=(const iterator& other) const { - return (!this->operator==(other)); + return ((m_bucketIdx == other.m_bucketIdx) && (m_bit == other.m_bit)); } + bool operator!=(const iterator& other) const { return (!this->operator==(other)); } void advanceUntilValid() { while (true) { if (m_bit != m_setp->m_bucketsp[m_bucketIdx].end()) { @@ -176,14 +156,14 @@ public: private: // MEMBERS - size_t m_numElements; // Number of entries present. - size_t m_log2Buckets; // Log-base-2 of the number of buckets. - mutable Bucket* m_bucketsp; // Hash table buckets. May be NULL; + size_t m_numElements; // Number of entries present. + size_t m_log2Buckets; // Log-base-2 of the number of buckets. + mutable Bucket* m_bucketsp; // Hash table buckets. May be NULL; // // we'll allocate it on the fly when // // the first entries are created. - Bucket m_emptyBucket; // A fake bucket, used to construct end(). - T_Hash m_hash; // Hash function provider. - T_Equal m_equal; // Equal-to function provider. + Bucket m_emptyBucket; // A fake bucket, used to construct end(). + T_Hash m_hash; // Hash function provider. + T_Equal m_equal; // Equal-to function provider. public: // CONSTRUCTORS @@ -202,26 +182,20 @@ public: , m_equal() { if (other.m_bucketsp) { m_bucketsp = new Bucket[numBuckets()]; - for (size_t i = 0; i < numBuckets(); i++) { - m_bucketsp[i] = other.m_bucketsp[i]; - } + for (size_t i = 0; i < numBuckets(); i++) m_bucketsp[i] = other.m_bucketsp[i]; } } - ~vl_unordered_set() { - VL_DO_DANGLING(delete [] m_bucketsp, m_bucketsp); - } + ~vl_unordered_set() { VL_DO_DANGLING(delete[] m_bucketsp, m_bucketsp); } vl_unordered_set& operator=(const vl_unordered_set& other) { if (this != &other) { clear(); - delete [] m_bucketsp; + delete[] m_bucketsp; m_numElements = other.m_numElements; m_log2Buckets = other.m_log2Buckets; if (other.m_bucketsp) { m_bucketsp = new Bucket[numBuckets()]; - for (size_t i = 0; i < numBuckets(); i++) { - m_bucketsp[i] = other.m_bucketsp[i]; - } + for (size_t i = 0; i < numBuckets(); i++) m_bucketsp[i] = other.m_bucketsp[i]; } else { m_bucketsp = NULL; } @@ -251,24 +225,21 @@ public: return end(); } const_iterator end() const { - return iterator(VL_ULL(0xFFFFFFFFFFFFFFFF), - const_cast(m_emptyBucket).begin(), this); + return iterator(VL_ULL(0xFFFFFFFFFFFFFFFF), const_cast(m_emptyBucket).begin(), + this); } bool empty() const { return m_numElements == 0; } size_t size() const { return m_numElements; } - size_t count(const T_Key& key) const { - return (find(key) == end()) ? 0 : 1; - } + size_t count(const T_Key& key) const { return (find(key) == end()) ? 0 : 1; } - size_t hashToBucket(size_t hashVal) const { - return hashToBucket(hashVal, m_log2Buckets); - } + size_t hashToBucket(size_t hashVal) const { return hashToBucket(hashVal, m_log2Buckets); } static size_t hashToBucket(size_t hashVal, unsigned log2Buckets) { - // Fibonacci hashing - // See https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization-that-the-world-forgot-or-a-better-alternative-to-integer-modulo/ + // Fibonacci hashing, see + // https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization + // -that-the-world-forgot-or-a-better-alternative-to-integer-modulo/ // // * The magic numbers below are UINT_MAX/phi where phi is the // golden ratio number (1.618...) for either 64- or 32-bit @@ -278,11 +249,9 @@ public: // function further. This permits the use of very fast client // hash funcs (like just returning the int or pointer value as // is!) and tolerates crappy client hash functions pretty well. - size_t mult = hashVal * ((sizeof(size_t) == 8) - ? VL_ULL(11400714819323198485) - : 2654435769lu); - size_t result = (mult >> (((sizeof(size_t) == 8) - ? 64 : 32) - log2Buckets)); + size_t mult + = hashVal * ((sizeof(size_t) == 8) ? VL_ULL(11400714819323198485) : 2654435769lu); + size_t result = (mult >> (((sizeof(size_t) == 8) ? 64 : 32) - log2Buckets)); return result; } @@ -292,19 +261,15 @@ public: initBuckets(); Bucket* bucketp = &m_bucketsp[bucketIdxOut]; - for (typename Bucket::iterator it = bucketp->begin(); - it != bucketp->end(); ++it) { - if (m_equal.operator()(*it, key)) { - return iterator(bucketIdxOut, it, this); - } + for (typename Bucket::iterator it = bucketp->begin(); it != bucketp->end(); ++it) { + if (m_equal.operator()(*it, key)) return iterator(bucketIdxOut, it, this); } return end(); } const_iterator find(const T_Key& key) const { size_t bucketIdx; - return const_cast(this)->find_internal(key, - bucketIdx); + return const_cast(this)->find_internal(key, bucketIdx); } iterator find(const T_Key& key) { @@ -358,9 +323,7 @@ public: // for the Scoreboard in V3Partition, which begins tracking // a huge number of vertices and then tracks a successively // smaller number over time. - if (needToRehash(SHRINK)) { - rehash(SHRINK); - } + if (needToRehash(SHRINK)) rehash(SHRINK); return 1; } return 0; @@ -419,8 +382,7 @@ private: size_t new_idx = hashToBucket(hash, new_log2Buckets); // Avoid mallocing one list elem and freeing another; // splice just moves it over. - new_bucketsp[new_idx].splice(new_bucketsp[new_idx].begin(), - m_bucketsp[i], bit); + new_bucketsp[new_idx].splice(new_bucketsp[new_idx].begin(), m_bucketsp[i], bit); } } @@ -433,9 +395,7 @@ private: //=================================================================== // /// Functional clone of the std::unordered_map hash table. -template , +template , class T_Equal = vl_equal_to > class vl_unordered_map { private: @@ -445,6 +405,7 @@ private: class KeyHash { private: T_Hash key_hash; + public: KeyHash() {} size_t operator()(const KeyValPair& kv_pair) const { @@ -455,6 +416,7 @@ private: class KeyEqual { private: T_Equal key_eq; + public: KeyEqual() {} bool operator()(const KeyValPair& kv_a, const KeyValPair& kv_b) const { @@ -491,24 +453,19 @@ public: size_t bucketIdxOut = m_set.hashToBucket(hash); typename MapSet::Bucket* bucketp = m_set.getBucket(bucketIdxOut); - for (typename MapSet::Bucket::iterator it = bucketp->begin(); - it != bucketp->end(); ++it) { - if (mapEq.operator()(it->first, k)) { - return iterator(bucketIdxOut, it, &m_set); - } + for (typename MapSet::Bucket::iterator it = bucketp->begin(); it != bucketp->end(); ++it) { + if (mapEq.operator()(it->first, k)) return iterator(bucketIdxOut, it, &m_set); } return end(); } const_iterator find(const T_Key& k) const { return const_cast(this)->find(k); } - std::pair insert(const KeyValPair& val) { - return m_set.insert(val); - } + std::pair insert(const KeyValPair& val) { return m_set.insert(val); } iterator erase(iterator it) { return m_set.erase(it); } size_t erase(const T_Key& k) { iterator it = find(k); - if (it == end()) { return 0; } + if (it == end()) return 0; m_set.erase(it); return 1; } @@ -517,9 +474,7 @@ public: // std::unordered_map::operator[] relies on it too. KeyValPair dummy = std::make_pair(k, T_Value()); iterator it = m_set.find(dummy); - if (it == m_set.end()) { - it = m_set.insert(dummy).first; - } + if (it == m_set.end()) it = m_set.insert(dummy).first; // For the 'set', it's generally not safe to modify // the value after deref. For the 'map' though, we know // it's safe to modify the value field and we can allow it: diff --git a/include/verilated_vcd_sc.cpp b/include/verilated_vcd_sc.cpp index ef3013d29..db863366a 100644 --- a/include/verilated_vcd_sc.cpp +++ b/include/verilated_vcd_sc.cpp @@ -25,21 +25,22 @@ //====================================================================== //-------------------------------------------------- -#if (SYSTEMC_VERSION>=20050714) - // SystemC 2.1.v1 +#if (SYSTEMC_VERSION >= 20050714) +// SystemC 2.1.v1 // cppcheck-suppress unusedFunction -void VerilatedVcdSc::write_comment(const std::string &) {} -void VerilatedVcdSc::trace(const unsigned int &, const std::string &, const char**) {} +void VerilatedVcdSc::write_comment(const std::string&) {} +void VerilatedVcdSc::trace(const unsigned int&, const std::string&, const char**) {} +// clang-format off # define DECL_TRACE_METHOD_A(tp) \ - void VerilatedVcdSc::trace( const tp& object, const std::string& name ) {} + void VerilatedVcdSc::trace(const tp& object, const std::string& name) {} # define DECL_TRACE_METHOD_B(tp) \ - void VerilatedVcdSc::trace( const tp& object, const std::string& name, int width ) {} + void VerilatedVcdSc::trace(const tp& object, const std::string& name, int width) {} -#if (SYSTEMC_VERSION>=20171012) +# if (SYSTEMC_VERSION >= 20171012) DECL_TRACE_METHOD_A( sc_event ) DECL_TRACE_METHOD_A( sc_time ) -#endif +# endif DECL_TRACE_METHOD_A( bool ) DECL_TRACE_METHOD_A( sc_dt::sc_bit ) @@ -49,9 +50,9 @@ void VerilatedVcdSc::trace(const unsigned int &, const std::string &, const char DECL_TRACE_METHOD_B( unsigned short ) DECL_TRACE_METHOD_B( unsigned int ) DECL_TRACE_METHOD_B( unsigned long ) -#ifdef SYSTEMC_64BIT_PATCHES +# ifdef SYSTEMC_64BIT_PATCHES DECL_TRACE_METHOD_B( unsigned long long) -#endif +# endif DECL_TRACE_METHOD_B( char ) DECL_TRACE_METHOD_B( short ) DECL_TRACE_METHOD_B( int ) @@ -73,19 +74,21 @@ void VerilatedVcdSc::trace(const unsigned int &, const std::string &, const char DECL_TRACE_METHOD_A( sc_dt::sc_bv_base ) DECL_TRACE_METHOD_A( sc_dt::sc_lv_base ) +// clang-format on //-------------------------------------------------- -#elif (SYSTEMC_VERSION>20011000) - // SystemC 2.0.1 +#elif (SYSTEMC_VERSION > 20011000) +// SystemC 2.0.1 // cppcheck-suppress unusedFunction -void VerilatedVcdSc::write_comment(const sc_string &) {} +void VerilatedVcdSc::write_comment(const sc_string&) {} void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {} #define DECL_TRACE_METHOD_A(tp) \ - void VerilatedVcdSc::trace( const tp& object, const sc_string& name ) {} + void VerilatedVcdSc::trace(const tp& object, const sc_string& name) {} #define DECL_TRACE_METHOD_B(tp) \ - void VerilatedVcdSc::trace( const tp& object, const sc_string& name, int width ) {} + void VerilatedVcdSc::trace(const tp& object, const sc_string& name, int width) {} +// clang-format off DECL_TRACE_METHOD_A( bool ) DECL_TRACE_METHOD_A( sc_bit ) DECL_TRACE_METHOD_A( sc_logic ) @@ -96,7 +99,7 @@ void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) #ifdef SYSTEMC_64BIT_PATCHES DECL_TRACE_METHOD_B( unsigned long long) #endif -#if (SYSTEMC_VERSION>20041000) +#if (SYSTEMC_VERSION > 20041000) DECL_TRACE_METHOD_B( unsigned long long) DECL_TRACE_METHOD_B( long long) #endif @@ -116,19 +119,21 @@ void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) DECL_TRACE_METHOD_A( sc_fxnum_fast ) DECL_TRACE_METHOD_A( sc_bv_base ) DECL_TRACE_METHOD_A( sc_lv_base ) +// clang-format on //-------------------------------------------------- #else - // SystemC 1.2.1beta +// SystemC 1.2.1beta // cppcheck-suppress unusedFunction -void VerilatedVcdSc::write_comment(const sc_string &) {} +void VerilatedVcdSc::write_comment(const sc_string&) {} void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {} #define DECL_TRACE_METHOD_A(tp) \ - void VerilatedVcdSc::trace( const tp& object, const sc_string& name ) {} + void VerilatedVcdSc::trace(const tp& object, const sc_string& name) {} #define DECL_TRACE_METHOD_B(tp) \ - void VerilatedVcdSc::trace( const tp& object, const sc_string& name, int width ) {} + void VerilatedVcdSc::trace(const tp& object, const sc_string& name, int width) {} +// clang-format off DECL_TRACE_METHOD_A( bool ) DECL_TRACE_METHOD_B( unsigned char ) DECL_TRACE_METHOD_B( short unsigned int ) @@ -154,6 +159,7 @@ void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) DECL_TRACE_METHOD_A( sc_signal_resolved_vector ) DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base ) DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base ) +// clang-format on #endif #undef DECL_TRACE_METHOD_A diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h index 030f8820a..7b8ffa33e 100644 --- a/include/verilated_vcd_sc.h +++ b/include/verilated_vcd_sc.h @@ -31,44 +31,42 @@ /// This class is passed to the SystemC simulation kernel, just like a /// documented SystemC trace format. -class VerilatedVcdSc - : sc_trace_file - , public VerilatedVcdC -{ +class VerilatedVcdSc : sc_trace_file, public VerilatedVcdC { // CONSTRUCTORS VL_UNCOPYABLE(VerilatedVcdSc); + public: VerilatedVcdSc() { sc_get_curr_simcontext()->add_trace_file(this); -# if (SYSTEMC_VERSION>=20060505) +#if (SYSTEMC_VERSION >= 20060505) // We want to avoid a depreciated warning, but still be back compatible. // Turning off the message just for this still results in an // annoying "to turn off" message. - sc_time t1sec(1,SC_SEC); - if (t1sec.to_default_time_units()!=0) { - sc_time tunits(1.0/t1sec.to_default_time_units(),SC_SEC); + sc_time t1sec(1, SC_SEC); + if (t1sec.to_default_time_units() != 0) { + sc_time tunits(1.0 / t1sec.to_default_time_units(), SC_SEC); spTrace()->set_time_unit(tunits.to_string()); } spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); -# elif (SYSTEMC_VERSION>20011000) +#elif (SYSTEMC_VERSION > 20011000) // To confuse matters 2.1.beta returns a char* here, while 2.1.v1 returns a std::string // we allow both flavors with overloaded set_time_* functions. spTrace()->set_time_unit(sc_get_default_time_unit().to_string()); spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); -# endif +#endif } virtual ~VerilatedVcdSc() { close(); } // METHODS /// Called by SystemC simulate() virtual void cycle(bool delta_cycle) { -# if (SYSTEMC_VERSION>20011000) +#if (SYSTEMC_VERSION > 20011000) if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); } -# else +#else // VCD files must have integer timestamps, so we write all times in // increments of time_resolution if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); } -# endif +#endif } private: @@ -78,26 +76,26 @@ private: // Cadence Incisive has these as abstract functions so we must create them virtual void set_time_unit(int exponent10_seconds) {} // deprecated #endif -#if defined(NC_SYSTEMC) || (SYSTEMC_VERSION>=20111100) +#if defined(NC_SYSTEMC) || (SYSTEMC_VERSION >= 20111100) virtual void set_time_unit(double v, sc_time_unit tu) {} #endif - //-------------------------------------------------- -# if (SYSTEMC_VERSION>=20050714) +#if (SYSTEMC_VERSION >= 20050714) // SystemC 2.1.v1 -# define DECL_TRACE_METHOD_A(tp) \ - virtual void trace(const tp& object, const std::string& name); + // clang-format off +# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name); # define DECL_TRACE_METHOD_B(tp) \ virtual void trace(const tp& object, const std::string& name, int width); virtual void write_comment(const std::string&); virtual void trace(const unsigned int&, const std::string&, const char**); -#if (SYSTEMC_VERSION>=20171012) + // Formatting matches that of sc_trace.h +# if (SYSTEMC_VERSION >= 20171012) DECL_TRACE_METHOD_A( sc_event ) DECL_TRACE_METHOD_A( sc_time ) -#endif +# endif DECL_TRACE_METHOD_A( bool ) DECL_TRACE_METHOD_A( sc_dt::sc_bit ) @@ -107,9 +105,9 @@ private: DECL_TRACE_METHOD_B( unsigned short ) DECL_TRACE_METHOD_B( unsigned int ) DECL_TRACE_METHOD_B( unsigned long ) -#ifdef SYSTEMC_64BIT_PATCHES +# ifdef SYSTEMC_64BIT_PATCHES DECL_TRACE_METHOD_B( unsigned long long) -#endif +# endif DECL_TRACE_METHOD_B( char ) DECL_TRACE_METHOD_B( short ) DECL_TRACE_METHOD_B( int ) @@ -131,12 +129,13 @@ private: DECL_TRACE_METHOD_A( sc_dt::sc_bv_base ) DECL_TRACE_METHOD_A( sc_dt::sc_lv_base ) + // clang-format on //-------------------------------------------------- -# elif (SYSTEMC_VERSION>20011000) +#elif (SYSTEMC_VERSION > 20011000) // SystemC 2.0.1 -# define DECL_TRACE_METHOD_A(tp) \ - virtual void trace(const tp& object, const sc_string& name); + // clang-format off +# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const sc_string& name); # define DECL_TRACE_METHOD_B(tp) \ virtual void trace(const tp& object, const sc_string& name, int width); @@ -152,13 +151,13 @@ private: DECL_TRACE_METHOD_B( unsigned short ) DECL_TRACE_METHOD_B( unsigned int ) DECL_TRACE_METHOD_B( unsigned long ) -#ifdef SYSTEMC_64BIT_PATCHES +# ifdef SYSTEMC_64BIT_PATCHES DECL_TRACE_METHOD_B( unsigned long long) -#endif -#if (SYSTEMC_VERSION>20041000) +# endif +# if (SYSTEMC_VERSION > 20041000) DECL_TRACE_METHOD_B( unsigned long long) DECL_TRACE_METHOD_B( long long) -#endif +# endif DECL_TRACE_METHOD_B( char ) DECL_TRACE_METHOD_B( short ) DECL_TRACE_METHOD_B( int ) @@ -175,12 +174,13 @@ private: DECL_TRACE_METHOD_A( sc_fxnum_fast ) DECL_TRACE_METHOD_A( sc_bv_base ) DECL_TRACE_METHOD_A( sc_lv_base ) + // clang-format on //-------------------------------------------------- -# else +#else // SystemC 1.2.1beta -# define DECL_TRACE_METHOD_A(tp) \ - virtual void trace(const tp& object, const sc_string& name); + // clang-format off +# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const sc_string& name); # define DECL_TRACE_METHOD_B(tp) \ virtual void trace(const tp& object, const sc_string& name, int width); @@ -213,9 +213,10 @@ private: DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base ) DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base ) # endif + // clang-format on -# undef DECL_TRACE_METHOD_A -# undef DECL_TRACE_METHOD_B +#undef DECL_TRACE_METHOD_A +#undef DECL_TRACE_METHOD_B }; #endif // Guard diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 11d6ae561..eaba5a782 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -23,9 +23,6 @@ #define _VERILATED_VPI_CPP_ -#if VM_SC -# include "verilated_sc.h" -#endif #include "verilated.h" #include "verilated_vpi.h" #include "verilated_imp.h" @@ -44,11 +41,11 @@ //====================================================================== // Internal macros -#define _VL_VPI_INTERNAL VerilatedVpiImp::error_info()->setMessage(vpiInternal)->setMessage -#define _VL_VPI_SYSTEM VerilatedVpiImp::error_info()->setMessage(vpiSystem )->setMessage -#define _VL_VPI_ERROR VerilatedVpiImp::error_info()->setMessage(vpiError )->setMessage -#define _VL_VPI_WARNING VerilatedVpiImp::error_info()->setMessage(vpiWarning )->setMessage -#define _VL_VPI_NOTICE VerilatedVpiImp::error_info()->setMessage(vpiNotice )->setMessage +#define _VL_VPI_INTERNAL VerilatedVpiImp::error_info()->setMessage(vpiInternal)->setMessage +#define _VL_VPI_SYSTEM VerilatedVpiImp::error_info()->setMessage(vpiSystem)->setMessage +#define _VL_VPI_ERROR VerilatedVpiImp::error_info()->setMessage(vpiError)->setMessage +#define _VL_VPI_WARNING VerilatedVpiImp::error_info()->setMessage(vpiWarning)->setMessage +#define _VL_VPI_NOTICE VerilatedVpiImp::error_info()->setMessage(vpiNotice)->setMessage #define _VL_VPI_ERROR_RESET VerilatedVpiImp::error_info()->resetError // Not supported yet @@ -73,15 +70,15 @@ public: // We reserve word zero for the next pointer, as that's safer in case a // dangling reference to the original remains around. static const size_t chunk = 96; - if (VL_UNCOVERABLE(size>chunk)) VL_FATAL_MT(__FILE__, __LINE__, "", "increase chunk"); + if (VL_UNCOVERABLE(size > chunk)) VL_FATAL_MT(__FILE__, __LINE__, "", "increase chunk"); if (VL_LIKELY(t_freeHead)) { vluint8_t* newp = t_freeHead; t_freeHead = *(reinterpret_cast(newp)); - return newp+8; + return newp + 8; } // +8: 8 bytes for next - vluint8_t* newp = reinterpret_cast(::operator new(chunk+8)); - return newp+8; + vluint8_t* newp = reinterpret_cast(::operator new(chunk + 8)); + return newp + 8; } inline static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE { vluint8_t* oldp = (static_cast(obj)) - 8; @@ -103,16 +100,18 @@ public: virtual vpiHandle dovpi_scan() { return 0; } }; -typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data *); +typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data*); class VerilatedVpioCb : public VerilatedVpio { - t_cb_data m_cbData; - s_vpi_value m_value; - QData m_time; + t_cb_data m_cbData; + s_vpi_value m_value; + QData m_time; + public: // cppcheck-suppress uninitVar // m_value VerilatedVpioCb(const t_cb_data* cbDatap, QData time) - : m_cbData(*cbDatap), m_time(time) { + : m_cbData(*cbDatap) + , m_time(time) { m_value.format = cbDatap->value ? cbDatap->value->format : vpiSuppressVal; m_cbData.value = &m_value; } @@ -128,9 +127,11 @@ public: }; class VerilatedVpioConst : public VerilatedVpio { - vlsint32_t m_num; + vlsint32_t m_num; + public: - explicit VerilatedVpioConst(vlsint32_t num) : m_num(num) {} + explicit VerilatedVpioConst(vlsint32_t num) + : m_num(num) {} virtual ~VerilatedVpioConst() {} static inline VerilatedVpioConst* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); @@ -142,8 +143,11 @@ public: class VerilatedVpioRange : public VerilatedVpio { const VerilatedRange* m_range; vlsint32_t m_iteration; + public: - explicit VerilatedVpioRange(const VerilatedRange* range) : m_range(range), m_iteration(0) {} + explicit VerilatedVpioRange(const VerilatedRange* range) + : m_range(range) + , m_iteration(0) {} virtual ~VerilatedVpioRange() {} static inline VerilatedVpioRange* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); @@ -165,7 +169,8 @@ public: class VerilatedVpioScope : public VerilatedVpio { protected: - const VerilatedScope* m_scopep; + const VerilatedScope* m_scopep; + public: explicit VerilatedVpioScope(const VerilatedScope* scopep) : m_scopep(scopep) {} @@ -180,24 +185,27 @@ public: }; class VerilatedVpioVar : public VerilatedVpio { - const VerilatedVar* m_varp; - const VerilatedScope* m_scopep; - vluint8_t* m_prevDatap; // Previous value of data, for cbValueChange + const VerilatedVar* m_varp; + const VerilatedScope* m_scopep; + vluint8_t* m_prevDatap; // Previous value of data, for cbValueChange union { vluint8_t u8[4]; vluint32_t u32; - } m_mask; // memoized variable mask - vluint32_t m_entSize; // memoized variable size + } m_mask; // memoized variable mask + vluint32_t m_entSize; // memoized variable size protected: - void* m_varDatap; // varp()->datap() adjusted for array entries - vlsint32_t m_index; + void* m_varDatap; // varp()->datap() adjusted for array entries + vlsint32_t m_index; const VerilatedRange& get_range() const { // Determine number of dimensions and return outermost - return (m_varp->dims()>1) ? m_varp->unpacked() : m_varp->packed(); + return (m_varp->dims() > 1) ? m_varp->unpacked() : m_varp->packed(); } + public: VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep) - : m_varp(varp), m_scopep(scopep), m_index(0) { + : m_varp(varp) + , m_scopep(scopep) + , m_index(0) { m_prevDatap = NULL; m_mask.u32 = VL_MASK_I(varp->packed().elements()); m_entSize = varp->entSize(); @@ -216,21 +224,21 @@ public: vluint32_t entSize() const { return m_entSize; } vluint32_t index() { return m_index; } virtual vluint32_t type() const { - return (varp()->dims()>1) ? vpiMemory : vpiReg; // but might be wire, logic + return (varp()->dims() > 1) ? vpiMemory : vpiReg; // but might be wire, logic } virtual vluint32_t size() const { return get_range().elements(); } virtual const VerilatedRange* rangep() const { return &get_range(); } virtual const char* name() const { return m_varp->name(); } virtual const char* fullname() const { static VL_THREAD_LOCAL std::string out; - out = std::string(m_scopep->name())+"."+name(); + out = std::string(m_scopep->name()) + "." + name(); return out.c_str(); } void* prevDatap() const { return m_prevDatap; } void* varDatap() const { return m_varDatap; } void createPrevDatap() { if (VL_UNLIKELY(!m_prevDatap)) { - m_prevDatap = new vluint8_t [entSize()]; + m_prevDatap = new vluint8_t[entSize()]; memcpy(prevDatap(), varp()->datap(), entSize()); } } @@ -249,23 +257,26 @@ public: return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const { return vpiMemoryWord; } - virtual vluint32_t size() const { return varp()->packed().elements(); } + virtual vluint32_t size() const { return varp()->packed().elements(); } virtual const VerilatedRange* rangep() const { return &(varp()->packed()); } virtual const char* fullname() const { static VL_THREAD_LOCAL std::string out; - char num[20]; sprintf(num, "%d", m_index); - out = std::string(scopep()->name())+"."+name()+"["+num+"]"; + char num[20]; + sprintf(num, "%d", m_index); + out = std::string(scopep()->name()) + "." + name() + "[" + num + "]"; return out.c_str(); } }; class VerilatedVpioVarIter : public VerilatedVpio { - const VerilatedScope* m_scopep; + const VerilatedScope* m_scopep; VerilatedVarNameMap::const_iterator m_it; bool m_started; + public: explicit VerilatedVpioVarIter(const VerilatedScope* scopep) - : m_scopep(scopep), m_started(false) { } + : m_scopep(scopep) + , m_started(false) {} virtual ~VerilatedVpioVarIter() {} static inline VerilatedVpioVarIter* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); @@ -274,38 +285,42 @@ public: virtual vpiHandle dovpi_scan() { if (VL_LIKELY(m_scopep->varsp())) { VerilatedVarNameMap* varsp = m_scopep->varsp(); - if (VL_UNLIKELY(!m_started)) { m_it = varsp->begin(); m_started=true; } - else if (VL_UNLIKELY(m_it == varsp->end())) return 0; - else ++m_it; + if (VL_UNLIKELY(!m_started)) { + m_it = varsp->begin(); + m_started = true; + } else if (VL_UNLIKELY(m_it == varsp->end())) { + return 0; + } else { + ++m_it; + } if (m_it == varsp->end()) return 0; - return ((new VerilatedVpioVar(&(m_it->second), m_scopep)) - ->castVpiHandle()); + return ((new VerilatedVpioVar(&(m_it->second), m_scopep))->castVpiHandle()); } return 0; // End of list - only one deep } }; class VerilatedVpioMemoryWordIter : public VerilatedVpio { - const vpiHandle m_handle; - const VerilatedVar* m_varp; - vlsint32_t m_iteration; - vlsint32_t m_direction; - bool m_done; + const vpiHandle m_handle; + const VerilatedVar* m_varp; + vlsint32_t m_iteration; + vlsint32_t m_direction; + bool m_done; + public: VerilatedVpioMemoryWordIter(const vpiHandle handle, const VerilatedVar* varp) - : m_handle(handle), m_varp(varp), m_iteration(varp->unpacked().right()), - m_direction(VL_LIKELY(varp->unpacked().left() > varp->unpacked().right()) - ? 1 : -1), - m_done(false) { } + : m_handle(handle) + , m_varp(varp) + , m_iteration(varp->unpacked().right()) + , m_direction(VL_LIKELY(varp->unpacked().left() > varp->unpacked().right()) ? 1 : -1) + , m_done(false) {} virtual ~VerilatedVpioMemoryWordIter() {} static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const { return vpiIterator; } void iterationInc() { - if (!(m_done = (m_iteration == m_varp->unpacked().left()))) { - m_iteration += m_direction; - } + if (!(m_done = (m_iteration == m_varp->unpacked().left()))) m_iteration += m_direction; } virtual vpiHandle dovpi_scan() { vpiHandle result; @@ -319,9 +334,10 @@ public: class VerilatedVpioModule : public VerilatedVpioScope { const char* m_name; const char* m_fullname; + public: explicit VerilatedVpioModule(const VerilatedScope* modulep) - : VerilatedVpioScope(modulep) { + : VerilatedVpioScope(modulep) { m_fullname = m_scopep->name(); if (strncmp(m_fullname, "TOP.", 4) == 0) m_fullname += 4; m_name = m_scopep->identifier(); @@ -335,10 +351,12 @@ public: }; class VerilatedVpioModuleIter : public VerilatedVpio { - const std::vector *m_vec; + const std::vector* m_vec; std::vector::const_iterator m_it; + public: - explicit VerilatedVpioModuleIter(const std::vector& vec) : m_vec(&vec) { + explicit VerilatedVpioModuleIter(const std::vector& vec) + : m_vec(&vec) { m_it = m_vec->begin(); } virtual ~VerilatedVpioModuleIter() {} @@ -347,9 +365,7 @@ public: } virtual vluint32_t type() const { return vpiIterator; } virtual vpiHandle dovpi_scan() { - if (m_it == m_vec->end()) { - return 0; - } + if (m_it == m_vec->end()) return 0; const VerilatedScope* modp = *m_it++; return (new VerilatedVpioModule(modp))->castVpiHandle(); } @@ -359,8 +375,8 @@ public: struct VerilatedVpiTimedCbsCmp { /// Ordering sets keyed by time, then callback descriptor - bool operator()(const std::pair& a, - const std::pair& b) const { + bool operator()(const std::pair& a, + const std::pair& b) const { if (a.first < b.first) return 1; if (a.first > b.first) return 0; return a.second < b.second; @@ -370,23 +386,23 @@ struct VerilatedVpiTimedCbsCmp { class VerilatedVpiError; class VerilatedVpiImp { - enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime+1 }; // Maxium callback reason + enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime + 1 }; // Maxium callback reason typedef std::list VpioCbList; - typedef std::set,VerilatedVpiTimedCbsCmp > VpioTimedCbs; + typedef std::set, VerilatedVpiTimedCbsCmp> VpioTimedCbs; struct product_info { PLI_BYTE8* product; }; - VpioCbList m_cbObjLists[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason - VpioTimedCbs m_timedCbs; // Time based callbacks - VerilatedVpiError* m_errorInfop; // Container for vpi error info + VpioCbList m_cbObjLists[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason + VpioTimedCbs m_timedCbs; // Time based callbacks + VerilatedVpiError* m_errorInfop; // Container for vpi error info VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread static VerilatedVpiImp s_s; // Singleton public: - VerilatedVpiImp() { m_errorInfop=NULL; } + VerilatedVpiImp() { m_errorInfop = NULL; } ~VerilatedVpiImp() {} static void assertOneCheck() { s_s.m_assertOne.check(); } static void cbReasonAdd(VerilatedVpioCb* vop) { @@ -407,49 +423,46 @@ public: VpioCbList& cbObjList = s_s.m_cbObjLists[cbp->reason()]; // We do not remove it now as we may be iterating the list, // instead set to NULL and will cleanup later - for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end(); ++it) { + for (VpioCbList::iterator it = cbObjList.begin(); it != cbObjList.end(); ++it) { if (*it == cbp) *it = NULL; } } static void cbTimedRemove(VerilatedVpioCb* cbp) { - VpioTimedCbs::iterator it=s_s.m_timedCbs.find(std::make_pair(cbp->time(), cbp)); - if (VL_LIKELY(it != s_s.m_timedCbs.end())) { - s_s.m_timedCbs.erase(it); - } + VpioTimedCbs::iterator it = s_s.m_timedCbs.find(std::make_pair(cbp->time(), cbp)); + if (VL_LIKELY(it != s_s.m_timedCbs.end())) { s_s.m_timedCbs.erase(it); } } static void callTimedCbs() VL_MT_UNSAFE_ONE { assertOneCheck(); QData time = VL_TIME_Q(); - for (VpioTimedCbs::iterator it=s_s.m_timedCbs.begin(); it!=s_s.m_timedCbs.end(); ) { + for (VpioTimedCbs::iterator it = s_s.m_timedCbs.begin(); it != s_s.m_timedCbs.end();) { if (VL_UNLIKELY(it->first <= time)) { VerilatedVpioCb* vop = it->second; VpioTimedCbs::iterator last_it = it; ++it; // Timed callbacks are one-shot s_s.m_timedCbs.erase(last_it); VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: timed_callback %p\n", vop);); - (vop->cb_rtnp()) (vop->cb_datap()); + (vop->cb_rtnp())(vop->cb_datap()); + } else { + ++it; } - else { ++it; } } } static QData cbNextDeadline() { - VpioTimedCbs::const_iterator it=s_s.m_timedCbs.begin(); - if (VL_LIKELY(it != s_s.m_timedCbs.end())) { - return it->first; - } + VpioTimedCbs::const_iterator it = s_s.m_timedCbs.begin(); + if (VL_LIKELY(it != s_s.m_timedCbs.end())) return it->first; return ~VL_ULL(0); // maxquad } static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE { VpioCbList& cbObjList = s_s.m_cbObjLists[reason]; bool called = false; - for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end();) { + for (VpioCbList::iterator it = cbObjList.begin(); it != cbObjList.end();) { if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup it = cbObjList.erase(it); continue; } VerilatedVpioCb* vop = *it++; VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: reason_callback %d %p\n", reason, vop);); - (vop->cb_rtnp()) (vop->cb_datap()); + (vop->cb_rtnp())(vop->cb_datap()); called = true; } return called; @@ -459,7 +472,7 @@ public: VpioCbList& cbObjList = s_s.m_cbObjLists[cbValueChange]; typedef std::set VpioVarSet; VpioVarSet update; // set of objects to update after callbacks - for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end();) { + for (VpioCbList::iterator it = cbObjList.begin(); it != cbObjList.end();) { if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup it = cbObjList.erase(it); continue; @@ -469,19 +482,18 @@ public: void* newDatap = varop->varDatap(); void* prevDatap = varop->prevDatap(); // Was malloced when we added the callback VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p\n", - varop->fullname(), - *((CData*)newDatap), *((CData*)prevDatap), - newDatap, prevDatap);); + varop->fullname(), *((CData*)newDatap), + *((CData*)prevDatap), newDatap, prevDatap);); if (memcmp(prevDatap, newDatap, varop->entSize()) != 0) { - VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %p %s v[0]=%d\n", - vop, varop->fullname(), *((CData*)newDatap));); + VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %p %s v[0]=%d\n", vop, + varop->fullname(), *((CData*)newDatap));); update.insert(varop); vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value); - (vop->cb_rtnp()) (vop->cb_datap()); + (vop->cb_rtnp())(vop->cb_datap()); } } } - for (VpioVarSet::const_iterator it=update.begin(); it!=update.end(); ++it) { + for (VpioVarSet::const_iterator it = update.begin(); it != update.end(); ++it) { memcpy((*it)->prevDatap(), (*it)->varDatap(), (*it)->entSize()); } } @@ -495,7 +507,7 @@ class VerilatedVpiError { t_vpi_error_info m_errorInfo; bool m_flag; char m_buff[VL_VPI_LINE_SIZE]; - void setError(PLI_BYTE8 *message, PLI_BYTE8 *code, PLI_BYTE8 *file, PLI_INT32 line) { + void setError(PLI_BYTE8* message, PLI_BYTE8* code, PLI_BYTE8* file, PLI_INT32 line) { m_errorInfo.message = message; m_errorInfo.file = file; m_errorInfo.line = line; @@ -512,9 +524,10 @@ class VerilatedVpiError { // as it will be overwritten. VerilatedVpiImp::callCbs(cbPLIError); } -public: - VerilatedVpiError() : m_flag(false) { +public: + VerilatedVpiError() + : m_flag(false) { m_buff[0] = '\0'; m_errorInfo.product = const_cast(Verilated::productName()); } @@ -565,30 +578,22 @@ VL_THREAD_LOCAL vluint8_t* VerilatedVpio::t_freeHead = NULL; //====================================================================== // VerilatedVpi implementation -void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { - VerilatedVpiImp::callTimedCbs(); -} +void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callTimedCbs(); } -void VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { - VerilatedVpiImp::callValueCbs(); -} +void VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callValueCbs(); } bool VerilatedVpi::callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE { return VerilatedVpiImp::callCbs(reason); } -QData VerilatedVpi::cbNextDeadline() VL_MT_UNSAFE_ONE { - return VerilatedVpiImp::cbNextDeadline(); -} +QData VerilatedVpi::cbNextDeadline() VL_MT_UNSAFE_ONE { return VerilatedVpiImp::cbNextDeadline(); } //====================================================================== // VerilatedVpiImp implementation VerilatedVpiError* VerilatedVpiImp::error_info() VL_MT_UNSAFE_ONE { VerilatedVpiImp::assertOneCheck(); - if (VL_UNLIKELY(!s_s.m_errorInfop)) { - s_s.m_errorInfop = new VerilatedVpiError(); - } + if (VL_UNLIKELY(!s_s.m_errorInfop)) { s_s.m_errorInfop = new VerilatedVpiError(); } return s_s.m_errorInfop; } @@ -596,6 +601,7 @@ VerilatedVpiError* VerilatedVpiImp::error_info() VL_MT_UNSAFE_ONE { // VerilatedVpiError Methods const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE { + // clang-format off static const char* const names[] = { "*undefined*", "vpiBinStrVal", @@ -617,10 +623,12 @@ const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE { "vpiRawTwoStateVal", "vpiRawFourStateVal", }; + // clang-format on if (vpiVal < 0) return names[0]; - return names[(vpiVal<=vpiRawFourStateVal) ? vpiVal : 0]; + return names[(vpiVal <= vpiRawFourStateVal) ? vpiVal : 0]; } const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE { + // clang-format off static const char* const names[] = { "*undefined*", "vpiAlways", @@ -759,10 +767,12 @@ const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE { "vpiGenScope", "vpiGenVar" }; + // clang-format on if (vpiVal < 0) return names[0]; - return names[(vpiVal<=vpiGenVar) ? vpiVal : 0]; + return names[(vpiVal <= vpiGenVar) ? vpiVal : 0]; } const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE { + // clang-format off static const char* const names[] = { "vpiCondition", "vpiDelay", @@ -799,13 +809,13 @@ const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE { "vpiPrimitive", "vpiStmt" }; - if (vpiVal>vpiStmt || vpiVal vpiStmt || vpiVal < vpiCondition) return "*undefined*"; + return names[vpiVal - vpiCondition]; } const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_SAFE { + // clang-format off static const char* const names[] = { "*undefined*", "cbValueChange", @@ -840,11 +850,13 @@ const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_ "cbNBASynch", "cbAtEndOfSimTime" }; + // clang-format on if (vpiVal < 0) return names[0]; - return names[(vpiVal<=cbAtEndOfSimTime) ? vpiVal : 0]; + return names[(vpiVal <= cbAtEndOfSimTime) ? vpiVal : 0]; } const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE { + // clang-format off static const char* const names[] = { "*undefined or other*", "vpiType", @@ -922,10 +934,9 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE { "vpiIsMemory", "vpiIsProtected" }; - if (vpiVal == vpiUndefined) { - return "vpiUndefined"; - } - return names[(vpiVal<=vpiIsProtected) ? vpiVal : 0]; + // clang-format on + if (vpiVal == vpiUndefined) return "vpiUndefined"; + return names[(vpiVal <= vpiIsProtected) ? vpiVal : 0]; } #define CHECK_RESULT_CSTR(got, exp) \ @@ -941,9 +952,7 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE { CHECK_RESULT_CSTR(strVal, #enum); \ } while (0) -void VerilatedVpi::selfTest() VL_MT_UNSAFE_ONE { - VerilatedVpiError::selfTest(); -} +void VerilatedVpi::selfTest() VL_MT_UNSAFE_ONE { VerilatedVpiError::selfTest(); } void VerilatedVpiError::selfTest() VL_MT_UNSAFE_ONE { VerilatedVpiImp::assertOneCheck(); @@ -992,21 +1001,21 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) { case cbAfterDelay: { QData time = 0; if (cb_data_p->time) time = _VL_SET_QII(cb_data_p->time->high, cb_data_p->time->low); - VerilatedVpioCb* vop = new VerilatedVpioCb(cb_data_p, VL_TIME_Q()+time); + VerilatedVpioCb* vop = new VerilatedVpioCb(cb_data_p, VL_TIME_Q() + time); VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_register_cb %d %p delay=%" VL_PRI64 "u\n", cb_data_p->reason, vop, time);); VerilatedVpiImp::cbTimedAdd(vop); return vop->castVpiHandle(); } - case cbReadWriteSynch: // FALLTHRU // Supported via vlt_main.cpp - case cbReadOnlySynch: // FALLTHRU // Supported via vlt_main.cpp - case cbNextSimTime: // FALLTHRU // Supported via vlt_main.cpp - case cbStartOfSimulation: // FALLTHRU // Supported via vlt_main.cpp - case cbEndOfSimulation: // FALLTHRU // Supported via vlt_main.cpp - case cbValueChange: // FALLTHRU // Supported via vlt_main.cpp - case cbPLIError: // FALLTHRU // NOP, but need to return handle, so make object - case cbEnterInteractive: // FALLTHRU // NOP, but need to return handle, so make object - case cbExitInteractive: // FALLTHRU // NOP, but need to return handle, so make object + case cbReadWriteSynch: // FALLTHRU // Supported via vlt_main.cpp + case cbReadOnlySynch: // FALLTHRU // Supported via vlt_main.cpp + case cbNextSimTime: // FALLTHRU // Supported via vlt_main.cpp + case cbStartOfSimulation: // FALLTHRU // Supported via vlt_main.cpp + case cbEndOfSimulation: // FALLTHRU // Supported via vlt_main.cpp + case cbValueChange: // FALLTHRU // Supported via vlt_main.cpp + case cbPLIError: // FALLTHRU // NOP, but need to return handle, so make object + case cbEnterInteractive: // FALLTHRU // NOP, but need to return handle, so make object + case cbExitInteractive: // FALLTHRU // NOP, but need to return handle, so make object case cbInteractiveScopeChange: { // FALLTHRU // NOP, but need to return handle, so make object VerilatedVpioCb* vop = new VerilatedVpioCb(cb_data_p, 0); VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_register_cb %d %p\n", cb_data_p->reason, vop);); @@ -1014,8 +1023,8 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) { return vop->castVpiHandle(); } default: - _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported callback type %s", - VL_FUNC, VerilatedVpiError::strFromVpiCallbackReason(cb_data_p->reason)); + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported callback type %s", VL_FUNC, + VerilatedVpiError::strFromVpiCallbackReason(cb_data_p->reason)); return NULL; }; } @@ -1072,16 +1081,14 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) { std::string scopename; const char* dotp = strrchr(namep, '.'); if (VL_LIKELY(dotp)) { - baseNamep = dotp+1; - scopename = std::string(namep, dotp-namep); + baseNamep = dotp + 1; + scopename = std::string(namep, dotp - namep); } if (scopename.find('.') == std::string::npos) { // This is a toplevel, hence search in our TOP ports first. scopep = Verilated::scopeFind("TOP"); - if (scopep) { - varp = scopep->varFind(baseNamep); - } + if (scopep) { varp = scopep->varFind(baseNamep); } } if (!varp) { scopep = Verilated::scopeFind(scopename.c_str()); @@ -1100,16 +1107,18 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) { VerilatedVpioVar* varop = VerilatedVpioVar::castp(object); _VL_VPI_ERROR_RESET(); if (VL_LIKELY(varop)) { - if (varop->varp()->dims()<2) return 0; + if (varop->varp()->dims() < 2) return 0; if (VL_LIKELY(varop->varp()->unpacked().left() >= varop->varp()->unpacked().right())) { if (VL_UNLIKELY(indx > varop->varp()->unpacked().left() - || indx < varop->varp()->unpacked().right())) return 0; + || indx < varop->varp()->unpacked().right())) + return 0; return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx, - indx - varop->varp()->unpacked().right())) + indx - varop->varp()->unpacked().right())) ->castVpiHandle(); } if (VL_UNLIKELY(indx < varop->varp()->unpacked().left() - || indx > varop->varp()->unpacked().right())) return 0; + || indx > varop->varp()->unpacked().right())) + return 0; return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx, indx - varop->varp()->unpacked().left())) ->castVpiHandle(); @@ -1176,9 +1185,9 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) { if (vop->varp()->dims() < 2) return 0; if (vop->varp()->dims() > 2) { _VL_VPI_WARNING(__FILE__, __LINE__, - "%s: %s, object %s has unsupported number of indices (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiMethod(type), - vop->fullname() , vop->varp()->dims()); + "%s: %s, object %s has unsupported number of indices (%d)", VL_FUNC, + VerilatedVpiError::strFromVpiMethod(type), vop->fullname(), + vop->varp()->dims()); } return (new VerilatedVpioMemoryWordIter(object, vop->varp()))->castVpiHandle(); } @@ -1189,25 +1198,24 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) { // Unsupported is multidim list if (vop->varp()->dims() > 2) { _VL_VPI_WARNING(__FILE__, __LINE__, - "%s: %s, object %s has unsupported number of indices (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiMethod(type), - vop->fullname() , vop->varp()->dims()); + "%s: %s, object %s has unsupported number of indices (%d)", VL_FUNC, + VerilatedVpiError::strFromVpiMethod(type), vop->fullname(), + vop->varp()->dims()); } return ((new VerilatedVpioRange(vop->rangep()))->castVpiHandle()); } case vpiReg: { VerilatedVpioScope* vop = VerilatedVpioScope::castp(object); if (VL_UNLIKELY(!vop)) return 0; - return ((new VerilatedVpioVarIter(vop->scopep())) - ->castVpiHandle()); + return ((new VerilatedVpioVarIter(vop->scopep()))->castVpiHandle()); } case vpiModule: { VerilatedVpioModule* vop = VerilatedVpioModule::castp(object); const VerilatedHierarchyMap* map = VerilatedImp::hierarchyMap(); - const VerilatedScope *mod = vop ? vop->scopep() : NULL; + const VerilatedScope* mod = vop ? vop->scopep() : NULL; VerilatedHierarchyMap::const_iterator it = map->find(const_cast(mod)); if (it == map->end()) return 0; - return ((new VerilatedVpioModuleIter(it->second))->castVpiHandle()); + return ((new VerilatedVpioModuleIter(it->second))->castVpiHandle()); } default: _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", @@ -1253,7 +1261,7 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) { case vpiVector: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); if (VL_UNLIKELY(!vop)) return 0; - return (property==vpiVector) ^ (vop->varp()->dims()==0); + return (property == vpiVector) ^ (vop->varp()->dims() == 0); } case vpiSize: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); @@ -1272,7 +1280,7 @@ PLI_INT64 vpi_get64(PLI_INT32 /*property*/, vpiHandle /*object*/) { return 0; } -PLI_BYTE8 *vpi_get_str(PLI_INT32 property, vpiHandle object) { +PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) { VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_get_str %d %p\n", property, object);); VerilatedVpiImp::assertOneCheck(); VerilatedVpio* vop = VerilatedVpio::castp(object); @@ -1307,9 +1315,9 @@ void vpi_put_delays(vpiHandle /*object*/, p_vpi_delay /*delay_p*/) { _VL_VPI_UNI void vpi_get_value(vpiHandle object, p_vpi_value value_p) { // Maximum required size is for binary string, one byte per bit plus null termination - static VL_THREAD_LOCAL char outStr[1+VL_MULS_MAX_WORDS*32]; + static VL_THREAD_LOCAL char outStr[1 + VL_MULS_MAX_WORDS * 32]; // cppcheck-suppress variableScope - static VL_THREAD_LOCAL int outStrSz = sizeof(outStr)-1; + static VL_THREAD_LOCAL int outStrSz = sizeof(outStr) - 1; VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_get_value %p\n", object);); VerilatedVpiImp::assertOneCheck(); _VL_VPI_ERROR_RESET(); @@ -1320,7 +1328,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { if (value_p->format == vpiVectorVal) { // Vector pointer must come from our memory pool // It only needs to persist until the next vpi_get_value - static VL_THREAD_LOCAL t_vpi_vecval out[VL_MULS_MAX_WORDS*2]; + static VL_THREAD_LOCAL t_vpi_vecval out[VL_MULS_MAX_WORDS * 2]; value_p->value.vector = out; switch (vop->varp()->vltype()) { case VLVT_UINT8: @@ -1338,11 +1346,12 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { case VLVT_WDATA: { int words = VL_WORDS_I(vop->varp()->packed().elements()); if (VL_UNCOVERABLE(words >= VL_MULS_MAX_WORDS)) { - VL_FATAL_MT(__FILE__, __LINE__, "", - "vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile"); + VL_FATAL_MT( + __FILE__, __LINE__, "", + "vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile"); } WDataInP datap = (reinterpret_cast(vop->varDatap())); - for (int i=0; i(vop->varDatap())); - out[1].aval = static_cast(data>>VL_ULL(32)); + out[1].aval = static_cast(data >> VL_ULL(32)); out[1].bval = 0; out[0].aval = static_cast(data); out[0].bval = 0; return; } default: { - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; } } @@ -1375,24 +1383,25 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { CData* datap = (reinterpret_cast(vop->varDatap())); int i; if (bits > outStrSz) { - // limit maximum size of output to size of buffer to prevent overrun. - bits = outStrSz; - _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s" - " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bits); + // limit maximum size of output to size of buffer to prevent overrun. + bits = outStrSz; + _VL_VPI_WARNING( + __FILE__, __LINE__, + "%s: Truncating string value of %s for %s" + " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), + vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bits); } - for (i=0; i>3]>>(i&7))&1; - outStr[bits-i-1] = val?'1':'0'; + for (i = 0; i < bits; ++i) { + char val = (datap[i >> 3] >> (i & 7)) & 1; + outStr[bits - i - 1] = val ? '1' : '0'; } outStr[i] = '\0'; return; } default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; } } else if (value_p->format == vpiOctStrVal) { @@ -1403,47 +1412,48 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { case VLVT_UINT32: case VLVT_UINT64: case VLVT_WDATA: { - int chars = (vop->varp()->packed().elements()+2)/3; + int chars = (vop->varp()->packed().elements() + 2) / 3; int bytes = VL_BYTES_I(vop->varp()->packed().elements()); CData* datap = (reinterpret_cast(vop->varDatap())); int i; if (chars > outStrSz) { // limit maximum size of output to size of buffer to prevent overrun. - _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s" - " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars); + _VL_VPI_WARNING( + __FILE__, __LINE__, + "%s: Truncating string value of %s for %s" + " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), + vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars); chars = outStrSz; } - for (i=0; i>= idx.rem; - if (i==(chars-1)) { + if (i == (chars - 1)) { // most signifcant char, mask off non existant bits when vector // size is not a multiple of 3 unsigned int rem = vop->varp()->packed().elements() % 3; if (rem) { // generate bit mask & zero non existant bits - val &= (1<format), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; } } else if (value_p->format == vpiDecStrVal) { @@ -1451,26 +1461,31 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { switch (vop->varp()->vltype()) { // outStrSz does not include NULL termination so add one case VLVT_UINT8: - VL_SNPRINTF(outStr, outStrSz+1, "%hhu", - static_cast(*(reinterpret_cast(vop->varDatap())))); + VL_SNPRINTF( + outStr, outStrSz + 1, "%hhu", + static_cast(*(reinterpret_cast(vop->varDatap())))); return; case VLVT_UINT16: - VL_SNPRINTF(outStr, outStrSz+1, "%hu", - static_cast(*(reinterpret_cast(vop->varDatap())))); + VL_SNPRINTF( + outStr, outStrSz + 1, "%hu", + static_cast(*(reinterpret_cast(vop->varDatap())))); return; case VLVT_UINT32: - VL_SNPRINTF(outStr, outStrSz+1, "%u", - static_cast(*(reinterpret_cast(vop->varDatap())))); + VL_SNPRINTF( + outStr, outStrSz + 1, "%u", + static_cast(*(reinterpret_cast(vop->varDatap())))); return; case VLVT_UINT64: - VL_SNPRINTF(outStr, outStrSz+1, "%llu", - static_cast(*(reinterpret_cast(vop->varDatap())))); + VL_SNPRINTF( + outStr, outStrSz + 1, "%llu", + static_cast(*(reinterpret_cast(vop->varDatap())))); return; default: strcpy(outStr, "-1"); _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s, maximum limit is 64 bits", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), + vop->fullname()); return; } } else if (value_p->format == vpiHexStrVal) { @@ -1481,37 +1496,38 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { case VLVT_UINT32: case VLVT_UINT64: case VLVT_WDATA: { - int chars = (vop->varp()->packed().elements()+3)>>2; + int chars = (vop->varp()->packed().elements() + 3) >> 2; CData* datap = (reinterpret_cast(vop->varDatap())); int i; if (chars > outStrSz) { - // limit maximum size of output to size of buffer to prevent overrun. - _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s" - " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars); - chars = outStrSz; + // limit maximum size of output to size of buffer to prevent overrun. + _VL_VPI_WARNING( + __FILE__, __LINE__, + "%s: Truncating string value of %s for %s" + " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), + vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars); + chars = outStrSz; } - for (i=0; i>1]>>((i&1)<<2))&15; - if (i==(chars-1)) { + for (i = 0; i < chars; ++i) { + char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15; + if (i == (chars - 1)) { // most signifcant char, mask off non existant bits when vector // size is not a multiple of 4 unsigned int rem = vop->varp()->packed().elements() & 3; if (rem) { // generate bit mask & zero non existant bits - val &= (1<(val)]; + outStr[chars - i - 1] = "0123456789abcdef"[static_cast(val)]; } outStr[i] = '\0'; return; } default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; } } else if (value_p->format == vpiStringVal) { @@ -1526,25 +1542,26 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { CData* datap = (reinterpret_cast(vop->varDatap())); int i; if (bytes > outStrSz) { - // limit maximum size of output to size of buffer to prevent overrun. - _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s" - " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bytes); - bytes = outStrSz; + // limit maximum size of output to size of buffer to prevent overrun. + _VL_VPI_WARNING( + __FILE__, __LINE__, + "%s: Truncating string value of %s for %s" + " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), + vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bytes); + bytes = outStrSz; } - for (i=0; iformat), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; } } else if (value_p->format == vpiIntVal) { @@ -1562,9 +1579,8 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { case VLVT_UINT64: // FALLTHRU default: value_p->value.integer = 0; - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; } } else if (value_p->format == vpiSuppressVal) { @@ -1573,18 +1589,17 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s", VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; - } - else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) { + } else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) { if (value_p->format == vpiIntVal) { - value_p->value.integer = vop->num(); - return; + value_p->value.integer = vop->num(); + return; } - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; } - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format)); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format)); } vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time_p*/, @@ -1593,14 +1608,14 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time VerilatedVpiImp::assertOneCheck(); _VL_VPI_ERROR_RESET(); if (VL_UNLIKELY(!value_p)) { - _VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value with NULL value pointer"); - return 0; + _VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value with NULL value pointer"); + return 0; } if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) { - VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_put_value name=%s fmt=%d vali=%d\n", - vop->fullname(), value_p->format, value_p->value.integer); - VL_DBG_MSGF("- vpi: varp=%p putatp=%p\n", - vop->varp()->datap(), vop->varDatap());); + VL_DEBUG_IF_PLI( + VL_DBG_MSGF("- vpi: vpi_put_value name=%s fmt=%d vali=%d\n", vop->fullname(), + value_p->format, value_p->value.integer); + VL_DBG_MSGF("- vpi: varp=%p putatp=%p\n", vop->varp()->datap(), vop->varDatap());); if (VL_UNLIKELY(!vop->varp()->isPublicRW())) { _VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value to signal marked read-only," @@ -1626,24 +1641,20 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time case VLVT_WDATA: { int words = VL_WORDS_I(vop->varp()->packed().elements()); WDataOutP datap = (reinterpret_cast(vop->varDatap())); - for (int i=0; ivalue.vector[i].aval; - if (i==(words-1)) { - datap[i] &= vop->mask(); - } + if (i == (words - 1)) datap[i] &= vop->mask(); } return object; } case VLVT_UINT64: { *(reinterpret_cast(vop->varDatap())) = _VL_SET_QII( - value_p->value.vector[1].aval & vop->mask(), - value_p->value.vector[0].aval); + value_p->value.vector[1].aval & vop->mask(), value_p->value.vector[0].aval); return object; } default: { - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return NULL; } } @@ -1655,24 +1666,23 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time case VLVT_UINT64: case VLVT_WDATA: { int bits = vop->varp()->packed().elements(); - int len = strlen(value_p->value.str); + int len = strlen(value_p->value.str); CData* datap = (reinterpret_cast(vop->varDatap())); - for (int i=0; ivalue.str[len-i-1]=='1'):0; + for (int i = 0; i < bits; ++i) { + char set = (i < len) ? (value_p->value.str[len - i - 1] == '1') : 0; // zero bits 7:1 of byte when assigning to bit 0, else // or in 1 if bit set - if (i&7) { - datap[i>>3] |= set<<(i&7); + if (i & 7) { + datap[i >> 3] |= set << (i & 7); } else { - datap[i>>3] = set; + datap[i >> 3] = set; } } return object; } default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return 0; } } else if (value_p->format == vpiOctStrVal) { @@ -1682,29 +1692,30 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time case VLVT_UINT32: case VLVT_UINT64: case VLVT_WDATA: { - int chars = (vop->varp()->packed().elements()+2)/3; + int chars = (vop->varp()->packed().elements() + 2) / 3; int bytes = VL_BYTES_I(vop->varp()->packed().elements()); - int len = strlen(value_p->value.str); + int len = strlen(value_p->value.str); CData* datap = (reinterpret_cast(vop->varDatap())); div_t idx; datap[0] = 0; // reset zero'th byte - for (int i=0; ivalue.str[len-i-1]; + char digit = value_p->value.str[len - i - 1]; if (digit >= '0' && digit <= '7') { - val.half = digit-'0'; + val.half = digit - '0'; } else { - _VL_VPI_WARNING(__FILE__, __LINE__, - "%s: Non octal character '%c' in '%s' as value %s for %s", - VL_FUNC, digit, value_p->value.str, - VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + _VL_VPI_WARNING( + __FILE__, __LINE__, + "%s: Non octal character '%c' in '%s' as value %s for %s", VL_FUNC, + digit, value_p->value.str, + VerilatedVpiError::strFromVpiVal(value_p->format), + vop->fullname()); val.half = 0; } } else { @@ -1717,27 +1728,24 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time // byte of the destination. val.half <<= idx.rem; datap[idx.quot] |= val.byte[0]; // or in value - if ((idx.quot+1) < bytes) { - datap[idx.quot+1] = val.byte[1]; // this also resets + if ((idx.quot + 1) < bytes) { + datap[idx.quot + 1] = val.byte[1]; // this also resets // all bits to 0 prior to or'ing above } } // mask off non existant bits in the most significant byte - if (idx.quot == (bytes-1)) { + if (idx.quot == (bytes - 1)) { datap[idx.quot] &= vop->mask_byte(idx.quot); - } else if (idx.quot+1 == (bytes-1)) { - datap[idx.quot+1] &= vop->mask_byte(idx.quot+1); + } else if (idx.quot + 1 == (bytes - 1)) { + datap[idx.quot + 1] &= vop->mask_byte(idx.quot + 1); } // zero off remaining top bytes - for (int i=idx.quot+2; iformat), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return 0; } } else if (value_p->format == vpiDecStrVal) { @@ -1745,28 +1753,31 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time unsigned long long val; int success = sscanf(value_p->value.str, "%30llu%15s", &val, remainder); if (success < 1) { - _VL_VPI_ERROR(__FILE__, __LINE__, - "%s: Parsing failed for '%s' as value %s for %s", + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s", VL_FUNC, value_p->value.str, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return 0; } if (success > 1) { - _VL_VPI_WARNING(__FILE__, __LINE__, - "%s: Trailing garbage '%s' in '%s' as value %s for %s", - VL_FUNC, remainder, value_p->value.str, - VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + _VL_VPI_WARNING( + __FILE__, __LINE__, "%s: Trailing garbage '%s' in '%s' as value %s for %s", + VL_FUNC, remainder, value_p->value.str, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); } switch (vop->varp()->vltype()) { case VLVT_UINT8: - *(reinterpret_cast(vop->varDatap())) = val & vop->mask(); break; + *(reinterpret_cast(vop->varDatap())) = val & vop->mask(); + break; case VLVT_UINT16: - *(reinterpret_cast(vop->varDatap())) = val & vop->mask(); break; + *(reinterpret_cast(vop->varDatap())) = val & vop->mask(); + break; case VLVT_UINT32: - *(reinterpret_cast(vop->varDatap())) = val & vop->mask(); break; - case VLVT_UINT64: *(reinterpret_cast(vop->varDatap())) = val; - (reinterpret_cast(vop->varDatap()))[1] &= vop->mask(); break; + *(reinterpret_cast(vop->varDatap())) = val & vop->mask(); + break; + case VLVT_UINT64: + *(reinterpret_cast(vop->varDatap())) = val; + (reinterpret_cast(vop->varDatap()))[1] &= vop->mask(); + break; case VLVT_WDATA: default: _VL_VPI_ERROR(__FILE__, __LINE__, @@ -1783,49 +1794,50 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time case VLVT_UINT32: case VLVT_UINT64: case VLVT_WDATA: { - int chars = (vop->varp()->packed().elements()+3)>>2; + int chars = (vop->varp()->packed().elements() + 3) >> 2; CData* datap = (reinterpret_cast(vop->varDatap())); char* val = value_p->value.str; // skip hex ident if one is detected at the start of the string - if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) { - val += 2; - } + if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) val += 2; int len = strlen(val); - for (int i=0; i= '0' && digit <= '9') hex = digit - '0'; - else if (digit >= 'a' && digit <= 'f') hex = digit - 'a' + 10; - else if (digit >= 'A' && digit <= 'F') hex = digit - 'A' + 10; - else { - _VL_VPI_WARNING(__FILE__, __LINE__, - "%s: Non hex character '%c' in '%s' as value %s for %s", - VL_FUNC, digit, value_p->value.str, - VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + char digit = val[len - i - 1]; + if (digit >= '0' && digit <= '9') { + hex = digit - '0'; + } else if (digit >= 'a' && digit <= 'f') { + hex = digit - 'a' + 10; + } else if (digit >= 'A' && digit <= 'F') { + hex = digit - 'A' + 10; + } else { + _VL_VPI_WARNING( + __FILE__, __LINE__, + "%s: Non hex character '%c' in '%s' as value %s for %s", VL_FUNC, + digit, value_p->value.str, + VerilatedVpiError::strFromVpiVal(value_p->format), + vop->fullname()); hex = 0; } } else { hex = 0; } // assign hex digit value to destination - if (i&1) { - datap[i>>1] |= hex<<4; + if (i & 1) { + datap[i >> 1] |= hex << 4; } else { - datap[i>>1] = hex; // this also resets all + datap[i >> 1] = hex; // this also resets all // bits to 0 prior to or'ing above of the msb } } // apply bit mask to most significant byte - datap[(chars-1)>>1] &= vop->mask_byte((chars-1)>>1); + datap[(chars - 1) >> 1] &= vop->mask_byte((chars - 1) >> 1); return object; } default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return 0; } } else if (value_p->format == vpiStringVal) { @@ -1836,18 +1848,17 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time case VLVT_UINT64: case VLVT_WDATA: { int bytes = VL_BYTES_I(vop->varp()->packed().elements()); - int len = strlen(value_p->value.str); + int len = strlen(value_p->value.str); CData* datap = (reinterpret_cast(vop->varDatap())); - for (int i=0; ivalue.str[len-i-1]:0; + datap[i] = (i < len) ? value_p->value.str[len - i - 1] : 0; } return object; } default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return 0; } } else if (value_p->format == vpiIntVal) { @@ -1876,8 +1887,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return NULL; } - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for ??", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format)); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for ??", VL_FUNC, + VerilatedVpiError::strFromVpiVal(value_p->format)); return NULL; } @@ -1907,13 +1918,12 @@ void vpi_get_time(vpiHandle /*object*/, p_vpi_time time_p) { time_p->high = itime[1]; return; } - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported type (%d)", - VL_FUNC, time_p->type); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported type (%d)", VL_FUNC, time_p->type); } // I/O routines -PLI_UINT32 vpi_mcd_open(PLI_BYTE8 *filenamep) { +PLI_UINT32 vpi_mcd_open(PLI_BYTE8* filenamep) { VerilatedVpiImp::assertOneCheck(); _VL_VPI_ERROR_RESET(); return VL_FOPEN_S(filenamep, "wb"); @@ -1931,7 +1941,7 @@ PLI_BYTE8* vpi_mcd_name(PLI_UINT32 /*mcd*/) { return 0; } -PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *formatp, ...) { +PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8* formatp, ...) { VerilatedVpiImp::assertOneCheck(); _VL_VPI_ERROR_RESET(); va_list ap; @@ -1941,7 +1951,7 @@ PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *formatp, ...) { return chars; } -PLI_INT32 vpi_printf(PLI_BYTE8 *formatp, ...) { +PLI_INT32 vpi_printf(PLI_BYTE8* formatp, ...) { VerilatedVpiImp::assertOneCheck(); _VL_VPI_ERROR_RESET(); va_list ap; @@ -1957,7 +1967,7 @@ PLI_INT32 vpi_vprintf(PLI_BYTE8* formatp, va_list ap) { return VL_VPRINTF(formatp, ap); } -PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8 *format, va_list ap) { +PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8* format, va_list ap) { VerilatedVpiImp::assertOneCheck(); FILE* fp = VL_CVT_I_FP(mcd); _VL_VPI_ERROR_RESET(); @@ -1994,9 +2004,7 @@ PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) { // error_info_p can be NULL, so only return level in that case VerilatedVpiImp::assertOneCheck(); p_vpi_error_info _error_info_p = VerilatedVpiImp::error_info()->getError(); - if (error_info_p && _error_info_p) { - *error_info_p = *_error_info_p; - } + if (error_info_p && _error_info_p) *error_info_p = *_error_info_p; if (!_error_info_p) return 0; // no error occured return _error_info_p->level; // return error severity level } @@ -2061,8 +2069,8 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) { return 1; } } - _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, ignoring", - VL_FUNC, VerilatedVpiError::strFromVpiProp(operation)); + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, ignoring", VL_FUNC, + VerilatedVpiError::strFromVpiProp(operation)); return 0; } diff --git a/include/verilatedos.h b/include/verilatedos.h index 7acc92183..ae2f14048 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -25,95 +25,97 @@ #ifndef _VERILATEDOS_H_ #define _VERILATEDOS_H_ 1 ///< Header Guard +// Current clang-format versions botch #ifdef inclusion, so +// clang-format off //========================================================================= // Compiler pragma abstraction #ifdef __GNUC__ -# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment))) -# define VL_ATTR_ALWINLINE __attribute__ ((always_inline)) -# define VL_ATTR_COLD __attribute__ ((cold)) -# define VL_ATTR_HOT __attribute__ ((hot)) -# define VL_ATTR_NORETURN __attribute__ ((noreturn)) -# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1))) -# define VL_ATTR_PURE __attribute__ ((pure)) -# define VL_ATTR_UNUSED __attribute__ ((unused)) -# define VL_FUNC __func__ +# define VL_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment))) +# define VL_ATTR_ALWINLINE __attribute__((always_inline)) +# define VL_ATTR_COLD __attribute__((cold)) +# define VL_ATTR_HOT __attribute__((hot)) +# define VL_ATTR_NORETURN __attribute__((noreturn)) +# define VL_ATTR_PRINTF(fmtArgNum) __attribute__((format(printf, (fmtArgNum), (fmtArgNum) + 1))) +# define VL_ATTR_PURE __attribute__((pure)) +# define VL_ATTR_UNUSED __attribute__((unused)) +# define VL_FUNC __func__ # if defined(__clang__) && defined(VL_THREADED) -# define VL_ACQUIRE(...) __attribute__ ((acquire_capability(__VA_ARGS__))) -# define VL_ACQUIRE_SHARED(...) __attribute__ ((acquire_shared_capability(__VA_ARGS__))) -# define VL_RELEASE(...) __attribute__ ((release_capability(__VA_ARGS__))) -# define VL_RELEASE_SHARED(...) __attribute__ ((release_shared_capability(__VA_ARGS__))) -# define VL_TRY_ACQUIRE(...) __attribute__ ((try_acquire_capability(__VA_ARGS__))) -# define VL_TRY_ACQUIRE_SHARED(...) __attribute__ ((try_acquire_shared_capability(__VA_ARGS__))) -# define VL_CAPABILITY(x) __attribute__ ((capability(x))) -# define VL_REQUIRES(x) __attribute__ ((requires_capability(x))) -# define VL_GUARDED_BY(x) __attribute__ ((guarded_by(x))) -# define VL_EXCLUDES(x) __attribute__ ((locks_excluded(x))) -# define VL_SCOPED_CAPABILITY __attribute__ ((scoped_lockable)) +# define VL_ACQUIRE(...) __attribute__((acquire_capability(__VA_ARGS__))) +# define VL_ACQUIRE_SHARED(...) __attribute__((acquire_shared_capability(__VA_ARGS__))) +# define VL_RELEASE(...) __attribute__((release_capability(__VA_ARGS__))) +# define VL_RELEASE_SHARED(...) __attribute__((release_shared_capability(__VA_ARGS__))) +# define VL_TRY_ACQUIRE(...) __attribute__((try_acquire_capability(__VA_ARGS__))) +# define VL_TRY_ACQUIRE_SHARED(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__))) +# define VL_CAPABILITY(x) __attribute__((capability(x))) +# define VL_REQUIRES(x) __attribute__((requires_capability(x))) +# define VL_GUARDED_BY(x) __attribute__((guarded_by(x))) +# define VL_EXCLUDES(x) __attribute__((locks_excluded(x))) +# define VL_SCOPED_CAPABILITY __attribute__((scoped_lockable)) # endif -# define VL_LIKELY(x) __builtin_expect(!!(x), 1) +# define VL_LIKELY(x) __builtin_expect(!!(x), 1) # define VL_UNLIKELY(x) __builtin_expect(!!(x), 0) # define VL_UNREACHABLE __builtin_unreachable(); -# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0) -# define VL_PREFETCH_RW(p) __builtin_prefetch((p),1) +# define VL_PREFETCH_RD(p) __builtin_prefetch((p), 0) +# define VL_PREFETCH_RW(p) __builtin_prefetch((p), 1) #elif defined(_MSC_VER) -# define VL_FUNC __FUNCTION__ +# define VL_FUNC __FUNCTION__ #endif // Defaults for unsupported compiler features #ifndef VL_ATTR_ALIGNED -# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment +# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment #endif #ifndef VL_ATTR_ALWINLINE -# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing +# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing #endif #ifndef VL_ATTR_COLD -# define VL_ATTR_COLD ///< Function is rarely executed +# define VL_ATTR_COLD ///< Function is rarely executed #endif #ifndef VL_ATTR_HOT -# define VL_ATTR_HOT ///< Function is highly executed +# define VL_ATTR_HOT ///< Function is highly executed #endif #ifndef VL_ATTR_NORETURN -# define VL_ATTR_NORETURN ///< Function does not ever return +# define VL_ATTR_NORETURN ///< Function does not ever return #endif #ifndef VL_ATTR_PRINTF -# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking +# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking #endif #ifndef VL_ATTR_PURE -# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE) +# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE) #endif #ifndef VL_ATTR_UNUSED -# define VL_ATTR_UNUSED ///< Function that may be never used +# define VL_ATTR_UNUSED ///< Function that may be never used #endif #ifndef VL_FUNC -# define VL_FUNC "__func__" ///< Name of current function for error macros +# define VL_FUNC "__func__" ///< Name of current function for error macros #endif #ifndef VL_CAPABILITY -# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety) -# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety) -# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety) -# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety) -# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety) -# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety) -# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety) -# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety) -# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety) -# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety) -# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety) +# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety) +# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety) +# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety) +# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety) +# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety) +# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired shared (-fthread-safety) +# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety) +# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety) +# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety) +# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety) +# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety) #endif #ifndef VL_LIKELY -# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false -# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true +# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false +# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true #endif -#define VL_UNCOVERABLE(x) VL_UNLIKELY(x) ///< Boolean expression never hit by users (no coverage) +# define VL_UNCOVERABLE(x) VL_UNLIKELY(x) ///< Boolean expression never hit by users (no coverage) #ifndef VL_UNREACHABLE -# define VL_UNREACHABLE ///< Point that may never be reached +# define VL_UNREACHABLE ///< Point that may never be reached #endif #ifndef VL_PREFETCH_RD -# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent +# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent #endif #ifndef VL_PREFETCH_RW -# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent +# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent #endif #ifdef VL_THREADED @@ -121,31 +123,34 @@ # define VL_THREAD_LOCAL thread_local # elif defined(__GNUC__) # if (__cplusplus < 201103L) && !defined(VL_THREADED_NO_C11_WARNING) -# error "VL_THREADED/--threads support requires C++-11 or newer only; use newer compiler" +# error "VL_THREADED/--threads support requires C++-11 or newer only; use newer compiler" # endif # else # error "Unsupported compiler for VL_THREADED: No thread-local declarator" # endif -# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread +# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread #else -# define VL_THREAD_LOCAL ///< Use new C++ static local thread +# define VL_THREAD_LOCAL ///< Use new C++ static local thread #endif -#define VL_THREAD ///< Deprecated -#define VL_STATIC_OR_THREAD static ///< Deprecated + +#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_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 +#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##ULL) ///< Add appropriate suffix to 64-bit constant +# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant // Was "(c##ui64)". C++11 has standardized on ULL, and MSVC now supports this. // We propose to no longer require using this macro no sooner than June 2020. // File an issue ASAP if this breaks anything. #else -# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant +# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant #endif // This is not necessarily the same as #UL, depending on what the IData typedef is. @@ -249,47 +254,47 @@ # include # include // __WORDSIZE # include // ssize_t -typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility) -typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility) -typedef char vlsint8_t; ///< 8-bit signed type -typedef unsigned char vluint8_t; ///< 8-bit unsigned type -typedef short int vlsint16_t; ///< 16-bit signed type -typedef unsigned short int vluint16_t; ///< 16-bit unsigned type +typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility) +typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility) +typedef char vlsint8_t; ///< 8-bit signed type +typedef unsigned char vluint8_t; ///< 8-bit unsigned type +typedef short int vlsint16_t; ///< 16-bit signed type +typedef unsigned short int vluint16_t; ///< 16-bit unsigned type # if defined(__uint32_t_defined) || defined(___int32_t_defined) // Newer Cygwin uint32_t in stdint.h as an unsigned int -typedef int32_t vlsint32_t; ///< 32-bit signed type -typedef uint32_t vluint32_t; ///< 32-bit unsigned type +typedef int32_t vlsint32_t; ///< 32-bit signed type +typedef uint32_t vluint32_t; ///< 32-bit unsigned type # else // Older Cygwin has long==uint32_t -typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility) -typedef long vlsint32_t; ///< 32-bit signed type -typedef unsigned long vluint32_t; ///< 32-bit unsigned type +typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility) +typedef long vlsint32_t; ///< 32-bit signed type +typedef unsigned long vluint32_t; ///< 32-bit unsigned type # endif # if defined(__WORDSIZE) && (__WORDSIZE == 64) -typedef long vlsint64_t; ///< 64-bit signed type -typedef unsigned long vluint64_t; ///< 64-bit unsigned type +typedef long vlsint64_t; ///< 64-bit signed type +typedef unsigned long vluint64_t; ///< 64-bit unsigned type # else -typedef long long vlsint64_t; ///< 64-bit signed type -typedef unsigned long long vluint64_t; ///< 64-bit unsigned type +typedef long long vlsint64_t; ///< 64-bit signed type +typedef unsigned long long vluint64_t; ///< 64-bit unsigned type # endif #elif defined(_WIN32) && defined(_MSC_VER) -typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility) -typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility) -typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility) -typedef signed __int8 vlsint8_t; ///< 8-bit signed type -typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type -typedef signed __int16 vlsint16_t; ///< 16-bit signed type -typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type -typedef signed __int32 vlsint32_t; ///< 32-bit signed type -typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type -typedef signed __int64 vlsint64_t; ///< 64-bit signed type -typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type +typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility) +typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility) +typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility) +typedef signed __int8 vlsint8_t; ///< 8-bit signed type +typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type +typedef signed __int16 vlsint16_t; ///< 16-bit signed type +typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type +typedef signed __int32 vlsint32_t; ///< 32-bit signed type +typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type +typedef signed __int64 vlsint64_t; ///< 64-bit signed type +typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type # ifndef _SSIZE_T_DEFINED -# ifdef _WIN64 -typedef signed __int64 ssize_t; ///< signed size_t; returned from read() +# ifdef _WIN64 +typedef signed __int64 ssize_t; ///< signed size_t; returned from read() # else -typedef signed __int32 ssize_t; ///< signed size_t; returned from read() +typedef signed __int32 ssize_t; ///< signed size_t; returned from read() # endif # endif @@ -299,18 +304,18 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned fro # include // Linux and most flavors # include // __WORDSIZE # include // ssize_t -typedef char vlsint8_t; ///< 8-bit signed type -typedef uint8_t vluint8_t; ///< 8-bit unsigned type -typedef short vlsint16_t; ///< 16-bit signed type -typedef uint16_t vluint16_t; ///< 16-bit unsigned type -typedef int vlsint32_t; ///< 32-bit signed type -typedef uint32_t vluint32_t; ///< 32-bit unsigned type +typedef char vlsint8_t; ///< 8-bit signed type +typedef uint8_t vluint8_t; ///< 8-bit unsigned type +typedef short vlsint16_t; ///< 16-bit signed type +typedef uint16_t vluint16_t; ///< 16-bit unsigned type +typedef int vlsint32_t; ///< 32-bit signed type +typedef uint32_t vluint32_t; ///< 32-bit unsigned type # if defined(__WORDSIZE) && (__WORDSIZE == 64) -typedef long vlsint64_t; ///< 64-bit signed type -typedef unsigned long vluint64_t; ///< 64-bit unsigned type +typedef long vlsint64_t; ///< 64-bit signed type +typedef unsigned long vluint64_t; ///< 64-bit unsigned type # else -typedef long long vlsint64_t; ///< 64-bit signed type -typedef unsigned long long vluint64_t; ///< 64-bit unsigned type +typedef long long vlsint64_t; ///< 64-bit signed type +typedef unsigned long long vluint64_t; ///< 64-bit unsigned type # endif #endif @@ -353,14 +358,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type //========================================================================= // Integer size macros -#define VL_BYTESIZE 8 ///< Bits in a CData / byte -#define VL_SHORTSIZE 16 ///< Bits in a SData / short -#define VL_IDATASIZE 32 ///< Bits in a IData / word -#define VL_WORDSIZE IDATASIZE ///< Legacy define -#define VL_QUADSIZE 64 ///< Bits in a QData / quadword -#define VL_EDATASIZE 32 ///< Bits in a EData (WData entry) -#define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE) -#define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment) +#define VL_BYTESIZE 8 ///< Bits in a CData / byte +#define VL_SHORTSIZE 16 ///< Bits in a SData / short +#define VL_IDATASIZE 32 ///< Bits in a IData / word +#define VL_WORDSIZE IDATASIZE ///< Legacy define +#define VL_QUADSIZE 64 ///< Bits in a QData / quadword +#define VL_EDATASIZE 32 ///< Bits in a EData (WData entry) +#define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE) +#define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment) /// Bytes this number of bits needs (1 bit=1 byte) #define VL_BYTES_I(nbits) (((nbits) + (VL_BYTESIZE - 1)) / VL_BYTESIZE) @@ -373,9 +378,9 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type // Class definition helpers // Used to declare a class as uncopyable; put after a private: -#define VL_UNCOPYABLE(Type) \ - Type(const Type& other) VL_EQ_DELETE; \ - Type& operator= (const Type&) VL_EQ_DELETE +#define VL_UNCOPYABLE(Type) \ + Type(const Type& other) VL_EQ_DELETE; \ + Type& operator=(const Type&) VL_EQ_DELETE //========================================================================= // Verilated function size macros @@ -391,11 +396,10 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type #define VL_SIZEBITS_E (VL_EDATASIZE - 1) ///< Bit mask for bits in a quad /// Mask for words with 1's where relevant bits are (0=all bits) -#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) \ - ? ((1U << ((nbits) & VL_SIZEBITS_I) )-1) : ~0) +#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) ? ((1U << ((nbits) & VL_SIZEBITS_I)) - 1) : ~0) /// Mask for quads with 1's where relevant bits are (0=all bits) -#define VL_MASK_Q(nbits) (((nbits) & VL_SIZEBITS_Q) \ - ? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q) )-VL_ULL(1)) : VL_ULL(~0)) +#define VL_MASK_Q(nbits) \ + (((nbits) & VL_SIZEBITS_Q) ? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q)) - VL_ULL(1)) : VL_ULL(~0)) /// Mask for EData with 1's where relevant bits are (0=all bits) #define VL_MASK_E(nbits) VL_MASK_I(nbits) #define VL_EUL(n) VL_UL(n) ///< Make constant number EData sized @@ -411,8 +415,8 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type // #defines, to avoid requiring math.h on all compile runs #ifdef _MSC_VER -# define VL_TRUNC(n) (((n)<0) ? ceil((n)) : floor((n))) -# define VL_ROUND(n) (((n)<0) ? ceil((n)-0.5) : floor((n)+0.5)) +# define VL_TRUNC(n) (((n) < 0) ? ceil((n)) : floor((n))) +# define VL_ROUND(n) (((n) < 0) ? ceil((n)-0.5) : floor((n) + 0.5)) #else # define VL_TRUNC(n) trunc(n) # define VL_ROUND(n) round(n) @@ -424,13 +428,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type /// The vluint64_t argument is loaded with a high-performance counter for profiling /// or 0x0 if not implemeted on this platform #if defined(__i386__) || defined(__x86_64__) -# define VL_RDTSC(val) { \ - vluint32_t hi, lo; \ - asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); \ - (val) = ((vluint64_t)lo) | (((vluint64_t)hi)<<32); \ -} +#define VL_RDTSC(val) \ + { \ + vluint32_t hi, lo; \ + asm volatile("rdtsc" : "=a"(lo), "=d"(hi)); \ + (val) = ((vluint64_t)lo) | (((vluint64_t)hi) << 32); \ + } #elif defined(__aarch64__) -# define VL_RDTSC(val) asm volatile("mrs %[rt],PMCCNTR_EL0" : [rt] "=r" (val)); +# define VL_RDTSC(val) asm volatile("mrs %[rt],PMCCNTR_EL0" : [rt] "=r"(val)); #else // We just silently ignore unknown OSes, as only leads to missing statistics # define VL_RDTSC(val) (val) = 0; @@ -468,6 +473,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type #else # define VL_STRCASECMP strcasecmp #endif +// clang-format on //========================================================================= // Stringify macros diff --git a/nodist/clang_formatter b/nodist/clang_formatter new file mode 100755 index 000000000..1acde0367 --- /dev/null +++ b/nodist/clang_formatter @@ -0,0 +1,260 @@ +#!/bin/bash +# +# clang-format is used to standardize the indentation of the internal C++ +# code. +# +# For the most part clang-format changes provide good consistency, the two +# main exceptions being the indentation of preprocessor directives, and +# tables of statements. Reformatting is generally performed only before +# other large changes are to be made to a file. +# +# "##" files commented out below are not yet clang-format clean. +# "#" files commented out hit a clang-format limitation with ifdefs. + +clang-format -i examples/make_hello_c/sim_main.cpp +clang-format -i examples/make_hello_sc/sc_main.cpp +#clang-format -i examples/make_protect_lib/sim_main.cpp +clang-format -i examples/make_tracing_c/sim_main.cpp +clang-format -i examples/make_tracing_sc/sc_main.cpp +clang-format -i include/verilated.cpp +clang-format -i include/verilated.h +clang-format -i include/verilated_config.h.in +clang-format -i include/verilated_cov.cpp +clang-format -i include/verilated_cov.h +clang-format -i include/verilated_cov_key.h +clang-format -i include/verilated_dpi.cpp +clang-format -i include/verilated_dpi.h +clang-format -i include/verilated_fst_c.cpp +clang-format -i include/verilated_fst_c.h +clang-format -i include/verilated_heavy.h +clang-format -i include/verilated_imp.h +clang-format -i include/verilated_save.cpp +clang-format -i include/verilated_save.h +clang-format -i include/verilated_sc.h +clang-format -i include/verilated_sym_props.h +clang-format -i include/verilated_syms.h +clang-format -i include/verilated_threads.cpp +clang-format -i include/verilated_threads.h +clang-format -i include/verilated_unordered_set_map.h +clang-format -i include/verilated_vcd_c.cpp +clang-format -i include/verilated_vcd_c.h +clang-format -i include/verilated_vcd_sc.cpp +clang-format -i include/verilated_vcd_sc.h +clang-format -i include/verilated_vpi.cpp +clang-format -i include/verilated_vpi.h +clang-format -i include/verilatedos.h +clang-format -i nodist/fuzzer/wrapper.cpp +clang-format -i src/V3Active.cpp +clang-format -i src/V3Active.h +clang-format -i src/V3ActiveTop.cpp +clang-format -i src/V3ActiveTop.h +clang-format -i src/V3Assert.cpp +clang-format -i src/V3Assert.h +clang-format -i src/V3AssertPre.cpp +clang-format -i src/V3AssertPre.h +##clang-format -i src/V3Ast.cpp +##clang-format -i src/V3Ast.h +clang-format -i src/V3AstConstOnly.h +##clang-format -i src/V3AstNodes.cpp +##clang-format -i src/V3AstNodes.h +##clang-format -i src/V3Begin.cpp +clang-format -i src/V3Begin.h +clang-format -i src/V3Branch.cpp +clang-format -i src/V3Branch.h +##clang-format -i src/V3Broken.cpp +clang-format -i src/V3Broken.h +##clang-format -i src/V3CCtors.cpp +clang-format -i src/V3CCtors.h +clang-format -i src/V3CUse.cpp +clang-format -i src/V3CUse.h +##clang-format -i src/V3Case.cpp +clang-format -i src/V3Case.h +##clang-format -i src/V3Cast.cpp +clang-format -i src/V3Cast.h +##clang-format -i src/V3Cdc.cpp +clang-format -i src/V3Cdc.h +##clang-format -i src/V3Changed.cpp +clang-format -i src/V3Changed.h +clang-format -i src/V3Class.cpp +clang-format -i src/V3Class.h +##clang-format -i src/V3Clean.cpp +clang-format -i src/V3Clean.h +##clang-format -i src/V3Clock.cpp +clang-format -i src/V3Clock.h +##clang-format -i src/V3Combine.cpp +clang-format -i src/V3Combine.h +clang-format -i src/V3Config.cpp +clang-format -i src/V3Config.h +##clang-format -i src/V3Const.cpp +clang-format -i src/V3Const.h +clang-format -i src/V3Coverage.cpp +clang-format -i src/V3Coverage.h +clang-format -i src/V3CoverageJoin.cpp +clang-format -i src/V3CoverageJoin.h +##clang-format -i src/V3Dead.cpp +clang-format -i src/V3Dead.h +##clang-format -i src/V3Delayed.cpp +clang-format -i src/V3Delayed.h +clang-format -i src/V3Depth.cpp +clang-format -i src/V3Depth.h +clang-format -i src/V3DepthBlock.cpp +clang-format -i src/V3DepthBlock.h +clang-format -i src/V3Descope.cpp +clang-format -i src/V3Descope.h +##clang-format -i src/V3EmitC.cpp +clang-format -i src/V3EmitC.h +##clang-format -i src/V3EmitCBase.h +clang-format -i src/V3EmitCInlines.cpp +##clang-format -i src/V3EmitCMake.cpp +clang-format -i src/V3EmitCMake.h +##clang-format -i src/V3EmitCSyms.cpp +##clang-format -i src/V3EmitMk.cpp +clang-format -i src/V3EmitMk.h +##clang-format -i src/V3EmitV.cpp +clang-format -i src/V3EmitV.h +##clang-format -i src/V3EmitXml.cpp +clang-format -i src/V3EmitXml.h +##clang-format -i src/V3Error.cpp +##clang-format -i src/V3Error.h +##clang-format -i src/V3Expand.cpp +clang-format -i src/V3Expand.h +##clang-format -i src/V3File.cpp +##clang-format -i src/V3File.h +##clang-format -i src/V3FileLine.cpp +##clang-format -i src/V3FileLine.h +##clang-format -i src/V3Gate.cpp +clang-format -i src/V3Gate.h +##clang-format -i src/V3GenClk.cpp +clang-format -i src/V3GenClk.h +clang-format -i src/V3Global.cpp +clang-format -i src/V3Global.h +##clang-format -i src/V3Graph.cpp +clang-format -i src/V3Graph.h +##clang-format -i src/V3GraphAcyc.cpp +##clang-format -i src/V3GraphAlg.cpp +clang-format -i src/V3GraphAlg.h +clang-format -i src/V3GraphDfa.cpp +clang-format -i src/V3GraphDfa.h +clang-format -i src/V3GraphPathChecker.cpp +clang-format -i src/V3GraphPathChecker.h +clang-format -i src/V3GraphStream.h +##clang-format -i src/V3GraphTest.cpp +##clang-format -i src/V3Hashed.cpp +clang-format -i src/V3Hashed.h +##clang-format -i src/V3Inline.cpp +clang-format -i src/V3Inline.h +##clang-format -i src/V3Inst.cpp +clang-format -i src/V3Inst.h +clang-format -i src/V3InstrCount.cpp +clang-format -i src/V3InstrCount.h +clang-format -i src/V3LangCode.h +clang-format -i src/V3LanguageWords.h +##clang-format -i src/V3Life.cpp +clang-format -i src/V3Life.h +##clang-format -i src/V3LifePost.cpp +clang-format -i src/V3LifePost.h +##clang-format -i src/V3LinkCells.cpp +clang-format -i src/V3LinkCells.h +##clang-format -i src/V3LinkDot.cpp +clang-format -i src/V3LinkDot.h +##clang-format -i src/V3LinkJump.cpp +clang-format -i src/V3LinkJump.h +clang-format -i src/V3LinkLValue.cpp +clang-format -i src/V3LinkLValue.h +##clang-format -i src/V3LinkLevel.cpp +clang-format -i src/V3LinkLevel.h +##clang-format -i src/V3LinkParse.cpp +clang-format -i src/V3LinkParse.h +##clang-format -i src/V3LinkResolve.cpp +clang-format -i src/V3LinkResolve.h +clang-format -i src/V3List.h +clang-format -i src/V3Localize.cpp +clang-format -i src/V3Localize.h +clang-format -i src/V3Name.cpp +clang-format -i src/V3Name.h +##clang-format -i src/V3Number.cpp +##clang-format -i src/V3Number.h +clang-format -i src/V3Number_test.cpp +##clang-format -i src/V3Options.cpp +##clang-format -i src/V3Options.h +##clang-format -i src/V3Order.cpp +clang-format -i src/V3Order.h +clang-format -i src/V3OrderGraph.h +##clang-format -i src/V3Os.cpp +clang-format -i src/V3Os.h +##clang-format -i src/V3Param.cpp +clang-format -i src/V3Param.h +clang-format -i src/V3Parse.h +##clang-format -i src/V3ParseGrammar.cpp +##clang-format -i src/V3ParseImp.cpp +##clang-format -i src/V3ParseImp.h +clang-format -i src/V3ParseLex.cpp +clang-format -i src/V3ParseSym.h +##clang-format -i src/V3Partition.cpp +clang-format -i src/V3Partition.h +clang-format -i src/V3PartitionGraph.h +clang-format -i src/V3PreLex.h +##clang-format -i src/V3PreProc.cpp +clang-format -i src/V3PreProc.h +clang-format -i src/V3PreShell.cpp +clang-format -i src/V3PreShell.h +##clang-format -i src/V3Premit.cpp +clang-format -i src/V3Premit.h +##clang-format -i src/V3ProtectLib.cpp +clang-format -i src/V3ProtectLib.h +clang-format -i src/V3Reloop.cpp +clang-format -i src/V3Reloop.h +##clang-format -i src/V3Scope.cpp +clang-format -i src/V3Scope.h +clang-format -i src/V3Scoreboard.cpp +clang-format -i src/V3Scoreboard.h +clang-format -i src/V3SenTree.h +##clang-format -i src/V3Simulate.h +##clang-format -i src/V3Slice.cpp +clang-format -i src/V3Slice.h +##clang-format -i src/V3Split.cpp +clang-format -i src/V3Split.h +##clang-format -i src/V3SplitAs.cpp +clang-format -i src/V3SplitAs.h +##clang-format -i src/V3SplitVar.cpp +clang-format -i src/V3SplitVar.h +clang-format -i src/V3Stats.cpp +clang-format -i src/V3Stats.h +clang-format -i src/V3StatsReport.cpp +clang-format -i src/V3String.cpp +clang-format -i src/V3String.h +##clang-format -i src/V3Subst.cpp +clang-format -i src/V3Subst.h +clang-format -i src/V3SymTable.h +##clang-format -i src/V3TSP.cpp +clang-format -i src/V3TSP.h +##clang-format -i src/V3Table.cpp +clang-format -i src/V3Table.h +##clang-format -i src/V3Task.cpp +clang-format -i src/V3Task.h +clang-format -i src/V3Trace.cpp +clang-format -i src/V3Trace.h +clang-format -i src/V3TraceDecl.cpp +clang-format -i src/V3TraceDecl.h +##clang-format -i src/V3Tristate.cpp +clang-format -i src/V3Tristate.h +##clang-format -i src/V3Undriven.cpp +clang-format -i src/V3Undriven.h +##clang-format -i src/V3Unknown.cpp +clang-format -i src/V3Unknown.h +##clang-format -i src/V3Unroll.cpp +clang-format -i src/V3Unroll.h +##clang-format -i src/V3Width.cpp +clang-format -i src/V3Width.h +clang-format -i src/V3WidthCommit.h +##clang-format -i src/V3WidthSel.cpp +##clang-format -i src/Verilator.cpp +clang-format -i src/VlcBucket.h +clang-format -i src/VlcMain.cpp +clang-format -i src/VlcOptions.h +clang-format -i src/VlcPoint.h +clang-format -i src/VlcSource.h +clang-format -i src/VlcTest.h +clang-format -i src/VlcTop.cpp +clang-format -i src/VlcTop.h +clang-format -i src/config_build.h.in diff --git a/src/V3Active.cpp b/src/V3Active.cpp index bb15e55c1..efc8eef8e 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -50,11 +50,11 @@ protected: class ActiveNamer : public ActiveBaseVisitor { private: - typedef std::map ActiveNameMap; + typedef std::map ActiveNameMap; // STATE - AstScope* m_scopep; // Current scope to add statement to - AstActive* m_iActivep; // For current scope, the IActive we're building - AstActive* m_cActivep; // For current scope, the SActive(combo) we're building + AstScope* m_scopep; // Current scope to add statement to + AstActive* m_iActivep; // For current scope, the IActive we're building + AstActive* m_cActivep; // For current scope, the SActive(combo) we're building SenTreeSet m_activeSens; // Sen lists for each active we've made typedef vl_unordered_map ActiveMap; @@ -89,8 +89,7 @@ public: AstActive* getCActive(FileLine* fl) { if (!m_cActivep) { m_cActivep = new AstActive( - fl, "combo", - new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Combo()))); + fl, "combo", new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Combo()))); m_cActivep->sensesStorep(m_cActivep->sensesp()); addActive(m_cActivep); } @@ -99,8 +98,7 @@ public: AstActive* getIActive(FileLine* fl) { if (!m_iActivep) { m_iActivep = new AstActive( - fl, "initial", - new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Initial()))); + fl, "initial", new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Initial()))); m_iActivep->sensesStorep(m_iActivep->sensesp()); addActive(m_iActivep); } @@ -122,7 +120,7 @@ public: AstSenTree* newsenp = sensesp->cloneTree(false); activep = new AstActive(fl, "sequent", newsenp); activep->sensesStorep(activep->sensesp()); - UINFO(8," New ACTIVE "<v3warn(INITIALDLY, "Delayed assignments (<=) in initial or final block\n" - <warnMore()<<"... Suggest blocking assignments (=)"); + << nodep->warnMore() + << "... Suggest blocking assignments (=)"); } else if (m_check == CT_LATCH) { // Suppress. Shouldn't matter that the interior of the latch races } else { nodep->v3warn(COMBDLY, "Delayed assignments (<=) in non-clocked" - " (non flop or latch) block\n" - <warnMore()<<"... Suggest blocking assignments (=)"); + " (non flop or latch) block\n" + << nodep->warnMore() + << "... Suggest blocking assignments (=)"); } - AstNode* newp = new AstAssign(nodep->fileline(), - nodep->lhsp()->unlinkFrBack(), + AstNode* newp = new AstAssign(nodep->fileline(), nodep->lhsp()->unlinkFrBack(), nodep->rhsp()->unlinkFrBack()); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -186,17 +185,18 @@ private: } virtual void visit(AstVarRef* nodep) VL_OVERRIDE { AstVar* varp = nodep->varp(); - if (m_check == CT_SEQ - && m_assignp - && !varp->isUsedLoopIdx() // Ignore loop indices + if (m_check == CT_SEQ && m_assignp && !varp->isUsedLoopIdx() // Ignore loop indices && !varp->isTemp()) { // Allow turning off warnings on the always, or the variable also if (!m_alwaysp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ) && !m_assignp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ) && !varp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)) { - m_assignp->v3warn(BLKSEQ, "Blocking assignments (=) in sequential (flop or latch) block\n" - <warnMore()<<"... Suggest delayed assignments (<=)"); - m_alwaysp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always + m_assignp->v3warn(BLKSEQ, + "Blocking assignments (=) in sequential (flop or latch) block\n" + << m_assignp->warnMore() + << "... Suggest delayed assignments (<=)"); + m_alwaysp->fileline()->modifyWarnOff( + V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always varp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); } } @@ -225,15 +225,15 @@ private: // AstNode::user4() Used by V3Const::constify, called below // STATE - ActiveNamer m_namer; // Tracking of active names - AstCFunc* m_scopeFinalp; // Final function for this scope - bool m_itemCombo; // Found a SenItem combo - bool m_itemSequent; // Found a SenItem sequential + ActiveNamer m_namer; // Tracking of active names + AstCFunc* m_scopeFinalp; // Final function for this scope + bool m_itemCombo; // Found a SenItem combo + bool m_itemSequent; // Found a SenItem sequential // VISITORS virtual void visit(AstScope* nodep) VL_OVERRIDE { // Create required actives and add to scope - UINFO(4," SCOPE "<fileline()); nodep->unlinkFrBack(); wantactivep->addStmtsp(nodep); } virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // Relink to CACTIVE, unless already under it - UINFO(4," ASSIGNW "<fileline()); nodep->unlinkFrBack(); wantactivep->addStmtsp(nodep); } virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // Relink to CACTIVE, unless already under it - UINFO(4," ASSIGNW "<fileline()); nodep->unlinkFrBack(); wantactivep->addStmtsp(nodep); } virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { // Relink to CACTIVE, unless already under it - UINFO(4," COVERTOGGLE "<fileline()); nodep->unlinkFrBack(); wantactivep->addStmtsp(nodep); } virtual void visit(AstFinal* nodep) VL_OVERRIDE { // Relink to CFUNC for the final - UINFO(4," FINAL "<bodysp()) { // Empty, Kill it. VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } - ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL); + ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_INITIAL); if (!m_scopeFinalp) { m_scopeFinalp = new AstCFunc( - nodep->fileline(), "_final_"+m_namer.scopep()->nameDotless(), - m_namer.scopep()); + nodep->fileline(), "_final_" + m_namer.scopep()->nameDotless(), m_namer.scopep()); m_scopeFinalp->argTypes(EmitCBaseVisitor::symClassVar()); m_scopeFinalp->addInitsp( - new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n")); + new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign() + "\n")); m_scopeFinalp->dontCombine(true); m_scopeFinalp->formCallTree(true); m_scopeFinalp->slow(true); @@ -300,9 +299,7 @@ private: // METHODS void visitAlways(AstNode* nodep, AstSenTree* oldsensesp, VAlwaysKwd kwd) { // Move always to appropriate ACTIVE based on its sense list - if (oldsensesp - && oldsensesp->sensesp() - && VN_IS(oldsensesp->sensesp(), SenItem) + if (oldsensesp && oldsensesp->sensesp() && VN_IS(oldsensesp->sensesp(), SenItem) && VN_CAST(oldsensesp->sensesp(), SenItem)->isNever()) { // Never executing. Kill it. UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep, @@ -318,10 +315,11 @@ private: bool combo = m_itemCombo; bool sequent = m_itemSequent; - if (!combo && !sequent) combo=true; // If no list, Verilog 2000: always @ (*) + if (!combo && !sequent) combo = true; // If no list, Verilog 2000: always @ (*) if (combo && sequent) { if (!v3Global.opt.bboxUnsup()) { - nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity (no edge) sensitive activity list"); + nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity " + "(no edge) sensitive activity list"); } sequent = false; } @@ -336,8 +334,9 @@ private: // always (posedge RESET) { if (RESET).... } we know RESET is true. // Summarize a long list of combo inputs as just "combo" #ifndef __COVERITY__ // Else dead code on next line. - if (combo) oldsensesp->addSensesp - (new AstSenItem(nodep->fileline(), AstSenItem::Combo())); + if (combo) { + oldsensesp->addSensesp(new AstSenItem(nodep->fileline(), AstSenItem::Combo())); + } #endif wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp); } @@ -354,19 +353,18 @@ private: // Warn and/or convert any delayed assignments if (combo && !sequent) { if (kwd == VAlwaysKwd::ALWAYS_LATCH) { - ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_LATCH); + ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_LATCH); } else { - ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_COMBO); + ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_COMBO); } - } - else if (!combo && sequent) { - ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_SEQ); + } else if (!combo && sequent) { + ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_SEQ); } } virtual void visit(AstAlways* nodep) VL_OVERRIDE { // Move always to appropriate ACTIVE based on its sense list - UINFO(4," ALW "<=9) nodep->dumpTree(cout, " Alw: "); + UINFO(4, " ALW " << nodep << endl); + // if (debug()>=9) nodep->dumpTree(cout, " Alw: "); if (!nodep->bodysp()) { // Empty always. Kill it. @@ -377,15 +375,15 @@ private: } virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // Move always to appropriate ACTIVE based on its sense list - UINFO(4," ALWPub "<=9) nodep->dumpTree(cout, " Alw: "); + UINFO(4, " ALWPub " << nodep << endl); + // if (debug()>=9) nodep->dumpTree(cout, " Alw: "); visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS); } virtual void visit(AstSenGate* nodep) VL_OVERRIDE { AstSenItem* subitemp = nodep->sensesp(); UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE - || subitemp->edgeType() == VEdgeType::ET_POSEDGE - || subitemp->edgeType() == VEdgeType::ET_NEGEDGE, + || subitemp->edgeType() == VEdgeType::ET_POSEDGE + || subitemp->edgeType() == VEdgeType::ET_NEGEDGE, nodep, "Strange activity type under SenGate"); iterateChildren(nodep); } @@ -399,7 +397,7 @@ private: // V3LinkResolve should have cleaned most of these up if (!nodep->varrefp()->width1()) { nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: " - <varrefp()->prettyNameQ()); + << nodep->varrefp()->prettyNameQ()); } m_itemSequent = true; nodep->varrefp()->varp()->usedClock(true); @@ -426,9 +424,7 @@ public: // Active class functions void V3Active::activeAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp index 43552c170..e7548a7c5 100644 --- a/src/V3ActiveTop.cpp +++ b/src/V3ActiveTop.cpp @@ -42,11 +42,11 @@ private: // AstNode::user() bool. True if processed // Each call to V3Const::constify // AstNode::user4() Used by V3Const::constify, called below - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE - AstTopScope* m_topscopep; // Top scope for adding sentrees under - SenTreeFinder m_finder; // Find global sentree's and add them + AstTopScope* m_topscopep; // Top scope for adding sentrees under + SenTreeFinder m_finder; // Find global sentree's and add them // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -61,16 +61,16 @@ private: virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { // Create required actives and add to module // We can start ordering at a module, or a scope - UINFO(4," MOD "<sensesp(); UASSERT_OBJ(sensesp, nodep, "NULL"); - if (sensesp->sensesp() - && VN_IS(sensesp->sensesp(), SenItem) + if (sensesp->sensesp() && VN_IS(sensesp->sensesp(), SenItem) && VN_CAST(sensesp->sensesp(), SenItem)->isNever()) { // Never executing. Kill it. UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep, @@ -80,10 +80,9 @@ private: } // Copy combo tree to settlement tree with duplicated statements if (sensesp->hasCombo()) { - AstSenTree* newsentreep - = new AstSenTree(nodep->fileline(), - new AstSenItem(nodep->fileline(), AstSenItem::Settle())); - AstActive* newp = new AstActive(nodep->fileline(),"settle", newsentreep); + AstSenTree* newsentreep = new AstSenTree( + nodep->fileline(), new AstSenItem(nodep->fileline(), AstSenItem::Settle())); + AstActive* newp = new AstActive(nodep->fileline(), "settle", newsentreep); newp->sensesStorep(newsentreep); if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->cloneTree(true)); nodep->addNextHere(newp); @@ -91,10 +90,10 @@ private: // Move the SENTREE for each active up to the global level. // This way we'll easily see what clock domains are identical AstSenTree* wantp = m_finder.getSenTree(nodep->fileline(), sensesp); - UINFO(4," lookdone\n"); + UINFO(4, " lookdone\n"); if (wantp != sensesp) { // Move the active's contents to the other active - UINFO(4," merge active "<sensesStorep()) { UASSERT_OBJ(sensesp == nodep->sensesStorep(), nodep, "sensesStore should have been deleted earlier if different"); @@ -107,7 +106,7 @@ private: nodep->sensesp(wantp); } // No need to do statements under it, they're already moved. - //iterateChildren(nodep); + // iterateChildren(nodep); } virtual void visit(AstInitial* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE nodep->v3fatalSrc("Node should have been under ACTIVE"); @@ -145,9 +144,7 @@ public: // Active class functions void V3ActiveTop::activeTopAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 023450b9c..37377ac38 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -34,24 +34,22 @@ private: // NODE STATE/TYPES // Cleared on netlist // AstNode::user() -> bool. True if processed - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE - AstNodeModule* m_modp; // Last module - AstBegin* m_beginp; // Last begin - unsigned m_modPastNum; // Module past numbering - VDouble0 m_statCover; // Statistic tracking - VDouble0 m_statAsNotImm; // Statistic tracking - VDouble0 m_statAsImm; // Statistic tracking - VDouble0 m_statAsFull; // Statistic tracking + AstNodeModule* m_modp; // Last module + AstBegin* m_beginp; // Last begin + unsigned m_modPastNum; // Module past numbering + VDouble0 m_statCover; // Statistic tracking + VDouble0 m_statAsNotImm; // Statistic tracking + VDouble0 m_statAsImm; // Statistic tracking + VDouble0 m_statAsFull; // Statistic tracking // METHODS string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) { - return (string("[%0t] "+prefix+": ")+nodep->fileline()->filebasename() - +":"+cvtToStr(nodep->fileline()->lineno()) - +": Assertion failed in %m" - +((message != "")?": ":"")+message - +"\n"); + return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":" + + cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m" + + ((message != "") ? ": " : "") + message + "\n"); } void replaceDisplay(AstDisplay* nodep, const string& prefix) { nodep->displayType(AstDisplayType::DT_WRITE); @@ -77,8 +75,8 @@ private: // If assertions are off, have constant propagation rip them out later // This allows syntax errors and such to be detected normally. (v3Global.opt.assertOn() - ? static_cast(new AstCMath(fl, "Verilated::assertOn()", 1)) - : static_cast(new AstConst(fl, AstConst::LogicFalse()))), + ? static_cast(new AstCMath(fl, "Verilated::assertOn()", 1)) + : static_cast(new AstConst(fl, AstConst::LogicFalse()))), nodep, NULL); newp->user1(true); // Don't assert/cover this if return newp; @@ -86,8 +84,8 @@ private: AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) { // Like newFireAssert() but omits the asserts-on check - AstDisplay* dispp = new AstDisplay(nodep->fileline(), - AstDisplayType::DT_ERROR, message, NULL, NULL); + AstDisplay* dispp + = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message, NULL, NULL); AstNode* bodysp = dispp; replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format bodysp->addNext(new AstStop(nodep->fileline(), true)); @@ -129,7 +127,7 @@ private: AstCoverInc* covincp = VN_CAST(snodep->coverincp(), CoverInc); UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion"); covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace - if (message!="") covincp->declp()->comment(message); + if (message != "") covincp->declp()->comment(message); bodysp = covincp; } @@ -137,8 +135,11 @@ private: ifp = new AstIf(nodep->fileline(), propp, bodysp, NULL); bodysp = ifp; } else if (VN_IS(nodep, Assert)) { - if (nodep->immediate()) ++m_statAsImm; - else ++m_statAsNotImm; + if (nodep->immediate()) { + ++m_statAsImm; + } else { + ++m_statAsNotImm; + } if (passsp) passsp = newIfAssertOn(passsp); if (failsp) failsp = newIfAssertOn(failsp); if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed."); @@ -153,9 +154,10 @@ private: AstNode* newp; if (sentreep) { - newp = new AstAlways(nodep->fileline(), - VAlwaysKwd::ALWAYS, sentreep, bodysp); - } else { newp = bodysp; } + newp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, bodysp); + } else { + newp = bodysp; + } // Install it if (selfDestruct) { // Delete it after making the tree. This way we can tell the user @@ -186,7 +188,7 @@ private: iterateAndNextNull(ifp->ifsp()); // If the last else is not an else if, recurse into that too. - if (ifp->elsesp() && !nextifp) { + if (ifp->elsesp() && !nextifp) { // iterateAndNextNull(ifp->elsesp()); } @@ -199,14 +201,12 @@ private: } // Record if this ends with an 'else' that does not have an if - if (ifp->elsesp() && !nextifp) { - hasDefaultElse = true; - } + if (ifp->elsesp() && !nextifp) hasDefaultElse = true; ifp = nextifp; } while (ifp); - AstNode *newifp = nodep->cloneTree(false); + AstNode* newifp = nodep->cloneTree(false); bool allow_none = nodep->unique0Pragma(); // Empty case means no property @@ -215,12 +215,11 @@ private: // Note: if this ends with an 'else', then we don't need to validate that one of the // predicates evaluates to true. AstNode* ohot = ((allow_none || hasDefaultElse) - ? static_cast(new AstOneHot0(nodep->fileline(), propp)) - : static_cast(new AstOneHot(nodep->fileline(), propp))); - AstIf* checkifp = new AstIf(nodep->fileline(), - new AstLogNot(nodep->fileline(), ohot), - newFireAssert(nodep, "'unique if' statement violated"), - newifp); + ? static_cast(new AstOneHot0(nodep->fileline(), propp)) + : static_cast(new AstOneHot(nodep->fileline(), propp))); + AstIf* checkifp + = new AstIf(nodep->fileline(), new AstLogNot(nodep->fileline(), ohot), + newFireAssert(nodep, "'unique if' statement violated"), newifp); checkifp->branchPred(VBranchPred::BP_UNLIKELY); nodep->replaceWith(checkifp); pushDeletep(nodep); @@ -234,16 +233,17 @@ private: iterateChildren(nodep); if (!nodep->user1SetOnce()) { bool has_default = false; - for (AstCaseItem* itemp = nodep->itemsp(); - itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { if (itemp->isDefault()) has_default = true; } if (nodep->fullPragma() || nodep->priorityPragma()) { // Simply need to add a default if there isn't one already ++m_statAsFull; if (!has_default) { - nodep->addItemsp(new AstCaseItem(nodep->fileline(), NULL/*DEFAULT*/, - newFireAssert(nodep, "synthesis full_case, but non-match found"))); + nodep->addItemsp(new AstCaseItem( + nodep->fileline(), NULL /*DEFAULT*/, + newFireAssert(nodep, "synthesis full_case, but non-match found"))); } } if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) { @@ -271,8 +271,11 @@ private: nodep->exprp()->cloneTree(false), icondp->cloneTree(false)); } - if (propp) propp = new AstConcat(icondp->fileline(), onep, propp); - else propp = onep; + if (propp) { + propp = new AstConcat(icondp->fileline(), onep, propp); + } else { + propp = onep; + } } } // Empty case means no property @@ -281,12 +284,13 @@ private: bool allow_none = has_default || nodep->unique0Pragma(); AstNode* ohot = (allow_none - ? static_cast(new AstOneHot0(nodep->fileline(), propp)) - : static_cast(new AstOneHot(nodep->fileline(), propp))); - AstIf* ifp = new AstIf(nodep->fileline(), - new AstLogNot(nodep->fileline(), ohot), - newFireAssert(nodep, "synthesis parallel_case, but multiple matches found"), - NULL); + ? static_cast(new AstOneHot0(nodep->fileline(), propp)) + : static_cast(new AstOneHot(nodep->fileline(), propp))); + AstIf* ifp = new AstIf( + nodep->fileline(), new AstLogNot(nodep->fileline(), ohot), + newFireAssert(nodep, + "synthesis parallel_case, but multiple matches found"), + NULL); ifp->branchPred(VBranchPred::BP_UNLIKELY); nodep->addNotParallelp(ifp); } @@ -303,23 +307,22 @@ private: "Expected constant ticks, checked in V3Width"); ticks = VN_CAST(nodep->ticksp(), Const)->toUInt(); } - UASSERT_OBJ(ticks>=1, nodep, "0 tick should have been checked in V3Width"); + UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width"); AstNode* inp = nodep->exprp()->unlinkFrBack(); AstVar* invarp = NULL; - AstSenTree* sentreep = nodep->sentreep(); sentreep->unlinkFrBack(); - AstAlways* alwaysp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, - sentreep, NULL); + AstSenTree* sentreep = nodep->sentreep(); + sentreep->unlinkFrBack(); + AstAlways* alwaysp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, NULL); m_modp->addStmtp(alwaysp); - for (uint32_t i=0; ifileline(), AstVarType::MODULETEMP, - "_Vpast_"+cvtToStr(m_modPastNum++)+"_"+cvtToStr(i), + "_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i), inp->dtypep()); m_modp->addStmtp(outvarp); AstNode* assp = new AstAssignDly(nodep->fileline(), - new AstVarRef(nodep->fileline(), outvarp, true), - inp); + new AstVarRef(nodep->fileline(), outvarp, true), inp); alwaysp->addStmtp(assp); - //if (debug()>-9) assp->dumpTree(cout, "-ass: "); + // if (debug()>-9) assp->dumpTree(cout, "-ass: "); invarp = outvarp; inp = new AstVarRef(nodep->fileline(), invarp, false); } @@ -334,12 +337,12 @@ private: virtual void visit(AstDisplay* nodep) VL_OVERRIDE { iterateChildren(nodep); // Replace the special types with standard text - if (nodep->displayType()==AstDisplayType::DT_INFO) { + if (nodep->displayType() == AstDisplayType::DT_INFO) { replaceDisplay(nodep, "-Info"); - } else if (nodep->displayType()==AstDisplayType::DT_WARNING) { + } else if (nodep->displayType() == AstDisplayType::DT_WARNING) { replaceDisplay(nodep, "%%Warning"); - } else if (nodep->displayType()==AstDisplayType::DT_ERROR - || nodep->displayType()==AstDisplayType::DT_FATAL) { + } else if (nodep->displayType() == AstDisplayType::DT_ERROR + || nodep->displayType() == AstDisplayType::DT_FATAL) { replaceDisplay(nodep, "%%Error"); } } @@ -403,9 +406,7 @@ public: // Top Assert class void V3Assert::assertAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index aec7c4761..0cd815b40 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -61,14 +61,12 @@ private: } return newp; } - void clearAssertInfo() { - m_senip = NULL; - } + void clearAssertInfo() { m_senip = NULL; } // VISITORS //========== Statements virtual void visit(AstClocking* nodep) VL_OVERRIDE { - UINFO(8," CLOCKING"<sensesp(); // Trash it, keeping children @@ -81,9 +79,7 @@ private: } virtual void visit(AstAlways* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->sensesp()); - if (nodep->sensesp()) { - m_seniAlwaysp = nodep->sensesp()->sensesp(); - } + if (nodep->sensesp()) m_seniAlwaysp = nodep->sensesp()->sensesp(); iterateAndNextNull(nodep->bodysp()); m_seniAlwaysp = NULL; } @@ -93,9 +89,7 @@ private: clearAssertInfo(); // Find Clocking's buried under nodep->exprsp iterateChildren(nodep); - if (!nodep->immediate()) { - nodep->sentreep(newSenTree(nodep)); - } + if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep)); clearAssertInfo(); } virtual void visit(AstPast* nodep) VL_OVERRIDE { @@ -106,21 +100,18 @@ private: virtual void visit(AstPropClocked* nodep) VL_OVERRIDE { // No need to iterate the body, once replace will get iterated iterateAndNextNull(nodep->sensesp()); - if (m_senip) { - nodep->v3error("Unsupported: Only one PSL clock allowed per assertion"); - } + if (m_senip) nodep->v3error("Unsupported: Only one PSL clock allowed per assertion"); // Block is the new expression to evaluate AstNode* blockp = nodep->propp()->unlinkFrBack(); if (nodep->disablep()) { if (VN_IS(nodep->backp(), Cover)) { - blockp = new AstAnd(nodep->disablep()->fileline(), - new AstNot(nodep->disablep()->fileline(), - nodep->disablep()->unlinkFrBack()), - blockp); + blockp = new AstAnd( + nodep->disablep()->fileline(), + new AstNot(nodep->disablep()->fileline(), nodep->disablep()->unlinkFrBack()), + blockp); } else { blockp = new AstOr(nodep->disablep()->fileline(), - nodep->disablep()->unlinkFrBack(), - blockp); + nodep->disablep()->unlinkFrBack(), blockp); } } // Unlink and just keep a pointer to it, convert to sentree as needed @@ -151,9 +142,7 @@ public: // Top Assert class void V3AssertPre::assertPreAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3AstConstOnly.h b/src/V3AstConstOnly.h index 7278ecfbe..1e9286c47 100644 --- a/src/V3AstConstOnly.h +++ b/src/V3AstConstOnly.h @@ -18,12 +18,12 @@ #define _V3ASTCONSTONLY_H_ 1 // Include only in visitors that do not not edit nodes, so should use constant iterators -#define iterateAndNext error_use_iterateAndNextConst -#define iterateChildren error_use_iterateChildrenConst +#define iterateAndNext error_use_iterateAndNextConst +#define iterateChildren error_use_iterateChildrenConst -#define addNext error_no_addNext_in_ConstOnlyVisitor -#define replaceWith error_no_replaceWith_in_ConstOnlyVisitor -#define deleteTree error_no_deleteTree_in_ConstOnlyVisitor -#define unlinkFrBack error_no_unlinkFrBack_in_ConstOnlyVisitor +#define addNext error_no_addNext_in_ConstOnlyVisitor +#define replaceWith error_no_replaceWith_in_ConstOnlyVisitor +#define deleteTree error_no_deleteTree_in_ConstOnlyVisitor +#define unlinkFrBack error_no_unlinkFrBack_in_ConstOnlyVisitor #endif // Guard diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp index 0a4a07ac2..b89dc427d 100644 --- a/src/V3Branch.cpp +++ b/src/V3Branch.cpp @@ -41,15 +41,15 @@ private: // NODE STATE // Entire netlist: // AstFTask::user1() -> int. Number of references - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // TYPES typedef std::vector CFuncVec; // STATE - int m_likely; // Excuses for branch likely taken - int m_unlikely; // Excuses for branch likely not taken - CFuncVec m_cfuncsp; // List of all tasks + int m_likely; // Excuses for branch likely taken + int m_unlikely; // Excuses for branch likely not taken + CFuncVec m_cfuncsp; // List of all tasks // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -60,14 +60,14 @@ private: } void checkUnlikely(AstNode* nodep) { if (nodep->isUnlikely()) { - UINFO(4," UNLIKELY: "<dontInline()) { - nodep->isInline(true); - } + if (!nodep->dontInline()) nodep->isInline(true); } } @@ -131,6 +129,6 @@ public: // Branch class functions void V3Branch::branchAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<classp(nodep); v3Global.rootp()->addModulep(packagep); // Add package to hierarchy - AstCell* cellp = new AstCell(packagep->fileline(), - packagep->fileline(), - packagep->name(), - packagep->name(), - NULL, NULL, NULL); + AstCell* cellp = new AstCell(packagep->fileline(), packagep->fileline(), packagep->name(), + packagep->name(), NULL, NULL, NULL); cellp->modp(packagep); v3Global.rootp()->topModulep()->addStmtp(cellp); // Find class's scope // Alternative would be to move this and related to V3Scope AstScope* classScopep = NULL; for (AstNode* itp = nodep->stmtsp(); itp; itp = itp->nextp()) { - if ((classScopep = VN_CAST(itp, Scope))) { - break; - } + if ((classScopep = VN_CAST(itp, Scope))) break; } UASSERT_OBJ(classScopep, nodep, "No scope under class"); // Add scope - AstScope* scopep = new AstScope(nodep->fileline(), - packagep, classScopep->name(), classScopep->aboveScopep(), - classScopep->aboveCellp()); + AstScope* scopep = new AstScope(nodep->fileline(), packagep, classScopep->name(), + classScopep->aboveScopep(), classScopep->aboveCellp()); packagep->addStmtp(scopep); // Iterate string prevPrefix = m_prefix; @@ -103,7 +97,7 @@ private: iterateChildren(nodep); // Don't move now, or wouldn't keep interating the class // TODO move class statics only - //if (m_classScopep) { + // if (m_classScopep) { // m_moves.push_back(make_pair(nodep, m_classScopep)); //} } @@ -111,7 +105,7 @@ private: iterateChildren(nodep); // Don't move now, or wouldn't keep interating the class // TODO move function statics only - //if (m_classScopep) { + // if (m_classScopep) { // m_moves.push_back(make_pair(nodep, m_classScopep)); //} } diff --git a/src/V3Config.cpp b/src/V3Config.cpp index 406b9b639..46b491e90 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -267,7 +267,7 @@ class V3ConfigFile { LineAttrMap m_lineAttrs; // Atributes to line mapping IgnLines m_ignLines; // Ignore line settings - Waivers m_waivers; // Waive messages + Waivers m_waivers; // Waive messages struct { int lineno; // Last line number @@ -346,7 +346,9 @@ public: bool waive(V3ErrorCode code, const string& match) { for (Waivers::const_iterator it = m_waivers.begin(); it != m_waivers.end(); ++it) { if (((it->first == code) || (it->first == V3ErrorCode::I_LINT)) - && VString::wildmatch(match, it->second)) return true; + && VString::wildmatch(match, it->second)) { + return true; + } } return false; } diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index 69f8288c8..953e9dc7c 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -40,14 +40,16 @@ class CoverageVisitor : public AstNVisitor { private: // TYPES - typedef std::map FileMap; + typedef std::map FileMap; struct ToggleEnt { - string m_comment; // Comment for coverage dump - AstNode* m_varRefp; // How to get to this element - AstNode* m_chgRefp; // How to get to this element + string m_comment; // Comment for coverage dump + AstNode* m_varRefp; // How to get to this element + AstNode* m_chgRefp; // How to get to this element ToggleEnt(const string& comment, AstNode* vp, AstNode* cp) - : m_comment(comment), m_varRefp(vp), m_chgRefp(cp) {} + : m_comment(comment) + , m_varRefp(vp) + , m_chgRefp(cp) {} ~ToggleEnt() {} void cleanup() { VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = NULL); @@ -58,15 +60,15 @@ private: // NODE STATE // Entire netlist: // AstIf::user1() -> bool. True indicates ifelse processed - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE - bool m_checkBlock; // Should this block get covered? - AstNodeModule* m_modp; // Current module to add statement to - bool m_inToggleOff; // In function/task etc - bool m_inModOff; // In module with no coverage - FileMap m_fileps; // Column counts for each fileline - string m_beginHier; // AstBegin hier name for user coverage points + bool m_checkBlock; // Should this block get covered? + AstNodeModule* m_modp; // Current module to add statement to + bool m_inToggleOff; // In function/task etc + bool m_inModOff; // In module with no coverage + FileMap m_fileps; // Column counts for each fileline + string m_beginHier; // AstBegin hier name for user coverage points // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -74,16 +76,13 @@ private: const char* varIgnoreToggle(AstVar* nodep) { // Return true if this shouldn't be traced // See also similar rule in V3TraceDecl::varIgnoreTrace - if (!nodep->isToggleCoverable()) - return "Not relevant signal type"; + if (!nodep->isToggleCoverable()) return "Not relevant signal type"; if (!v3Global.opt.coverageUnderscore()) { string prettyName = nodep->prettyName(); - if (prettyName[0] == '_') - return "Leading underscore"; - if (prettyName.find("._") != string::npos) - return "Inlined leading underscore"; + if (prettyName[0] == '_') return "Leading underscore"; + if (prettyName.find("._") != string::npos) return "Inlined leading underscore"; } - if ((nodep->width()*nodep->dtypep()->arrayUnpackedElements()) > 256) { + if ((nodep->width() * nodep->dtypep()->arrayUnpackedElements()) > 256) { return "Wide bus/array > 256 bits"; } // We allow this, though tracing doesn't @@ -91,19 +90,18 @@ private: return NULL; } - AstCoverInc* newCoverInc(FileLine* fl, const string& hier, - const string& page_prefix, const string& comment, - const string& trace_var_name) { + AstCoverInc* newCoverInc(FileLine* fl, const string& hier, const string& page_prefix, + const string& comment, const string& trace_var_name) { // For line coverage, we may have multiple if's on one line, so disambiguate if // everything is otherwise identical // (Don't set column otherwise as it may result in making bins not match up with // different types of coverage enabled.) - string key = fl->filename()+"\001"+cvtToStr(fl->lineno()) - +"\001"+hier+"\001"+page_prefix+"\001"+comment; + string key = fl->filename() + "\001" + cvtToStr(fl->lineno()) + "\001" + hier + "\001" + + page_prefix + "\001" + comment; int column = 0; FileMap::iterator it = m_fileps.find(key); if (it == m_fileps.end()) { - m_fileps.insert(make_pair(key, column+1)); + m_fileps.insert(make_pair(key, column + 1)); } else { column = (it->second)++; } @@ -122,27 +120,23 @@ private: AstCoverInc* incp = new AstCoverInc(fl, declp); if (!trace_var_name.empty() && v3Global.opt.traceCoverage()) { - AstVar* varp = new AstVar(incp->fileline(), - AstVarType::MODULETEMP, trace_var_name, + AstVar* varp = new AstVar(incp->fileline(), AstVarType::MODULETEMP, trace_var_name, incp->findUInt32DType()); varp->trace(true); varp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); m_modp->addStmtp(varp); - UINFO(5, "New coverage trace: "<fileline(), - new AstVarRef(incp->fileline(), varp, true), - new AstAdd(incp->fileline(), - new AstVarRef(incp->fileline(), varp, false), + UINFO(5, "New coverage trace: " << varp << endl); + AstAssign* assp = new AstAssign( + incp->fileline(), new AstVarRef(incp->fileline(), varp, true), + new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, false), new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1))); incp->addNext(assp); } return incp; } string traceNameForLine(AstNode* nodep, const string& type) { - return "vlCoverageLineTrace_"+nodep->fileline()->filebasenameNoExt() - +"__"+cvtToStr(nodep->fileline()->lineno()) - +"_"+type; + return "vlCoverageLineTrace_" + nodep->fileline()->filebasenameNoExt() + "__" + + cvtToStr(nodep->fileline()->lineno()) + "_" + type; } // VISITORS - BOTH virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { @@ -169,13 +163,13 @@ private: } virtual void visit(AstVar* nodep) VL_OVERRIDE { iterateChildren(nodep); - if (m_modp && !m_inModOff && !m_inToggleOff - && nodep->fileline()->coverageOn() && v3Global.opt.coverageToggle()) { + if (m_modp && !m_inModOff && !m_inToggleOff && nodep->fileline()->coverageOn() + && v3Global.opt.coverageToggle()) { const char* disablep = varIgnoreToggle(nodep); if (disablep) { - UINFO(4, " Disable Toggle: "<shortName(); - AstVar* chgVarp = new AstVar(nodep->fileline(), - AstVarType::MODULETEMP, newvarname, nodep); + string newvarname = string("__Vtogcov__") + nodep->shortName(); + AstVar* chgVarp + = new AstVar(nodep->fileline(), AstVarType::MODULETEMP, newvarname, nodep); chgVarp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); m_modp->addStmtp(chgVarp); @@ -198,123 +192,108 @@ private: // This is necessarily an O(n^2) expansion, which is why // we limit coverage to signals with < 256 bits. - ToggleEnt newvec (string(""), - new AstVarRef(nodep->fileline(), nodep, false), - new AstVarRef(nodep->fileline(), chgVarp, true)); - toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec, - nodep, chgVarp); + ToggleEnt newvec(string(""), new AstVarRef(nodep->fileline(), nodep, false), + new AstVarRef(nodep->fileline(), chgVarp, true)); + toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec, nodep, chgVarp); newvec.cleanup(); } } } void toggleVarBottom(const ToggleEnt& above, const AstVar* varp) { - AstCoverToggle* newp - = new AstCoverToggle(varp->fileline(), - newCoverInc(varp->fileline(), "", "v_toggle", - varp->name()+above.m_comment, ""), - above.m_varRefp->cloneTree(true), - above.m_chgRefp->cloneTree(true)); + AstCoverToggle* newp = new AstCoverToggle( + varp->fileline(), + newCoverInc(varp->fileline(), "", "v_toggle", varp->name() + above.m_comment, ""), + above.m_varRefp->cloneTree(true), above.m_chgRefp->cloneTree(true)); m_modp->addStmtp(newp); } void toggleVarRecurse(AstNodeDType* dtypep, int depth, // per-iteration - const ToggleEnt& above, - AstVar* varp, AstVar* chgVarp) { // Constant + const ToggleEnt& above, AstVar* varp, AstVar* chgVarp) { // Constant if (const AstBasicDType* bdtypep = VN_CAST(dtypep, BasicDType)) { if (bdtypep->isRanged()) { - for (int index_docs=bdtypep->lsb(); index_docsmsb()+1; index_docs++) { + for (int index_docs = bdtypep->lsb(); index_docs < bdtypep->msb() + 1; + index_docs++) { int index_code = index_docs - bdtypep->lsb(); - ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]", - new AstSel(varp->fileline(), - above.m_varRefp->cloneTree(true), index_code, 1), - new AstSel(varp->fileline(), - above.m_chgRefp->cloneTree(true), index_code, 1)); + ToggleEnt newent(above.m_comment + string("[") + cvtToStr(index_docs) + "]", + new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true), + index_code, 1), + new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true), + index_code, 1)); toggleVarBottom(newent, varp); newent.cleanup(); } } else { toggleVarBottom(above, varp); } - } - else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { - for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb(); ++index_docs) { + } else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { + for (int index_docs = adtypep->lsb(); index_docs <= adtypep->msb(); ++index_docs) { int index_code = index_docs - adtypep->lsb(); - ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]", - new AstArraySel(varp->fileline(), - above.m_varRefp->cloneTree(true), index_code), - new AstArraySel(varp->fileline(), - above.m_chgRefp->cloneTree(true), index_code)); - toggleVarRecurse(adtypep->subDTypep()->skipRefp(), depth+1, - newent, - varp, chgVarp); + ToggleEnt newent(above.m_comment + string("[") + cvtToStr(index_docs) + "]", + new AstArraySel(varp->fileline(), + above.m_varRefp->cloneTree(true), index_code), + new AstArraySel(varp->fileline(), + above.m_chgRefp->cloneTree(true), index_code)); + toggleVarRecurse(adtypep->subDTypep()->skipRefp(), depth + 1, newent, varp, + chgVarp); newent.cleanup(); } - } - else if (AstPackArrayDType* adtypep = VN_CAST(dtypep, PackArrayDType)) { - for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb(); ++index_docs) { + } else if (AstPackArrayDType* adtypep = VN_CAST(dtypep, PackArrayDType)) { + for (int index_docs = adtypep->lsb(); index_docs <= adtypep->msb(); ++index_docs) { AstNodeDType* subtypep = adtypep->subDTypep()->skipRefp(); int index_code = index_docs - adtypep->lsb(); - ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]", - new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true), - index_code*subtypep->width(), subtypep->width()), - new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true), - index_code*subtypep->width(), subtypep->width())); - toggleVarRecurse(adtypep->subDTypep()->skipRefp(), depth+1, - newent, - varp, chgVarp); + ToggleEnt newent(above.m_comment + string("[") + cvtToStr(index_docs) + "]", + new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true), + index_code * subtypep->width(), subtypep->width()), + new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true), + index_code * subtypep->width(), subtypep->width())); + toggleVarRecurse(adtypep->subDTypep()->skipRefp(), depth + 1, newent, varp, + chgVarp); newent.cleanup(); } - } - else if (AstStructDType* adtypep = VN_CAST(dtypep, StructDType)) { + } else if (AstStructDType* adtypep = VN_CAST(dtypep, StructDType)) { // For now it's packed, so similar to array - for (AstMemberDType* itemp = adtypep->membersp(); - itemp; itemp=VN_CAST(itemp->nextp(), MemberDType)) { + for (AstMemberDType* itemp = adtypep->membersp(); itemp; + itemp = VN_CAST(itemp->nextp(), MemberDType)) { AstNodeDType* subtypep = itemp->subDTypep()->skipRefp(); int index_code = itemp->lsb(); - ToggleEnt newent (above.m_comment+string(".")+itemp->name(), - new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true), - index_code, subtypep->width()), - new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true), - index_code, subtypep->width())); - toggleVarRecurse(subtypep, depth+1, - newent, - varp, chgVarp); + ToggleEnt newent(above.m_comment + string(".") + itemp->name(), + new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true), + index_code, subtypep->width()), + new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true), + index_code, subtypep->width())); + toggleVarRecurse(subtypep, depth + 1, newent, varp, chgVarp); newent.cleanup(); } - } - else if (AstUnionDType* adtypep = VN_CAST(dtypep, UnionDType)) { + } else if (AstUnionDType* adtypep = VN_CAST(dtypep, UnionDType)) { // Arbitrarily handle only the first member of the union if (AstMemberDType* itemp = adtypep->membersp()) { AstNodeDType* subtypep = itemp->subDTypep()->skipRefp(); - ToggleEnt newent (above.m_comment+string(".")+itemp->name(), - above.m_varRefp->cloneTree(true), - above.m_chgRefp->cloneTree(true)); - toggleVarRecurse(subtypep, depth+1, - newent, - varp, chgVarp); + ToggleEnt newent(above.m_comment + string(".") + itemp->name(), + above.m_varRefp->cloneTree(true), + above.m_chgRefp->cloneTree(true)); + toggleVarRecurse(subtypep, depth + 1, newent, varp, chgVarp); newent.cleanup(); } - } - else { + } else { dtypep->v3fatalSrc("Unexpected node data type in toggle coverage generation: " - <prettyTypeName()); + << dtypep->prettyTypeName()); } } // VISITORS - LINE COVERAGE - virtual void visit(AstIf* nodep) VL_OVERRIDE { // Note not AstNodeIf; other types don't get covered - UINFO(4," IF: "<elsesp(), If) - && !VN_CAST(nodep->elsesp(), If)->nextp()); + bool elsif = (VN_IS(nodep->elsesp(), If) && !VN_CAST(nodep->elsesp(), If)->nextp()); if (elsif) VN_CAST(nodep->elsesp(), If)->user1(true); // iterateAndNextNull(nodep->ifsp()); - if (m_checkBlock && !m_inModOff - && nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) { // if a "if" branch didn't disable it - UINFO(4," COVER: "<fileline()->coverageOn() + && v3Global.opt.coverageLine()) { // if a "if" branch didn't disable it + UINFO(4, " COVER: " << nodep << endl); if (nodep->user1()) { nodep->addIfsp(newCoverInc(nodep->fileline(), "", "v_line", "elsif", traceNameForLine(nodep, "elsif"))); @@ -327,13 +306,12 @@ private: if (nodep->elsesp()) { m_checkBlock = true; iterateAndNextNull(nodep->elsesp()); - if (m_checkBlock && !m_inModOff - && nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) { // if a "else" branch didn't disable it - UINFO(4," COVER: "<fileline()->coverageOn() + && v3Global.opt.coverageLine()) { // if a "else" branch didn't disable it + UINFO(4, " COVER: " << nodep << endl); if (!elsif) { // elsif done inside if() - nodep->addElsesp(newCoverInc(nodep->elsesp()->fileline(), - "", "v_line", "else", - traceNameForLine(nodep, "else"))); + nodep->addElsesp(newCoverInc(nodep->elsesp()->fileline(), "", "v_line", + "else", traceNameForLine(nodep, "else"))); } } } @@ -341,12 +319,12 @@ private: } } virtual void visit(AstCaseItem* nodep) VL_OVERRIDE { - UINFO(4," CASEI: "<fileline()->coverageOn() && v3Global.opt.coverageLine()) { + UINFO(4, " CASEI: " << nodep << endl); + if (m_checkBlock && !m_inModOff && nodep->fileline()->coverageOn() + && v3Global.opt.coverageLine()) { iterateAndNextNull(nodep->bodysp()); if (m_checkBlock) { // if the case body didn't disable it - UINFO(4," COVER: "<addBodysp(newCoverInc(nodep->fileline(), "", "v_line", "case", traceNameForLine(nodep, "case"))); } @@ -354,24 +332,24 @@ private: } } virtual void visit(AstCover* nodep) VL_OVERRIDE { - UINFO(4," COVER: "<coverincp()) { // Note the name may be overridden by V3Assert processing nodep->coverincp(newCoverInc(nodep->fileline(), m_beginHier, "v_user", "cover", - m_beginHier+"_vlCoverageUserTrace")); + m_beginHier + "_vlCoverageUserTrace")); } m_checkBlock = true; // Reset as a child may have cleared it } virtual void visit(AstStop* nodep) VL_OVERRIDE { - UINFO(4," STOP: "<pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) { // Skip all NEXT nodes under this block, and skip this if/case branch - UINFO(4," OFF: "<unlinkFrBack()->deleteTree(), nodep); } else { @@ -388,8 +366,8 @@ private: bool oldtog = m_inToggleOff; { m_inToggleOff = true; - if (nodep->name()!="") { - m_beginHier = m_beginHier + (m_beginHier!=""?".":"") + nodep->name(); + if (nodep->name() != "") { + m_beginHier = m_beginHier + (m_beginHier != "" ? "." : "") + nodep->name(); } iterateChildren(nodep); } @@ -423,9 +401,7 @@ public: // Coverage class functions void V3Coverage::coverage(AstNetlist* rootp) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp index f721b4eeb..d25bd8c8f 100644 --- a/src/V3CoverageJoin.cpp +++ b/src/V3CoverageJoin.cpp @@ -17,7 +17,6 @@ // If two COVERTOGGLEs have same VARSCOPE, combine them //************************************************************************* - #include "config_build.h" #include "verilatedos.h" @@ -38,23 +37,23 @@ private: // V3Hashed // AstCoverToggle->VarRef::user4() // V3Hashed calculation - //AstUser4InUse In V3Hashed + // AstUser4InUse In V3Hashed // TYPES typedef std::vector ToggleList; // STATE - ToggleList m_toggleps; // List of of all AstCoverToggle's + ToggleList m_toggleps; // List of of all AstCoverToggle's - VDouble0 m_statToggleJoins; // Statistic tracking + VDouble0 m_statToggleJoins; // Statistic tracking // METHODS VL_DEBUG_FUNC; // Declare debug() void detectDuplicates() { - UINFO(9,"Finding duplicates\n"); + UINFO(9, "Finding duplicates\n"); // Note uses user4 - V3Hashed hashed; // Duplicate code detection + V3Hashed hashed; // Duplicate code detection // Hash all of the original signals we toggle cover for (ToggleList::iterator it = m_toggleps.begin(); it != m_toggleps.end(); ++it) { AstCoverToggle* nodep = *it; @@ -78,17 +77,18 @@ private: // covertoggle which is immediately above, so: AstCoverToggle* removep = VN_CAST(duporigp->backp(), CoverToggle); UASSERT_OBJ(removep, nodep, "CoverageJoin duplicate of wrong type"); - UINFO(8," Orig "<> "<incp()->declp()<> "<incp()->declp()<> " << nodep->incp()->declp() << endl); + UINFO(8, " dup " << removep << " -->> " << removep->incp()->declp() << endl); // The CoverDecl the duplicate pointed to now needs to point to the // original's data. I.e. the duplicate will get the coverage number // from the non-duplicate AstCoverDecl* datadeclp = nodep->incp()->declp()->dataDeclThisp(); removep->incp()->declp()->dataDeclp(datadeclp); - UINFO(8," new "<incp()->declp()<incp()->declp() << endl); // Mark the found node as a duplicate of the first node // (Not vice-versa as we have the iterator for the found node) - removep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(removep), removep); + removep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(removep), removep); // Remove node from comparison so don't hit it again hashed.erase(dupit); ++m_statToggleJoins; @@ -114,9 +114,7 @@ private: public: // CONSTRUCTORS - explicit CoverageJoinVisitor(AstNetlist* nodep) { - iterate(nodep); - } + explicit CoverageJoinVisitor(AstNetlist* nodep) { iterate(nodep); } virtual ~CoverageJoinVisitor() { V3Stats::addStat("Coverage, Toggle points joined", m_statToggleJoins); } @@ -126,9 +124,7 @@ public: // Coverage class functions void V3CoverageJoin::coverageJoin(AstNetlist* rootp) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index 8763ca6b8..9565a4a7a 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -40,20 +40,20 @@ private: // NODE STATE // STATE - AstNodeModule* m_modp; // Current module - AstCFunc* m_funcp; // Current block - AstNode* m_stmtp; // Current statement - int m_depth; // How deep in an expression - int m_maxdepth; // Maximum depth in an expression + AstNodeModule* m_modp; // Current module + AstCFunc* m_funcp; // Current block + AstNode* m_stmtp; // Current statement + int m_depth; // How deep in an expression + int m_maxdepth; // Maximum depth in an expression // METHODS VL_DEBUG_FUNC; // Declare debug() void createDeepTemp(AstNode* nodep) { - UINFO(6," Deep "<=9) nodep->dumpTree(cout, "deep:"); + UINFO(6, " Deep " << nodep << endl); + // if (debug()>=9) nodep->dumpTree(cout, "deep:"); - string newvarname = (string("__Vdeeptemp")+cvtToStr(m_modp->varNumGetInc())); + string newvarname = (string("__Vdeeptemp") + cvtToStr(m_modp->varNumGetInc())); AstVar* varp = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, // Width, not widthMin, as we may be in // middle of BITSEL expression which though @@ -69,8 +69,7 @@ private: nodep->replaceWith(newp); // Put assignment before the referencing statement AstAssign* assp = new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), varp, true), - nodep); + new AstVarRef(nodep->fileline(), varp, true), nodep); AstNRelinker linker2; m_stmtp->unlinkFrBack(&linker2); assp->addNext(m_stmtp); @@ -79,7 +78,7 @@ private: // VISITORS virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { - UINFO(4," MOD "<m_maxdepth) m_maxdepth = m_depth; + if (m_depth > m_maxdepth) m_maxdepth = m_depth; iterateChildren(nodep); m_depth -= 2; - if (m_stmtp - && (v3Global.opt.compLimitParens() >= 1) // Else compiler doesn't need it - && (m_maxdepth-m_depth) > v3Global.opt.compLimitParens() + if (m_stmtp && (v3Global.opt.compLimitParens() >= 1) // Else compiler doesn't need it + && (m_maxdepth - m_depth) > v3Global.opt.compLimitParens() && !VN_IS(nodep->backp(), NodeStmt) // Not much point if we're about to use it - ) { + ) { m_maxdepth = m_depth; createDeepTemp(nodep); } @@ -135,7 +132,7 @@ private: void needNonStaticFunc(AstNode* nodep) { UASSERT_OBJ(m_funcp, nodep, "Non-static accessor not under a function"); if (m_funcp->isStatic().trueUnknown()) { - UINFO(5,"Mark non-public due to "<isStatic(false); } } @@ -171,9 +168,7 @@ public: // Depth class functions void V3Depth::depthAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 6); } diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index 2abd25e6c..04fab51f6 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -38,10 +38,10 @@ private: // NODE STATE // STATE - AstNodeModule* m_modp; // Current module - AstCFunc* m_funcp; // Current function - int m_depth; // How deep in an expression - int m_deepNum; // How many functions made + AstNodeModule* m_modp; // Current module + AstCFunc* m_funcp; // Current function + int m_depth; // How deep in an expression + int m_deepNum; // How many functions made // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -50,7 +50,7 @@ private: AstNRelinker relinkHandle; nodep->unlinkFrBack(&relinkHandle); // Create function - string name = m_funcp->name()+"__deep"+cvtToStr(++m_deepNum); + string name = m_funcp->name() + "__deep" + cvtToStr(++m_deepNum); AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, NULL); funcp->argTypes(EmitCBaseVisitor::symClassVar()); funcp->symProlog(true); @@ -60,7 +60,7 @@ private: // Call it at the point where the body was removed from AstCCall* callp = new AstCCall(nodep->fileline(), funcp); callp->argTypes("vlSymsp"); - UINFO(6," New "< v3Global.opt.compLimitBlocks() && !VN_IS(nodep, NodeCCall)) { // Already done - UINFO(4, "DeepBlocks "<backp(); // Only for debug - if (debug()>=9) backp->dumpTree(cout, "- pre : "); + if (debug() >= 9) backp->dumpTree(cout, "- pre : "); AstCFunc* funcp = createDeepFunc(nodep); iterate(funcp); - if (debug()>=9) backp->dumpTree(cout, "- post: "); - if (debug()>=9) funcp->dumpTree(cout, "- func: "); + if (debug() >= 9) backp->dumpTree(cout, "- post: "); + if (debug() >= 9) funcp->dumpTree(cout, "- func: "); } else { iterateChildren(nodep); } @@ -135,9 +135,7 @@ public: // DepthBlock class functions void V3DepthBlock::depthBlockAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 3a20eefdc..3b0beaa15 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -119,8 +119,7 @@ private: } else if (relativeRefOk && scopep == m_scopep) { m_needThis = true; return "this->"; - } else if (relativeRefOk && scopep->aboveScopep() - && scopep->aboveScopep()==m_scopep) { + } else if (relativeRefOk && scopep->aboveScopep() && scopep->aboveScopep() == m_scopep) { // Reference to scope of cell directly under this module, can just "cell->" string name = scopep->name(); string::size_type pos; @@ -179,8 +178,8 @@ private: UASSERT_OBJ(funcp->scopep(), funcp, "Not scoped"); UINFO(6, " Wrapping " << name << " " << funcp << endl); - UINFO(6, " at " << newfuncp->argTypes() - << " und " << funcp->argTypes() << endl); + UINFO(6, + " at " << newfuncp->argTypes() << " und " << funcp->argTypes() << endl); funcp->declPrivate(true); AstNode* argsp = NULL; for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) { @@ -310,9 +309,7 @@ public: // Descope class functions void V3Descope::descopeAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index 3d6ee4b17..23a4aecf8 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -107,16 +107,14 @@ class EmitCInlines : EmitCBaseVisitor { public: explicit EmitCInlines(AstNetlist* nodep) { iterate(nodep); - if (v3Global.needHInlines()) { - emitInt(); - } + if (v3Global.needHInlines()) emitInt(); } }; void EmitCInlines::emitInt() { - string filename = v3Global.opt.makeDir()+"/"+topClassName()+"__Inlines.h"; - newCFile(filename, false/*slow*/, false/*source*/); - V3OutCFile hf (filename); + string filename = v3Global.opt.makeDir() + "/" + topClassName() + "__Inlines.h"; + newCFile(filename, false /*slow*/, false /*source*/); + V3OutCFile hf(filename); m_ofp = &hf; ofp()->putsHeader(); diff --git a/src/V3EmitV.h b/src/V3EmitV.h index 003c1e892..12dc38509 100644 --- a/src/V3EmitV.h +++ b/src/V3EmitV.h @@ -28,10 +28,9 @@ class V3EmitV { public: static void emitv(); - static void verilogForTree(AstNode* nodep, std::ostream& os=std::cout); - static void verilogPrefixedTree(AstNode* nodep, std::ostream& os, - const string& prefix, int flWidth, - AstSenTree* domainp, bool user3mark); + static void verilogForTree(AstNode* nodep, std::ostream& os = std::cout); + static void verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix, + int flWidth, AstSenTree* domainp, bool user3mark); static void emitvFiles(); }; diff --git a/src/V3Global.cpp b/src/V3Global.cpp index 226eb6915..54d20cb5d 100644 --- a/src/V3Global.cpp +++ b/src/V3Global.cpp @@ -76,7 +76,7 @@ void V3Global::readFiles() { } void V3Global::dumpCheckGlobalTree(const string& stagename, int newNumber, bool doDump) { - v3Global.rootp()->dumpTreeFile(v3Global.debugFilename(stagename + ".tree", newNumber), - false, doDump); + v3Global.rootp()->dumpTreeFile(v3Global.debugFilename(stagename + ".tree", newNumber), false, + doDump); if (v3Global.opt.stats()) V3Stats::statsStage(stagename); } diff --git a/src/V3Global.h b/src/V3Global.h index 5ae33fbf9..07bc52e7b 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -17,10 +17,12 @@ #ifndef _V3GLOBAL_H_ #define _V3GLOBAL_H_ 1 +// clang-format off #include "config_build.h" #ifndef HAVE_CONFIG_BUILD # error "Something failed during ./configure as config_build.h is incomplete. Perhaps you used autoreconf, don't." #endif +// clang-format on #include "verilatedos.h" @@ -35,21 +37,19 @@ class AstNetlist; //====================================================================== // Statics - //###################################################################### class VWidthMinUsage { public: - enum en { - LINT_WIDTH, - MATCHES_WIDTH, - VERILOG_WIDTH - }; + enum en { LINT_WIDTH, MATCHES_WIDTH, VERILOG_WIDTH }; enum en m_e; - inline VWidthMinUsage() : m_e(LINT_WIDTH) {} + inline VWidthMinUsage() + : m_e(LINT_WIDTH) {} // cppcheck-suppress noExplicitConstructor - inline VWidthMinUsage(en _e) : m_e(_e) {} - explicit inline VWidthMinUsage(int _e) : m_e(static_cast(_e)) {} + inline VWidthMinUsage(en _e) + : m_e(_e) {} + explicit inline VWidthMinUsage(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } }; inline bool operator==(const VWidthMinUsage& lhs, const VWidthMinUsage& rhs) { @@ -97,7 +97,10 @@ public: , m_needTraceDumper(false) , m_dpi(false) {} AstNetlist* makeNetlist(); - void boot() { UASSERT(!m_rootp, "call once"); m_rootp = makeNetlist(); } + void boot() { + UASSERT(!m_rootp, "call once"); + m_rootp = makeNetlist(); + } void clear(); // ACCESSORS (general) AstNetlist* rootp() const { return m_rootp; } @@ -107,16 +110,18 @@ public: // METHODS void readFiles(); void checkTree(); - static void dumpCheckGlobalTree(const string& stagename, int newNumber=0, bool doDump=true); + static void dumpCheckGlobalTree(const string& stagename, int newNumber = 0, + bool doDump = true); void assertDTypesResolved(bool flag) { m_assertDTypesResolved = flag; } void widthMinUsage(const VWidthMinUsage& flag) { m_widthMinUsage = flag; } bool constRemoveXs() const { return m_constRemoveXs; } void constRemoveXs(bool flag) { m_constRemoveXs = flag; } - string debugFilename(const string& nameComment, int newNumber=0) { + string debugFilename(const string& nameComment, int newNumber = 0) { ++m_debugFileNumber; if (newNumber) m_debugFileNumber = newNumber; - char digits[100]; sprintf(digits, "%03d", m_debugFileNumber); - return opt.makeDir()+"/"+opt.prefix()+"_"+digits+"_"+nameComment; + char digits[100]; + sprintf(digits, "%03d", m_debugFileNumber); + return opt.makeDir() + "/" + opt.prefix() + "_" + digits + "_" + nameComment; } bool needC11() const { return m_needC11; } void needC11(bool flag) { m_needC11 = flag; } diff --git a/src/V3Graph.h b/src/V3Graph.h index 7249c97a0..c30f12618 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -47,19 +47,23 @@ typedef bool (*V3EdgeFuncP)(const V3GraphEdge* edgep); class GraphWay { public: - enum en { FORWARD=0, - REVERSE=1, - NUM_WAYS=2 // NUM_WAYS is not an actual way, it's typically - // // an array dimension or loop bound. + enum en { + FORWARD = 0, + REVERSE = 1, + NUM_WAYS = 2 // NUM_WAYS is not an actual way, it's typically + // // an array dimension or loop bound. }; enum en m_e; - inline GraphWay() : m_e(FORWARD) {} + inline GraphWay() + : m_e(FORWARD) {} // cppcheck-suppress noExplicitConstructor - inline GraphWay(en _e) : m_e(_e) {} - explicit inline GraphWay(int _e) : m_e(static_cast(_e)) {} + inline GraphWay(en _e) + : m_e(_e) {} + explicit inline GraphWay(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } const char* ascii() const { - static const char* const names[] = { "FORWARD", "REVERSE" }; + static const char* const names[] = {"FORWARD", "REVERSE"}; return names[m_e]; } // METHODS unique to this class @@ -78,12 +82,14 @@ private: // MEMBERS V3List m_vertices; // All vertices static int s_debug; + protected: - friend class V3GraphVertex; friend class V3GraphEdge; + friend class V3GraphVertex; + friend class V3GraphEdge; friend class GraphAcyc; // METHODS void acyclicDFS(); - void acyclicDFSIterate(V3GraphVertex *vertexp, int depth, uint32_t currentRank); + void acyclicDFSIterate(V3GraphVertex* vertexp, int depth, uint32_t currentRank); void acyclicCut(); void acyclicLoop(V3GraphVertex* vertexp, int depth); double orderDFSIterate(V3GraphVertex* vertexp); @@ -91,6 +97,7 @@ protected: void verticesUnlink() { m_vertices.reset(); } // ACCESSORS static int debug(); + public: V3Graph(); virtual ~V3Graph(); @@ -163,10 +170,10 @@ public: void subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, V3Graph* loopGraphp); /// Debugging - void dump(std::ostream& os=std::cout); + void dump(std::ostream& os = std::cout); void dumpDotFile(const string& filename, bool colorAsSubgraph) const; - void dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph=false) const; - void dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph=false) const; + void dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph = false) const; + void dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph = false) const; void userClearVertices(); void userClearEdges(); static void selfTest(); @@ -181,17 +188,19 @@ public: class V3GraphVertex { // Vertices may be a 'gate'/wire statement OR a variable protected: - friend class V3Graph; friend class V3GraphEdge; - friend class GraphAcyc; friend class GraphAlgRank; + friend class V3Graph; + friend class V3GraphEdge; + friend class GraphAcyc; + friend class GraphAlgRank; V3ListEnt m_vertices; // All vertices, linked list - V3List m_outs; // Outbound edges,linked list - V3List m_ins; // Inbound edges, linked list - double m_fanout; // Order fanout - uint32_t m_color; // Color of the node - uint32_t m_rank; // Rank of edge + V3List m_outs; // Outbound edges,linked list + V3List m_ins; // Inbound edges, linked list + double m_fanout; // Order fanout + uint32_t m_color; // Color of the node + uint32_t m_rank; // Rank of edge union { - void* m_userp; // Marker for some algorithms - uint32_t m_user; // Marker for some algorithms + void* m_userp; // Marker for some algorithms + uint32_t m_user; // Marker for some algorithms }; // METHODS void verticesPushBack(V3Graph* graphp); @@ -202,14 +211,16 @@ protected: protected: // CONSTRUCTORS V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old); + public: explicit V3GraphVertex(V3Graph* graphp); //! Clone copy constructor. Doesn't copy edges or user/userp. virtual V3GraphVertex* clone(V3Graph* graphp) const { - return new V3GraphVertex(graphp, *this); } + return new V3GraphVertex(graphp, *this); + } virtual ~V3GraphVertex() {} - void unlinkEdges(V3Graph* graphp); - void unlinkDelete(V3Graph* graphp); + void unlinkEdges(V3Graph* graphp); + void unlinkDelete(V3Graph* graphp); // ACCESSORS virtual string name() const { return ""; } @@ -227,27 +238,26 @@ public: if (m_fanout > rhsp->m_fanout) return 1; return 0; } - uint32_t color() const { return m_color; } - void color(uint32_t color) { m_color = color; } - uint32_t rank() const { return m_rank; } - void rank(uint32_t rank) { m_rank = rank; } - double fanout() const { return m_fanout; } - void user(uint32_t user) { m_user = user; } - uint32_t user() const { return m_user; } - void userp(void* userp) { m_userp = userp; } - void* userp() const { return m_userp; } + uint32_t color() const { return m_color; } + void color(uint32_t color) { m_color = color; } + uint32_t rank() const { return m_rank; } + void rank(uint32_t rank) { m_rank = rank; } + double fanout() const { return m_fanout; } + void user(uint32_t user) { m_user = user; } + uint32_t user() const { return m_user; } + void userp(void* userp) { m_userp = userp; } + void* userp() const { return m_userp; } // ITERATORS V3GraphVertex* verticesNextp() const { return m_vertices.nextp(); } V3GraphEdge* inBeginp() const { return m_ins.begin(); } - bool inEmpty() const { return inBeginp()==NULL; } - bool inSize1() const; - uint32_t inHash() const; + bool inEmpty() const { return inBeginp() == NULL; } + bool inSize1() const; + uint32_t inHash() const; V3GraphEdge* outBeginp() const { return m_outs.begin(); } - bool outEmpty() const { return outBeginp()==NULL; } - bool outSize1() const; - uint32_t outHash() const; - V3GraphEdge* beginp(GraphWay way) const { - return way.forward() ? outBeginp() : inBeginp(); } + bool outEmpty() const { return outBeginp() == NULL; } + bool outSize1() const; + uint32_t outHash() const; + V3GraphEdge* beginp(GraphWay way) const { return way.forward() ? outBeginp() : inBeginp(); } // METHODS /// Error reporting void v3errorEnd(std::ostringstream& str) const; @@ -269,22 +279,24 @@ public: // ENUMS enum Cutable { NOT_CUTABLE = false, CUTABLE = true }; // For passing to V3GraphEdge protected: - friend class V3Graph; friend class V3GraphVertex; - friend class GraphAcyc; friend class GraphAcycEdge; - V3ListEnt m_outs; // Next Outbound edge for same vertex (linked list) - V3ListEnt m_ins; // Next Inbound edge for same vertex (linked list) + friend class V3Graph; + friend class V3GraphVertex; + friend class GraphAcyc; + friend class GraphAcycEdge; + V3ListEnt m_outs; // Next Outbound edge for same vertex (linked list) + V3ListEnt m_ins; // Next Inbound edge for same vertex (linked list) // - V3GraphVertex* m_fromp; // Vertices pointing to this edge - V3GraphVertex* m_top; // Vertices this edge points to - int m_weight; // Weight of the connection - bool m_cutable; // Interconnect may be broken in order sorting + V3GraphVertex* m_fromp; // Vertices pointing to this edge + V3GraphVertex* m_top; // Vertices this edge points to + int m_weight; // Weight of the connection + bool m_cutable; // Interconnect may be broken in order sorting union { - void* m_userp; // Marker for some algorithms - uint32_t m_user; // Marker for some algorithms + void* m_userp; // Marker for some algorithms + uint32_t m_user; // Marker for some algorithms }; // METHODS - void init(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, - int weight, bool cutable=false); + void init(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, + bool cutable = false); void cut() { m_weight = 0; } // 0 weight is same as disconnected void outPushBack(); void inPushBack(); @@ -294,21 +306,23 @@ protected: const V3GraphEdge& old) { init(graphp, fromp, top, old.m_weight, old.m_cutable); } + public: //! Add DAG from one node to the specified node - V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, - int weight, bool cutable=false) { + V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, + bool cutable = false) { init(graphp, fromp, top, weight, cutable); } //! Clone copy constructor. Doesn't copy existing vertices or user/userp. virtual V3GraphEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const { - return new V3GraphEdge(graphp, fromp, top, *this); } + return new V3GraphEdge(graphp, fromp, top, *this); + } virtual ~V3GraphEdge() {} // METHODS - virtual string name() const { return m_fromp->name()+"->"+m_top->name(); } + virtual string name() const { return m_fromp->name() + "->" + m_top->name(); } virtual string dotLabel() const { return ""; } - virtual string dotColor() const { return cutable()?"yellowGreen":"red"; } - virtual string dotStyle() const { return cutable()?"dashed":""; } + virtual string dotColor() const { return cutable() ? "yellowGreen" : "red"; } + virtual string dotStyle() const { return cutable() ? "dashed" : ""; } virtual int sortCmp(const V3GraphEdge* rhsp) const { if (!m_weight || !rhsp->m_weight) return 0; return top()->sortCmp(rhsp->top()); @@ -334,8 +348,7 @@ public: // ITERATORS V3GraphEdge* outNextp() const { return m_outs.nextp(); } V3GraphEdge* inNextp() const { return m_ins.nextp(); } - V3GraphEdge* nextp(GraphWay way) const { - return way.forward() ? outNextp() : inNextp(); } + V3GraphEdge* nextp(GraphWay way) const { return way.forward() ? outNextp() : inNextp(); } }; //============================================================================ diff --git a/src/V3GraphDfa.cpp b/src/V3GraphDfa.cpp index 3804c3272..69160fbfd 100644 --- a/src/V3GraphDfa.cpp +++ b/src/V3GraphDfa.cpp @@ -32,8 +32,8 @@ DfaVertex* DfaGraph::findStart() { DfaVertex* startp = NULL; - for (V3GraphVertex* vertexp = this->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = this->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { if (DfaVertex* vvertexp = dynamic_cast(vertexp)) { if (vvertexp->start()) { UASSERT_OBJ(!startp, vertexp, "Multiple start points in NFA graph"); @@ -60,11 +60,11 @@ class GraphNfaToDfa : GraphAlg<> { private: // TYPES typedef std::deque DfaStates; - typedef std::multimap HashMap; + typedef std::multimap HashMap; // MEMBERS - uint32_t m_step; // Processing step, so we can avoid clearUser all the time - HashMap m_hashMap; // Dfa Vertex for each set of NFA vertexes + uint32_t m_step; // Processing step, so we can avoid clearUser all the time + HashMap m_hashMap; // Dfa Vertex for each set of NFA vertexes #ifdef VL_CPPCHECK static int debug() { return 9; } @@ -74,29 +74,37 @@ private: // METHODS DfaGraph* graphp() { return static_cast(m_graphp); } - bool nfaState(V3GraphVertex* vertexp) { return vertexp->color()==0; } - //bool dfaState(V3GraphVertex* vertexp) { return vertexp->color()==1; } + bool nfaState(V3GraphVertex* vertexp) { return vertexp->color() == 0; } + // bool dfaState(V3GraphVertex* vertexp) { return vertexp->color()==1; } void nextStep() { m_step++; } bool unseenNfaThisStep(V3GraphVertex* vertexp) { // A nfa node not already seen this processing step - return (nfaState(vertexp) && !(vertexp->user()==m_step)); + return (nfaState(vertexp) && !(vertexp->user() == m_step)); } - DfaVertex* newDfaVertex(DfaVertex* nfaTemplatep=NULL) { + DfaVertex* newDfaVertex(DfaVertex* nfaTemplatep = NULL) { DfaVertex* vertexp = new DfaVertex(graphp()); vertexp->color(1); // Mark as dfa if (nfaTemplatep && nfaTemplatep->start()) vertexp->start(true); if (nfaTemplatep && nfaTemplatep->accepting()) vertexp->accepting(true); - UINFO(9, " New "<outBeginp(); - dfaEdgep; dfaEdgep=dfaEdgep->outNextp()) { + for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep; + dfaEdgep = dfaEdgep->outNextp()) { if (nfaState(dfaEdgep->top())) { DfaVertex* nfaStatep = static_cast(dfaEdgep->top()); hash ^= hashVertex(nfaStatep); @@ -126,8 +134,8 @@ private: uint32_t hashDfaOrigins(const DfaStates& nfasWithInput) { // Find the NFA states this dfa came from, uint32_t hash = 0; - for (DfaStates::const_iterator nfaIt=nfasWithInput.begin(); - nfaIt!=nfasWithInput.end(); ++nfaIt) { + for (DfaStates::const_iterator nfaIt = nfasWithInput.begin(); nfaIt != nfasWithInput.end(); + ++nfaIt) { DfaVertex* nfaStatep = *nfaIt; hash ^= hashVertex(nfaStatep); } @@ -140,8 +148,8 @@ private: nextStep(); // Mark all input vertexes int num1s = 0; - for (DfaStates::const_iterator nfaIt=nfasWithInput.begin(); - nfaIt!=nfasWithInput.end(); ++nfaIt) { + for (DfaStates::const_iterator nfaIt = nfasWithInput.begin(); nfaIt != nfasWithInput.end(); + ++nfaIt) { DfaVertex* nfaStatep = *nfaIt; nfaStatep->user(m_step); num1s++; @@ -151,7 +159,8 @@ private: // Check comparison; must all be marked // (Check all in dfa2p were in dfa1p) int num2s = 0; - for (V3GraphEdge* dfaEdgep = dfa2p->outBeginp(); dfaEdgep; dfaEdgep=dfaEdgep->outNextp()) { + for (V3GraphEdge* dfaEdgep = dfa2p->outBeginp(); dfaEdgep; + dfaEdgep = dfaEdgep->outNextp()) { if (nfaState(dfaEdgep->top())) { if (dfaEdgep->top()->user() != m_step) return false; num2s++; @@ -174,39 +183,38 @@ private: // not depend on order of edges uint32_t hash = hashDfaOrigins(nfasWithInput); - std::pair eqrange = m_hashMap.equal_range(hash); + std::pair eqrange = m_hashMap.equal_range(hash); for (HashMap::iterator it = eqrange.first; it != eqrange.second; ++it) { DfaVertex* testp = it->second; if (compareDfaOrigins(nfasWithInput, testp)) { - UINFO(9," DFA match for set: "<outBeginp(); - dfaEdgep; dfaEdgep=dfaEdgep->outNextp()) { + for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep; + dfaEdgep = dfaEdgep->outNextp()) { if (nfaState(dfaEdgep->top())) { DfaVertex* nfaStatep = static_cast(dfaEdgep->top()); // Foreach input transition (on this nfaStatep) - for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); - nfaEdgep; nfaEdgep=nfaEdgep->outNextp()) { + for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep; + nfaEdgep = nfaEdgep->outNextp()) { DfaEdge* cNfaEdgep = static_cast(nfaEdgep); if (cNfaEdgep->input().toNodep() == input.toNodep()) { DfaVertex* nextStatep = static_cast(cNfaEdgep->top()); if (unseenNfaThisStep(nextStatep)) { // Not processed? nfasWithInput.push_back(nextStatep); nextStatep->user(m_step); - UINFO(9," Reachable "<outBeginp(); - nfaEdgep; nfaEdgep=nfaEdgep->outNextp()) { + for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep; + nfaEdgep = nfaEdgep->outNextp()) { DfaEdge* cNfaEdgep = static_cast(nfaEdgep); if (cNfaEdgep->epsilon()) { DfaVertex* nextStatep = static_cast(cNfaEdgep->top()); if (unseenNfaThisStep(nextStatep)) { // Not processed? nfasTodo.push_back(nextStatep); nextStatep->user(m_step); - UINFO(9," Epsilon Reachable "<clearColors(); // Vertex::m_user begin: # indicates processed this m_step number m_graphp->userClearVertices(); - if (debug()>=6) m_graphp->dumpDotFilePrefixed("dfa_nfa"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_nfa"); // Find NFA start DfaVertex* nfaStartp = graphp()->findStart(); @@ -256,55 +265,58 @@ private: DfaStates dfaUnprocps; // Unprocessed DFA nodes dfaUnprocps.push_back(dfaStartp); - UINFO(5,"Starting state conversion...\n"); + UINFO(5, "Starting state conversion...\n"); // Form DFA starting state from epsilon closure of NFA start nextStep(); - DfaStates workps; workps.push_back(nfaStartp); + DfaStates workps; + workps.push_back(nfaStartp); while (!workps.empty()) { // While work - DfaVertex* nfaStatep = workps.back(); workps.pop_back(); - //UINFO(9," Processing "<user(m_step); // Mark as processed // Add a edge so we can find NFAs from a given DFA. // The NFA will never see this edge, because we only look at TO edges. new DfaEdge(graphp(), dfaStartp, nfaStatep, DfaEdge::NA()); // Find epsilon closure of this nfa node, and destinations to work list - for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); - nfaEdgep; nfaEdgep=nfaEdgep->outNextp()) { + for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep; + nfaEdgep = nfaEdgep->outNextp()) { DfaEdge* cNfaEdgep = static_cast(nfaEdgep); DfaVertex* ecNfaStatep = static_cast(nfaEdgep->top()); - //UINFO(9," Consider "<top()<<" EP "<epsilon()<epsilon() - && unseenNfaThisStep(ecNfaStatep)) { // Not processed? + // UINFO(9," Consider "<top()<<" EP "<epsilon()<epsilon() && unseenNfaThisStep(ecNfaStatep)) { // Not processed? workps.push_back(ecNfaStatep); } } } - if (debug()>=6) m_graphp->dumpDotFilePrefixed("dfa_start"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_start"); insertDfaOrigins(dfaStartp); int i = 0; - UINFO(5,"Main state conversion...\n"); + UINFO(5, "Main state conversion...\n"); while (!dfaUnprocps.empty()) { - DfaVertex* dfaStatep = dfaUnprocps.back(); dfaUnprocps.pop_back(); - UINFO(9," On dfaState "< inputs; // Foreach NFA state (this DFA state was formed from) - for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); - dfaEdgep; dfaEdgep=dfaEdgep->outNextp()) { + for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep; + dfaEdgep = dfaEdgep->outNextp()) { if (nfaState(dfaEdgep->top())) { DfaVertex* nfaStatep = static_cast(dfaEdgep->top()); // Foreach input on this nfaStatep - for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); - nfaEdgep; nfaEdgep=nfaEdgep->outNextp()) { + for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep; + nfaEdgep = nfaEdgep->outNextp()) { DfaEdge* cNfaEdgep = static_cast(nfaEdgep); if (!cNfaEdgep->epsilon()) { if (inputs.find(cNfaEdgep->input().toInt()) == inputs.end()) { inputs.insert(cNfaEdgep->input().toInt()); - UINFO(9," Input to "<input().toInt())<<" via "<input().toInt()) << " via " + << nfaStatep << endl); } } } @@ -312,14 +324,15 @@ private: } // Foreach input state (NFA inputs of this DFA state) - for (std::set::const_iterator inIt=inputs.begin(); inIt!=inputs.end(); ++inIt) { + for (std::set::const_iterator inIt = inputs.begin(); inIt != inputs.end(); + ++inIt) { DfaInput input = *inIt; - UINFO(9," ==="<<++i<<"=======================\n"); - UINFO(9," On input "<accepting()) toDfaStatep->accepting(true); } @@ -340,22 +353,21 @@ private: // Add input transition new DfaEdge(graphp(), dfaStatep, toDfaStatep, input); - if (debug()>=6) m_graphp->dumpDotFilePrefixed("step"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("step"); } } // Remove old NFA states - UINFO(5,"Removing NFA states...\n"); - if (debug()>=6) m_graphp->dumpDotFilePrefixed("dfa_withnfa"); - for (V3GraphVertex* nextp,*vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=nextp) { + UINFO(5, "Removing NFA states...\n"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_withnfa"); + for (V3GraphVertex *nextp, *vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = nextp) { nextp = vertexp->verticesNextp(); - if (nfaState(vertexp)) { - VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp); - } + if (nfaState(vertexp)) VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp); } - UINFO(5,"Done.\n"); - if (debug()>=6) m_graphp->dumpDotFilePrefixed("dfa_done"); + UINFO(5, "Done.\n"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_done"); } public: @@ -367,9 +379,7 @@ public: ~GraphNfaToDfa() {} }; -void DfaGraph::nfaToDfa() { - GraphNfaToDfa(this, &V3GraphEdge::followAlwaysTrue); -} +void DfaGraph::nfaToDfa() { GraphNfaToDfa(this, &V3GraphEdge::followAlwaysTrue); } //###################################################################### //###################################################################### @@ -390,7 +400,7 @@ private: bool isDead(DfaVertex* vertexp) { // A state is dead if not accepting, and goes nowhere if (vertexp->accepting() || vertexp->start()) return false; - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (edgep->top() != vertexp) return false; } return true; @@ -399,11 +409,11 @@ private: void optimize_accepting_out() { // Delete outbound edges from accepting states // (As once we've accepted, we no longer care about anything else.) - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { if (DfaVertex* vvertexp = dynamic_cast(vertexp)) { if (vvertexp->accepting()) { - for (V3GraphEdge* nextp,*edgep = vertexp->outBeginp(); edgep; edgep=nextp) { + for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep = nextp) { nextp = edgep->outNextp(); VL_DO_DANGLING(edgep->unlinkDelete(), edgep); } @@ -421,14 +431,16 @@ private: m_graphp->userClearVertices(); DfaVertex* startp = graphp()->findStart(); - std::stack workps; workps.push(startp); + std::stack workps; + workps.push(startp); // Mark all nodes connected to start while (!workps.empty()) { - V3GraphVertex* vertexp = workps.top(); workps.pop(); + V3GraphVertex* vertexp = workps.top(); + workps.pop(); vertexp->user(2); // Processed // Add nodes from here to the work list - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { V3GraphVertex* tovertexp = edgep->top(); if (!tovertexp->user()) { workps.push(tovertexp); @@ -438,11 +450,10 @@ private: } // Delete all nodes not connected - for (V3GraphVertex* nextp,*vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=nextp) { + for (V3GraphVertex *nextp, *vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = nextp) { nextp = vertexp->verticesNextp(); - if (!vertexp->user()) { - VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp); - } + if (!vertexp->user()) { VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp); } } } @@ -457,8 +468,8 @@ private: // Find all dead vertexes std::stack workps; - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { if (DfaVertex* vvertexp = dynamic_cast(vertexp)) { workps.push(vvertexp); vertexp->user(1); @@ -470,14 +481,14 @@ private: // While deadness... Delete and find new dead nodes. while (!workps.empty()) { - DfaVertex* vertexp = workps.top(); workps.pop(); + DfaVertex* vertexp = workps.top(); + workps.pop(); vertexp->user(0); if (isDead(vertexp)) { // Add nodes that go here to the work list - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { DfaVertex* fromvertexp = static_cast(edgep->fromp()); - if (fromvertexp != vertexp - && !fromvertexp->user()) { + if (fromvertexp != vertexp && !fromvertexp->user()) { workps.push(fromvertexp); fromvertexp->user(1); } @@ -487,23 +498,22 @@ private: } } } + public: DfaGraphReduce(V3Graph* graphp, V3EdgeFuncP edgeFuncp) : GraphAlg<>(graphp, edgeFuncp) { - if (debug()>=6) m_graphp->dumpDotFilePrefixed("opt_in"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_in"); optimize_accepting_out(); - if (debug()>=6) m_graphp->dumpDotFilePrefixed("opt_acc"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_acc"); optimize_orphans(); - if (debug()>=6) m_graphp->dumpDotFilePrefixed("opt_orph"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_orph"); optimize_no_outbound(); - if (debug()>=6) m_graphp->dumpDotFilePrefixed("opt_noout"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_noout"); } ~DfaGraphReduce() {} }; -void DfaGraph::dfaReduce() { - DfaGraphReduce(this, &V3GraphEdge::followAlwaysTrue); -} +void DfaGraph::dfaReduce() { DfaGraphReduce(this, &V3GraphEdge::followAlwaysTrue); } //###################################################################### //###################################################################### @@ -537,8 +547,8 @@ private: void add_complement_edges() { // Find accepting vertex DfaVertex* acceptp = NULL; - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { if (DfaVertex* vvertexp = dynamic_cast(vertexp)) { if (vvertexp->accepting()) { acceptp = vvertexp; @@ -549,12 +559,12 @@ private: if (!acceptp) v3fatalSrc("No accepting vertex in DFA"); // Remap edges - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { if (DfaVertex* vvertexp = dynamic_cast(vertexp)) { - //UINFO(9, " on vertex "<name()<name()<accepting() && vvertexp != m_tempNewerReject) { - for (V3GraphEdge* nextp, *edgep = vertexp->outBeginp(); edgep; edgep=nextp) { + for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep = nextp) { nextp = edgep->outNextp(); if (!edgep->user()) { // Not processed // Old edges to accept now go to new reject @@ -568,7 +578,8 @@ private: // NOT of all values goes to accept // We make a edge for each value to OR, IE // edge(complemented,a) edge(complemented,b) means !(a | b) - if (!tovertexp->accepting()) { // Note we must include edges moved above to reject + if (!tovertexp->accepting()) { + // Note we must include edges moved above to reject DfaEdge* newp = new DfaEdge(graphp(), vvertexp, acceptp, vedgep); newp->complement(!newp->complement()); newp->user(1); @@ -579,25 +590,24 @@ private: } } } + public: DfaGraphComplement(V3Graph* dfagraphp, V3EdgeFuncP edgeFuncp) : GraphAlg<>(dfagraphp, edgeFuncp) { - if (debug()>=6) m_graphp->dumpDotFilePrefixed("comp_in"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("comp_in"); // Vertex::m_user begin: 1 indicates new edge, no more processing m_graphp->userClearEdges(); m_tempNewerReject = new DfaVertex(graphp()); add_complement_edges(); - if (debug()>=6) m_graphp->dumpDotFilePrefixed("comp_preswap"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("comp_preswap"); VL_DO_CLEAR(m_tempNewerReject->unlinkDelete(graphp()), m_tempNewerReject = NULL); - if (debug()>=6) m_graphp->dumpDotFilePrefixed("comp_out"); + if (debug() >= 6) m_graphp->dumpDotFilePrefixed("comp_out"); } ~DfaGraphComplement() {} VL_UNCOPYABLE(DfaGraphComplement); }; -void DfaGraph::dfaComplement() { - DfaGraphComplement(this, &V3GraphEdge::followAlwaysTrue); -} +void DfaGraph::dfaComplement() { DfaGraphComplement(this, &V3GraphEdge::followAlwaysTrue); } diff --git a/src/V3GraphDfa.h b/src/V3GraphDfa.h index 0edf4bb5b..85fc47f60 100644 --- a/src/V3GraphDfa.h +++ b/src/V3GraphDfa.h @@ -85,16 +85,18 @@ class DfaVertex : public V3GraphVertex { bool m_accepting; // Accepting state? public: // CONSTRUCTORS - explicit DfaVertex(DfaGraph* graphp, bool start=false, bool accepting=false) + explicit DfaVertex(DfaGraph* graphp, bool start = false, bool accepting = false) : V3GraphVertex(graphp) - , m_start(start), m_accepting(accepting) {} + , m_start(start) + , m_accepting(accepting) {} using V3GraphVertex::clone; // We are overriding, not overloading clone(V3Graph*) virtual DfaVertex* clone(DfaGraph* graphp) { - return new DfaVertex(graphp, start(), accepting()); } + return new DfaVertex(graphp, start(), accepting()); + } virtual ~DfaVertex() {} // ACCESSORS - virtual string dotShape() const { return (accepting()?"doublecircle":""); } - virtual string dotColor() const { return start()?"blue":(color()?"red":"black"); } + virtual string dotShape() const { return (accepting() ? "doublecircle" : ""); } + virtual string dotColor() const { return start() ? "blue" : (color() ? "red" : "black"); } bool start() const { return m_start; } void start(bool flag) { m_start = flag; } bool accepting() const { return m_accepting; } @@ -118,24 +120,24 @@ public: // CONSTRUCTORS DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, const DfaInput& input) : V3GraphEdge(graphp, fromp, top, 1) - , m_input(input), m_complement(false) {} + , m_input(input) + , m_complement(false) {} DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, const DfaEdge* copyfrom) : V3GraphEdge(graphp, fromp, top, copyfrom->weight()) - , m_input(copyfrom->input()), m_complement(copyfrom->complement()) {} + , m_input(copyfrom->input()) + , m_complement(copyfrom->complement()) {} virtual ~DfaEdge() {} // METHODS - virtual string dotColor() const { - return (na() ? "yellow" - : epsilon() ? "green" - : "black"); } + virtual string dotColor() const { return (na() ? "yellow" : epsilon() ? "green" : "black"); } virtual string dotLabel() const { return (na() ? "" - : epsilon() ? "e" - : complement() ? ("not "+cvtToStr(input().toInt())) - : cvtToStr(input().toInt())); } - virtual string dotStyle() const { return (na()||cutable())?"dashed":""; } - bool epsilon() const { return input().toInt()==EPSILON().toInt(); } - bool na() const { return input().toInt()==NA().toInt(); } + : epsilon() ? "e" + : complement() ? ("not " + cvtToStr(input().toInt())) + : cvtToStr(input().toInt())); + } + virtual string dotStyle() const { return (na() || cutable()) ? "dashed" : ""; } + bool epsilon() const { return input().toInt() == EPSILON().toInt(); } + bool na() const { return input().toInt() == NA().toInt(); } bool complement() const { return m_complement; } void complement(bool value) { m_complement = value; } DfaInput input() const { return m_input; } diff --git a/src/V3GraphPathChecker.cpp b/src/V3GraphPathChecker.cpp index 409c8737f..611ed8fe2 100644 --- a/src/V3GraphPathChecker.cpp +++ b/src/V3GraphPathChecker.cpp @@ -41,10 +41,11 @@ struct GraphPCNode { vluint64_t m_seenAtGeneration; // CONSTRUCTORS - GraphPCNode() : m_seenAtGeneration(0) { + GraphPCNode() + : m_seenAtGeneration(0) { for (int w = 0; w < GraphWay::NUM_WAYS; w++) m_cp[w] = 0; } - ~GraphPCNode() { } + ~GraphPCNode() {} }; //###################################################################### @@ -53,8 +54,7 @@ struct GraphPCNode { GraphPathChecker::GraphPathChecker(const V3Graph* graphp, V3EdgeFuncP edgeFuncp) : GraphAlg(graphp, edgeFuncp) , m_generation(0) { - for (V3GraphVertex* vxp = graphp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (V3GraphVertex* vxp = graphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { // Setup tracking structure for each node. If delete a vertex // there would be a leak, but ok as accept only const V3Graph*'s. vxp->userp(new GraphPCNode); @@ -66,8 +66,7 @@ GraphPathChecker::GraphPathChecker(const V3Graph* graphp, V3EdgeFuncP edgeFuncp) GraphPathChecker::~GraphPathChecker() { // Free every GraphPCNode - for (V3GraphVertex* vxp = m_graphp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (V3GraphVertex* vxp = m_graphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { GraphPCNode* nodep = static_cast(vxp->userp()); VL_DO_DANGLING(delete nodep, nodep); vxp->userp(NULL); @@ -79,8 +78,7 @@ void GraphPathChecker::initHalfCriticalPaths(GraphWay way, bool checkOnly) { GraphWay rev = way.invert(); while (const V3GraphVertex* vertexp = order.nextp()) { unsigned critPathCost = 0; - for (V3GraphEdge* edgep = vertexp->beginp(rev); - edgep; edgep = edgep->nextp(rev)) { + for (V3GraphEdge* edgep = vertexp->beginp(rev); edgep; edgep = edgep->nextp(rev)) { if (!m_edgeFuncp(edgep)) continue; V3GraphVertex* wrelativep = edgep->furtherp(rev); @@ -90,16 +88,15 @@ void GraphPathChecker::initHalfCriticalPaths(GraphWay way, bool checkOnly) { GraphPCNode* ourUserp = static_cast(vertexp->userp()); if (checkOnly) { - UASSERT_OBJ(ourUserp->m_cp[way] == critPathCost, - vertexp, "Validation of critical paths failed"); + UASSERT_OBJ(ourUserp->m_cp[way] == critPathCost, vertexp, + "Validation of critical paths failed"); } else { ourUserp->m_cp[way] = critPathCost; } } } -bool GraphPathChecker::pathExistsInternal(const V3GraphVertex* ap, - const V3GraphVertex* bp, +bool GraphPathChecker::pathExistsInternal(const V3GraphVertex* ap, const V3GraphVertex* bp, unsigned* costp) { GraphPCNode* auserp = static_cast(ap->userp()); GraphPCNode* buserp = static_cast(bp->userp()); @@ -118,31 +115,23 @@ bool GraphPathChecker::pathExistsInternal(const V3GraphVertex* ap, if (ap == bp) return true; // Rule out an a->b path based on their CPs - if (auserp->m_cp[GraphWay::REVERSE] < buserp->m_cp[GraphWay::REVERSE] + 1) { - return false; - } - if (buserp->m_cp[GraphWay::FORWARD] < auserp->m_cp[GraphWay::FORWARD] + 1) { - return false; - } + if (auserp->m_cp[GraphWay::REVERSE] < buserp->m_cp[GraphWay::REVERSE] + 1) return false; + if (buserp->m_cp[GraphWay::FORWARD] < auserp->m_cp[GraphWay::FORWARD] + 1) return false; // Slow path; visit some extended family bool foundPath = false; - for (V3GraphEdge* edgep = ap->outBeginp(); - edgep && !foundPath; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = ap->outBeginp(); edgep && !foundPath; edgep = edgep->outNextp()) { if (!m_edgeFuncp(edgep)) continue; unsigned childCost; - if (pathExistsInternal(edgep->top(), bp, &childCost)) { - foundPath = true; - } + if (pathExistsInternal(edgep->top(), bp, &childCost)) foundPath = true; if (costp) *costp += childCost; } return foundPath; } -bool GraphPathChecker::pathExistsFrom(const V3GraphVertex* fromp, - const V3GraphVertex* top) { +bool GraphPathChecker::pathExistsFrom(const V3GraphVertex* fromp, const V3GraphVertex* top) { incGeneration(); return pathExistsInternal(fromp, top); } @@ -151,12 +140,10 @@ bool GraphPathChecker::isTransitiveEdge(const V3GraphEdge* edgep) { const V3GraphVertex* fromp = edgep->fromp(); const V3GraphVertex* top = edgep->top(); incGeneration(); - for (const V3GraphEdge* fromOutp = fromp->outBeginp(); - fromOutp; fromOutp = fromOutp->outNextp()) { + for (const V3GraphEdge* fromOutp = fromp->outBeginp(); fromOutp; + fromOutp = fromOutp->outNextp()) { if (fromOutp == edgep) continue; - if (pathExistsInternal(fromOutp->top(), top)) { - return true; - } + if (pathExistsInternal(fromOutp->top(), top)) return true; } return false; } diff --git a/src/V3GraphStream.h b/src/V3GraphStream.h index bf5f4d02b..028d0a203 100644 --- a/src/V3GraphStream.h +++ b/src/V3GraphStream.h @@ -70,11 +70,12 @@ private: explicit VxHolderCmp(const T_Compare& lessThan) : m_lessThan(lessThan) {} // METHODS - bool operator() (const VxHolder& a, const VxHolder& b) const { + bool operator()(const VxHolder& a, const VxHolder& b) const { if (m_lessThan.operator()(a.vertexp(), b.vertexp())) return true; if (m_lessThan.operator()(b.vertexp(), a.vertexp())) return false; return a.m_pos < b.m_pos; } + private: VL_UNCOPYABLE(VxHolderCmp); }; @@ -91,8 +92,7 @@ private: public: // CONSTRUCTORS - explicit GraphStream(const V3Graph* graphp, - GraphWay way = GraphWay::FORWARD, + explicit GraphStream(const V3Graph* graphp, GraphWay way = GraphWay::FORWARD, const T_Compare& lessThan = T_Compare()) // NOTE: Perhaps REVERSE way should also reverse the sense of the // lessThan function? For now the only usage of REVERSE is not @@ -102,8 +102,8 @@ public: , m_last(m_readyVertices.end()) , m_way(way) { uint32_t pos = 0; - for (const V3GraphVertex* vxp = graphp->verticesBeginp(); - vxp; vxp=vxp->verticesNextp()) { + for (const V3GraphVertex* vxp = graphp->verticesBeginp(); vxp; + vxp = vxp->verticesNextp()) { // Every vertex initially is waiting, or ready. if (way == GraphWay::FORWARD) { if (vxp->inEmpty()) { @@ -111,8 +111,7 @@ public: m_readyVertices.insert(newVx); } else { uint32_t depCount = 0; - for (V3GraphEdge* depp = vxp->inBeginp(); - depp; depp = depp->inNextp()) { + for (V3GraphEdge* depp = vxp->inBeginp(); depp; depp = depp->inNextp()) { depCount++; } VxHolder newVx(vxp, pos++, depCount); @@ -124,8 +123,7 @@ public: m_readyVertices.insert(newVx); } else { uint32_t depCount = 0; - for (V3GraphEdge* depp = vxp->outBeginp(); - depp; depp = depp->outNextp()) { + for (V3GraphEdge* depp = vxp->outBeginp(); depp; depp = depp->outNextp()) { depCount++; } VxHolder newVx(vxp, pos++, depCount); @@ -177,9 +175,7 @@ public: // Wrap curIt. Expect to wrap, and make another pass, to find // newly-ready elements that could have appeared ahead of the // m_last iterator - if (curIt == m_readyVertices.end()) { - curIt = m_readyVertices.begin(); - } + if (curIt == m_readyVertices.end()) { curIt = m_readyVertices.begin(); } } if (curIt != m_readyVertices.end()) { @@ -198,12 +194,10 @@ public: private: void unblockDeps(const V3GraphVertex* vertexp) { if (m_way == GraphWay::FORWARD) { - for (V3GraphEdge* edgep = vertexp->outBeginp(); - edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { V3GraphVertex* toVertexp = edgep->top(); - typename WaitingVertices::iterator it = - m_waitingVertices.find(toVertexp); + typename WaitingVertices::iterator it = m_waitingVertices.find(toVertexp); UASSERT_OBJ(it != m_waitingVertices.end(), toVertexp, "Found edge into vertex not in waiting list."); if (it->second.unblock()) { @@ -212,12 +206,10 @@ private: } } } else { - for (V3GraphEdge* edgep = vertexp->inBeginp(); - edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { V3GraphVertex* fromVertexp = edgep->fromp(); - typename WaitingVertices::iterator it = - m_waitingVertices.find(fromVertexp); + typename WaitingVertices::iterator it = m_waitingVertices.find(fromVertexp); UASSERT_OBJ(it != m_waitingVertices.end(), fromVertexp, "Found edge into vertex not in waiting list."); if (it->second.unblock()) { diff --git a/src/V3Hashed.h b/src/V3Hashed.h index 0915c7385..0ea3ee10d 100644 --- a/src/V3Hashed.h +++ b/src/V3Hashed.h @@ -50,8 +50,9 @@ class V3Hashed : public VHashedBase { // TYPES public: - typedef std::multimap HashMmap; + typedef std::multimap HashMmap; typedef HashMmap::iterator iterator; + private: // MEMBERS HashMmap m_hashMmap; // hashvalue -> nodes with that hash @@ -67,17 +68,21 @@ public: iterator end() { return m_hashMmap.end(); } // METHODS - void clear() { m_hashMmap.clear(); AstNode::user4ClearTree(); } + void clear() { + m_hashMmap.clear(); + AstNode::user4ClearTree(); + } void check(); // Check assertions on structure - iterator hashAndInsert(AstNode* nodep); // Hash the node, and insert into map. Return iterator to inserted + // Hash the node, and insert into map. Return iterator to inserted + iterator hashAndInsert(AstNode* nodep); void hash(AstNode* nodep); // Only hash the node bool sameNodes(AstNode* node1p, AstNode* node2p); // After hashing, and tell if identical void erase(iterator it); // Remove node from structures // Return duplicate in hash, if any, with optional user check for sameness - iterator findDuplicate(AstNode* nodep, V3HashedUserSame* checkp=NULL); + iterator findDuplicate(AstNode* nodep, V3HashedUserSame* checkp = NULL); AstNode* iteratorNodep(iterator it) { return it->second; } void dumpFile(const string& filename, bool tree); - void dumpFilePrefixed(const string& nameComment, bool tree=false); + void dumpFilePrefixed(const string& nameComment, bool tree = false); static V3Hash nodeHash(AstNode* nodep) { return V3Hash(nodep->user4p()); } // Hash of the nodep tree, without caching in user4. static V3Hash uncachedHash(const AstNode* nodep); diff --git a/src/V3Inst.h b/src/V3Inst.h index 3617180e9..7fa389256 100644 --- a/src/V3Inst.h +++ b/src/V3Inst.h @@ -29,8 +29,8 @@ class V3Inst { public: static void instAll(AstNetlist* nodep); static void dearrayAll(AstNetlist* nodep); - static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, - bool forTristate, bool alwaysCvt=false); + static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate, + bool alwaysCvt = false); static void checkOutputShort(AstPin* nodep); }; diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index 5c2e46edb..e0a24b201 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -52,15 +52,16 @@ private: uint32_t m_savedCount; AstNode* m_nodep; InstrCountVisitor* m_visitor; + public: // CONSTRUCTORS VisitBase(InstrCountVisitor* visitor, AstNode* nodep) - : m_nodep(nodep), m_visitor(visitor) { + : m_nodep(nodep) + , m_visitor(visitor) { m_savedCount = m_visitor->startVisitBase(nodep); } - ~VisitBase() { - m_visitor->endVisitBase(m_savedCount, m_nodep); - } + ~VisitBase() { m_visitor->endVisitBase(m_savedCount, m_nodep); } + private: VL_UNCOPYABLE(VisitBase); }; @@ -68,13 +69,12 @@ private: public: // CONSTRUCTORS InstrCountVisitor(AstNode* nodep, bool assertNoDups, std::ostream* osp) - : m_instrCount(0), - m_startNodep(nodep), - m_tracingCall(false), - m_inCFunc(false), - m_assertNoDups(assertNoDups), - m_osp(osp) - { + : m_instrCount(0) + , m_startNodep(nodep) + , m_tracingCall(false) + , m_inCFunc(false) + , m_assertNoDups(assertNoDups) + , m_osp(osp) { if (nodep) iterate(nodep); } virtual ~InstrCountVisitor() {} @@ -98,7 +98,7 @@ private: // collisions in CFuncs. UASSERT_OBJ(!nodep->user5p(), nodep, "Node originally inserted below logic vertex " - <(nodep->user5p())); + << static_cast(nodep->user5p())); nodep->user5p(const_cast(reinterpret_cast(m_startNodep))); } @@ -110,13 +110,12 @@ private: return savedCount; } void endVisitBase(uint32_t savedCount, AstNode* nodep) { - UINFO(8, "cost "<user4(m_instrCount+1); // Else don't mark to avoid writeback + if (m_osp) nodep->user4(m_instrCount + 1); // Else don't mark to avoid writeback } // VISITORS @@ -275,7 +274,8 @@ private: public: // CONSTRUCTORS InstrCountDumpVisitor(AstNode* nodep, std::ostream* osp) - : m_osp(osp), m_depth(0) { + : m_osp(osp) + , m_depth(0) { // No check for NULL output, so... UASSERT_OBJ(osp, nodep, "Don't call if not dumping"); if (nodep) iterate(nodep); @@ -284,13 +284,12 @@ public: private: // METHODS - string indent() { return string(m_depth, ':')+" "; } + string indent() { return string(m_depth, ':') + " "; } virtual void visit(AstNode* nodep) VL_OVERRIDE { ++m_depth; if (unsigned costPlus1 = nodep->user4()) { - *m_osp <<" "<(_e)) {} + explicit inline V3LangCode(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } }; diff --git a/src/V3LanguageWords.h b/src/V3LanguageWords.h index 17416dab4..ecccfe693 100644 --- a/src/V3LanguageWords.h +++ b/src/V3LanguageWords.h @@ -26,17 +26,16 @@ class V3LanguageWords { // List of common reserved keywords - private: - typedef std::map KeywordMap; +private: + typedef std::map KeywordMap; struct Singleton { KeywordMap s_kwdMap; // List of keywords, and what language applies Singleton() { init(); } - void addKwd(const string& kwd, const string& why) { - s_kwdMap.insert(make_pair(kwd, why)); - } + void addKwd(const string& kwd, const string& why) { s_kwdMap.insert(make_pair(kwd, why)); } void init(); }; - public: + +public: typedef KeywordMap::const_iterator const_iterator; // METHODS static const_iterator begin() { return s().s_kwdMap.begin(); } @@ -46,12 +45,17 @@ class V3LanguageWords { if (it == s().s_kwdMap.end()) return ""; return it->second; } + private: - static Singleton& s() { static Singleton s_s; return s_s; } + static Singleton& s() { + static Singleton s_s; + return s_s; + } }; inline void V3LanguageWords::Singleton::init() { // C++ keywords + // clang-format off addKwd("NULL", "C++ common word"); addKwd("abort", "C++ common word"); addKwd("alignas", "C++11 keyword"); @@ -242,6 +246,7 @@ inline void V3LanguageWords::Singleton::init() { addKwd("`undefineall", "Verilog preprocessor directive"); addKwd("`verilator_config", "Verilator preprocessor directive"); addKwd("`verilog", "Verilator preprocessor directive"); + // clang-format on } #endif // Guard diff --git a/src/V3LinkDot.h b/src/V3LinkDot.h index 2df4ac3b9..55371bd55 100644 --- a/src/V3LinkDot.h +++ b/src/V3LinkDot.h @@ -31,25 +31,26 @@ class V3LinkDot { private: static int debug(); static void linkDotGuts(AstNetlist* rootp, VLinkDotStep step); + public: static void linkDotPrimary(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 6); } static void linkDotParamed(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } static void linkDotArrayed(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 6); } static void linkDotScope(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } }; diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 4a6e32d92..251146a94 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -38,8 +38,8 @@ private: // NODE STATE // STATE - bool m_setRefLvalue; // Set VarRefs to lvalues for pin assignments - AstNodeFTask* m_ftaskp; // Function or task we're inside + bool m_setRefLvalue; // Set VarRefs to lvalues for pin assignments + AstNodeFTask* m_ftaskp; // Function or task we're inside // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -48,14 +48,11 @@ private: // Result handing virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE { // VarRef: LValue its reference - if (m_setRefLvalue) { - nodep->lvalue(true); - } + if (m_setRefLvalue) nodep->lvalue(true); if (nodep->varp()) { - if (nodep->lvalue() && !m_ftaskp - && nodep->varp()->isReadOnly()) { - nodep->v3warn(ASSIGNIN, "Assigning to input/const variable: " - <prettyNameQ()); + if (nodep->lvalue() && !m_ftaskp && nodep->varp()->isReadOnly()) { + nodep->v3warn(ASSIGNIN, + "Assigning to input/const variable: " << nodep->prettyNameQ()); } } iterateChildren(nodep); @@ -223,7 +220,7 @@ private: } virtual void visit(AstNodeSel* nodep) VL_OVERRIDE { bool last_setRefLvalue = m_setRefLvalue; - { // Only set lvalues on the from + { // Only set lvalues on the from iterateAndNextNull(nodep->lhsp()); m_setRefLvalue = false; iterateAndNextNull(nodep->rhsp()); @@ -232,7 +229,7 @@ private: } virtual void visit(AstCellArrayRef* nodep) VL_OVERRIDE { bool last_setRefLvalue = m_setRefLvalue; - { // selp is not an lvalue + { // selp is not an lvalue m_setRefLvalue = false; iterateAndNextNull(nodep->selp()); } @@ -240,7 +237,7 @@ private: } virtual void visit(AstNodePreSel* nodep) VL_OVERRIDE { bool last_setRefLvalue = m_setRefLvalue; - { // Only set lvalues on the from + { // Only set lvalues on the from iterateAndNextNull(nodep->lhsp()); m_setRefLvalue = false; iterateAndNextNull(nodep->rhsp()); @@ -258,7 +255,7 @@ private: AstNodeFTask* taskp = nodep->taskp(); // We'll deal with mismatching pins later if (!taskp) return; - for (AstNode* stmtp = taskp->stmtsp(); stmtp && pinp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = taskp->stmtsp(); stmtp && pinp; stmtp = stmtp->nextp()) { if (const AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO()) { if (portp->isWritable()) { @@ -291,15 +288,13 @@ public: // Link class functions void V3LinkLValue::linkLValue(AstNetlist* nodep) { - UINFO(4,__FUNCTION__<<": "<= 6); } void V3LinkLValue::linkLValueSet(AstNode* nodep) { // Called by later link functions when it is known a node needs // to be converted to a lvalue. - UINFO(9,__FUNCTION__<<": "< class V3List; template class V3ListEnt; -template -class V3List { +template class V3List { // List container for linked list of elements of type *T (T is a pointer type) private: // MEMBERS T m_headp; // First element T m_tailp; // Last element friend class V3ListEnt; + public: V3List() - : m_headp(NULL), m_tailp(NULL) {} + : m_headp(NULL) + , m_tailp(NULL) {} ~V3List() {} // METHODS T begin() const { return m_headp; } T end() const { return NULL; } - bool empty() const { return m_headp==NULL; } - void reset() { m_headp = NULL; m_tailp = NULL; } // clear() without walking the list + bool empty() const { return m_headp == NULL; } + void reset() { // clear() without walking the list + m_headp = NULL; + m_tailp = NULL; + } }; //============================================================================ -template -class V3ListEnt { +template class V3ListEnt { // List entry for linked list of elements of type *T (T is a pointer type) private: // MEMBERS @@ -60,11 +63,13 @@ private: // "this" must be a element inside of *basep // Use that to determine a structure offset, then apply to the new base // to get our new pointer information - return (V3ListEnt*) ( ((vluint8_t*)newbasep) + offset); + return (V3ListEnt*)(((vluint8_t*)newbasep) + offset); } + public: V3ListEnt() - : m_nextp(NULL), m_prevp(NULL) {} + : m_nextp(NULL) + , m_prevp(NULL) {} ~V3ListEnt() { #ifdef VL_DEBUG // Load bogus pointers so we can catch deletion bugs @@ -99,10 +104,16 @@ public: // "this" must be a element inside of *oldp // cppcheck-suppress thisSubtraction size_t offset = (size_t)(vluint8_t*)(this) - (size_t)(vluint8_t*)(oldp); - if (m_nextp) baseToListEnt(m_nextp, offset)->m_prevp = m_prevp; - else listr.m_tailp = m_prevp; - if (m_prevp) baseToListEnt(m_prevp, offset)->m_nextp = m_nextp; - else listr.m_headp = m_nextp; + if (m_nextp) { + baseToListEnt(m_nextp, offset)->m_prevp = m_prevp; + } else { + listr.m_tailp = m_prevp; + } + if (m_prevp) { + baseToListEnt(m_prevp, offset)->m_nextp = m_nextp; + } else { + listr.m_headp = m_nextp; + } m_prevp = m_nextp = NULL; } }; diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index 7a001ad43..1ca733c6a 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -52,10 +52,10 @@ protected: // Per-variable flags // Used in user()'s so initializes to all zeros struct { - int m_notOpt:1; // NOT optimizable - int m_notStd:1; // NOT optimizable if a non-blocktemp signal - int m_stdFuncAsn:1; // Found simple assignment - int m_done:1; // Removed + int m_notOpt : 1; // NOT optimizable + int m_notStd : 1; // NOT optimizable if a non-blocktemp signal + int m_stdFuncAsn : 1; // Found simple assignment + int m_done : 1; // Removed }; // cppcheck-suppress unusedStructMember uint32_t m_flags; @@ -75,7 +75,7 @@ private: // METHODS virtual void visit(AstVarRef* nodep) VL_OVERRIDE { // cppcheck-suppress unreadVariable // cppcheck 1.90 bug - VarFlags flags (nodep->varp()); + VarFlags flags(nodep->varp()); if (flags.m_done) { nodep->hiername(""); // Remove this-> nodep->hierThis(true); @@ -85,9 +85,7 @@ private: public: // CONSTRUCTORS - explicit LocalizeDehierVisitor(AstNetlist* nodep) { - iterate(nodep); - } + explicit LocalizeDehierVisitor(AstNetlist* nodep) { iterate(nodep); } virtual ~LocalizeDehierVisitor() {} }; @@ -98,9 +96,9 @@ class LocalizeVisitor : public LocalizeBaseVisitor { private: // NODE STATE/TYPES // See above - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser4InUse m_inuser4; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; + AstUser4InUse m_inuser4; // STATE VDouble0 m_statLocVars; // Statistic tracking @@ -109,14 +107,14 @@ private: // METHODS void clearOptimizable(AstVar* nodep, const char* reason) { - UINFO(4," NoOpt "<valuep()) clearOptimizable(nodep, "HasInitValue"); if (!VarFlags(nodep).m_stdFuncAsn) clearStdOptimizable(nodep, "NoStdAssign"); - VarFlags flags (nodep); + VarFlags flags(nodep); if ((nodep->isMovableToBlock() // Blocktemp || !flags.m_notStd) // Or used only in block && !flags.m_notOpt // Optimizable - && !nodep->isClassMember() - && nodep->user1p()) { // Single cfunc + && !nodep->isClassMember() && nodep->user1p()) { // Single cfunc // We don't need to test for tracing; it would be in the tracefunc if it was needed - UINFO(4," ModVar->BlkVar "<BlkVar " << nodep << endl); ++m_statLocVars; AstCFunc* newfuncp = VN_CAST(nodep->user1p(), CFunc); nodep->unlinkFrBack(); @@ -154,7 +151,7 @@ private: moveVars(); } virtual void visit(AstCFunc* nodep) VL_OVERRIDE { - UINFO(4," CFUNC "<argsp()); searchFuncStmts(nodep->initsp()); @@ -168,14 +165,14 @@ private: // For now we only find simple assignments not under any other statement. // This could be more complicated; allow always-set under both branches of a IF. // If so, check for ArrayRef's and such, as they aren't acceptable. - for (; nodep; nodep=nodep->nextp()) { + for (; nodep; nodep = nodep->nextp()) { if (VN_IS(nodep, NodeAssign)) { if (AstVarRef* varrefp = VN_CAST(VN_CAST(nodep, NodeAssign)->lhsp(), VarRef)) { UASSERT_OBJ(varrefp->lvalue(), varrefp, "LHS assignment not lvalue"); if (!varrefp->varp()->user4p()) { - UINFO(4," FuncAsn "<varp()->user4p(varrefp); - VarFlags flags (varrefp->varp()); + VarFlags flags(varrefp->varp()); flags.m_stdFuncAsn = true; flags.setNodeFlags(varrefp->varp()); } @@ -185,10 +182,9 @@ private: } virtual void visit(AstVar* nodep) VL_OVERRIDE { - if (!nodep->isSigPublic() - && !nodep->isPrimaryIO() + if (!nodep->isSigPublic() && !nodep->isPrimaryIO() && !m_cfuncp) { // Not already inside a function - UINFO(4," BLKVAR "<varp()).m_notOpt) { if (!m_cfuncp) { // Not in function, can't optimize clearOptimizable(nodep->varp(), "BVnofunc"); - } - else { + } else { // If we're scoping down to it, it isn't really in the same block if (!nodep->hierThis()) clearOptimizable(nodep->varp(), "HierRef"); // Allow a variable to appear in only a single function AstNode* oldfunc = nodep->varp()->user1p(); if (!oldfunc) { - UINFO(4," BVnewref "<varp()->user1p(m_cfuncp); // Remember where it was used } else if (m_cfuncp == oldfunc) { // Same usage @@ -214,7 +209,7 @@ private: } // First varref in function must be assignment found earlier AstVarRef* firstasn = static_cast(nodep->varp()->user4p()); - if (firstasn && nodep!=firstasn) { + if (firstasn && nodep != firstasn) { clearStdOptimizable(nodep->varp(), "notFirstAsn"); nodep->varp()->user4p(NULL); } @@ -239,11 +234,11 @@ public: // Localize class functions void V3Localize::localizeAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 6); } diff --git a/src/V3Name.cpp b/src/V3Name.cpp index c2dc0aa39..e1004b0ef 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -41,11 +41,11 @@ private: // AstCell::user1() -> bool. Set true if already processed // AstScope::user1() -> bool. Set true if already processed // AstVar::user1() -> bool. Set true if already processed - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE - AstNodeModule* m_modp; - V3LanguageWords m_words; // Reserved word detector + AstNodeModule* m_modp; + V3LanguageWords m_words; // Reserved word detector // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -53,16 +53,16 @@ private: void rename(AstNode* nodep, bool addPvt) { if (!nodep->user1()) { // Not already done if (addPvt) { - string newname = string("__PVT__")+nodep->name(); + string newname = string("__PVT__") + nodep->name(); nodep->name(newname); nodep->editCountInc(); } else if (VN_IS(nodep, CFunc) && VN_CAST(nodep, CFunc)->isConstructor()) { } else { string rsvd = m_words.isKeyword(nodep->name()); if (rsvd != "") { - nodep->v3warn(SYMRSVDWORD, "Symbol matches "+rsvd - +": "<prettyNameQ()); - string newname = string("__SYM__")+nodep->name(); + nodep->v3warn(SYMRSVDWORD, + "Symbol matches " + rsvd + ": " << nodep->prettyNameQ()); + string newname = string("__SYM__") + nodep->name(); nodep->name(newname); nodep->editCountInc(); } @@ -83,10 +83,10 @@ private: // Add __PVT__ to names of local signals virtual void visit(AstVar* nodep) VL_OVERRIDE { // Don't iterate... Don't need temps for RANGES under the Var. - rename(nodep, ((!m_modp || !m_modp->isTop()) - && !nodep->isSigPublic() - && !nodep->isFuncLocal() // Isn't exposed, and would mess up dpi import wrappers - && !nodep->isTemp())); // Don't bother to rename internal signals + rename(nodep, + ((!m_modp || !m_modp->isTop()) && !nodep->isSigPublic() + && !nodep->isFuncLocal() // Isn't exposed, and would mess up dpi import wrappers + && !nodep->isTemp())); // Don't bother to rename internal signals } virtual void visit(AstCFunc* nodep) VL_OVERRIDE { if (!nodep->user1()) { @@ -102,8 +102,7 @@ private: } virtual void visit(AstCell* nodep) VL_OVERRIDE { if (!nodep->user1()) { - rename(nodep, (!nodep->modp()->modPublic() - && !VN_IS(nodep->modp(), ClassPackage))); + rename(nodep, (!nodep->modp()->modPublic() && !VN_IS(nodep->modp(), ClassPackage))); iterateChildren(nodep); } } @@ -125,10 +124,13 @@ private: if (nodep->aboveCellp()) iterate(nodep->aboveCellp()); // Always recompute name (as many levels above scope may have changed) // Same formula as V3Scope - nodep->name(nodep->isTop() ? "TOP" - : VN_IS(m_modp, Class) ? ("TOP." + m_modp->name()) - : VN_IS(m_modp, ClassPackage) ? ("TOP." + m_modp->name()) - : (nodep->aboveScopep()->name() + "." + nodep->aboveCellp()->name())); + nodep->name(nodep->isTop() + ? "TOP" + : VN_IS(m_modp, Class) ? ("TOP." + m_modp->name()) + : VN_IS(m_modp, ClassPackage) + ? ("TOP." + m_modp->name()) + : (nodep->aboveScopep()->name() + "." + + nodep->aboveCellp()->name())); nodep->editCountInc(); iterateChildren(nodep); } @@ -150,9 +152,7 @@ public: // Name class functions void V3Name::nameAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 6); } diff --git a/src/V3Number_test.cpp b/src/V3Number_test.cpp index f4a5638e7..894ba5228 100644 --- a/src/V3Number_test.cpp +++ b/src/V3Number_test.cpp @@ -36,54 +36,83 @@ void test(const string& lhss, const string& op, const string& rhss, const string FileLine fl = new FileLine(FileLine::builtInFinename()); - V3Number lhnum (fl, l1); - V3Number rhnum (fl, r1); - V3Number expnum (fl, e1); - V3Number gotnum (fl, expnum.width()); + V3Number lhnum(fl, l1); + V3Number rhnum(fl, r1); + V3Number expnum(fl, e1); + V3Number gotnum(fl, expnum.width()); - if (op=="redOr") gotnum.opRedOr (lhnum); - else if (op=="redAnd") gotnum.opRedAnd (lhnum); - else if (op=="redXor") gotnum.opRedXor (lhnum); - else if (op=="redXnor") gotnum.opRedXnor (lhnum); - else if (op=="concat") gotnum.opConcat (lhnum, rhnum); - else if (op=="repl") gotnum.opRepl (lhnum, rhnum); - else if (op=="~") gotnum.opNot (lhnum); - else if (op=="!") gotnum.opLogNot (lhnum); - else if (op=="negate") gotnum.opNegate (lhnum); - else if (op=="+") gotnum.opAdd (lhnum, rhnum); - else if (op=="-") gotnum.opSub (lhnum, rhnum); - else if (op=="*") gotnum.opMul (lhnum, rhnum); - else if (op=="/") gotnum.opDiv (lhnum, rhnum); - else if (op=="%") gotnum.opModDiv (lhnum, rhnum); - else if (op=="&") gotnum.opAnd (lhnum, rhnum); - else if (op=="|") gotnum.opOr (lhnum, rhnum); - else if (op=="<") gotnum.opLt (lhnum, rhnum); - else if (op==">") gotnum.opGt (lhnum, rhnum); - else if (op==">>") gotnum.opShiftR (lhnum, rhnum); - else if (op=="<<") gotnum.opShiftL (lhnum, rhnum); - else if (op=="==") gotnum.opEq (lhnum, rhnum); - else if (op=="===") gotnum.opCaseEq (lhnum, rhnum); - else if (op=="==?") gotnum.opWildEq (lhnum, rhnum); - else if (op=="!=") gotnum.opNeq (lhnum, rhnum); - else if (op=="!==") gotnum.opCaseNeq (lhnum, rhnum); - else if (op=="!=?") gotnum.opWildNeq (lhnum, rhnum); - else if (op=="<=") gotnum.opLte (lhnum, rhnum); - else if (op==">=") gotnum.opGte (lhnum, rhnum); - else if (op=="&&") gotnum.opLogAnd (lhnum, rhnum); - else if (op=="||") gotnum.opLogOr (lhnum, rhnum); - else v3fatalSrc("Bad opcode: "<") { + gotnum.opGt(lhnum, rhnum); + } else if (op == ">>") { + gotnum.opShiftR(lhnum, rhnum); + } else if (op == "<<") { + gotnum.opShiftL(lhnum, rhnum); + } else if (op == "==") { + gotnum.opEq(lhnum, rhnum); + } else if (op == "===") { + gotnum.opCaseEq(lhnum, rhnum); + } else if (op == "==?") { + gotnum.opWildEq(lhnum, rhnum); + } else if (op == "!=") { + gotnum.opNeq(lhnum, rhnum); + } else if (op == "!==") { + gotnum.opCaseNeq(lhnum, rhnum); + } else if (op == "!=?") { + gotnum.opWildNeq(lhnum, rhnum); + } else if (op == "<=") { + gotnum.opLte(lhnum, rhnum); + } else if (op == ">=") { + gotnum.opGte(lhnum, rhnum); + } else if (op == "&&") { + gotnum.opLogAnd(lhnum, rhnum); + } else if (op == "||") { + gotnum.opLogOr(lhnum, rhnum); + } else + v3fatalSrc("Bad opcode: " << op); - UINFO(0,"------- Test:\n" - <<" "<(_e)) {} + inline OrderVEdgeType(en _e) + : m_e(_e) {} + explicit inline OrderVEdgeType(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } }; inline bool operator==(const OrderVEdgeType& lhs, const OrderVEdgeType& rhs) { @@ -139,18 +140,23 @@ class OrderEitherVertex : public V3GraphVertex { bool m_isFromInput; // From input, or derived therefrom (conservatively false) protected: OrderEitherVertex(V3Graph* graphp, const OrderEitherVertex& old) - : V3GraphVertex(graphp, old), m_scopep(old.m_scopep), m_domainp(old.m_domainp) + : V3GraphVertex(graphp, old) + , m_scopep(old.m_scopep) + , m_domainp(old.m_domainp) , m_isFromInput(old.m_isFromInput) {} + public: OrderEitherVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp) - : V3GraphVertex(graphp), m_scopep(scopep), m_domainp(domainp) + : V3GraphVertex(graphp) + , m_scopep(scopep) + , m_domainp(domainp) , m_isFromInput(false) {} virtual ~OrderEitherVertex() {} virtual OrderEitherVertex* clone(V3Graph* graphp) const = 0; // Methods virtual OrderVEdgeType type() const = 0; virtual bool domainMatters() = 0; // Must be in same domain when cross edge to this vertex - virtual string dotName() const { return cvtToHex(m_scopep)+"_"; } + virtual string dotName() const { return cvtToHex(m_scopep) + "_"; } // ACCESSORS void domainp(AstSenTree* domainp) { m_domainp = domainp; } AstScope* scopep() const { return m_scopep; } @@ -162,6 +168,7 @@ public: class OrderInputsVertex : public OrderEitherVertex { OrderInputsVertex(V3Graph* graphp, const OrderInputsVertex& old) : OrderEitherVertex(graphp, old) {} + public: OrderInputsVertex(V3Graph* graphp, AstSenTree* domainp) : OrderEitherVertex(graphp, NULL, domainp) { @@ -169,7 +176,8 @@ public: } virtual ~OrderInputsVertex() {} virtual OrderInputsVertex* clone(V3Graph* graphp) const { - return new OrderInputsVertex(graphp, *this); } + return new OrderInputsVertex(graphp, *this); + } virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_INPUTS; } virtual string name() const { return "*INPUTS*"; } virtual string dotColor() const { return "green"; } @@ -180,12 +188,14 @@ public: class OrderSettleVertex : public OrderEitherVertex { OrderSettleVertex(V3Graph* graphp, const OrderSettleVertex& old) : OrderEitherVertex(graphp, old) {} + public: OrderSettleVertex(V3Graph* graphp, AstSenTree* domainp) : OrderEitherVertex(graphp, NULL, domainp) {} virtual ~OrderSettleVertex() {} virtual OrderSettleVertex* clone(V3Graph* graphp) const { - return new OrderSettleVertex(graphp, *this); } + return new OrderSettleVertex(graphp, *this); + } virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_SETTLE; } virtual string name() const { return "*SETTLE*"; } virtual string dotColor() const { return "green"; } @@ -194,21 +204,27 @@ public: }; class OrderLogicVertex : public OrderEitherVertex { - AstNode* m_nodep; + AstNode* m_nodep; + protected: OrderLogicVertex(V3Graph* graphp, const OrderLogicVertex& old) - : OrderEitherVertex(graphp, old), m_nodep(old.m_nodep) {} + : OrderEitherVertex(graphp, old) + , m_nodep(old.m_nodep) {} + public: OrderLogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp, AstNode* nodep) - : OrderEitherVertex(graphp, scopep, domainp), m_nodep(nodep) {} + : OrderEitherVertex(graphp, scopep, domainp) + , m_nodep(nodep) {} virtual ~OrderLogicVertex() {} virtual OrderLogicVertex* clone(V3Graph* graphp) const { - return new OrderLogicVertex(graphp, *this); } + return new OrderLogicVertex(graphp, *this); + } virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_LOGIC; } virtual bool domainMatters() { return true; } // ACCESSORS virtual string name() const { - return (cvtToHex(m_nodep)+"\\n "+cvtToStr(nodep()->typeName())); } + return (cvtToHex(m_nodep) + "\\n " + cvtToStr(nodep()->typeName())); + } AstNode* nodep() const { return m_nodep; } virtual string dotColor() const { return "yellow"; } }; @@ -220,12 +236,16 @@ class OrderVarVertex : public OrderEitherVertex { protected: OrderVarVertex(V3Graph* graphp, const OrderVarVertex& old) : OrderEitherVertex(graphp, old) - , m_varScp(old.m_varScp), m_isClock(old.m_isClock) + , m_varScp(old.m_varScp) + , m_isClock(old.m_isClock) , m_isDelayed(old.m_isDelayed) {} + public: OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) - : OrderEitherVertex(graphp, scopep, NULL), m_varScp(varScp) - , m_isClock(false), m_isDelayed(false) {} + : OrderEitherVertex(graphp, scopep, NULL) + , m_varScp(varScp) + , m_isClock(false) + , m_isDelayed(false) {} virtual ~OrderVarVertex() {} virtual OrderVarVertex* clone(V3Graph* graphp) const = 0; virtual OrderVEdgeType type() const = 0; @@ -241,70 +261,80 @@ public: class OrderVarStdVertex : public OrderVarVertex { OrderVarStdVertex(V3Graph* graphp, const OrderVarStdVertex& old) : OrderVarVertex(graphp, old) {} + public: OrderVarStdVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex(graphp, scopep, varScp) {} virtual ~OrderVarStdVertex() {} virtual OrderVarStdVertex* clone(V3Graph* graphp) const { - return new OrderVarStdVertex(graphp, *this); } + return new OrderVarStdVertex(graphp, *this); + } virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARSTD; } - virtual string name() const { return (cvtToHex(varScp())+"\\n "+varScp()->name());} + virtual string name() const { return (cvtToHex(varScp()) + "\\n " + varScp()->name()); } virtual string dotColor() const { return "skyblue"; } virtual bool domainMatters() { return true; } }; class OrderVarPreVertex : public OrderVarVertex { OrderVarPreVertex(V3Graph* graphp, const OrderVarPreVertex& old) : OrderVarVertex(graphp, old) {} + public: OrderVarPreVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex(graphp, scopep, varScp) {} virtual ~OrderVarPreVertex() {} virtual OrderVarPreVertex* clone(V3Graph* graphp) const { - return new OrderVarPreVertex(graphp, *this); } + return new OrderVarPreVertex(graphp, *this); + } virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARPRE; } - virtual string name() const { return (cvtToHex(varScp())+" PRE\\n "+varScp()->name());} + virtual string name() const { return (cvtToHex(varScp()) + " PRE\\n " + varScp()->name()); } virtual string dotColor() const { return "lightblue"; } virtual bool domainMatters() { return false; } }; class OrderVarPostVertex : public OrderVarVertex { OrderVarPostVertex(V3Graph* graphp, const OrderVarPostVertex& old) : OrderVarVertex(graphp, old) {} + public: OrderVarPostVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex(graphp, scopep, varScp) {} virtual OrderVarPostVertex* clone(V3Graph* graphp) const { - return new OrderVarPostVertex(graphp, *this); } + return new OrderVarPostVertex(graphp, *this); + } virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARPOST; } virtual ~OrderVarPostVertex() {} - virtual string name() const { return (cvtToHex(varScp())+" POST\\n "+varScp()->name());} + virtual string name() const { return (cvtToHex(varScp()) + " POST\\n " + varScp()->name()); } virtual string dotColor() const { return "CadetBlue"; } virtual bool domainMatters() { return false; } }; class OrderVarPordVertex : public OrderVarVertex { OrderVarPordVertex(V3Graph* graphp, const OrderVarPordVertex& old) : OrderVarVertex(graphp, old) {} + public: OrderVarPordVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex(graphp, scopep, varScp) {} virtual ~OrderVarPordVertex() {} virtual OrderVarPordVertex* clone(V3Graph* graphp) const { - return new OrderVarPordVertex(graphp, *this); } + return new OrderVarPordVertex(graphp, *this); + } virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARPORD; } - virtual string name() const { return (cvtToHex(varScp())+" PORD\\n "+varScp()->name());} + virtual string name() const { return (cvtToHex(varScp()) + " PORD\\n " + varScp()->name()); } virtual string dotColor() const { return "NavyBlue"; } virtual bool domainMatters() { return false; } }; class OrderVarSettleVertex : public OrderVarVertex { OrderVarSettleVertex(V3Graph* graphp, const OrderVarSettleVertex& old) : OrderVarVertex(graphp, old) {} + public: OrderVarSettleVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex(graphp, scopep, varScp) {} virtual ~OrderVarSettleVertex() {} virtual OrderVarSettleVertex* clone(V3Graph* graphp) const { - return new OrderVarSettleVertex(graphp, *this); } + return new OrderVarSettleVertex(graphp, *this); + } virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARSETTLE; } - virtual string name() const { return (cvtToHex(varScp())+" STL\\n "+varScp()->name());} + virtual string name() const { return (cvtToHex(varScp()) + " STL\\n " + varScp()->name()); } virtual string dotColor() const { return "PowderBlue"; } virtual bool domainMatters() { return false; } }; @@ -313,7 +343,7 @@ public: //--- Following only under the move graph, not the main graph class OrderMoveVertex : public V3GraphVertex { - typedef enum {POM_WAIT, POM_READY, POM_MOVED} OrderMState; + typedef enum { POM_WAIT, POM_READY, POM_MOVED } OrderMState; OrderLogicVertex* m_logicp; OrderMState m_state; // Movement state @@ -329,40 +359,50 @@ protected: public: // CONSTRUCTORS OrderMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp) - : V3GraphVertex(graphp), m_logicp(logicp), m_state(POM_WAIT), m_domScopep(NULL) {} + : V3GraphVertex(graphp) + , m_logicp(logicp) + , m_state(POM_WAIT) + , m_domScopep(NULL) {} virtual ~OrderMoveVertex() {} virtual OrderMoveVertex* clone(V3Graph* graphp) const { - v3fatalSrc("Unsupported"); return NULL; } + v3fatalSrc("Unsupported"); + return NULL; + } // METHODS virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_MOVE; } virtual string dotColor() const { - if (logicp()) return logicp()->dotColor(); - else return ""; + if (logicp()) { + return logicp()->dotColor(); + } else { + return ""; + } } virtual FileLine* fileline() const { - if (logicp()) return logicp()->fileline(); - else return NULL; + if (logicp()) { + return logicp()->fileline(); + } else { + return NULL; + } } virtual string name() const { string nm; if (logicp()) { nm = logicp()->name(); - nm += (string("\\nMV:") - +" d="+cvtToHex(logicp()->domainp()) - +" s="+cvtToHex(logicp()->scopep())); + nm += (string("\\nMV:") + " d=" + cvtToHex(logicp()->domainp()) + + " s=" + cvtToHex(logicp()->scopep())); } else { nm = "nul"; } return nm; } OrderLogicVertex* logicp() const { return m_logicp; } - bool isWait() const { return m_state==POM_WAIT; } + bool isWait() const { return m_state == POM_WAIT; } void setReady() { - UASSERT(m_state==POM_WAIT, "Wait->Ready on node not in proper state"); + UASSERT(m_state == POM_WAIT, "Wait->Ready on node not in proper state"); m_state = POM_READY; } void setMoved() { - UASSERT(m_state==POM_READY, "Ready->Moved on node not in proper state"); + UASSERT(m_state == POM_READY, "Ready->Moved on node not in proper state"); m_state = POM_MOVED; } OrderMoveDomScope* domScopep() const { return m_domScopep; } @@ -383,34 +423,40 @@ class MTaskMoveVertex : public V3GraphVertex { protected: friend class OrderVisitor; friend class MTaskMoveVertexMaker; + public: - MTaskMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp, - const OrderEitherVertex* varp, + MTaskMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp, const OrderEitherVertex* varp, const AstScope* scopep, const AstSenTree* domainp) - : V3GraphVertex(graphp), m_logicp(logicp), - m_varp(varp), m_scopep(scopep), m_domainp(domainp) { - UASSERT(!(logicp && varp), - "MTaskMoveVertex: logicp and varp may not both be set!\n"); + : V3GraphVertex(graphp) + , m_logicp(logicp) + , m_varp(varp) + , m_scopep(scopep) + , m_domainp(domainp) { + UASSERT(!(logicp && varp), "MTaskMoveVertex: logicp and varp may not both be set!\n"); } virtual ~MTaskMoveVertex() {} virtual MTaskMoveVertex* clone(V3Graph* graphp) const { - v3fatalSrc("Unsupported"); return NULL; } + v3fatalSrc("Unsupported"); + return NULL; + } virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_MOVE; } virtual string dotColor() const { - if (logicp()) return logicp()->dotColor(); - else return "yellow"; + if (logicp()) { + return logicp()->dotColor(); + } else { + return "yellow"; + } } virtual string name() const { string nm; if (logicp()) { nm = logicp()->name(); - nm += (string("\\nMV:") - +" d="+cvtToHex(logicp()->domainp()) - +" s="+cvtToHex(logicp()->scopep()) + nm += (string("\\nMV:") + " d=" + cvtToHex(logicp()->domainp()) + " s=" + + cvtToHex(logicp()->scopep()) // "color()" represents the mtask ID. - +"\\nt="+cvtToStr(color())); + + "\\nt=" + cvtToStr(color())); } else { - nm = "nolog\\nt="+cvtToStr(color()); + nm = "nolog\\nt=" + cvtToStr(color()); } return nm; } @@ -426,12 +472,12 @@ public: class OrderEdge : public V3GraphEdge { protected: - OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, - const OrderEdge& old) + OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, const OrderEdge& old) : V3GraphEdge(graphp, fromp, top, old) {} + public: - OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, - int weight, bool cutable=false) + OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, + bool cutable = false) : V3GraphEdge(graphp, fromp, top, weight, cutable) {} virtual ~OrderEdge() {} virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_STD; } @@ -461,13 +507,14 @@ class OrderComboCutEdge : public OrderEdge { OrderComboCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, const OrderComboCutEdge& old) : OrderEdge(graphp, fromp, top, old) {} + public: OrderComboCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : OrderEdge(graphp, fromp, top, WEIGHT_COMBO, CUTABLE) {} virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_COMBOCUT; } virtual ~OrderComboCutEdge() {} - virtual OrderComboCutEdge* clone(V3Graph* graphp, - V3GraphVertex* fromp, V3GraphVertex* top) const { + virtual OrderComboCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, + V3GraphVertex* top) const { return new OrderComboCutEdge(graphp, fromp, top, *this); } virtual string dotColor() const { return "yellowGreen"; } @@ -482,13 +529,14 @@ class OrderPostCutEdge : public OrderEdge { OrderPostCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, const OrderPostCutEdge& old) : OrderEdge(graphp, fromp, top, old) {} + public: OrderPostCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : OrderEdge(graphp, fromp, top, WEIGHT_COMBO, CUTABLE) {} virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_POSTCUT; } virtual ~OrderPostCutEdge() {} - virtual OrderPostCutEdge* clone(V3Graph* graphp, - V3GraphVertex* fromp, V3GraphVertex* top) const { + virtual OrderPostCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, + V3GraphVertex* top) const { return new OrderPostCutEdge(graphp, fromp, top, *this); } virtual string dotColor() const { return "PaleGreen"; } @@ -503,12 +551,13 @@ class OrderPreCutEdge : public OrderEdge { OrderPreCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, const OrderPreCutEdge& old) : OrderEdge(graphp, fromp, top, old) {} + public: OrderPreCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : OrderEdge(graphp, fromp, top, WEIGHT_PRE, CUTABLE) {} virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_PRECUT; } - virtual OrderPreCutEdge* clone(V3Graph* graphp, - V3GraphVertex* fromp, V3GraphVertex* top) const { + virtual OrderPreCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, + V3GraphVertex* top) const { return new OrderPreCutEdge(graphp, fromp, top, *this); } virtual ~OrderPreCutEdge() {} diff --git a/src/V3Os.h b/src/V3Os.h index d1b2b4436..cfebdfc7e 100644 --- a/src/V3Os.h +++ b/src/V3Os.h @@ -34,17 +34,21 @@ public: // METHODS (generic filename utilities) static string filenameFromDirBase(const string& dir, const string& basename); - static string filenameNonDir(const string& filename); ///< Return non-directory part of filename - static string filenameNonExt(const string& filename); ///< Return non-extensioned (no .) part of filename + /// Return non-directory part of filename + static string filenameNonDir(const string& filename); + /// Return non-extensioned (no .) part of filename + static string filenameNonExt(const string& filename); static string filenameNonDirExt(const string& filename) { ///< Return basename of filename - return filenameNonExt(filenameNonDir(filename)); } + return filenameNonExt(filenameNonDir(filename)); + } static string filenameDir(const string& filename); ///< Return directory part of filename - static string filenameSubstitute(const string& filename); ///< Return filename with env vars removed + /// Return filename with env vars removed + static string filenameSubstitute(const string& filename); static string filenameRealPath(const string& filename); ///< Return realpath of filename static bool filenameIsRel(const string& filename); ///< True if relative // METHODS (file utilities) - static string getline(std::istream& is, char delim='\n'); + static string getline(std::istream& is, char delim = '\n'); // METHODS (directory utilities) static void createDir(const string& dirname); @@ -56,7 +60,8 @@ public: // METHODS (time & performance) static void u_sleep(int64_t usec); ///< Sleep for a given number of microseconds. - static uint64_t timeUsecs(); ///< Return wall time since epoch in microseconds, or 0 if not implemented + /// Return wall time since epoch in microseconds, or 0 if not implemented + static uint64_t timeUsecs(); static uint64_t memUsageBytes(); ///< Return memory usage in bytes, or 0 if not implemented }; diff --git a/src/V3ParseLex.cpp b/src/V3ParseLex.cpp index c59a7283e..7f5895d93 100644 --- a/src/V3ParseLex.cpp +++ b/src/V3ParseLex.cpp @@ -39,18 +39,15 @@ class V3Lexer : public V3LexerBase { public: // CONSTRUCTORS - V3Lexer() : V3LexerBase(NULL) {} + V3Lexer() + : V3LexerBase(NULL) {} ~V3Lexer() {} // METHODS - void statePop() { - yy_pop_state(); - } + void statePop() { yy_pop_state(); } void unputString(const char* textp, size_t length) { // Add characters to input stream in back-to-front order const char* cp = textp; - for (cp += length - 1; length--; cp--) { - unput(*cp); - } + for (cp += length - 1; length--; cp--) unput(*cp); } }; @@ -74,7 +71,7 @@ int V3ParseImp::yylexReadTok() { void V3ParseImp::lexNew() { if (m_lexerp) delete m_lexerp; // Restart from clean slate. m_lexerp = new V3Lexer(); - if (debugFlex()>=9) { m_lexerp->set_debug(~0); } + if (debugFlex() >= 9) { m_lexerp->set_debug(~0); } } void V3ParseImp::lexDestroy() { diff --git a/src/V3ParseSym.h b/src/V3ParseSym.h index fda4f4411..d8c39b7d7 100644 --- a/src/V3ParseSym.h +++ b/src/V3ParseSym.h @@ -36,11 +36,11 @@ class V3ParseSym { private: // MEMBERS - static int s_anonNum; // Number of next anonymous object (parser use only) - VSymGraph m_syms; // Graph of symbol tree - VSymEnt* m_symTableNextId; // Symbol table for next lexer lookup (parser use only) - VSymEnt* m_symCurrentp; // Active symbol table for additions/lookups - SymStack m_sympStack; // Stack of upper nodes with pending symbol tables + static int s_anonNum; // Number of next anonymous object (parser use only) + VSymGraph m_syms; // Graph of symbol tree + VSymEnt* m_symTableNextId; // Symbol table for next lexer lookup (parser use only) + VSymEnt* m_symCurrentp; // Active symbol table for additions/lookups + SymStack m_sympStack; // Stack of upper nodes with pending symbol tables public: // CONSTRUCTORS @@ -74,15 +74,14 @@ public: } void nextId(AstNode* entp) { if (entp) { - UINFO(9,"symTableNextId under "<type().ascii()<type().ascii() << endl); m_symTableNextId = getTable(entp); - } - else { - UINFO(9,"symTableNextId under NULL"<name()); } void reinsert(AstNode* nodep, VSymEnt* parentp, string name) { @@ -95,7 +94,8 @@ public: void pushNew(AstNode* nodep) { pushNewUnder(nodep, NULL); } void pushNewUnder(AstNode* nodep, VSymEnt* parentp) { if (!parentp) parentp = symCurrentp(); - VSymEnt* symp = findNewTable(nodep); // Will set user4p, which is how we connect table to node + VSymEnt* symp + = findNewTable(nodep); // Will set user4p, which is how we connect table to node symp->fallbackp(parentp); reinsert(nodep, parentp); pushScope(symp); @@ -106,9 +106,13 @@ public: } void popScope(AstNode* nodep) { if (symCurrentp()->nodep() != nodep) { - if (debug()) { showUpward(); dump(cout, "-mism: "); } - nodep->v3fatalSrc("Symbols suggest ending "<nodep()->prettyTypeName() - <<" but parser thinks ending "<prettyTypeName()); + if (debug()) { + showUpward(); + dump(cout, "-mism: "); + } + nodep->v3fatalSrc("Symbols suggest ending " << symCurrentp()->nodep()->prettyTypeName() + << " but parser thinks ending " + << nodep->prettyTypeName()); return; } m_sympStack.pop_back(); @@ -116,21 +120,23 @@ public: m_symCurrentp = m_sympStack.back(); } void showUpward() { - UINFO(1,"ParseSym Stack:\n"); - for (SymStack::reverse_iterator it=m_sympStack.rbegin(); it!=m_sympStack.rend(); ++it) { + UINFO(1, "ParseSym Stack:\n"); + for (SymStack::reverse_iterator it = m_sympStack.rbegin(); it != m_sympStack.rend(); + ++it) { VSymEnt* symp = *it; - UINFO(1," "<nodep()<nodep() << endl); } - UINFO(1,"ParseSym Current: "<nodep()<nodep() << endl); } + void dump(std::ostream& os, const string& indent = "") { m_syms.dump(os, indent); } AstNode* findEntUpward(const string& name) { // Lookup the given string as an identifier, return type of the id, scanning upward VSymEnt* foundp = symCurrentp()->findIdFallback(name); - if (foundp) return foundp->nodep(); - else return NULL; + if (foundp) { + return foundp->nodep(); + } else { + return NULL; + } } void importItem(AstNode* packagep, const string& id_or_star) { // Import from package::id_or_star to this diff --git a/src/V3Partition.h b/src/V3Partition.h index b5a78a756..9226cb666 100644 --- a/src/V3Partition.h +++ b/src/V3Partition.h @@ -61,6 +61,7 @@ public: // Operate on the final ExecMTask graph, immediately prior to code // generation time. static void finalize(); + private: static void finalizeCosts(V3Graph* execMTaskGraphp); static void setupMTaskDeps(V3Graph* mtasksp, const Vx2MTaskMap* vx2mtaskp); @@ -75,13 +76,15 @@ private: class PartPtrIdMap { private: // TYPES - typedef vl_unordered_map PtrMap; + typedef vl_unordered_map PtrMap; // MEMBERS mutable vluint64_t m_nextId; mutable PtrMap m_id; + public: // CONSTRUCTORS - PartPtrIdMap() : m_nextId(0) {} + PartPtrIdMap() + : m_nextId(0) {} // METHODS vluint64_t findId(const void* ptrp) const { PtrMap::const_iterator it = m_id.find(ptrp); diff --git a/src/V3PartitionGraph.h b/src/V3PartitionGraph.h index 6aeb6e411..1c2abd59b 100644 --- a/src/V3PartitionGraph.h +++ b/src/V3PartitionGraph.h @@ -30,7 +30,8 @@ class AbstractMTask : public V3GraphVertex { public: - AbstractMTask(V3Graph* graphp) : V3GraphVertex(graphp) {} + AbstractMTask(V3Graph* graphp) + : V3GraphVertex(graphp) {} virtual ~AbstractMTask() {} virtual uint32_t id() const = 0; virtual uint32_t cost() const = 0; @@ -41,7 +42,8 @@ public: // TYPES typedef std::list VxList; // CONSTRUCTORS - AbstractLogicMTask(V3Graph* graphp) : AbstractMTask(graphp) {} + AbstractLogicMTask(V3Graph* graphp) + : AbstractMTask(graphp) {} virtual ~AbstractLogicMTask() {} // METHODS // Set of logic vertices in this mtask. Order is not significant. @@ -52,28 +54,29 @@ public: class ExecMTask : public AbstractMTask { private: - AstMTaskBody* m_bodyp; // Task body - uint32_t m_id; // Unique id of this mtask. - uint32_t m_priority; // Predicted critical path from the start of + AstMTaskBody* m_bodyp; // Task body + uint32_t m_id; // Unique id of this mtask. + uint32_t m_priority; // Predicted critical path from the start of // this mtask to the ends of the graph that are reachable from this // mtask. In abstract time units. - uint32_t m_cost; // Predicted runtime of this mtask, in the same + uint32_t m_cost; // Predicted runtime of this mtask, in the same // abstract time units as priority(). - uint32_t m_thread; // Thread for static (pack_mtasks) scheduling, + uint32_t m_thread; // Thread for static (pack_mtasks) scheduling, // or 0xffffffff if not yet assigned. - const ExecMTask* m_packNextp; // Next for static (pack_mtasks) scheduling - bool m_threadRoot; // Is root thread + const ExecMTask* m_packNextp; // Next for static (pack_mtasks) scheduling + bool m_threadRoot; // Is root thread VL_UNCOPYABLE(ExecMTask); + public: ExecMTask(V3Graph* graphp, AstMTaskBody* bodyp, uint32_t id) - : AbstractMTask(graphp), - m_bodyp(bodyp), - m_id(id), - m_priority(0), - m_cost(0), - m_thread(0xffffffff), - m_packNextp(NULL), - m_threadRoot(false) {} + : AbstractMTask(graphp) + , m_bodyp(bodyp) + , m_id(id) + , m_priority(0) + , m_cost(0) + , m_thread(0xffffffff) + , m_packNextp(NULL) + , m_threadRoot(false) {} AstMTaskBody* bodyp() const { return m_bodyp; } virtual uint32_t id() const { return m_id; } uint32_t priority() const { return m_priority; } @@ -88,18 +91,20 @@ public: void threadRoot(bool threadRoot) { m_threadRoot = threadRoot; } string cFuncName() const { // If this MTask maps to a C function, this should be the name - return string("__Vmtask")+"__"+cvtToStr(m_id); + return string("__Vmtask") + "__" + cvtToStr(m_id); } - string name() const { return string("mt")+cvtToStr(id()); } + string name() const { return string("mt") + cvtToStr(id()); } void dump(std::ostream& str) const { - str < m_buffers; // Buffer of characters to process + int m_ignNewlines; // Ignore multiline newlines + bool m_eof; // "EOF" buffer + bool m_file; // Buffer is start of new file + int m_termState; // Termination fsm VPreStream(FileLine* fl, V3PreLex* lexp) - : m_curFilelinep(fl), m_lexp(lexp), - m_ignNewlines(0), - m_eof(false), m_file(false), m_termState(0) { + : m_curFilelinep(fl) + , m_lexp(lexp) + , m_ignNewlines(0) + , m_eof(false) + , m_file(false) + , m_termState(0) { lexStreamDepthAdd(1); } - ~VPreStream() { - lexStreamDepthAdd(-1); - } + ~VPreStream() { lexStreamDepthAdd(-1); } + private: void lexStreamDepthAdd(int delta); }; @@ -147,26 +154,26 @@ private: // Class entry for each per-lexer state class V3PreLex { - public: // Used only by V3PreLex.cpp and V3PreProc.cpp - V3PreProcImp* m_preimpp; // Preprocessor lexor belongs to +public: // Used only by V3PreLex.cpp and V3PreProc.cpp + V3PreProcImp* m_preimpp; // Preprocessor lexor belongs to std::stack m_streampStack; // Stack of processing files - int m_streamDepth; // Depth of stream processing - YY_BUFFER_STATE m_bufferState; // Flex state - FileLine* m_tokFilelinep; // Starting position of current token + int m_streamDepth; // Depth of stream processing + YY_BUFFER_STATE m_bufferState; // Flex state + FileLine* m_tokFilelinep; // Starting position of current token // State to lexer - static V3PreLex* s_currentLexp; ///< Current lexing point - int m_keepComments; ///< Emit comments in output text - int m_keepWhitespace; ///< Emit all whitespace in output text - bool m_pedantic; ///< Obey standard; don't Substitute `error + static V3PreLex* s_currentLexp; ///< Current lexing point + int m_keepComments; ///< Emit comments in output text + int m_keepWhitespace; ///< Emit all whitespace in output text + bool m_pedantic; ///< Obey standard; don't Substitute `error // State from lexer - int m_formalLevel; // Parenthesis counting inside def formals - int m_parenLevel; // Parenthesis counting inside def args - bool m_defCmtSlash; // /*...*/ comment in define had \ ending - bool m_defQuote; // Definition value inside quote - string m_defValue; // Definition value being built. - int m_enterExit; // For VL_LINE, the enter/exit level + int m_formalLevel; // Parenthesis counting inside def formals + int m_parenLevel; // Parenthesis counting inside def args + bool m_defCmtSlash; // /*...*/ comment in define had \ ending + bool m_defQuote; // Definition value inside quote + string m_defValue; // Definition value being built. + int m_enterExit; // For VL_LINE, the enter/exit level // CONSTRUCTORS V3PreLex(V3PreProcImp* preimpp, FileLine* filelinep) { @@ -184,7 +191,10 @@ class V3PreLex { initFirstBuffer(filelinep); } ~V3PreLex() { - while (!m_streampStack.empty()) { delete m_streampStack.top(); m_streampStack.pop(); } + while (!m_streampStack.empty()) { + delete m_streampStack.top(); + m_streampStack.pop(); + } VL_DO_CLEAR(yy_delete_buffer(m_bufferState), m_bufferState = NULL); } @@ -213,8 +223,8 @@ class V3PreLex { size_t inputToLex(char* buf, size_t max_size); /// Called by V3PreProc.cpp to get data from lexer YY_BUFFER_STATE currentBuffer(); - int lex(); - int currentStartState() const; + int lex(); + int currentStartState() const; void dumpSummary(); void dumpStack(); void unused(); diff --git a/src/V3PreProc.h b/src/V3PreProc.h index ae03e7d16..4bed3ae54 100644 --- a/src/V3PreProc.h +++ b/src/V3PreProc.h @@ -44,13 +44,13 @@ protected: public: // CONSTANTS enum MiscConsts { - DEFINE_RECURSION_LEVEL_MAX = 1000, // How many `def substitutions before an error - LINE_TOKEN_MAX = 20000, // How many tokens on a line before an error - INCLUDE_DEPTH_MAX = 500, // How many `includes deep before an error - STREAM_DEPTH_LEVEL_MAX = 2000, // How many streams deep (sometimes `def deep) before an error - // // Set more than DEFINE_RECURSION_LEVEL_MAX - // // or INCLUDE_DEPTH_MAX - NEWLINES_VS_TICKLINE = 20 // Use `line in place of this many newlines + DEFINE_RECURSION_LEVEL_MAX = 1000, // How many `def substitutions before an error + LINE_TOKEN_MAX = 20000, // How many tokens on a line before an error + INCLUDE_DEPTH_MAX = 500, // How many `includes deep before an error + // Streams deep (sometimes `def deep) before an error. + // Set more than DEFINE_RECURSION_LEVEL_MAX or INCLUDE_DEPTH_MAX. + STREAM_DEPTH_LEVEL_MAX = 2000, + NEWLINES_VS_TICKLINE = 20 // Use `line in place of this many newlines }; // ACCESSORS @@ -80,9 +80,10 @@ public: virtual void include(const string& filename) = 0; // Request a include file be processed virtual void undef(const string& name) = 0; // Remove a definition - virtual void define(FileLine* fileline, const string& name, - const string& value, const string& params="", - bool cmdline=false) = 0; // `define without any parameters + virtual void define(FileLine* fileline, const string& name, const string& value, + const string& params = "", + bool cmdline = false) + = 0; // `define without any parameters virtual void defineCmdLine(FileLine* fileline, const string& name, const string& value) { // `define without any parameters define(fileline, name, value, "", true); @@ -97,10 +98,9 @@ public: protected: // CONSTRUCTORS - V3PreProc() { - m_debug = 0; - } + V3PreProc() { m_debug = 0; } void configure(FileLine* fl); + public: static V3PreProc* createPreProc(FileLine* fl); virtual ~V3PreProc() {} diff --git a/src/V3PreShell.cpp b/src/V3PreShell.cpp index c0c7fd05c..714f2ac22 100644 --- a/src/V3PreShell.cpp +++ b/src/V3PreShell.cpp @@ -43,7 +43,7 @@ protected: //--------------------------------------- // METHODS - static int debug(bool reset=false) { + static int debug(bool reset = false) { static int level = -1; if (VL_UNLIKELY(level < 0) || reset) { level = v3Global.opt.debugSrcLevel(__FILE__); @@ -64,8 +64,10 @@ protected: s_preprocp->defineCmdLine(prefl, "VERILATOR", "1"); // LEAK_OK s_preprocp->defineCmdLine(prefl, "verilator", "1"); // LEAK_OK s_preprocp->defineCmdLine(prefl, "verilator3", "1"); // LEAK_OK - s_preprocp->defineCmdLine(prefl, "systemc_clock", "/*verilator systemc_clock*/"); // LEAK_OK - s_preprocp->defineCmdLine(prefl, "coverage_block_off", "/*verilator coverage_block_off*/"); // LEAK_OK + s_preprocp->defineCmdLine(prefl, "systemc_clock", + "/*verilator systemc_clock*/"); // LEAK_OK + s_preprocp->defineCmdLine(prefl, "coverage_block_off", + "/*verilator coverage_block_off*/"); // LEAK_OK if (prefl->language().systemVerilog()) { // Synthesis compatibility s_preprocp->defineCmdLine(prefl, "SYSTEMVERILOG", "1"); // LEAK_OK @@ -94,7 +96,7 @@ protected: debug(true); // Recheck if debug on - first check was before command line passed // Preprocess the given module, putting output in vppFilename - UINFONL(1," Preprocessing "<ext+ options since it was first encountered. FileLine* modfileline = new FileLine(modfilename); modfileline->language(v3Global.opt.fileLanguage(modfilename)); - V3Parse::ppPushText(parsep, (string("`begin_keywords \"") - +modfileline->language().ascii()+"\"\n")); + V3Parse::ppPushText( + parsep, (string("`begin_keywords \"") + modfileline->language().ascii() + "\"\n")); } while (!s_preprocp->isEof()) { @@ -121,31 +123,32 @@ protected: } void preprocInclude(FileLine* fl, const string& modname) { - if (modname[0]=='/' || modname[0]=='\\') { - fl->v3warn(INCABSPATH, "Suggest `include with absolute path be made relative, and use +include: " - <v3warn(INCABSPATH, + "Suggest `include with absolute path be made relative, and use +include: " + << modname); } preprocOpen(fl, s_filterp, modname, V3Os::filenameDir(fl->filename()), "Cannot find include file: "); } private: - string preprocOpen(FileLine* fl, VInFilter* filterp, - const string& modname, const string& lastpath, + string preprocOpen(FileLine* fl, VInFilter* filterp, const string& modname, + const string& lastpath, const string& errmsg) { // Error message or "" to suppress // Returns filename if successful // Try a pure name in case user has a bogus `filename they don't expect string filename = v3Global.opt.filePath(fl, modname, lastpath, errmsg); - if (filename=="") { + if (filename == "") { // Allow user to put `defined names on the command line instead of filenames, // then convert them properly. string ppmodname = s_preprocp->removeDefines(modname); filename = v3Global.opt.filePath(fl, ppmodname, lastpath, errmsg); } - if (filename=="") return ""; // Not found + if (filename == "") return ""; // Not found - UINFO(2," Reading "<openFile(fl, filterp, filename); return filename; } @@ -163,9 +166,7 @@ VInFilter* V3PreShellImp::s_filterp = NULL; //###################################################################### // Perl class functions -void V3PreShell::boot(char** env) { - V3PreShellImp::s_preImp.boot(env); -} +void V3PreShell::boot(char** env) { V3PreShellImp::s_preImp.boot(env); } bool V3PreShell::preproc(FileLine* fl, const string& modname, VInFilter* filterp, V3ParseImp* parsep, const string& errmsg) { return V3PreShellImp::s_preImp.preproc(fl, modname, filterp, parsep, errmsg); @@ -177,12 +178,8 @@ void V3PreShell::defineCmdLine(const string& name, const string& value) { FileLine* prefl = new FileLine(FileLine::commandLineFilename()); V3PreShellImp::s_preprocp->defineCmdLine(prefl, name, value); } -void V3PreShell::undef(const string& name) { - V3PreShellImp::s_preprocp->undef(name); -} -void V3PreShell::dumpDefines(std::ostream& os) { - V3PreShellImp::s_preprocp->dumpDefines(os); -} +void V3PreShell::undef(const string& name) { V3PreShellImp::s_preprocp->undef(name); } +void V3PreShell::dumpDefines(std::ostream& os) { V3PreShellImp::s_preprocp->dumpDefines(os); } void V3PreShell::candidateDefines(VSpellCheck* spellerp) { V3PreShellImp::s_preprocp->candidateDefines(spellerp); } diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index 0654a7dae..350aa2dd2 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -47,27 +47,27 @@ class ReloopVisitor : public AstNVisitor { private: // TYPES - typedef std::vector AssVec; + typedef std::vector AssVec; // NODE STATE // AstCFunc::user1p -> Var* for temp var, 0=not set yet - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE - VDouble0 m_statReloops; // Statistic tracking - VDouble0 m_statReItems; // Statistic tracking - AstCFunc* m_cfuncp; // Current block + VDouble0 m_statReloops; // Statistic tracking + VDouble0 m_statReItems; // Statistic tracking + AstCFunc* m_cfuncp; // Current block - AssVec m_mgAssignps; // List of assignments merging - AstCFunc* m_mgCfuncp; // Parent C function - AstNode* m_mgNextp; // Next node - AstNodeSel* m_mgSelLp; // Parent select, NULL = idle - AstNodeSel* m_mgSelRp; // Parent select, NULL = constant - AstNodeVarRef* m_mgVarrefLp; // Parent varref - AstNodeVarRef* m_mgVarrefRp; // Parent varref, NULL = constant - AstConst* m_mgConstRp; // Parent RHS constant, NULL = sel - uint32_t m_mgIndexLo; // Merge range - uint32_t m_mgIndexHi; // Merge range + AssVec m_mgAssignps; // List of assignments merging + AstCFunc* m_mgCfuncp; // Parent C function + AstNode* m_mgNextp; // Next node + AstNodeSel* m_mgSelLp; // Parent select, NULL = idle + AstNodeSel* m_mgSelRp; // Parent select, NULL = constant + AstNodeVarRef* m_mgVarrefLp; // Parent varref + AstNodeVarRef* m_mgVarrefRp; // Parent varref, NULL = constant + AstConst* m_mgConstRp; // Parent RHS constant, NULL = sel + uint32_t m_mgIndexLo; // Merge range + uint32_t m_mgIndexHi; // Merge range // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -76,8 +76,7 @@ private: AstVar* varp = VN_CAST(cfuncp->user1p(), Var); if (!varp) { string newvarname = string("__Vilp"); - varp = new AstVar(fl, AstVarType::STMTTEMP, - newvarname, VFlagLogicPacked(), 32); + varp = new AstVar(fl, AstVarType::STMTTEMP, newvarname, VFlagLogicPacked(), 32); UASSERT_OBJ(cfuncp, fl, "Assignment not under a function"); cfuncp->addInitsp(varp); cfuncp->user1p(varp); @@ -87,11 +86,11 @@ private: void mergeEnd() { if (!m_mgAssignps.empty()) { uint32_t items = m_mgIndexHi - m_mgIndexLo + 1; - UINFO(9, "End merge iter="<= RELOOP_MIN_ITERS) { - UINFO(6, "Reloop merging items="<addNext(whilep); bodyp->replaceWith(initp); @@ -122,11 +121,11 @@ private: rbitp->replaceWith(new AstVarRef(fl, itp, false)); VL_DO_DANGLING(rbitp->deleteTree(), lbitp); } - if (debug()>=9) initp->dumpTree(cout, "-new: "); - if (debug()>=9) whilep->dumpTree(cout, "-new: "); + if (debug() >= 9) initp->dumpTree(cout, "-new: "); + if (debug() >= 9) whilep->dumpTree(cout, "-new: "); // Remove remaining assigns - for (AssVec::iterator it=m_mgAssignps.begin(); it!=m_mgAssignps.end(); ++it) { + for (AssVec::iterator it = m_mgAssignps.begin(); it != m_mgAssignps.end(); ++it) { AstNodeAssign* assp = *it; if (assp != bodyp) { VL_DO_DANGLING(assp->unlinkFrBack()->deleteTree(), assp); @@ -154,15 +153,27 @@ private: // Left select WordSel or ArraySel AstNodeSel* lselp = VN_CAST(nodep->lhsp(), NodeSel); - if (!lselp) { mergeEnd(); return; } // Not ever merged + if (!lselp) { // Not ever merged + mergeEnd(); + return; + } // Of a constant index AstConst* lbitp = VN_CAST(lselp->bitp(), Const); - if (!lbitp) { mergeEnd(); return; } - if (lbitp->width() > 32) { mergeEnd(); return; } // Assoc arrays can do this + if (!lbitp) { + mergeEnd(); + return; + } + if (lbitp->width() > 32) { // Assoc arrays can do this + mergeEnd(); + return; + } uint32_t index = lbitp->toUInt(); // Of variable AstNodeVarRef* lvarrefp = VN_CAST(lselp->fromp(), NodeVarRef); - if (!lvarrefp) { mergeEnd(); return; } + if (!lvarrefp) { + mergeEnd(); + return; + } // RHS is a constant or a select AstConst* rconstp = VN_CAST(nodep->rhsp(), Const); @@ -170,38 +181,38 @@ private: AstNodeVarRef* rvarrefp = NULL; if (rconstp) { // Ok } else { - if (!rselp) { mergeEnd(); return; } + if (!rselp) { + mergeEnd(); + return; + } AstConst* rbitp = VN_CAST(rselp->bitp(), Const); rvarrefp = VN_CAST(rselp->fromp(), NodeVarRef); - if (!rbitp || rbitp->toUInt() != index - || !rvarrefp + if (!rbitp || rbitp->toUInt() != index || !rvarrefp || lvarrefp->varp() == rvarrefp->varp()) { - mergeEnd(); return; + mergeEnd(); + return; } } if (m_mgSelLp) { // Old merge - if (m_mgCfuncp == m_cfuncp - && m_mgNextp == nodep - && m_mgSelLp->same(lselp) + if (m_mgCfuncp == m_cfuncp && m_mgNextp == nodep && m_mgSelLp->same(lselp) && m_mgVarrefLp->same(lvarrefp) && (m_mgConstRp - ? (rconstp && m_mgConstRp->same(rconstp)) - : (rselp - && m_mgSelRp->same(rselp) - && m_mgVarrefRp->same(rvarrefp))) - && (index == m_mgIndexLo-1 - || index == m_mgIndexHi+1)) { + ? (rconstp && m_mgConstRp->same(rconstp)) + : (rselp && m_mgSelRp->same(rselp) && m_mgVarrefRp->same(rvarrefp))) + && (index == m_mgIndexLo - 1 || index == m_mgIndexHi + 1)) { // Sequentially next to last assign; continue merge - if (index == m_mgIndexLo-1) m_mgIndexLo = index; - else if (index == m_mgIndexHi+1) m_mgIndexHi = index; - UINFO(9, "Continue merge i="<nextp(); return; - } - else { + } else { // This assign doesn't merge with previous assign, // but should start a new merge mergeEnd(); @@ -219,7 +230,7 @@ private: m_mgConstRp = rconstp; m_mgIndexLo = index; m_mgIndexHi = index; - UINFO(9, "Start merge i="<= 6); } diff --git a/src/V3Scoreboard.cpp b/src/V3Scoreboard.cpp index 11021858b..e0813489f 100644 --- a/src/V3Scoreboard.cpp +++ b/src/V3Scoreboard.cpp @@ -25,7 +25,8 @@ public: uint32_t m_score; uint32_t m_id; // CONSTRUCTORS - explicit ScoreboardTestElem(uint32_t score) : m_score(score) { + explicit ScoreboardTestElem(uint32_t score) + : m_score(score) { static uint32_t s_serial = 0; m_id = ++s_serial; } @@ -33,9 +34,7 @@ public: // METHODS static uint32_t scoreFn(const ScoreboardTestElem* elp) { return elp->m_score; } - bool operator< (const ScoreboardTestElem& other) const { - return m_id < other.m_id; - } + bool operator<(const ScoreboardTestElem& other) const { return m_id < other.m_id; } }; void V3ScoreboardBase::selfTest() { @@ -52,8 +51,7 @@ void V3ScoreboardBase::selfTest() { sb.addElem(&e3); UASSERT(sb.needsRescore(), "SelfTest: Newly filled sb should need a rescore."); - UASSERT(sb.needsRescore(&e1), - "SelfTest: Individual newly-added element should need rescore"); + UASSERT(sb.needsRescore(&e1), "SelfTest: Individual newly-added element should need rescore"); UASSERT(NULL == sb.bestp(), "SelfTest: Newly filled sb should have nothing eligible for Bestp()"); @@ -64,14 +62,12 @@ void V3ScoreboardBase::selfTest() { "SelfTest: Newly rescored sb should not need an element rescored"); UASSERT(e2.m_score == sb.cachedScore(&e2), "SelfTest: Cached score should match current score"); - UASSERT(&e1 == sb.bestp(), - "SelfTest: Should return element with lowest (best) score"); + UASSERT(&e1 == sb.bestp(), "SelfTest: Should return element with lowest (best) score"); // Change one element's score sb.hintScoreChanged(&e2); e2.m_score = 21; - UASSERT(sb.needsRescore(&e2), - "SelfTest: Should need rescore on elem after hintScoreChanged"); + UASSERT(sb.needsRescore(&e2), "SelfTest: Should need rescore on elem after hintScoreChanged"); // Remove an element UASSERT(sb.contains(&e1), "SelfTest: e1 should be there"); diff --git a/src/V3Scoreboard.h b/src/V3Scoreboard.h index 4ad378437..84621b775 100644 --- a/src/V3Scoreboard.h +++ b/src/V3Scoreboard.h @@ -64,6 +64,7 @@ public: typedef void pointer; typedef std::ptrdiff_t difference_type; typedef std::bidirectional_iterator_tag iterator_category; + protected: friend class SortByValueMap; @@ -77,8 +78,7 @@ public: explicit const_iterator(SortByValueMap* sbmvp) // for end() : m_sbvmp(sbmvp) , m_end(true) {} - const_iterator(typename Val2Keys::iterator valIt, - typename KeySet::iterator keyIt, + const_iterator(typename Val2Keys::iterator valIt, typename KeySet::iterator keyIt, SortByValueMap* sbvmp) : m_keyIt(keyIt) , m_valIt(valIt) @@ -135,6 +135,7 @@ public: --m_keyIt; UASSERT(m_keyIt != m_valIt->second.end(), "Value bucket should have key"); } + public: const T_Key& key() const { return *m_keyIt; } const T_Value& value() const { return m_valIt->first; } @@ -151,15 +152,10 @@ public: // sequences. So check m_end before comparing m_valIt, and // compare m_valIt's before comparing m_keyIt to ensure nothing // here is undefined. - if (m_end || other.m_end) { - return m_end && other.m_end; - } - return ((m_valIt == other.m_valIt) - && (m_keyIt == other.m_keyIt)); - } - bool operator!=(const const_iterator& other) const { - return (!this->operator==(other)); + if (m_end || other.m_end) return m_end && other.m_end; + return ((m_valIt == other.m_valIt) && (m_keyIt == other.m_keyIt)); } + bool operator!=(const const_iterator& other) const { return (!this->operator==(other)); } // WARNING: Cleverness. // @@ -209,8 +205,7 @@ public: // CONSTRUCTORS explicit iterator(SortByValueMap* sbvmp) : const_iterator(sbvmp) {} - iterator(typename Val2Keys::iterator valIt, - typename KeySet::iterator keyIt, + iterator(typename Val2Keys::iterator valIt, typename KeySet::iterator keyIt, SortByValueMap* sbvmp) : const_iterator(valIt, keyIt, sbvmp) {} @@ -248,49 +243,33 @@ private: } void removeKeyFromOldVal(iterator it) { it.m_valIt->second.erase(it.m_keyIt); - if (it.m_valIt->second.empty()) { - m_vals.erase(it.m_valIt); - } + if (it.m_valIt->second.empty()) m_vals.erase(it.m_valIt); } public: iterator begin() { typename Val2Keys::iterator valIt = m_vals.begin(); - if (valIt == m_vals.end()) { - return end(); - } + if (valIt == m_vals.end()) return end(); typename KeySet::const_iterator keyIt = valIt->second.begin(); return iterator(valIt, keyIt, this); } const_iterator begin() const { SortByValueMap* mutp = const_cast(this); typename Val2Keys::iterator valIt = mutp->m_vals.begin(); - if (valIt == mutp->m_vals.end()) { - return end(); - } + if (valIt == mutp->m_vals.end()) return end(); typename KeySet::const_iterator keyIt = valIt->second.begin(); return const_iterator(valIt, keyIt, mutp); } - iterator end() { - return iterator(this); - } + iterator end() { return iterator(this); } const_iterator end() const { // Safe to cast away const; the const_iterator will still enforce // it. Same for the const begin() below. return const_iterator(const_cast(this)); } - reverse_iterator rbegin() { - return reverse_iterator(end()); - } - reverse_iterator rend() { - return reverse_iterator(begin()); - } - const_reverse_iterator rbegin() const { - return const_reverse_iterator(end()); - } - const_reverse_iterator rend() const { - return const_reverse_iterator(begin()); - } + reverse_iterator rbegin() { return reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } iterator find(const T_Key& k) { typename Key2Val::iterator kvit = m_keys.find(k); @@ -335,12 +314,8 @@ public: void erase(const reverse_iterator& it) { erase(*it); // Dereferencing returns a copy of the forward iterator } - bool has(const T_Key& k) const { - return (m_keys.find(k) != m_keys.end()); - } - bool empty() const { - return m_keys.empty(); - } + bool has(const T_Key& k) const { return (m_keys.find(k) != m_keys.end()); } + bool empty() const { return m_keys.empty(); } // Look up a value. Returns a reference for efficiency. Note this must // be a const reference, otherwise the client could corrupt the sorted // order of m_byValue by reaching through and changing the value. @@ -375,16 +350,14 @@ private: /// when the subset of elements whose scores change is much smaller than /// the full set size. -template > +template > class V3Scoreboard { private: // TYPES typedef vl_unordered_set NeedRescoreSet; class CmpElems { public: - bool operator() (const T_Elem* const& ap, const T_Elem* const& bp) const { + bool operator()(const T_Elem* const& ap, const T_Elem* const& bp) const { T_ElemCompare cmp; return cmp.operator()(*ap, *bp); } @@ -412,8 +385,7 @@ public: // bestp() until after the next rescore(). void addElem(const T_Elem* elp) { if (m_slowAsserts) { - UASSERT(!contains(elp), - "Adding element to scoreboard that was already in scoreboard"); + UASSERT(!contains(elp), "Adding element to scoreboard that was already in scoreboard"); } m_unknown.insert(elp); } @@ -470,22 +442,19 @@ public: bool needsRescore() { return !m_unknown.empty(); } // False if elp's score is known to V3Scoreboard, // else true if elp's score is unknown until the next rescore(). - bool needsRescore(const T_Elem* elp) { - return (m_unknown.find(elp) != m_unknown.end()); - } + bool needsRescore(const T_Elem* elp) { return (m_unknown.find(elp) != m_unknown.end()); } // Retrieve the last known score for an element. T_Score cachedScore(const T_Elem* elp) { typename SortedMap::iterator result = m_sorted.find(elp); - UASSERT(result != m_sorted.end(), - "V3Scoreboard::cachedScore() failed to find element"); + UASSERT(result != m_sorted.end(), "V3Scoreboard::cachedScore() failed to find element"); return (*result).value(); } // For each element whose score is unknown to V3Scoreboard, // call the client's scoring function to get a new score, // and sort all elements by their current score. void rescore() { - for (typename NeedRescoreSet::iterator it = m_unknown.begin(); - it != m_unknown.end(); ++it) { + for (typename NeedRescoreSet::iterator it = m_unknown.begin(); it != m_unknown.end(); + ++it) { const T_Elem* elp = *it; T_Score sortScore = m_scoreFnp(elp); m_sorted.set(elp, sortScore); @@ -500,7 +469,7 @@ private: //###################################################################### namespace V3ScoreboardBase { - void selfTest(); +void selfTest(); } // namespace V3ScoreboardBase #endif // Guard diff --git a/src/V3SenTree.h b/src/V3SenTree.h index 4832014d7..a40b495ec 100644 --- a/src/V3SenTree.h +++ b/src/V3SenTree.h @@ -53,7 +53,7 @@ private: class HashSenTree { public: HashSenTree() {} - size_t operator() (const AstSenTree* kp) const { + size_t operator()(const AstSenTree* kp) const { return V3Hashed::uncachedHash(kp).fullValue(); } // Copying required for OSX's libc++ @@ -62,7 +62,7 @@ private: class EqSenTree { public: EqSenTree() {} - bool operator() (const AstSenTree* ap, const AstSenTree* bp) const { + bool operator()(const AstSenTree* ap, const AstSenTree* bp) const { return ap->sameTree(bp); } // Copying required for OSX's libc++ @@ -81,9 +81,7 @@ public: AstSenTree* find(AstSenTree* likep) { AstSenTree* resultp = NULL; Set::iterator it = m_trees.find(likep); - if (it != m_trees.end()) { - resultp = *it; - } + if (it != m_trees.end()) resultp = *it; return resultp; } void clear() { m_trees.clear(); } @@ -103,9 +101,7 @@ private: virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { // Only do the top - if (nodep->isTop()) { - iterateChildren(nodep); - } + if (nodep->isTop()) iterateChildren(nodep); } virtual void visit(AstTopScope* nodep) VL_OVERRIDE { m_topscopep = nodep; @@ -139,21 +135,18 @@ public: UASSERT(m_topscopep, "Never called main()"); treep = sensesp->cloneTree(false); m_topscopep->addStmtsp(treep); - UINFO(8," New SENTREE "< NameMap; // Number of times a name appears + typedef std::map NameMap; // Number of times a name appears // STATE - string m_stage; // Name of the stage we are scanning + string m_stage; // Name of the stage we are scanning /// m_fast = true: Counting only critical branch of fastpath /// m_fast = false: Counting every node, ignoring structure of program - bool m_fast; + bool m_fast; - AstCFunc* m_cfuncp; // Current CFUNC - VDouble0 m_statInstrLong; // Instruction count - bool m_counting; // Currently counting - double m_instrs; // Current instr count (for determining branch direction) - bool m_tracingCall; // Iterating into a CCall to a CFunc + AstCFunc* m_cfuncp; // Current CFUNC + VDouble0 m_statInstrLong; // Instruction count + bool m_counting; // Currently counting + double m_instrs; // Current instr count (for determining branch direction) + bool m_tracingCall; // Iterating into a CCall to a CFunc - std::vector m_statTypeCount; // Nodes of given type - VDouble0 m_statAbove[AstType::_ENUM_END][AstType::_ENUM_END]; // Nodes of given type - VDouble0 m_statPred[VBranchPred::_ENUM_END]; // Nodes of given type - VDouble0 m_statInstr; // Instruction count - VDouble0 m_statInstrFast; // Instruction count, non-slow() eval functions only - std::vector m_statVarWidths; // Variables of given width - std::vector m_statVarWidthNames; // Var names of given width - VDouble0 m_statVarArray; // Statistic tracking - VDouble0 m_statVarBytes; // Statistic tracking - VDouble0 m_statVarClock; // Statistic tracking - VDouble0 m_statVarScpBytes; // Statistic tracking + std::vector m_statTypeCount; // Nodes of given type + VDouble0 m_statAbove[AstType::_ENUM_END][AstType::_ENUM_END]; // Nodes of given type + VDouble0 m_statPred[VBranchPred::_ENUM_END]; // Nodes of given type + VDouble0 m_statInstr; // Instruction count + VDouble0 m_statInstrFast; // Instruction count, non-slow() eval functions only + std::vector m_statVarWidths; // Variables of given width + std::vector m_statVarWidthNames; // Var names of given width + VDouble0 m_statVarArray; // Statistic tracking + VDouble0 m_statVarBytes; // Statistic tracking + VDouble0 m_statVarClock; // Statistic tracking + VDouble0 m_statVarScpBytes; // Statistic tracking // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -92,13 +92,16 @@ private: iterateChildrenConst(nodep); if (m_counting && nodep->dtypep()) { if (nodep->isUsedClock()) ++m_statVarClock; - if (VN_IS(nodep->dtypeSkipRefp(), UnpackArrayDType)) ++m_statVarArray; - else m_statVarBytes += nodep->dtypeSkipRefp()->widthTotalBytes(); - if (int(m_statVarWidths.size()) <= nodep->width()) { - m_statVarWidths.resize(nodep->width()+5); - if (v3Global.opt.statsVars()) m_statVarWidthNames.resize(nodep->width()+5); + if (VN_IS(nodep->dtypeSkipRefp(), UnpackArrayDType)) { + ++m_statVarArray; + } else { + m_statVarBytes += nodep->dtypeSkipRefp()->widthTotalBytes(); } - ++ m_statVarWidths.at(nodep->width()); + if (int(m_statVarWidths.size()) <= nodep->width()) { + m_statVarWidths.resize(nodep->width() + 5); + if (v3Global.opt.statsVars()) m_statVarWidthNames.resize(nodep->width() + 5); + } + ++m_statVarWidths.at(nodep->width()); string pn = nodep->prettyName(); if (v3Global.opt.statsVars()) { NameMap& nameMapr = m_statVarWidthNames.at(nodep->width()); @@ -120,14 +123,12 @@ private: } } virtual void visit(AstNodeIf* nodep) VL_OVERRIDE { - UINFO(4," IF i="<condp()); // Track prediction - if (m_counting) { - ++m_statPred[nodep->branchPred()]; - } + if (m_counting) ++m_statPred[nodep->branchPred()]; if (!m_fast) { // Count everything iterateChildrenConst(nodep); @@ -171,7 +172,7 @@ private: } } // While's we assume evaluate once. - //virtual void visit(AstWhile* nodep) VL_OVERRIDE { + // virtual void visit(AstWhile* nodep) VL_OVERRIDE { virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { allNodes(nodep); @@ -206,11 +207,13 @@ private: allNodes(nodep); iterateChildrenConst(nodep); } + public: // CONSTRUCTORS StatsVisitor(AstNetlist* nodep, const string& stage, bool fast) - : m_stage(stage), m_fast(fast) { - UINFO(9,"Starting stats, fast="<first; + for (NameMap::iterator it = nameMapr.begin(); it != nameMapr.end(); ++it) { + std::ostringstream os; + os << "Vars, width " << std::setw(5) << std::dec << i << " " << it->first; V3Stats::addStat(m_stage, os.str(), it->second); } } else { - std::ostringstream os; os<<"Vars, width "<m_printit = false; } // CONSTRUCTORS - V3Statistic(const string& stage, const string& name, - double count, bool sumit=false, bool perf=false) - : m_name(name), m_count(count), m_stage(stage), m_sumit(sumit), m_perf(perf) + V3Statistic(const string& stage, const string& name, double count, bool sumit = false, + bool perf = false) + : m_name(name) + , m_count(count) + , m_stage(stage) + , m_sumit(sumit) + , m_perf(perf) , m_printit(true) {} virtual ~V3Statistic() {} }; @@ -83,21 +105,24 @@ class V3Stats { public: static void addStat(const V3Statistic&); static void addStat(const string& stage, const string& name, double count) { - addStat(V3Statistic(stage, name, count)); } + addStat(V3Statistic(stage, name, count)); + } static void addStat(const string& name, double count) { - addStat(V3Statistic("*", name, count)); } + addStat(V3Statistic("*", name, count)); + } static void addStatSum(const string& name, double count) { - addStat(V3Statistic("*", name, count, true)); } + addStat(V3Statistic("*", name, count, true)); + } static void addStatPerf(const string& name, double count) { - addStat(V3Statistic("*", name, count, true, true)); } + addStat(V3Statistic("*", name, count, true, true)); + } /// Called each stage static void statsStage(const string& name); /// Called by the top level to collect statistics - static void statsStageAll(AstNetlist* nodep, const string& stage, bool fast=false); + static void statsStageAll(AstNetlist* nodep, const string& stage, bool fast = false); static void statsFinalAll(AstNetlist* nodep); /// Called by the top level to dump the statistics static void statsReport(); }; - #endif // Guard diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp index 3f28b025b..6ce36bf70 100644 --- a/src/V3StatsReport.cpp +++ b/src/V3StatsReport.cpp @@ -40,31 +40,31 @@ class StatsReport { static StatColl s_allStats; ///< All statistics void header() { - os<<"Verilator Statistics Report\n"; - os< ByName; + typedef std::multimap ByName; ByName byName; // * is always first - for (StatColl::iterator it = s_allStats.begin(); it!=s_allStats.end(); ++it) { + for (StatColl::iterator it = s_allStats.begin(); it != s_allStats.end(); ++it) { V3Statistic* repp = &(*it); byName.insert(make_pair(repp->name(), repp)); } // Process duplicates V3Statistic* lastp = NULL; - for (ByName::iterator it = byName.begin(); it!=byName.end(); ++it) { + for (ByName::iterator it = byName.begin(); it != byName.end(); ++it) { V3Statistic* repp = it->second; - if (lastp && lastp->sumit() && lastp->printit() - && lastp->name() == repp->name() && lastp->stage() == repp->stage()) { + if (lastp && lastp->sumit() && lastp->printit() && lastp->name() == repp->name() + && lastp->stage() == repp->stage()) { repp->combineWith(lastp); } lastp = repp; @@ -74,10 +74,10 @@ class StatsReport { void stars() { // Find all stages size_t maxWidth = 0; - typedef std::multimap ByName; + typedef std::multimap ByName; ByName byName; // * is always first - for (StatColl::iterator it = s_allStats.begin(); it!=s_allStats.end(); ++it) { + for (StatColl::iterator it = s_allStats.begin(); it != s_allStats.end(); ++it) { const V3Statistic* repp = &(*it); if (repp->stage() == "*" && repp->printit()) { if (maxWidth < repp->name().length()) maxWidth = repp->name().length(); @@ -86,43 +86,43 @@ class StatsReport { } // Print organized by stage - os<<"Global Statistics:\n"; - os<second; if (repp->perf()) continue; - os<<" "<name(); + os << " " << std::left << std::setw(maxWidth) << repp->name(); repp->dump(os); - os<second; if (!repp->perf()) continue; - os<<" "<name(); + os << " " << std::left << std::setw(maxWidth) << repp->name(); repp->dump(os); - os< Stages; Stages stages; - vl_unordered_map stageInt; - typedef std::multimap ByName; + vl_unordered_map stageInt; + typedef std::multimap ByName; ByName byName; // * is always first - for (StatColl::iterator it = s_allStats.begin(); it!=s_allStats.end(); ++it) { + for (StatColl::iterator it = s_allStats.begin(); it != s_allStats.end(); ++it) { const V3Statistic* repp = &(*it); if (repp->stage() != "*" && repp->printit()) { if (maxWidth < repp->name().length()) maxWidth = repp->name().length(); @@ -135,16 +135,16 @@ class StatsReport { } // Header - os<<" Stat "<name(); + os << " " << std::left << std::setw(maxWidth) << repp->name(); } - while (colstage()) { - os<stage()) { + os << std::setw(11) << ""; col++; } repp->dump(os); col++; } - os<fail()) v3fatal("Can't write "<fail()) v3fatal("Can't write " << filename); - StatsReport reporter (ofp); + StatsReport reporter(ofp); // Cleanup ofp->close(); diff --git a/src/V3String.cpp b/src/V3String.cpp index 63f3f1f1b..48f1d76d2 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -31,18 +31,14 @@ size_t VName::s_maxLength = 0; // Disabled // Double procedures, inlined, unrolls loop much better inline bool VString::wildmatchi(const char* s, const char* p) { - for ( ; *p; s++, p++) { - if (*p!='*') { - if (((*s)!=(*p)) && *p != '?') - return false; - } - else { + for (; *p; s++, p++) { + if (*p != '*') { + if (((*s) != (*p)) && *p != '?') return false; + } else { // Trailing star matches everything. if (!*++p) return true; while (!wildmatch(s, p)) { - if (*++s == '\0') { - return false; - } + if (*++s == '\0') return false; } return true; } @@ -51,18 +47,14 @@ inline bool VString::wildmatchi(const char* s, const char* p) { } bool VString::wildmatch(const char* s, const char* p) { - for ( ; *p; s++, p++) { - if (*p!='*') { - if (((*s)!=(*p)) && *p != '?') - return false; - } - else { + for (; *p; s++, p++) { + if (*p != '*') { + if (((*s) != (*p)) && *p != '?') return false; + } else { // Trailing star matches everything. if (!*++p) return true; while (!wildmatchi(s, p)) { - if (*++s == '\0') { - return false; - } + if (*++s == '\0') return false; } return true; } @@ -74,29 +66,25 @@ bool VString::wildmatch(const string& s, const string& p) { return wildmatch(s.c_str(), p.c_str()); } -bool VString::isWildcard(const string &p) { +bool VString::isWildcard(const string& p) { return ((p.find('*') != string::npos) || (p.find('?') != string::npos)); } string VString::dot(const string& a, const string& dot, const string& b) { - if (b=="") return a; - if (a=="") return b; - return a+dot+b; + if (b == "") return a; + if (a == "") return b; + return a + dot + b; } string VString::downcase(const string& str) { string out = str; - for (string::iterator pos = out.begin(); pos != out.end(); ++pos) { - *pos = tolower(*pos); - } + for (string::iterator pos = out.begin(); pos != out.end(); ++pos) *pos = tolower(*pos); return out; } string VString::upcase(const string& str) { string out = str; - for (string::iterator pos = out.begin(); pos != out.end(); ++pos) { - *pos = toupper(*pos); - } + for (string::iterator pos = out.begin(); pos != out.end(); ++pos) *pos = toupper(*pos); return out; } @@ -112,8 +100,11 @@ string VString::quotePercent(const string& str) { string VString::spaceUnprintable(const string& str) { string out; for (string::const_iterator pos = str.begin(); pos != str.end(); ++pos) { - if (isprint(*pos)) out += *pos; - else out += ' '; + if (isprint(*pos)) { + out += *pos; + } else { + out += ' '; + } } return out; } @@ -128,16 +119,17 @@ bool VString::isWhitespace(const string& str) { //###################################################################### // VHashSha256 -static const uint32_t sha256K[] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; +static const uint32_t sha256K[] + = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, + 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, + 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, + 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, + 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, + 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, + 0xc67178f2}; static inline uint32_t shaRotr32(uint32_t lhs, uint32_t rhs) VL_ATTR_ALWINLINE; static inline uint32_t shaRotr32(uint32_t lhs, uint32_t rhs) { @@ -150,9 +142,7 @@ static inline void sha256Block(uint32_t* h, const uint32_t* chunk) { const uint32_t* p = chunk; // Initialize working variables to current hash value - for (unsigned i = 0; i < 8; i++) { - ah[i] = h[i]; - } + for (unsigned i = 0; i < 8; i++) ah[i] = h[i]; // Compression function main loop for (unsigned i = 0; i < 4; ++i) { uint32_t w[16]; @@ -164,17 +154,15 @@ static inline void sha256Block(uint32_t* h, const uint32_t* chunk) { // Extend the first 16 words into the remaining // 48 words w[16..63] of the message schedule array: const uint32_t s0 = shaRotr32(w[(j + 1) & 0xf], 7) - ^ shaRotr32(w[(j + 1) & 0xf], 18) ^ (w[(j + 1) & 0xf] >> 3); + ^ shaRotr32(w[(j + 1) & 0xf], 18) ^ (w[(j + 1) & 0xf] >> 3); const uint32_t s1 = shaRotr32(w[(j + 14) & 0xf], 17) - ^ shaRotr32(w[(j + 14) & 0xf], 19) ^ (w[(j + 14) & 0xf] >> 10); + ^ shaRotr32(w[(j + 14) & 0xf], 19) ^ (w[(j + 14) & 0xf] >> 10); w[j] = w[j] + s0 + w[(j + 9) & 0xf] + s1; } - const uint32_t s1 = shaRotr32(ah[4], 6) - ^ shaRotr32(ah[4], 11) ^ shaRotr32(ah[4], 25); + const uint32_t s1 = shaRotr32(ah[4], 6) ^ shaRotr32(ah[4], 11) ^ shaRotr32(ah[4], 25); const uint32_t ch = (ah[4] & ah[5]) ^ (~ah[4] & ah[6]); const uint32_t temp1 = ah[7] + s1 + ch + sha256K[i << 4 | j] + w[j]; - const uint32_t s0 = shaRotr32(ah[0], 2) - ^ shaRotr32(ah[0], 13) ^ shaRotr32(ah[0], 22); + const uint32_t s0 = shaRotr32(ah[0], 2) ^ shaRotr32(ah[0], 13) ^ shaRotr32(ah[0], 22); const uint32_t maj = (ah[0] & ah[1]) ^ (ah[0] & ah[2]) ^ (ah[1] & ah[2]); const uint32_t temp2 = s0 + maj; @@ -191,7 +179,6 @@ static inline void sha256Block(uint32_t* h, const uint32_t* chunk) { for (unsigned i = 0; i < 8; ++i) h[i] += ah[i]; } - void VHashSha256::insert(const void* datap, size_t length) { UASSERT(!m_final, "Called VHashSha256::insert after finalized the hash value"); m_totLength += length; @@ -199,7 +186,7 @@ void VHashSha256::insert(const void* datap, size_t length) { string tempData; int chunkLen; const uint8_t* chunkp; - if (m_remainder=="") { + if (m_remainder == "") { chunkLen = length; chunkp = static_cast(datap); } else { @@ -229,7 +216,7 @@ void VHashSha256::insert(const void* datap, size_t length) { sha256Block(m_inthash, w); } - m_remainder = string(reinterpret_cast(chunkp+posBegin), chunkLen-posEnd); + m_remainder = string(reinterpret_cast(chunkp + posBegin), chunkLen - posEnd); } void VHashSha256::finalize() { @@ -240,16 +227,16 @@ void VHashSha256::finalize() { // Process final possibly non-complete 64-byte block uint32_t w[16]; // Round buffer, [0..15] are input data - for (int i=0; i<16; ++i) w[i] = 0; + for (int i = 0; i < 16; ++i) w[i] = 0; size_t blockPos = 0; for (; blockPos < m_remainder.length(); ++blockPos) { - w[blockPos >> 2] |= ((static_cast(m_remainder[blockPos])) - << ((3 - (blockPos & 3)) << 3)); + w[blockPos >> 2] + |= ((static_cast(m_remainder[blockPos])) << ((3 - (blockPos & 3)) << 3)); } w[blockPos >> 2] |= 0x80 << ((3 - (blockPos & 3)) << 3); if (m_remainder.length() >= 56) { sha256Block(m_inthash, w); - for (int i=0; i<16; ++i) w[i] = 0; + for (int i = 0; i < 16; ++i) w[i] = 0; } w[15] = m_totLength << 3; sha256Block(m_inthash, w); @@ -260,8 +247,9 @@ void VHashSha256::finalize() { string VHashSha256::digestBinary() { finalize(); - string out; out.reserve(32); - for (size_t i=0; i<32; ++i) { + string out; + out.reserve(32); + for (size_t i = 0; i < 32; ++i) { out += (m_inthash[i >> 2] >> (((3 - i) & 0x3) << 3)) & 0xff; } return out; @@ -270,20 +258,21 @@ string VHashSha256::digestBinary() { uint64_t VHashSha256::digestUInt64() { const string& binhash = digestBinary(); uint64_t out = 0; - for (size_t byte=0; byte>4) & 0xf ]; - out += digits[ (binhash[byte]>>0) & 0xf ]; + string out; + out.reserve(70); + for (size_t byte = 0; byte < 32; ++byte) { + out += digits[(binhash[byte] >> 4) & 0xf]; + out += digits[(binhash[byte] >> 0) & 0xf]; } return out; } @@ -293,12 +282,13 @@ string VHashSha256::digestSymbol() { // has + and / for last two digits, but need C symbol, and we also // avoid conflicts with use of _, so use "AB" at the end. // Thus this function is non-reversible. - static const char digits[64+1] + static const char digits[64 + 1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"; const string& binhash = digestBinary(); - string out; out.reserve(28); + string out; + out.reserve(28); int pos = 0; - for (; pos < (256/8) - 2; pos += 3) { + for (; pos < (256 / 8) - 2; pos += 3) { out += digits[((binhash[pos] >> 2) & 0x3f)]; out += digits[((binhash[pos] & 0x3) << 4) | (static_cast(binhash[pos + 1] & 0xf0) >> 4)]; @@ -310,28 +300,26 @@ string VHashSha256::digestSymbol() { return out; } -void VHashSha256::selfTestOne(const string& data, const string& data2, - const string& exp, const string& exp64) { - VHashSha256 digest (data); - if (data2!="") digest.insert(data2); +void VHashSha256::selfTestOne(const string& data, const string& data2, const string& exp, + const string& exp64) { + VHashSha256 digest(data); + if (data2 != "") digest.insert(data2); if (VL_UNCOVERABLE(digest.digestHex() != exp)) { - std::cerr << "%Error: When hashing '"< cutoff) continue; // Short-circuit if already too bad EditDistance dist = editDistance(goal, candidate); - UINFO(9, "EditDistance dist="< VSymConstMap; class VSymEnt { // Symbol table that can have a "superior" table for resolving upper references // MEMBERS - typedef std::multimap IdNameMap; - IdNameMap m_idNameMap; // Hash of variables by name - AstNode* m_nodep; // Node that entry belongs to - VSymEnt* m_fallbackp; // Table "above" this one in name scope, for fallback resolution - VSymEnt* m_parentp; // Table that created this table, dot notation needed to resolve into it + typedef std::multimap IdNameMap; + IdNameMap m_idNameMap; // Hash of variables by name + AstNode* m_nodep; // Node that entry belongs to + VSymEnt* m_fallbackp; // Table "above" this one in name scope, for fallback resolution + VSymEnt* m_parentp; // Table that created this table, dot notation needed to resolve into it AstNodeModule* m_packagep; // Package node is in (for V3LinkDot, unused here) - string m_symPrefix; // String to prefix symbols with (for V3LinkDot, unused here) - bool m_exported; // Allow importing - bool m_imported; // Was imported + string m_symPrefix; // String to prefix symbols with (for V3LinkDot, unused here) + bool m_exported; // Allow importing + bool m_imported; // Was imported #ifdef VL_DEBUG static int debug() { static int level = -1; @@ -61,32 +61,33 @@ class VSymEnt { static inline int debug() { return 0; } // NOT runtime, too hot of a function #endif public: - typedef IdNameMap::const_iterator const_iterator; const_iterator begin() const { return m_idNameMap.begin(); } const_iterator end() const { return m_idNameMap.end(); } void dumpIterate(std::ostream& os, VSymConstMap& doneSymsr, const string& indent, int numLevels, const string& searchName) const { - os<= 1) { - it->second->dumpIterate(os, doneSymsr, indent+"| ", numLevels-1, it->first); + it->second->dumpIterate(os, doneSymsr, indent + "| ", numLevels - 1, + it->first); } } } } - void dump(std::ostream& os, const string& indent="", int numLevels=1) const { + void dump(std::ostream& os, const string& indent = "", int numLevels = 1) const { VSymConstMap doneSyms; dumpIterate(os, doneSyms, indent, numLevels, "TOP"); } @@ -120,12 +121,13 @@ public: bool imported() const { return m_imported; } void imported(bool flag) { m_imported = flag; } void insert(const string& name, VSymEnt* entp) { - UINFO(9, " SymInsert se"<nodep()<nodep() << endl); if (name != "" && m_idNameMap.find(name) != m_idNameMap.end()) { if (!V3Error::errorCount()) { // Else may have just reported warning - if (debug()>=9 || V3Error::debugDefault()) dump(cout,"- err-dump: ", 1); - entp->nodep()->v3fatalSrc("Inserting two symbols with same name: "<= 9 || V3Error::debugDefault()) dump(cout, "- err-dump: ", 1); + entp->nodep()->v3fatalSrc("Inserting two symbols with same name: " << name + << endl); } } else { m_idNameMap.insert(make_pair(name, entp)); @@ -133,9 +135,9 @@ public: } void reinsert(const string& name, VSymEnt* entp) { IdNameMap::iterator it = m_idNameMap.find(name); - if (name!="" && it != m_idNameMap.end()) { - UINFO(9, " SymReinsert se"<nodep()<nodep() << endl); it->second = entp; // Replace } else { insert(name, entp); @@ -145,9 +147,12 @@ public: // Find identifier without looking upward through symbol hierarchy // First, scan this begin/end block or module for the name IdNameMap::const_iterator it = m_idNameMap.find(name); - UINFO(9, " SymFind se"< "<<(it == m_idNameMap.end() ? "NONE" - : "se"+cvtToHex(it->second)+" n="+cvtToHex(it->second->nodep()))< " + << (it == m_idNameMap.end() + ? "NONE" + : "se" + cvtToHex(it->second) + " n=" + cvtToHex(it->second->nodep())) + << endl); if (it != m_idNameMap.end()) return (it->second); return NULL; } @@ -161,8 +166,7 @@ public: } void candidateIdFlat(VSpellCheck* spellerp, const VNodeMatcher* matcherp) const { // Suggest alternative symbol candidates without looking upward through symbol hierarchy - for (IdNameMap::const_iterator it = m_idNameMap.begin(); - it != m_idNameMap.end(); ++it) { + for (IdNameMap::const_iterator it = m_idNameMap.begin(); it != m_idNameMap.end(); ++it) { const AstNode* itemp = it->second->nodep(); if (itemp && (!matcherp || matcherp->nodeMatch(itemp))) { spellerp->pushCandidate(itemp->prettyName()); @@ -176,10 +180,10 @@ public: // Then suggest the upper begin/end block or module if (m_fallbackp) m_fallbackp->candidateIdFallback(spellerp, matcherp); } + private: void importOneSymbol(VSymGraph* graphp, const string& name, const VSymEnt* srcp) { - if (srcp->exported() - && !findIdFlat(name)) { // Don't insert over existing entry + if (srcp->exported() && !findIdFlat(name)) { // Don't insert over existing entry VSymEnt* symp = new VSymEnt(graphp, srcp); symp->exported(false); // Can't reimport an import without an export symp->imported(true); @@ -193,14 +197,13 @@ private: } } } + public: void importFromPackage(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) { // Import tokens from source symbol table into this symbol table if (id_or_star != "*") { IdNameMap::const_iterator it = srcp->m_idNameMap.find(id_or_star); - if (it != srcp->m_idNameMap.end()) { - importOneSymbol(graphp, it->first, it->second); - } + if (it != srcp->m_idNameMap.end()) importOneSymbol(graphp, it->first, it->second); } else { for (IdNameMap::const_iterator it = srcp->m_idNameMap.begin(); it != srcp->m_idNameMap.end(); ++it) { @@ -212,9 +215,7 @@ public: // Export tokens from source symbol table into this symbol table if (id_or_star != "*") { IdNameMap::const_iterator it = srcp->m_idNameMap.find(id_or_star); - if (it != srcp->m_idNameMap.end()) { - exportOneSymbol(graphp, it->first, it->second); - } + if (it != srcp->m_idNameMap.end()) exportOneSymbol(graphp, it->first, it->second); } else { for (IdNameMap::const_iterator it = srcp->m_idNameMap.begin(); it != srcp->m_idNameMap.end(); ++it) { @@ -224,14 +225,14 @@ public: } void exportStarStar(VSymGraph* graphp) { // Export *:*: Export all tokens from imported packages - for (IdNameMap::const_iterator it=m_idNameMap.begin(); it!=m_idNameMap.end(); ++it) { + for (IdNameMap::const_iterator it = m_idNameMap.begin(); it != m_idNameMap.end(); ++it) { VSymEnt* symp = it->second; if (!symp->exported()) symp->exported(true); } } void importFromIface(VSymGraph* graphp, const VSymEnt* srcp, bool onlyUnmodportable = false) { // Import interface tokens from source symbol table into this symbol table, recursively - UINFO(9, " importIf se"<m_idNameMap.begin(); it != srcp->m_idNameMap.end(); ++it) { const string& name = it->first; @@ -245,20 +246,19 @@ public: } } } - void cellErrorScopes(AstNode* lookp, string prettyName="") { - if (prettyName=="") prettyName = lookp->prettyName(); + void cellErrorScopes(AstNode* lookp, string prettyName = "") { + if (prettyName == "") prettyName = lookp->prettyName(); string scopes; - for (IdNameMap::iterator it = m_idNameMap.begin(); it!=m_idNameMap.end(); ++it) { + for (IdNameMap::iterator it = m_idNameMap.begin(); it != m_idNameMap.end(); ++it) { AstNode* itemp = it->second->nodep(); - if (VN_IS(itemp, Cell) - || (VN_IS(itemp, Module) && VN_CAST(itemp, Module)->isTop())) { + if (VN_IS(itemp, Cell) || (VN_IS(itemp, Module) && VN_CAST(itemp, Module)->isTop())) { if (scopes != "") scopes += ", "; scopes += AstNode::prettyName(it->first); } } - if (scopes=="") scopes=""; - std::cerr< SymStack; // MEMBERS - VSymEnt* m_symRootp; // Root symbol table - SymStack m_symsp; // All symbol tables, to cleanup + VSymEnt* m_symRootp; // Root symbol table + SymStack m_symsp; // All symbol tables, to cleanup // CONSTRUCTORS VL_UNCOPYABLE(VSymGraph); + public: - explicit VSymGraph(AstNetlist* nodep) { - m_symRootp = new VSymEnt(this, nodep); - } + explicit VSymGraph(AstNetlist* nodep) { m_symRootp = new VSymEnt(this, nodep); } ~VSymGraph() { - for (SymStack::iterator it = m_symsp.begin(); it != m_symsp.end(); ++it) { - delete (*it); - } + for (SymStack::iterator it = m_symsp.begin(); it != m_symsp.end(); ++it) delete (*it); } public: // METHODS VSymEnt* rootp() const { return m_symRootp; } // Debug - void dump(std::ostream& os, const string& indent="") { + void dump(std::ostream& os, const string& indent = "") { VSymConstMap doneSyms; - os<<"SymEnt Dump:\n"; + os << "SymEnt Dump:\n"; m_symRootp->dumpIterate(os, doneSyms, indent, 9999, "$root"); bool first = true; for (SymStack::iterator it = m_symsp.begin(); it != m_symsp.end(); ++it) { if (doneSyms.find(*it) == doneSyms.end()) { - if (first) { first=false; os<<"%%Warning: SymEnt Orphans:\n"; } + if (first) { + first = false; + os << "%%Warning: SymEnt Orphans:\n"; + } (*it)->dumpIterate(os, doneSyms, indent, 9999, "Orphan"); } } } void dumpFilePrefixed(const string& nameComment) { if (v3Global.opt.dumpTree()) { - string filename = v3Global.debugFilename(nameComment)+".txt"; - UINFO(2,"Dumping "< logp (V3File::new_ofstream(filename)); - if (logp->fail()) v3fatal("Can't write "< logp(V3File::new_ofstream(filename)); + if (logp->fail()) v3fatal("Can't write " << filename); dump(*logp, ""); } } @@ -336,7 +336,7 @@ inline VSymEnt::VSymEnt(VSymGraph* graphp, AstNode* nodep) inline VSymEnt::VSymEnt(VSymGraph* graphp, const VSymEnt* symp) : m_nodep(symp->m_nodep) { m_fallbackp = symp->m_fallbackp; - m_parentp = symp->m_parentp; + m_parentp = symp->m_parentp; m_packagep = symp->m_packagep; m_exported = symp->m_exported; m_imported = symp->m_imported; diff --git a/src/V3TSP.h b/src/V3TSP.h index 78f93fb09..cc9e79fed 100644 --- a/src/V3TSP.h +++ b/src/V3TSP.h @@ -24,30 +24,30 @@ #include "V3Error.h" namespace V3TSP { - // Perform a "Traveling Salesman Problem" optimizing sort - // on any type you like -- so long as inherits from TspStateBase. +// Perform a "Traveling Salesman Problem" optimizing sort +// on any type you like -- so long as inherits from TspStateBase. - class TspStateBase { - public: - // This is the cost function that the TSP sort will minimize. - // All costs in V3TSP are int, chosen to match the type of - // V3GraphEdge::weight() which will reflect each edge's cost. - virtual int cost(const TspStateBase* otherp) const = 0; +class TspStateBase { +public: + // This is the cost function that the TSP sort will minimize. + // All costs in V3TSP are int, chosen to match the type of + // V3GraphEdge::weight() which will reflect each edge's cost. + virtual int cost(const TspStateBase* otherp) const = 0; - // This operator< must place a meaningless, arbitrary, but - // stable order on all TspStateBase's. It's used only to - // key maps so that iteration is stable, without relying - // on pointer values that could lead to nondeterminism. - virtual bool operator<(const TspStateBase& otherp) const = 0; - }; + // This operator< must place a meaningless, arbitrary, but + // stable order on all TspStateBase's. It's used only to + // key maps so that iteration is stable, without relying + // on pointer values that could lead to nondeterminism. + virtual bool operator<(const TspStateBase& otherp) const = 0; +}; - typedef std::vector StateVec; +typedef std::vector StateVec; - // Given an unsorted set of TspState's, sort them to minimize - // the transition cost for walking the sorted list. - void tspSort(const StateVec& states, StateVec* resultp); +// Given an unsorted set of TspState's, sort them to minimize +// the transition cost for walking the sorted list. +void tspSort(const StateVec& states, StateVec* resultp); - void selfTest(); +void selfTest(); } // namespace V3TSP #endif // Guard diff --git a/src/V3Task.h b/src/V3Task.h index b711bfcb1..90eed1bab 100644 --- a/src/V3Task.h +++ b/src/V3Task.h @@ -27,7 +27,7 @@ //============================================================================ -typedef std::pair V3TaskConnect; // [port, pin-connects-to] +typedef std::pair V3TaskConnect; // [port, pin-connects-to] typedef std::vector V3TaskConnects; // [ [port, pin-connects-to] ... ] //============================================================================ diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 6e8296b85..39602289f 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -60,22 +60,24 @@ // Graph vertexes class TraceActivityVertex : public V3GraphVertex { - AstNode* m_insertp; // Insert before this statement - vlsint32_t m_activityCode; - bool m_activityCodeValid; - bool m_slow; // If always slow, we can use the same code + AstNode* m_insertp; // Insert before this statement + vlsint32_t m_activityCode; + bool m_activityCodeValid; + bool m_slow; // If always slow, we can use the same code public: - enum { ACTIVITY_NEVER =((1UL<<31) - 1) }; - enum { ACTIVITY_ALWAYS=((1UL<<31) - 2) }; - enum { ACTIVITY_SLOW=0 }; + enum { ACTIVITY_NEVER = ((1UL << 31) - 1) }; + enum { ACTIVITY_ALWAYS = ((1UL << 31) - 2) }; + enum { ACTIVITY_SLOW = 0 }; TraceActivityVertex(V3Graph* graphp, AstNode* nodep, bool slow) - : V3GraphVertex(graphp), m_insertp(nodep) { + : V3GraphVertex(graphp) + , m_insertp(nodep) { m_activityCode = 0; m_activityCodeValid = false; m_slow = slow; } TraceActivityVertex(V3Graph* graphp, vlsint32_t code) - : V3GraphVertex(graphp), m_insertp(NULL) { + : V3GraphVertex(graphp) + , m_insertp(NULL) { m_activityCode = code; m_activityCodeValid = true; m_slow = false; @@ -87,24 +89,33 @@ public: return m_insertp; } virtual string name() const { - if (activityAlways()) return "*ALWAYS*"; - else return (string(slow()?"*SLOW* ":""))+insertp()->name(); + if (activityAlways()) { + return "*ALWAYS*"; + } else { + return (string(slow() ? "*SLOW* " : "")) + insertp()->name(); + } } - virtual string dotColor() const { return slow()?"yellowGreen":"green"; } + virtual string dotColor() const { return slow() ? "yellowGreen" : "green"; } bool activityCodeValid() const { return m_activityCodeValid; } vlsint32_t activityCode() const { return m_activityCode; } - bool activityAlways() const { return activityCode()==ACTIVITY_ALWAYS; } - void activityCode(vlsint32_t code) { m_activityCode = code; m_activityCodeValid = true;} + bool activityAlways() const { return activityCode() == ACTIVITY_ALWAYS; } + void activityCode(vlsint32_t code) { + m_activityCode = code; + m_activityCodeValid = true; + } bool slow() const { return m_slow; } - void slow(bool flag) { if (!flag) m_slow = false; } + void slow(bool flag) { + if (!flag) m_slow = false; + } }; class TraceCFuncVertex : public V3GraphVertex { AstCFunc* m_nodep; + public: TraceCFuncVertex(V3Graph* graphp, AstCFunc* nodep) - : V3GraphVertex(graphp), m_nodep(nodep) { - } + : V3GraphVertex(graphp) + , m_nodep(nodep) {} virtual ~TraceCFuncVertex() {} // ACCESSORS AstCFunc* nodep() const { return m_nodep; } @@ -115,10 +126,14 @@ public: class TraceTraceVertex : public V3GraphVertex { AstTraceInc* m_nodep; // TRACEINC this represents - TraceTraceVertex* m_duplicatep; // NULL, or other vertex with the real code() that duplicates this one + // NULL, or other vertex with the real code() that duplicates this one + TraceTraceVertex* m_duplicatep; + public: TraceTraceVertex(V3Graph* graphp, AstTraceInc* nodep) - : V3GraphVertex(graphp), m_nodep(nodep), m_duplicatep(NULL) {} + : V3GraphVertex(graphp) + , m_nodep(nodep) + , m_duplicatep(NULL) {} virtual ~TraceTraceVertex() {} // ACCESSORS AstTraceInc* nodep() const { return m_nodep; } @@ -127,17 +142,18 @@ public: virtual FileLine* fileline() const { return nodep()->fileline(); } TraceTraceVertex* duplicatep() const { return m_duplicatep; } void duplicatep(TraceTraceVertex* dupp) { - UASSERT_OBJ(!duplicatep(), nodep(), - "Assigning duplicatep() to already duplicated node"); + UASSERT_OBJ(!duplicatep(), nodep(), "Assigning duplicatep() to already duplicated node"); m_duplicatep = dupp; } }; class TraceVarVertex : public V3GraphVertex { - AstVarScope* m_nodep; + AstVarScope* m_nodep; + public: TraceVarVertex(V3Graph* graphp, AstVarScope* nodep) - : V3GraphVertex(graphp), m_nodep(nodep) {} + : V3GraphVertex(graphp) + , m_nodep(nodep) {} virtual ~TraceVarVertex() {} // ACCESSORS AstVarScope* nodep() const { return m_nodep; } @@ -160,31 +176,31 @@ private: // AstVarScope::user1() // V3GraphVertex* for this node // AstCCall::user2() // bool; walked next list for other ccalls // Ast*::user3() // TraceActivityVertex* for this node - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser3InUse m_inuser3; - //AstUser4InUse In V3Hashed + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; + AstUser3InUse m_inuser3; + // AstUser4InUse In V3Hashed // STATE - AstNodeModule* m_topModp; // Module to add variables to - AstScope* m_highScopep; // Scope to add variables to - AstCFunc* m_funcp; // C function adding to graph - AstTraceInc* m_tracep; // Trace function adding to graph - AstCFunc* m_initFuncp; // Trace function we add statements to - AstCFunc* m_fullFuncp; // Trace function we add statements to - AstCFunc* m_fullSubFuncp; // Trace function we add statements to (under full) - int m_fullSubStmts; // Statements under function being built - AstCFunc* m_chgFuncp; // Trace function we add statements to - AstCFunc* m_chgSubFuncp; // Trace function we add statements to (under full) - AstNode* m_chgSubParentp;// Which node has call to m_chgSubFuncp - int m_chgSubStmts; // Statements under function being built - AstVarScope* m_activityVscp; // Activity variable - uint32_t m_activityNumber; // Count of fields in activity variable - uint32_t m_code; // Trace ident code# being assigned - V3Graph m_graph; // Var/CFunc tracking + AstNodeModule* m_topModp; // Module to add variables to + AstScope* m_highScopep; // Scope to add variables to + AstCFunc* m_funcp; // C function adding to graph + AstTraceInc* m_tracep; // Trace function adding to graph + AstCFunc* m_initFuncp; // Trace function we add statements to + AstCFunc* m_fullFuncp; // Trace function we add statements to + AstCFunc* m_fullSubFuncp; // Trace function we add statements to (under full) + int m_fullSubStmts; // Statements under function being built + AstCFunc* m_chgFuncp; // Trace function we add statements to + AstCFunc* m_chgSubFuncp; // Trace function we add statements to (under full) + AstNode* m_chgSubParentp; // Which node has call to m_chgSubFuncp + int m_chgSubStmts; // Statements under function being built + AstVarScope* m_activityVscp; // Activity variable + uint32_t m_activityNumber; // Count of fields in activity variable + uint32_t m_code; // Trace ident code# being assigned + V3Graph m_graph; // Var/CFunc tracking TraceActivityVertex* m_alwaysVtxp; // "Always trace" vertex - bool m_finding; // Pass one of algorithm? - int m_funcNum; // Function number being built + bool m_finding; // Pass one of algorithm? + int m_funcNum; // Function number being built VDouble0 m_statChgSigs; // Statistic tracking VDouble0 m_statUniqSigs; // Statistic tracking @@ -194,11 +210,11 @@ private: VL_DEBUG_FUNC; // Declare debug() void detectDuplicates() { - UINFO(9,"Finding duplicates\n"); + UINFO(9, "Finding duplicates\n"); // Note uses user4 V3Hashed hashed; // Duplicate code detection // Hash all of the values the traceIncs need - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (TraceTraceVertex* vvertexp = dynamic_cast(itp)) { AstTraceInc* nodep = vvertexp->nodep(); if (nodep->valuep()) { @@ -206,8 +222,8 @@ private: "Trace duplicate back needs consistency," " so we can map duplicates back to TRACEINCs"); hashed.hash(nodep->valuep()); - UINFO(8, " Hashed "<valuep()) - <<" "<valuep()) << " " + << nodep << endl); // Just keep one node in the map and point all duplicates to this node if (hashed.findDuplicate(nodep->valuep()) == hashed.end()) { @@ -217,7 +233,7 @@ private: } } // Find if there are any duplicates - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (TraceTraceVertex* vvertexp = dynamic_cast(itp)) { AstTraceInc* nodep = vvertexp->nodep(); if (nodep->valuep() && !vvertexp->duplicatep()) { @@ -228,8 +244,8 @@ private: UASSERT_OBJ(dupincp, nodep, "Trace duplicate of wrong type"); TraceTraceVertex* dupvertexp = dynamic_cast(dupincp->user1u().toGraphVertex()); - UINFO(8," Orig "<duplicatep(dupvertexp); @@ -242,7 +258,7 @@ private: void graphSimplify() { // Remove all variable nodes - for (V3GraphVertex* nextp, *itp = m_graph.verticesBeginp(); itp; itp=nextp) { + for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) { nextp = itp->verticesNextp(); if (TraceVarVertex* vvertexp = dynamic_cast(itp)) { vvertexp->rerouteEdges(&m_graph); @@ -253,7 +269,7 @@ private: // We do this twice, as then we have fewer edges to multiply out in the below expansion. m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); // Remove all Cfunc nodes - for (V3GraphVertex* nextp, *itp = m_graph.verticesBeginp(); itp; itp=nextp) { + for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) { nextp = itp->verticesNextp(); if (TraceCFuncVertex* vvertexp = dynamic_cast(itp)) { vvertexp->rerouteEdges(&m_graph); @@ -265,10 +281,10 @@ private: m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); // If there are any edges from a always, keep only the always - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (TraceTraceVertex* vvertexp = dynamic_cast(itp)) { V3GraphEdge* alwaysEdgep = NULL; - for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { TraceActivityVertex* actVtxp = dynamic_cast(edgep->fromp()); UASSERT_OBJ(actVtxp, vvertexp->nodep(), @@ -279,21 +295,19 @@ private: } } if (alwaysEdgep) { - for (V3GraphEdge* nextp, *edgep = vvertexp->inBeginp(); edgep; edgep=nextp) { + for (V3GraphEdge *nextp, *edgep = vvertexp->inBeginp(); edgep; edgep = nextp) { nextp = edgep->inNextp(); - if (edgep!=alwaysEdgep) edgep->unlinkDelete(); + if (edgep != alwaysEdgep) edgep->unlinkDelete(); } } } } // Activity points with no outputs can be removed - for (V3GraphVertex* nextp, *itp = m_graph.verticesBeginp(); itp; itp=nextp) { + for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) { nextp = itp->verticesNextp(); if (TraceActivityVertex* vvertexp = dynamic_cast(itp)) { - if (!vvertexp->outBeginp()) { - vvertexp->unlinkDelete(&m_graph); - } + if (!vvertexp->outBeginp()) { vvertexp->unlinkDelete(&m_graph); } } } } @@ -301,7 +315,7 @@ private: void assignActivity() { // Select activity numbers and put into each CFunc vertex m_activityNumber = 1; // Note 0 indicates "slow" - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (TraceActivityVertex* vvertexp = dynamic_cast(itp)) { if (!vvertexp->activityCodeValid()) { if (vvertexp->slow()) { @@ -328,14 +342,11 @@ private: = new AstBasicDType(m_chgFuncp->fileline(), VFlagLogicPacked(), 1); v3Global.rootp()->typeTablep()->addTypesp(newScalarDtp); AstNodeDType* newArrDtp = new AstUnpackArrayDType( - m_chgFuncp->fileline(), - newScalarDtp, - new AstRange(m_chgFuncp->fileline(), - VNumRange(m_activityNumber-1, 0, false))); + m_chgFuncp->fileline(), newScalarDtp, + new AstRange(m_chgFuncp->fileline(), VNumRange(m_activityNumber - 1, 0, false))); v3Global.rootp()->typeTablep()->addTypesp(newArrDtp); - newvarp = new AstVar(m_chgFuncp->fileline(), - AstVarType::MODULETEMP, - "__Vm_traceActivity", newArrDtp); + newvarp = new AstVar(m_chgFuncp->fileline(), AstVarType::MODULETEMP, + "__Vm_traceActivity", newArrDtp); } else { // For tighter code; round to next word point. int activityBits = VL_WORDS_I(m_activityNumber) * VL_EDATASIZE; @@ -348,14 +359,14 @@ private: m_activityVscp = newvscp; // Insert activity setter - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (TraceActivityVertex* vvertexp = dynamic_cast(itp)) { if (!vvertexp->activityAlways()) { FileLine* fl = vvertexp->insertp()->fileline(); uint32_t acode = vvertexp->activityCode(); - vvertexp->insertp()->addNextHere - (new AstAssign(fl, selectActivity(fl, acode, true), - new AstConst(fl, AstConst::LogicTrue()))); + vvertexp->insertp()->addNextHere( + new AstAssign(fl, selectActivity(fl, acode, true), + new AstConst(fl, AstConst::LogicTrue()))); } } } @@ -363,31 +374,29 @@ private: AstNode* selectActivity(FileLine* flp, uint32_t acode, bool lvalue) { if (v3Global.opt.mtasks()) { - return new AstArraySel( - flp, new AstVarRef(flp, m_activityVscp, lvalue), acode); + return new AstArraySel(flp, new AstVarRef(flp, m_activityVscp, lvalue), acode); } else { - return new AstSel( - flp, new AstVarRef(flp, m_activityVscp, lvalue), acode, 1); + return new AstSel(flp, new AstVarRef(flp, m_activityVscp, lvalue), acode, 1); } } AstCFunc* newCFunc(AstCFuncType type, const string& name, AstCFunc* basep) { AstCFunc* funcp = new AstCFunc(basep->fileline(), name, basep->scopep()); funcp->slow(basep->slow()); - funcp->argTypes(EmitCBaseVisitor::symClassVar() - +", "+v3Global.opt.traceClassBase()+"* vcdp, uint32_t code"); + funcp->argTypes(EmitCBaseVisitor::symClassVar() + ", " + v3Global.opt.traceClassBase() + + "* vcdp, uint32_t code"); funcp->funcType(type); funcp->symProlog(true); basep->addNext(funcp); - UINFO(5," Newfunc "<name()+"__"+cvtToStr(++m_funcNum); + string name = basep->name() + "__" + cvtToStr(++m_funcNum); AstCFunc* funcp = NULL; - if (basep->funcType()==AstCFuncType::TRACE_FULL) { + if (basep->funcType() == AstCFuncType::TRACE_FULL) { funcp = newCFunc(AstCFuncType::TRACE_FULL_SUB, name, basep); - } else if (basep->funcType()==AstCFuncType::TRACE_CHANGE) { + } else if (basep->funcType() == AstCFuncType::TRACE_CHANGE) { funcp = newCFunc(AstCFuncType::TRACE_CHANGE_SUB, name, basep); } else { basep->v3fatalSrc("Strange base function type"); @@ -404,8 +413,7 @@ private: return funcp; } void addToChgSub(AstNode* underp, AstNode* stmtsp) { - if (!m_chgSubFuncp - || (m_chgSubParentp != underp) + if (!m_chgSubFuncp || (m_chgSubParentp != underp) || (m_chgSubStmts && v3Global.opt.outputSplitCTrace() && m_chgSubStmts > v3Global.opt.outputSplitCTrace())) { m_chgSubFuncp = newCFuncSub(m_chgFuncp, underp); @@ -418,26 +426,27 @@ private: void putTracesIntoTree() { // Form a sorted list of the traces we are interested in - UINFO(9,"Making trees\n"); + UINFO(9, "Making trees\n"); typedef std::set ActCodeSet; // All activity numbers applying to a given trace - typedef std::multimap TraceVec; // For activity set, what traces apply + typedef std::multimap + TraceVec; // For activity set, what traces apply TraceVec traces; // Form sort structure // If a trace doesn't have activity, it's constant, and we don't // need to track changes on it. - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (TraceTraceVertex* vvertexp = dynamic_cast(itp)) { ActCodeSet actset; - UINFO(9," Add to sort: "<=9) vvertexp->nodep()->dumpTree(cout, "- trnode: "); - for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { + UINFO(9, " Add to sort: " << vvertexp << endl); + if (debug() >= 9) vvertexp->nodep()->dumpTree(cout, "- trnode: "); + for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { TraceActivityVertex* cfvertexp = dynamic_cast(edgep->fromp()); UASSERT_OBJ(cfvertexp, vvertexp->nodep(), "Should have been function pointing to this trace"); - UINFO(9," Activity: "<activityAlways()) { // If code 0, we always trace; ignore other codes actset.clear(); @@ -464,10 +473,10 @@ private: // Put TRACEs back into the tree const ActCodeSet* lastactp = NULL; AstNode* ifnodep = NULL; - for (TraceVec::iterator it = traces.begin(); it!=traces.end(); ++it) { + for (TraceVec::iterator it = traces.begin(); it != traces.end(); ++it) { const ActCodeSet& actset = it->first; TraceTraceVertex* vvertexp = it->second; - UINFO(9," Done sort: "<nodep(), needChg); if (addp) { // Else no activity or duplicate if (actset.find(TraceActivityVertex::ACTIVITY_NEVER) != actset.end()) { - vvertexp->nodep()->v3fatalSrc("If never, needChg=0 and shouldn't need to add."); + vvertexp->nodep()->v3fatalSrc( + "If never, needChg=0 and shouldn't need to add."); } else if (actset.find(TraceActivityVertex::ACTIVITY_ALWAYS) != actset.end()) { // Must always set it; add to base of function addToChgSub(m_chgFuncp, addp); @@ -487,12 +497,14 @@ private: // Build a new IF statement FileLine* fl = addp->fileline(); AstNode* condp = NULL; - for (ActCodeSet::const_iterator csit = actset.begin(); - csit != actset.end(); ++csit) { + for (ActCodeSet::const_iterator csit = actset.begin(); csit != actset.end(); + ++csit) { uint32_t acode = *csit; AstNode* selp = selectActivity(fl, acode, false); - if (condp) condp = new AstOr(fl, condp, selp); - else condp = selp; + if (condp) + condp = new AstOr(fl, condp, selp); + else + condp = selp; } AstIf* ifp = new AstIf(fl, condp, NULL, NULL); ifp->branchPred(VBranchPred::BP_UNLIKELY); @@ -517,9 +529,9 @@ private: m_chgFuncp->addFinalsp(clrp); } } else { - AstNode* clrp = new AstAssign(fl, new AstVarRef(fl, m_activityVscp, true), - new AstConst(fl, AstConst::WidthedValue(), - m_activityVscp->width(), 0)); + AstNode* clrp = new AstAssign( + fl, new AstVarRef(fl, m_activityVscp, true), + new AstConst(fl, AstConst::WidthedValue(), m_activityVscp->width(), 0)); m_fullFuncp->addFinalsp(clrp->cloneTree(true)); m_chgFuncp->addFinalsp(clrp); } @@ -539,13 +551,13 @@ private: // Assign trace code, add to tree, return node for change tree or null // Look for identical copies uint32_t codePreassigned = 0; - //if (debug()>=9) nodep->dumpTree(cout, "- assnnode: "); + // if (debug()>=9) nodep->dumpTree(cout, "- assnnode: "); // Find non-duplicated node; note some nodep's maybe null, as they were deleted below TraceTraceVertex* dupvertexp = vvertexp; if (dupvertexp->duplicatep()) { dupvertexp = dupvertexp->duplicatep(); - UINFO(9," dupOf "<nodep()) - <<" "<nodep()) + << " " << dupvertexp << endl); UASSERT_OBJ(!dupvertexp->duplicatep(), dupvertexp->nodep(), "Original node was marked as a duplicate"); } @@ -558,9 +570,9 @@ private: } else { assignDeclCode(nodep->declp()); } - UINFO(8," Created code="<declp()->code() - <<" "<<(codePreassigned?"[PREASS]":"") - <<" "<<(needChg?"[CHG]":"")<<" "<=6) m_graph.dumpDotFilePrefixed("trace_pre"); + if (debug() >= 6) m_graph.dumpDotFilePrefixed("trace_pre"); graphSimplify(); - if (debug()>=6) m_graph.dumpDotFilePrefixed("trace_opt"); + if (debug() >= 6) m_graph.dumpDotFilePrefixed("trace_opt"); // Create new TRACEINCs assignActivity(); @@ -646,15 +658,15 @@ private: iterateChildren(nodep); } virtual void visit(AstCCall* nodep) VL_OVERRIDE { - UINFO(8," CCALL "<user2()) { // See if there are other calls in same statement list; // If so, all funcs might share the same activity code TraceActivityVertex* activityVtxp = getActivityVertexp(nodep, nodep->funcp()->slow()); - for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) { + for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) { if (AstCCall* ccallp = VN_CAST(nextp, CCall)) { ccallp->user2(true); // Processed - UINFO(8," SubCCALL "<funcp()); activityVtxp->slow(ccallp->funcp()->slow()); new V3GraphEdge(&m_graph, activityVtxp, ccallFuncVtxp, 1); @@ -664,7 +676,7 @@ private: iterateChildren(nodep); } virtual void visit(AstCFunc* nodep) VL_OVERRIDE { - UINFO(8," CFUNC "<funcType() == AstCFuncType::TRACE_INIT) { m_initFuncp = nodep; } else if (nodep->funcType() == AstCFuncType::TRACE_FULL) { @@ -673,12 +685,13 @@ private: m_chgFuncp = nodep; } V3GraphVertex* funcVtxp = getCFuncVertexp(nodep); - if (!m_finding) { // If public, we need a unique activity code to allow for sets directly in this func - if (nodep->funcPublic() || nodep->dpiExport() - || nodep == v3Global.rootp()->evalp()) { + if (!m_finding) { // If public, we need a unique activity code to allow for sets directly + // in this func + if (nodep->funcPublic() || nodep->dpiExport() || nodep == v3Global.rootp()->evalp()) { // Need a non-null place to remember to later add a statement; make one - if (!nodep->stmtsp()) nodep->addStmtsp( - new AstComment(nodep->fileline(), "Tracing activity check", true)); + if (!nodep->stmtsp()) + nodep->addStmtsp( + new AstComment(nodep->fileline(), "Tracing activity check", true)); V3GraphVertex* activityVtxp = getActivityVertexp(nodep->stmtsp(), nodep->slow()); new V3GraphEdge(&m_graph, activityVtxp, funcVtxp, 1); } @@ -688,7 +701,7 @@ private: m_funcp = NULL; } virtual void visit(AstTraceInc* nodep) VL_OVERRIDE { - UINFO(8," TRACE "<unlinkFrBack(); @@ -715,8 +728,7 @@ private: || nodep->varp()->isSigPublic()) { // Or ones user can change new V3GraphEdge(&m_graph, m_alwaysVtxp, traceVtxp, 1); } - } - else if (m_funcp && m_finding && nodep->lvalue()) { + } else if (m_funcp && m_finding && nodep->lvalue()) { UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?"); V3GraphVertex* funcVtxp = getCFuncVertexp(m_funcp); V3GraphVertex* varVtxp = nodep->varScopep()->user1u().toGraphVertex(); @@ -762,9 +774,7 @@ public: // Trace class functions void V3Trace::traceAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 4d203704b..029587e88 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -38,20 +38,20 @@ private: // NODE STATE // STATE - AstScope* m_scopetopp; // Current top scope - AstCFunc* m_initFuncp; // Trace function being built - AstCFunc* m_initSubFuncp; // Trace function being built (under m_init) - int m_initSubStmts; // Number of statements in function - AstCFunc* m_fullFuncp; // Trace function being built - AstCFunc* m_chgFuncp; // Trace function being built - int m_funcNum; // Function number being built - AstVarScope* m_traVscp; // Signal being trace constructed - AstNode* m_traValuep; // Signal being traced's value to trace in it - string m_traShowname; // Signal being traced's component name - bool m_interface; // Currently tracing an interface + AstScope* m_scopetopp; // Current top scope + AstCFunc* m_initFuncp; // Trace function being built + AstCFunc* m_initSubFuncp; // Trace function being built (under m_init) + int m_initSubStmts; // Number of statements in function + AstCFunc* m_fullFuncp; // Trace function being built + AstCFunc* m_chgFuncp; // Trace function being built + int m_funcNum; // Function number being built + AstVarScope* m_traVscp; // Signal being trace constructed + AstNode* m_traValuep; // Signal being traced's value to trace in it + string m_traShowname; // Signal being traced's component name + bool m_interface; // Currently tracing an interface - VDouble0 m_statSigs; // Statistic tracking - VDouble0 m_statIgnSigs; // Statistic tracking + VDouble0 m_statSigs; // Statistic tracking + VDouble0 m_statIgnSigs; // Statistic tracking // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -62,16 +62,12 @@ private: AstVar* varp = nodep->varp(); if (!varp->isTrace()) { return "Verilator trace_off"; - } - else if (!nodep->isTrace()) { + } else if (!nodep->isTrace()) { return "Verilator cell trace_off"; - } - else if (!v3Global.opt.traceUnderscore()) { + } else if (!v3Global.opt.traceUnderscore()) { string prettyName = varp->prettyName(); - if (!prettyName.empty() && prettyName[0] == '_') - return "Leading underscore"; - if (prettyName.find("._") != string::npos) - return "Inlined leading underscore"; + if (!prettyName.empty() && prettyName[0] == '_') return "Leading underscore"; + if (prettyName.find("._") != string::npos) return "Inlined leading underscore"; } return NULL; } @@ -79,14 +75,14 @@ private: AstCFunc* newCFunc(AstCFuncType type, const string& name, bool slow) { AstCFunc* funcp = new AstCFunc(m_scopetopp->fileline(), name, m_scopetopp); funcp->slow(slow); - string argTypes(EmitCBaseVisitor::symClassVar()+", "+v3Global.opt.traceClassBase() - +"* vcdp, uint32_t code"); + string argTypes(EmitCBaseVisitor::symClassVar() + ", " + v3Global.opt.traceClassBase() + + "* vcdp, uint32_t code"); if (m_interface) argTypes += ", const char* scopep"; funcp->argTypes(argTypes); funcp->funcType(type); funcp->symProlog(true); m_scopetopp->addActivep(funcp); - UINFO(5," Newfunc "<addStmtsp(callp); } AstCFunc* newCFuncSub(AstCFunc* basep) { - string name = basep->name()+"__"+cvtToStr(++m_funcNum); + string name = basep->name() + "__" + cvtToStr(++m_funcNum); AstCFunc* funcp = NULL; - if (basep->funcType()==AstCFuncType::TRACE_INIT - || basep->funcType()==AstCFuncType::TRACE_INIT_SUB) { + if (basep->funcType() == AstCFuncType::TRACE_INIT + || basep->funcType() == AstCFuncType::TRACE_INIT_SUB) { funcp = newCFunc(AstCFuncType::TRACE_INIT_SUB, name, basep->slow()); } else { basep->v3fatalSrc("Strange base function type"); @@ -108,15 +104,19 @@ private: return funcp; } void addTraceDecl(const VNumRange& arrayRange, - int widthOverride) { // If !=0, is packed struct/array where basicp size misreflects one element + int widthOverride) { // If !=0, is packed struct/array where basicp size + // misreflects one element VNumRange bitRange; AstBasicDType* bdtypep = m_traValuep->dtypep()->basicp(); - if (widthOverride) bitRange = VNumRange(widthOverride-1, 0, false); - else if (bdtypep) bitRange = bdtypep->nrange(); - AstTraceDecl* declp = new AstTraceDecl(m_traVscp->fileline(), m_traShowname, - m_traVscp->varp(), m_traValuep, - bitRange, arrayRange, m_interface); - UINFO(9,"Decl "<nrange(); + } + AstTraceDecl* declp + = new AstTraceDecl(m_traVscp->fileline(), m_traShowname, m_traVscp->varp(), + m_traValuep, bitRange, arrayRange, m_interface); + UINFO(9, "Decl " << declp << endl); if (!m_interface && v3Global.opt.outputSplitCTrace() && m_initSubStmts > v3Global.opt.outputSplitCTrace()) { @@ -127,15 +127,14 @@ private: m_initSubFuncp->addStmtsp(declp); m_initSubStmts += EmitCBaseCounterVisitor(declp).count(); - m_chgFuncp->addStmtsp(new AstTraceInc(m_traVscp->fileline(), - declp, m_traValuep->cloneTree(true))); + m_chgFuncp->addStmtsp( + new AstTraceInc(m_traVscp->fileline(), declp, m_traValuep->cloneTree(true))); // The full version will get constructed in V3Trace } void addIgnore(const char* why) { ++m_statIgnSigs; - m_initSubFuncp->addStmtsp( - new AstComment(m_traVscp->fileline(), - "Tracing: "+m_traShowname+" // Ignored: "+why, true)); + m_initSubFuncp->addStmtsp(new AstComment( + m_traVscp->fileline(), "Tracing: " + m_traShowname + " // Ignored: " + why, true)); } // VISITORS @@ -144,7 +143,7 @@ private: // Make containers for TRACEDECLs first m_initFuncp = newCFunc(AstCFuncType::TRACE_INIT, "traceInitThis", true); m_fullFuncp = newCFunc(AstCFuncType::TRACE_FULL, "traceFullThis", true); - m_chgFuncp = newCFunc(AstCFuncType::TRACE_CHANGE, "traceChgThis", false); + m_chgFuncp = newCFunc(AstCFuncType::TRACE_CHANGE, "traceChgThis", false); // m_initSubFuncp = newCFuncSub(m_initFuncp); // And find variables @@ -162,7 +161,7 @@ private: size_t lastDot = scopeName.find_last_of('.'); UASSERT_OBJ(lastDot != string::npos, nodep, "Expected an interface scope name to have at least one dot"); - scopeName = scopeName.substr(0, lastDot+1); + scopeName = scopeName.substr(0, lastDot + 1); size_t scopeLen = scopeName.length(); AstIntfRef* nextIrp = cellp->intfRefp(); @@ -195,9 +194,8 @@ private: // Generally this equation doesn't need updating, instead use // varp->isTrace() and/or vscIgnoreTrace. if ((!nodep->varp()->isTemp() || nodep->varp()->isTrace()) - && !nodep->varp()->isClassMember() - && !nodep->varp()->isFuncLocal()) { - UINFO(5, " vsc "<varp()->isClassMember() && !nodep->varp()->isFuncLocal()) { + UINFO(5, " vsc " << nodep << endl); AstVar* varp = nodep->varp(); AstScope* scopep = nodep->scopep(); // Compute show name @@ -217,8 +215,11 @@ private: addIgnore(vscIgnoreTrace(nodep)); } else { ++m_statSigs; - if (nodep->valuep()) m_traValuep = nodep->valuep()->cloneTree(true); - else m_traValuep = new AstVarRef(nodep->fileline(), nodep, false); + if (nodep->valuep()) { + m_traValuep = nodep->valuep()->cloneTree(true); + } else { + m_traValuep = new AstVarRef(nodep->fileline(), nodep, false); + } { // Recurse into data type of the signal; the visitors will call addTraceDecl() iterate(varp->dtypep()->skipRefToEnump()); @@ -233,22 +234,20 @@ private: } // VISITORS - Data types when tracing virtual void visit(AstConstDType* nodep) VL_OVERRIDE { - if (m_traVscp) { - iterate(nodep->subDTypep()->skipRefToEnump()); - } + if (m_traVscp) iterate(nodep->subDTypep()->skipRefToEnump()); } virtual void visit(AstRefDType* nodep) VL_OVERRIDE { - if (m_traVscp) { - iterate(nodep->subDTypep()->skipRefToEnump()); - } + if (m_traVscp) iterate(nodep->subDTypep()->skipRefToEnump()); } virtual void visit(AstUnpackArrayDType* nodep) VL_OVERRIDE { // Note more specific dtypes above if (m_traVscp) { if (static_cast(nodep->arrayUnpackedElements()) > v3Global.opt.traceMaxArray()) { addIgnore("Wide memory > --trace-max-array ents"); - } else if (VN_IS(nodep->subDTypep()->skipRefToEnump(), BasicDType) // Nothing lower than this array - && m_traVscp->dtypep()->skipRefToEnump() == nodep) { // Nothing above this array + } else if (VN_IS(nodep->subDTypep()->skipRefToEnump(), + BasicDType) // Nothing lower than this array + && m_traVscp->dtypep()->skipRefToEnump() + == nodep) { // Nothing above this array // Simple 1-D array, use existing V3EmitC runtime loop rather than unrolling // This will put "(index)" at end of signal name for us if (m_traVscp->dtypep()->skipRefToEnump()->isString()) { @@ -259,14 +258,13 @@ private: } else { // Unroll now, as have no other method to get right signal names AstNodeDType* subtypep = nodep->subDTypep()->skipRefToEnump(); - for (int i=nodep->lsb(); i<=nodep->msb(); ++i) { + for (int i = nodep->lsb(); i <= nodep->msb(); ++i) { string oldShowname = m_traShowname; AstNode* oldValuep = m_traValuep; { - m_traShowname += string("(")+cvtToStr(i)+string(")"); - m_traValuep = new AstArraySel(nodep->fileline(), - m_traValuep->cloneTree(true), - i - nodep->lsb()); + m_traShowname += string("(") + cvtToStr(i) + string(")"); + m_traValuep = new AstArraySel( + nodep->fileline(), m_traValuep->cloneTree(true), i - nodep->lsb()); m_traValuep->dtypep(subtypep); iterate(subtypep); @@ -287,13 +285,13 @@ private: addTraceDecl(VNumRange(), nodep->width()); } else { AstNodeDType* subtypep = nodep->subDTypep()->skipRefToEnump(); - for (int i=nodep->lsb(); i<=nodep->msb(); ++i) { + for (int i = nodep->lsb(); i <= nodep->msb(); ++i) { string oldShowname = m_traShowname; AstNode* oldValuep = m_traValuep; { - m_traShowname += string("(")+cvtToStr(i)+string(")"); + m_traShowname += string("(") + cvtToStr(i) + string(")"); m_traValuep = new AstSel(nodep->fileline(), m_traValuep->cloneTree(true), - (i - nodep->lsb())*subtypep->width(), + (i - nodep->lsb()) * subtypep->width(), subtypep->width()); m_traValuep->dtypep(subtypep); iterate(subtypep); @@ -316,17 +314,17 @@ private: if (!nodep->packed()) { addIgnore("Unsupported: Unpacked struct/union"); } else { - for (AstMemberDType* itemp = nodep->membersp(); - itemp; itemp=VN_CAST(itemp->nextp(), MemberDType)) { + for (AstMemberDType* itemp = nodep->membersp(); itemp; + itemp = VN_CAST(itemp->nextp(), MemberDType)) { AstNodeDType* subtypep = itemp->subDTypep()->skipRefToEnump(); string oldShowname = m_traShowname; AstNode* oldValuep = m_traValuep; { - m_traShowname += string(" ")+itemp->prettyName(); + m_traShowname += string(" ") + itemp->prettyName(); if (VN_IS(nodep, StructDType)) { - m_traValuep = new AstSel(nodep->fileline(), - m_traValuep->cloneTree(true), - itemp->lsb(), subtypep->width()); + m_traValuep + = new AstSel(nodep->fileline(), m_traValuep->cloneTree(true), + itemp->lsb(), subtypep->width()); m_traValuep->dtypep(subtypep); iterate(subtypep); VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = NULL); @@ -350,9 +348,7 @@ private: } } } - virtual void visit(AstEnumDType* nodep) VL_OVERRIDE { - iterate(nodep->skipRefp()); - } + virtual void visit(AstEnumDType* nodep) VL_OVERRIDE { iterate(nodep->skipRefp()); } virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { // Note more specific dtypes above if (!m_traVscp) return; @@ -387,9 +383,7 @@ public: // Trace class functions void V3TraceDecl::traceDeclAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index 7f4617b9d..25036ebd2 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -23,9 +23,11 @@ #include "V3Error.h" #include "V3Ast.h" +// clang-format off #ifndef _V3WIDTH_CPP_ # error "V3WidthCommit for V3Width internal use only" #endif +// clang-format on //###################################################################### @@ -55,9 +57,7 @@ public: // CONSTRUCTORS WidthRemoveVisitor() {} virtual ~WidthRemoveVisitor() {} - AstNode* mainAcceptEdit(AstNode* nodep) { - return iterateSubtreeReturnEdits(nodep); - } + AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); } }; //###################################################################### @@ -67,15 +67,14 @@ public: class WidthCommitVisitor : public AstNVisitor { // NODE STATE // AstVar::user1p -> bool, processed - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; public: // METHODS static AstConst* newIfConstCommitSize(AstConst* nodep) { - if (((nodep->dtypep()->width() != nodep->num().width()) - || !nodep->num().sized()) + if (((nodep->dtypep()->width() != nodep->num().width()) || !nodep->num().sized()) && !nodep->num().isString()) { // Need to force the number from unsized to sized - V3Number num (nodep, nodep->dtypep()->width()); + V3Number num(nodep, nodep->dtypep()->width()); num.opAssign(nodep->num()); num.isSigned(nodep->isSigned()); AstConst* newp = new AstConst(nodep->fileline(), num); @@ -102,9 +101,12 @@ private: // Look for duplicate if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) { AstBasicDType* newp = nodep->findInsertSameDType(bdtypep); - if (newp != bdtypep && debug()>=9) { - UINFO(9,"dtype replacement "); nodep->dumpSmall(cout); - cout<<" ----> "; newp->dumpSmall(cout); cout<= 9) { + UINFO(9, "dtype replacement "); + nodep->dumpSmall(cout); + cout << " ----> "; + newp->dumpSmall(cout); + cout << endl; } return newp; } @@ -116,16 +118,15 @@ private: iterate(nodep->dtypep()); // Do datatype first if (AstConst* newp = newIfConstCommitSize(nodep)) { nodep->replaceWith(newp); - AstNode* oldp = nodep; nodep = newp; - //if (debug()>4) oldp->dumpTree(cout, " fixConstSize_old: "); - //if (debug()>4) newp->dumpTree(cout, " _new: "); + AstNode* oldp = nodep; + nodep = newp; + // if (debug()>4) oldp->dumpTree(cout, " fixConstSize_old: "); + // if (debug()>4) newp->dumpTree(cout, " _new: "); VL_DO_DANGLING(pushDeletep(oldp), oldp); } editDType(nodep); } - virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { - visitIterateNodeDType(nodep); - } + virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { visitIterateNodeDType(nodep); } virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE { if (nodep->user1SetOnce()) return; // Process once visitIterateNodeDType(nodep); @@ -158,6 +159,7 @@ private: iterateChildren(nodep); editDType(nodep); } + public: // CONSTRUCTORS explicit WidthCommitVisitor(AstNetlist* nodep) { diff --git a/src/VlcBucket.h b/src/VlcBucket.h index 5e09e82d9..994c2e3d2 100644 --- a/src/VlcBucket.h +++ b/src/VlcBucket.h @@ -47,9 +47,7 @@ private: v3fatal("Out of memory increasing buckets"); } m_datap = newp; - for (vluint64_t i = oldsize; i < m_dataSize; i += 64) { - m_datap[i / 64] = 0; - } + for (vluint64_t i = oldsize; i < m_dataSize; i += 64) m_datap[i / 64] = 0; } public: diff --git a/src/VlcMain.cpp b/src/VlcMain.cpp index e24bfa6e9..5cdbdb36d 100644 --- a/src/VlcMain.cpp +++ b/src/VlcMain.cpp @@ -14,14 +14,16 @@ // //************************************************************************* -// Cheat for speed and compile .cpp files into one object +// clang-format off #include "config_build.h" #ifndef HAVE_CONFIG_BUILD # error "Something failed during ./configure as config_build.h is incomplete. Perhaps you used autoreconf, don't." #endif +// clang-format on #include "verilatedos.h" +// Cheat for speed and compile .cpp files into one object #define _V3ERROR_NO_GLOBAL_ 1 #include "V3Error.cpp" #include "V3String.cpp" diff --git a/src/VlcOptions.h b/src/VlcOptions.h index 0c6ea5abc..e2af6e5e6 100644 --- a/src/VlcOptions.h +++ b/src/VlcOptions.h @@ -34,6 +34,7 @@ typedef std::set VlStringSet; class VlcOptions { // MEMBERS (general options) + // clang-format off string m_annotateOut; // main switch: --annotate I bool m_annotateAll; // main switch: --annotate-all int m_annotateMin; // main switch: --annotate-min I @@ -41,6 +42,7 @@ class VlcOptions { bool m_rank; // main switch: --rank bool m_unlink; // main switch: --unlink string m_writeFile; // main switch: --write + // clang-format on private: // METHODS diff --git a/src/VlcPoint.h b/src/VlcPoint.h index b68518d8b..90c42e7fc 100644 --- a/src/VlcPoint.h +++ b/src/VlcPoint.h @@ -67,8 +67,7 @@ public: const string namestr = name(); for (const char* cp = namestr.c_str(); *cp; ++cp) { if (*cp == '\001') { - if (0 == strncmp(cp + 1, shortKey, shortLen) - && cp[shortLen + 1] == '\002') { + if (0 == strncmp(cp + 1, shortKey, shortLen) && cp[shortLen + 1] == '\002') { cp += shortLen + 2; // Skip \001+short+\002 const char* ep = cp; while (*ep && *ep != '\001') ++ep; @@ -110,7 +109,8 @@ public: public: // CONSTRUCTORS - VlcPoints() : m_numPoints(0) {} + VlcPoints() + : m_numPoints(0) {} ~VlcPoints() {} // METHODS diff --git a/src/VlcSource.h b/src/VlcSource.h index ea9f3ed2b..f01a575a7 100644 --- a/src/VlcSource.h +++ b/src/VlcSource.h @@ -89,9 +89,7 @@ public: // METHODS void incCount(int lineno, int column, vluint64_t count, bool ok) { LinenoMap::iterator lit = m_lines.find(lineno); - if (lit == m_lines.end()) { - lit = m_lines.insert(make_pair(lineno, ColumnMap())).first; - } + if (lit == m_lines.end()) lit = m_lines.insert(make_pair(lineno, ColumnMap())).first; ColumnMap& cmap = lit->second; ColumnMap::iterator cit = cmap.find(column); if (cit == cmap.end()) { diff --git a/src/VlcTest.h b/src/VlcTest.h index 0b38ce9e8..42c17993e 100644 --- a/src/VlcTest.h +++ b/src/VlcTest.h @@ -126,9 +126,7 @@ public: return testp; } void clearUser() { - for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) { - (*it)->user(0); - } + for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) (*it)->user(0); } }; diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index 0e08d299f..864479146 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -114,7 +114,10 @@ void VlcTop::rank() { // then hierarchically solve a small subset of tests, and take resulting // solution and move up to larger subset of tests. (Aka quick sort.) while (true) { - if (debug()) { UINFO(9, "Left on iter" << nextrank << ": "); remaining.dump(); } + if (debug()) { + UINFO(9, "Left on iter" << nextrank << ": "); + remaining.dump(); + } VlcTest* bestTestp = NULL; vluint64_t bestRemain = 0; for (std::vector::iterator it = bytime.begin(); it != bytime.end(); ++it) { @@ -151,7 +154,8 @@ void VlcTop::annotateCalc() { string threshStr = point.thresh(); unsigned thresh = (!threshStr.empty()) ? atoi(threshStr.c_str()) : opt.annotateMin(); bool ok = (point.count() >= thresh); - UINFO(9, "AnnoCalc count " << filename << " " << lineno << " " << point.count() << endl); + UINFO(9, + "AnnoCalc count " << filename << " " << lineno << " " << point.count() << endl); source.incCount(lineno, column, point.count(), ok); } } diff --git a/src/config_build.h.in b/src/config_build.h.in index f06671416..02c915300 100644 --- a/src/config_build.h.in +++ b/src/config_build.h.in @@ -37,6 +37,7 @@ // If set to "", this default is ignored and the user is expected // to set them at Verilator runtime. +// clang-format off #ifndef DEFENV_SYSTEMC # define DEFENV_SYSTEMC "" #endif @@ -52,6 +53,7 @@ #ifndef DEFENV_VERILATOR_ROOT # define DEFENV_VERILATOR_ROOT "" #endif +// clang-format on //********************************************************************** //**** Compile options From 08b74e5ab902e0705286ab719be529093ab99fef Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 14 Apr 2020 23:07:09 +0100 Subject: [PATCH 051/127] Fix crash when formatting constant wider than 1023 bits (#2260) --- src/V3Number.cpp | 9 ++++++--- test_regress/t/t_format_wide_decimal.out | 2 ++ test_regress/t/t_format_wide_decimal.pl | 24 ++++++++++++++++++++++++ test_regress/t/t_format_wide_decimal.v | 20 ++++++++++++++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 test_regress/t/t_format_wide_decimal.out create mode 100755 test_regress/t/t_format_wide_decimal.pl create mode 100644 test_regress/t/t_format_wide_decimal.v diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 72d6a61e6..b9172f90e 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -583,9 +583,12 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { case 'd': { // Unsigned decimal bool issigned = (code == '~'); if (fmtsize == "") { - double mantissabits = this->width() - (issigned?1:0); - double maxval = pow(2.0, mantissabits); - double dchars = log10(maxval)+1.0; + const double mantissabits = this->width() - (issigned ? 1 : 0); + // To get the number of digits required, we want to compute + // log10(2**mantissabits) and round it up. To be able to handle + // a very wide mantissa, we use log2(2**mantissabits)/log2(10), + // which is simply (+1.0 is for rounding bias): + double dchars = mantissabits / 3.321928094887362 + 1.0; if (issigned) dchars++; // space for sign fmtsize = cvtToStr(int(dchars)); } diff --git a/test_regress/t/t_format_wide_decimal.out b/test_regress/t/t_format_wide_decimal.out new file mode 100644 index 000000000..4c5c7138a --- /dev/null +++ b/test_regress/t/t_format_wide_decimal.out @@ -0,0 +1,2 @@ +179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137215 +*-* All Finished *-* diff --git a/test_regress/t/t_format_wide_decimal.pl b/test_regress/t/t_format_wide_decimal.pl new file mode 100755 index 000000000..81690404c --- /dev/null +++ b/test_regress/t/t_format_wide_decimal.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Geza Lore. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["-Wall"] + ); + + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_format_wide_decimal.v b/test_regress/t/t_format_wide_decimal.v new file mode 100644 index 000000000..c901f959d --- /dev/null +++ b/test_regress/t/t_format_wide_decimal.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +module t_format_wide_decimal; + + initial begin + // Format very wide constant number (which has more bits than can + // be counted in exponent of a double precision float), with %d. + $display("%d", 1024'hffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 1b94e3b0e28df16122f24d2676404eec41175878 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 14 Apr 2020 19:55:00 -0400 Subject: [PATCH 052/127] Internals: clang-format files needed for #2249. --- nodist/clang_formatter | 38 +- src/V3EmitCSyms.cpp | 417 +++++++++++--------- src/V3Options.cpp | 873 +++++++++++++++++++---------------------- src/V3Options.h | 78 ++-- src/V3Os.cpp | 106 ++--- src/Verilator.cpp | 107 ++--- 6 files changed, 752 insertions(+), 867 deletions(-) diff --git a/nodist/clang_formatter b/nodist/clang_formatter index 1acde0367..c9ee2b72a 100755 --- a/nodist/clang_formatter +++ b/nodist/clang_formatter @@ -16,33 +16,9 @@ clang-format -i examples/make_hello_sc/sc_main.cpp #clang-format -i examples/make_protect_lib/sim_main.cpp clang-format -i examples/make_tracing_c/sim_main.cpp clang-format -i examples/make_tracing_sc/sc_main.cpp -clang-format -i include/verilated.cpp -clang-format -i include/verilated.h +clang-format -i include/*.cpp +clang-format -i include/*.h clang-format -i include/verilated_config.h.in -clang-format -i include/verilated_cov.cpp -clang-format -i include/verilated_cov.h -clang-format -i include/verilated_cov_key.h -clang-format -i include/verilated_dpi.cpp -clang-format -i include/verilated_dpi.h -clang-format -i include/verilated_fst_c.cpp -clang-format -i include/verilated_fst_c.h -clang-format -i include/verilated_heavy.h -clang-format -i include/verilated_imp.h -clang-format -i include/verilated_save.cpp -clang-format -i include/verilated_save.h -clang-format -i include/verilated_sc.h -clang-format -i include/verilated_sym_props.h -clang-format -i include/verilated_syms.h -clang-format -i include/verilated_threads.cpp -clang-format -i include/verilated_threads.h -clang-format -i include/verilated_unordered_set_map.h -clang-format -i include/verilated_vcd_c.cpp -clang-format -i include/verilated_vcd_c.h -clang-format -i include/verilated_vcd_sc.cpp -clang-format -i include/verilated_vcd_sc.h -clang-format -i include/verilated_vpi.cpp -clang-format -i include/verilated_vpi.h -clang-format -i include/verilatedos.h clang-format -i nodist/fuzzer/wrapper.cpp clang-format -i src/V3Active.cpp clang-format -i src/V3Active.h @@ -107,7 +83,7 @@ clang-format -i src/V3EmitC.h clang-format -i src/V3EmitCInlines.cpp ##clang-format -i src/V3EmitCMake.cpp clang-format -i src/V3EmitCMake.h -##clang-format -i src/V3EmitCSyms.cpp +clang-format -i src/V3EmitCSyms.cpp ##clang-format -i src/V3EmitMk.cpp clang-format -i src/V3EmitMk.h ##clang-format -i src/V3EmitV.cpp @@ -175,12 +151,12 @@ clang-format -i src/V3Name.h ##clang-format -i src/V3Number.cpp ##clang-format -i src/V3Number.h clang-format -i src/V3Number_test.cpp -##clang-format -i src/V3Options.cpp -##clang-format -i src/V3Options.h +clang-format -i src/V3Options.cpp +clang-format -i src/V3Options.h ##clang-format -i src/V3Order.cpp clang-format -i src/V3Order.h clang-format -i src/V3OrderGraph.h -##clang-format -i src/V3Os.cpp +clang-format -i src/V3Os.cpp clang-format -i src/V3Os.h ##clang-format -i src/V3Param.cpp clang-format -i src/V3Param.h @@ -248,7 +224,7 @@ clang-format -i src/V3Unroll.h clang-format -i src/V3Width.h clang-format -i src/V3WidthCommit.h ##clang-format -i src/V3WidthSel.cpp -##clang-format -i src/Verilator.cpp +clang-format -i src/Verilator.cpp clang-format -i src/VlcBucket.h clang-format -i src/VlcMain.cpp clang-format -i src/VlcOptions.h diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index eb427a728..39489097d 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -36,38 +36,55 @@ class EmitCSyms : EmitCBaseVisitor { // NODE STATE // Cleared on Netlist // AstNodeModule::user1() -> bool. Set true __Vconfigure called - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // TYPES - struct ScopeData { string m_symName; string m_prettyName; string m_type; + struct ScopeData { + string m_symName; + string m_prettyName; + string m_type; ScopeData(const string& symName, const string& prettyName, const string& type) - : m_symName(symName), m_prettyName(prettyName), m_type(type) {} + : m_symName(symName) + , m_prettyName(prettyName) + , m_type(type) {} }; - struct ScopeFuncData { AstScopeName* m_scopep; AstCFunc* m_funcp; AstNodeModule* m_modp; + struct ScopeFuncData { + AstScopeName* m_scopep; + AstCFunc* m_funcp; + AstNodeModule* m_modp; ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp) - : m_scopep(scopep), m_funcp(funcp), m_modp(modp) {} + : m_scopep(scopep) + , m_funcp(funcp) + , m_modp(modp) {} }; - struct ScopeVarData { string m_scopeName; string m_varBasePretty; AstVar* m_varp; - AstNodeModule* m_modp; AstScope* m_scopep; - ScopeVarData(const string& scopeName, const string& varBasePretty, - AstVar* varp, AstNodeModule* modp, AstScope* scopep) - : m_scopeName(scopeName), m_varBasePretty(varBasePretty) - , m_varp(varp), m_modp(modp), m_scopep(scopep) {} + struct ScopeVarData { + string m_scopeName; + string m_varBasePretty; + AstVar* m_varp; + AstNodeModule* m_modp; + AstScope* m_scopep; + ScopeVarData(const string& scopeName, const string& varBasePretty, AstVar* varp, + AstNodeModule* modp, AstScope* scopep) + : m_scopeName(scopeName) + , m_varBasePretty(varBasePretty) + , m_varp(varp) + , m_modp(modp) + , m_scopep(scopep) {} }; - typedef std::map ScopeFuncs; - typedef std::map ScopeVars; - typedef std::map ScopeNames; - typedef std::pair ScopeModPair; - typedef std::pair ModVarPair; + typedef std::map ScopeFuncs; + typedef std::map ScopeVars; + typedef std::map ScopeNames; + typedef std::pair ScopeModPair; + typedef std::pair ModVarPair; typedef std::vector ScopeNameList; typedef std::map ScopeNameHierarchy; struct CmpName { - inline bool operator() (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const { + inline bool operator()(const ScopeModPair& lhsp, const ScopeModPair& rhsp) const { return lhsp.first->name() < rhsp.first->name(); } }; struct CmpDpi { - inline bool operator() (const AstCFunc* lhsp, const AstCFunc* rhsp) const { + inline bool operator()(const AstCFunc* lhsp, const AstCFunc* rhsp) const { if (lhsp->dpiImport() != rhsp->dpiImport()) { // cppcheck-suppress comparisonOfFuncReturningBoolError return lhsp->dpiImport() < rhsp->dpiImport(); @@ -77,23 +94,23 @@ class EmitCSyms : EmitCBaseVisitor { }; // STATE - AstCFunc* m_funcp; // Current function - AstNodeModule* m_modp; // Current module + AstCFunc* m_funcp; // Current function + AstNodeModule* m_modp; // Current module std::vector m_scopes; // Every scope by module - std::vector m_dpis; // DPI functions - std::vector m_modVars; // Each public {mod,var} - ScopeNames m_scopeNames; // Each unique AstScopeName - ScopeFuncs m_scopeFuncs; // Each {scope,dpi-export-func} - ScopeVars m_scopeVars; // Each {scope,public-var} - ScopeNames m_vpiScopeCandidates; // All scopes for VPI - ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes - V3LanguageWords m_words; // Reserved word detector - int m_coverBins; // Coverage bin number - bool m_dpiHdrOnly; // Only emit the DPI header - int m_numStmts; // Number of statements output - int m_funcNum; // CFunc split function number - V3OutCFile* m_ofpBase; // Base (not split) C file - std::map m_usesVfinal; // Split method uses __Vfinal + std::vector m_dpis; // DPI functions + std::vector m_modVars; // Each public {mod,var} + ScopeNames m_scopeNames; // Each unique AstScopeName + ScopeFuncs m_scopeFuncs; // Each {scope,dpi-export-func} + ScopeVars m_scopeVars; // Each {scope,public-var} + ScopeNames m_vpiScopeCandidates; // All scopes for VPI + ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes + V3LanguageWords m_words; // Reserved word detector + int m_coverBins; // Coverage bin number + bool m_dpiHdrOnly; // Only emit the DPI header + int m_numStmts; // Number of statements output + int m_funcNum; // CFunc split function number + V3OutCFile* m_ofpBase; // Base (not split) C file + std::map m_usesVfinal; // Split method uses __Vfinal // METHODS void emitSymHdr(); @@ -115,8 +132,10 @@ class EmitCSyms : EmitCBaseVisitor { // Generally V3Name should find all of these and throw SYMRSVDWORD. // We'll still check here because the compiler errors // resulting if we miss this warning are SO nasty - nodep->v3error("Symbol matching "+rsvd+" reserved word reached emitter," - " should have hit SYMRSVDWORD: "<prettyNameQ()); + nodep->v3error("Symbol matching " + rsvd + + " reserved word reached emitter," + " should have hit SYMRSVDWORD: " + << nodep->prettyNameQ()); } } } @@ -124,17 +143,11 @@ class EmitCSyms : EmitCBaseVisitor { string scopeSymString(const string& scpname) { string out = scpname; string::size_type pos; - while ((pos = out.find("__PVT__")) != string::npos) { - out.replace(pos, 7, ""); - } + while ((pos = out.find("__PVT__")) != string::npos) out.replace(pos, 7, ""); if (out.substr(0, 10) == "TOP__DOT__") out.replace(0, 10, ""); if (out.substr(0, 4) == "TOP.") out.replace(0, 4, ""); - while ((pos = out.find('.')) != string::npos) { - out.replace(pos, 1, "__"); - } - while ((pos = out.find("__DOT__")) != string::npos) { - out.replace(pos, 7, "__"); - } + while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__"); + while ((pos = out.find("__DOT__")) != string::npos) out.replace(pos, 7, "__"); return out; } @@ -147,9 +160,9 @@ class EmitCSyms : EmitCBaseVisitor { while ((pos = out.find("__0")) != string::npos) { unsigned int x; std::stringstream ss; - ss << std::hex << out.substr(pos+3, 2); + ss << std::hex << out.substr(pos + 3, 2); ss >> x; - out.replace(pos, 5, 1, (char) x); + out.replace(pos, 5, 1, (char)x); } return out; } @@ -158,7 +171,7 @@ class EmitCSyms : EmitCBaseVisitor { while (!scp.empty()) { ScopeNames::const_iterator scpit = m_vpiScopeCandidates.find(scp); if ((scpit != m_vpiScopeCandidates.end()) - && (m_scopeNames.find(scp) == m_scopeNames.end())) { + && (m_scopeNames.find(scp) == m_scopeNames.end())) { m_scopeNames.insert(make_pair(scpit->second.m_symName, scpit->second)); } string::size_type pos = scp.rfind("__DOT__"); @@ -174,11 +187,12 @@ class EmitCSyms : EmitCBaseVisitor { // We didn't have all m_scopes loaded when we encountered variables, so expand them now // It would be less code if each module inserted its own variables. // Someday. For now public isn't common. - for (std::vector::iterator itsc = m_scopes.begin(); - itsc != m_scopes.end(); ++itsc) { - AstScope* scopep = itsc->first; AstNodeModule* smodp = itsc->second; - for (std::vector::iterator it = m_modVars.begin(); - it != m_modVars.end(); ++it) { + for (std::vector::iterator itsc = m_scopes.begin(); itsc != m_scopes.end(); + ++itsc) { + AstScope* scopep = itsc->first; + AstNodeModule* smodp = itsc->second; + for (std::vector::iterator it = m_modVars.begin(); it != m_modVars.end(); + ++it) { AstNodeModule* modp = it->first; AstVar* varp = it->second; if (modp == smodp) { @@ -186,28 +200,27 @@ class EmitCSyms : EmitCBaseVisitor { // original-ish full scope and variable name under that scope. // The module instance name is included later, when we // know the scopes this module is under - string whole = scopep->name()+"__DOT__"+varp->name(); + string whole = scopep->name() + "__DOT__" + varp->name(); string scpName; string varBase; if (whole.substr(0, 10) == "__DOT__TOP") whole.replace(0, 10, ""); string::size_type dpos = whole.rfind("__DOT__"); if (dpos != string::npos) { scpName = whole.substr(0, dpos); - varBase = whole.substr(dpos+strlen("__DOT__")); + varBase = whole.substr(dpos + strlen("__DOT__")); } else { varBase = whole; } - //UINFO(9,"For "<name()<<" - "<name()<<" Scp "<name()<<" - "<name()<<" Scp "<name(), @@ -218,7 +231,8 @@ class EmitCSyms : EmitCBaseVisitor { } void buildVpiHierarchy() { - for (ScopeNames::const_iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) { + for (ScopeNames::const_iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); + ++it) { if (it->second.m_type != "SCOPE_MODULE") continue; string name = it->second.m_prettyName; @@ -244,9 +258,7 @@ class EmitCSyms : EmitCBaseVisitor { iterateChildren(nodep); varsExpand(); - if (v3Global.opt.vpi()) { - buildVpiHierarchy(); - } + if (v3Global.opt.vpi()) buildVpiHierarchy(); // Sort by names, so line/process order matters less stable_sort(m_scopes.begin(), m_scopes.end(), CmpName()); @@ -274,12 +286,11 @@ class EmitCSyms : EmitCBaseVisitor { } virtual void visit(AstCellInline* nodep) VL_OVERRIDE { if (v3Global.opt.vpi()) { - string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" - : "SCOPE_MODULE"; + string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" : "SCOPE_MODULE"; string name = nodep->scopep()->name() + "__DOT__" + nodep->name(); string name_dedot = AstNode::dedotName(name); - m_vpiScopeCandidates.insert(make_pair(name, ScopeData(scopeSymString(name), - name_dedot, type))); + m_vpiScopeCandidates.insert( + make_pair(name, ScopeData(scopeSymString(name), name_dedot, type))); } } virtual void visit(AstScope* nodep) VL_OVERRIDE { @@ -290,28 +301,28 @@ class EmitCSyms : EmitCBaseVisitor { if (v3Global.opt.vpi() && !nodep->isTop()) { string name_dedot = AstNode::dedotName(nodep->shortName()); - m_vpiScopeCandidates.insert(make_pair(nodep->name(), - ScopeData(scopeSymString(nodep->name()), - name_dedot, "SCOPE_MODULE"))); + m_vpiScopeCandidates.insert( + make_pair(nodep->name(), + ScopeData(scopeSymString(nodep->name()), name_dedot, "SCOPE_MODULE"))); } } virtual void visit(AstScopeName* nodep) VL_OVERRIDE { string name = nodep->scopeSymName(); - //UINFO(9,"scnameins sp "<name()<<" sp "<scopePrettySymName()<<" ss "<name()<<" sp "<scopePrettySymName()<<" ss + // "<scopePrettySymName(), - "SCOPE_OTHER"))); + m_scopeNames.insert( + make_pair(name, ScopeData(name, nodep->scopePrettySymName(), "SCOPE_OTHER"))); } if (nodep->dpiExport()) { UASSERT_OBJ(m_funcp, nodep, "ScopeName not under DPI function"); - m_scopeFuncs.insert(make_pair(name + " " + m_funcp->name(), - ScopeFuncData(nodep, m_funcp, m_modp))); + m_scopeFuncs.insert( + make_pair(name + " " + m_funcp->name(), ScopeFuncData(nodep, m_funcp, m_modp))); } else { if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) { - m_scopeNames.insert(make_pair(nodep->scopeDpiName(), - ScopeData(nodep->scopeDpiName(), - nodep->scopePrettyDpiName(), - "SCOPE_OTHER"))); + m_scopeNames.insert(make_pair( + nodep->scopeDpiName(), + ScopeData(nodep->scopeDpiName(), nodep->scopePrettyDpiName(), "SCOPE_OTHER"))); } } } @@ -319,7 +330,9 @@ class EmitCSyms : EmitCBaseVisitor { nameCheck(nodep); iterateChildren(nodep); if (nodep->isSigUserRdPublic() - && !nodep->isParam()) { // The VPI functions require a pointer to allow modification, but parameters are constants + // The VPI functions require a pointer to allow modification, + // but parameters are constants + && !nodep->isParam()) { m_modVars.push_back(make_pair(m_modp, nodep)); } } @@ -331,9 +344,7 @@ class EmitCSyms : EmitCBaseVisitor { } virtual void visit(AstCFunc* nodep) VL_OVERRIDE { nameCheck(nodep); - if (nodep->dpiImport() || nodep->dpiExportWrapper()) { - m_dpis.push_back(nodep); - } + if (nodep->dpiImport() || nodep->dpiExportWrapper()) m_dpis.push_back(nodep); m_funcp = nodep; iterateChildren(nodep); m_funcp = NULL; @@ -357,9 +368,9 @@ public: }; void EmitCSyms::emitSymHdr() { - UINFO(6,__FUNCTION__<<": "<putsHeader(); - puts("// DESCR" "IPTION: Verilator output: Symbol table internal header\n"); + puts("// DESCR" + "IPTION: Verilator output: Symbol table internal header\n"); puts("//\n"); puts("// Internal details; most calling programs do not need this header,\n"); puts("// unless using verilator public meta comments.\n"); @@ -392,25 +404,27 @@ void EmitCSyms::emitSymHdr() { if (v3Global.dpi()) { puts("\n// DPI TYPES for DPI Export callbacks (Internal use)\n"); - std::map types; // Remove duplicates and sort + std::map types; // Remove duplicates and sort for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) { AstCFunc* funcp = it->second.m_funcp; if (funcp->dpiExport()) { - string cbtype = protect(v3Global.opt.prefix()+"__Vcb_"+funcp->cname()+"_t"); - types["typedef void (*"+cbtype+") ("+cFuncArgs(funcp)+");\n"] = 1; + string cbtype = protect(v3Global.opt.prefix() + "__Vcb_" + funcp->cname() + "_t"); + types["typedef void (*" + cbtype + ") (" + cFuncArgs(funcp) + ");\n"] = 1; } } - for (std::map::iterator it = types.begin(); it != types.end(); ++it) { + for (std::map::iterator it = types.begin(); it != types.end(); ++it) { puts(it->first); } } puts("\n// SYMS CLASS\n"); - puts(string("class ")+symClassName()+" : public VerilatedSyms {\n"); + puts(string("class ") + symClassName() + " : public VerilatedSyms {\n"); ofp()->putsPrivate(false); // public: puts("\n// LOCAL STATE\n"); - puts("const char* __Vm_namep;\n"); // Must be before subcells, as constructor order needed before _vlCoverInsert. + // Must be before subcells, as constructor order needed before _vlCoverInsert. + puts("const char* __Vm_namep;\n"); + if (v3Global.needTraceDumper()) { // __Vm_dumperp is local, otherwise we wouldn't know what design's eval() // should call a global dumpperp @@ -449,7 +463,7 @@ void EmitCSyms::emitSymHdr() { if (!m_scopeNames.empty()) { // Scope names puts("\n// SCOPE NAMES\n"); for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) { - puts("VerilatedScope "+protect("__Vscope_"+it->second.m_symName)+";\n"); + puts("VerilatedScope " + protect("__Vscope_" + it->second.m_symName) + ";\n"); } } @@ -459,16 +473,15 @@ void EmitCSyms::emitSymHdr() { } puts("\n// CREATORS\n"); - puts(symClassName()+"("+topClassName()+"* topp, const char* namep);\n"); - puts(string("~")+symClassName()+"() {}\n"); + puts(symClassName() + "(" + topClassName() + "* topp, const char* namep);\n"); + puts(string("~") + symClassName() + "() {}\n"); - for (std::map::iterator it = m_usesVfinal.begin(); - it != m_usesVfinal.end(); ++it) { - puts("void "+symClassName()+"_"+cvtToStr(it->first)+"("); + for (std::map::iterator it = m_usesVfinal.begin(); it != m_usesVfinal.end(); ++it) { + puts("void " + symClassName() + "_" + cvtToStr(it->first) + "("); if (it->second) { puts("int __Vfinal"); } else { - puts(topClassName()+"* topp"); + puts(topClassName() + "* topp"); } puts(");\n"); } @@ -476,11 +489,12 @@ void EmitCSyms::emitSymHdr() { puts("\n// METHODS\n"); puts("inline const char* name() { return __Vm_namep; }\n"); if (v3Global.opt.trace()) { - puts("inline bool getClearActivity() { bool r=__Vm_activity; __Vm_activity=false; return r; }\n"); + puts("inline bool getClearActivity() { bool r=__Vm_activity; " + "__Vm_activity=false; return r; }\n"); } - if (v3Global.opt.savable() ) { - puts("void "+protect("__Vserialize")+"(VerilatedSerialize& os);\n"); - puts("void "+protect("__Vdeserialize")+"(VerilatedDeserialize& os);\n"); + if (v3Global.opt.savable()) { + puts("void " + protect("__Vserialize") + "(VerilatedSerialize& os);\n"); + puts("void " + protect("__Vdeserialize") + "(VerilatedDeserialize& os);\n"); } puts("\n"); puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n"); @@ -497,12 +511,15 @@ void EmitCSyms::closeSplit() { } void EmitCSyms::checkSplit(bool usesVfinal) { - if (m_ofp && (!v3Global.opt.outputSplitCFuncs() || - m_numStmts < v3Global.opt.outputSplitCFuncs())) return; + if (m_ofp + && (!v3Global.opt.outputSplitCFuncs() || m_numStmts < v3Global.opt.outputSplitCFuncs())) { + return; + } m_numStmts = 0; - string filename = v3Global.opt.makeDir()+"/"+symClassName()+"__"+cvtToStr(++m_funcNum)+".cpp"; - AstCFile* cfilep = newCFile(filename, true/*slow*/, true/*source*/); + string filename + = v3Global.opt.makeDir() + "/" + symClassName() + "__" + cvtToStr(++m_funcNum) + ".cpp"; + AstCFile* cfilep = newCFile(filename, true /*slow*/, true /*source*/); cfilep->support(true); m_usesVfinal[m_funcNum] = usesVfinal; closeSplit(); @@ -513,7 +530,7 @@ void EmitCSyms::checkSplit(bool usesVfinal) { m_ofp = new V3OutCFile(filename); } - m_ofpBase->puts(symClassName()+"_"+cvtToStr(m_funcNum)+"("); + m_ofpBase->puts(symClassName() + "_" + cvtToStr(m_funcNum) + "("); if (usesVfinal) { m_ofpBase->puts("__Vfinal"); } else { @@ -522,22 +539,23 @@ void EmitCSyms::checkSplit(bool usesVfinal) { m_ofpBase->puts(");\n"); emitSymImpPreamble(); - puts("void "+symClassName()+"::"+symClassName()+"_"+cvtToStr(m_funcNum)+"("); + puts("void " + symClassName() + "::" + symClassName() + "_" + cvtToStr(m_funcNum) + "("); if (usesVfinal) { puts("int __Vfinal"); } else { - puts(topClassName()+"* topp"); + puts(topClassName() + "* topp"); } puts(") {\n"); } void EmitCSyms::emitSymImpPreamble() { ofp()->putsHeader(); - puts("// DESCR" "IPTION: Verilator output: Symbol table implementation internals\n"); + puts("// DESCR" + "IPTION: Verilator output: Symbol table implementation internals\n"); puts("\n"); // Includes - puts("#include \""+symClassName()+".h\"\n"); + puts("#include \"" + symClassName() + ".h\"\n"); for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_CAST(nodep->nextp(), NodeModule)) { if (VN_IS(nodep, Class)) continue; // Class included earlier @@ -546,9 +564,9 @@ void EmitCSyms::emitSymImpPreamble() { } void EmitCSyms::emitSymImp() { - UINFO(6,__FUNCTION__<<": "<support(true); if (v3Global.opt.systemC()) { @@ -560,31 +578,31 @@ void EmitCSyms::emitSymImp() { m_ofpBase = m_ofp; emitSymImpPreamble(); - //puts("\n// GLOBALS\n"); + // puts("\n// GLOBALS\n"); puts("\n"); - if (v3Global.opt.savable() ) { + if (v3Global.opt.savable()) { puts("\n"); - for (int de=0; de<2; ++de) { + for (int de = 0; de < 2; ++de) { string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize"; string funcname = de ? "__Vdeserialize" : "__Vserialize"; string op = de ? ">>" : "<<"; // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - puts("void "+symClassName()+"::"+protect(funcname)+"("+classname+"& os) {\n"); - puts( "// LOCAL STATE\n"); + puts("void " + symClassName() + "::" + protect(funcname) + "(" + classname + + "& os) {\n"); + puts("// LOCAL STATE\n"); // __Vm_namep presumably already correct - if (v3Global.opt.trace()) { - puts( "os"+op+"__Vm_activity;\n"); - } - puts( "os"+op+"__Vm_didInit;\n"); - puts( "// SUBCELL STATE\n"); - for (std::vector::iterator it = m_scopes.begin(); - it != m_scopes.end(); ++it) { - AstScope* scopep = it->first; AstNodeModule* modp = it->second; + if (v3Global.opt.trace()) { puts("os" + op + "__Vm_activity;\n"); } + puts("os" + op + "__Vm_didInit;\n"); + puts("// SUBCELL STATE\n"); + for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); + ++it) { + AstScope* scopep = it->first; + AstNodeModule* modp = it->second; if (!modp->isTop()) { - puts(protectIf(scopep->nameDotless(), scopep->protect()) - +"."+protect(funcname)+"(os);\n"); + puts(protectIf(scopep->nameDotless(), scopep->protect()) + "." + + protect(funcname) + "(os);\n"); } } puts("}\n"); @@ -594,7 +612,8 @@ void EmitCSyms::emitSymImp() { puts("\n"); puts("\n// FUNCTIONS\n"); - puts(symClassName()+"::"+symClassName()+"("+topClassName()+"* topp, const char* namep)\n"); + puts(symClassName() + "::" + symClassName() + "(" + topClassName() + + "* topp, const char* namep)\n"); puts(" // Setup locals\n"); puts(" : __Vm_namep(namep)\n"); // No leak, as gets destroyed when the top is destroyed if (v3Global.needTraceDumper()) { @@ -631,9 +650,7 @@ void EmitCSyms::emitSymImp() { checkSplit(false); string arrow = scopep->name(); string::size_type pos; - while ((pos = arrow.find('.')) != string::npos) { - arrow.replace(pos, 1, "->"); - } + while ((pos = arrow.find('.')) != string::npos) arrow.replace(pos, 1, "->"); if (arrow.substr(0, 5) == "TOP->") arrow.replace(0, 5, "TOPp->"); ofp()->puts(protectWordsIf(arrow, scopep->protect())); puts(" = &"); @@ -643,7 +660,7 @@ void EmitCSyms::emitSymImp() { } puts("// Setup each module's pointer back to symbol table (for public functions)\n"); - puts("TOPp->"+protect("__Vconfigure")+"(this, true);\n"); + puts("TOPp->" + protect("__Vconfigure") + "(this, true);\n"); for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* modp = it->second; @@ -652,10 +669,8 @@ void EmitCSyms::emitSymImp() { // first is used by AstCoverDecl's call to __vlCoverInsert bool first = !modp->user1(); modp->user1(true); - puts(protectIf(scopep->nameDotless(), scopep->protect()) - +"."+protect("__Vconfigure")+"(this, " - +(first?"true":"false") - +");\n"); + puts(protectIf(scopep->nameDotless(), scopep->protect()) + "." + + protect("__Vconfigure") + "(this, " + (first ? "true" : "false") + ");\n"); ++m_numStmts; } } @@ -664,20 +679,19 @@ void EmitCSyms::emitSymImp() { puts("// Setup scopes\n"); for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) { checkSplit(false); - puts(protect("__Vscope_"+it->second.m_symName) - +".configure(this, name(), "); + puts(protect("__Vscope_" + it->second.m_symName) + ".configure(this, name(), "); putsQuoted(protectWordsIf(it->second.m_prettyName, true)); puts(", "); putsQuoted(protect(scopeDecodeIdentifier(it->second.m_prettyName))); - puts(", VerilatedScope::"+it->second.m_type+");\n"); + puts(", VerilatedScope::" + it->second.m_type + ");\n"); ++m_numStmts; } } if (v3Global.opt.vpi()) { puts("\n// Setup scope hierarchy\n"); - for (ScopeNames::const_iterator it = m_scopeNames.begin(); - it != m_scopeNames.end(); ++it) { + for (ScopeNames::const_iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); + ++it) { string name = it->second.m_prettyName; if (it->first == "TOP") continue; name = name.replace(0, 4, ""); // Remove the "TOP." @@ -688,17 +702,17 @@ void EmitCSyms::emitSymImp() { for (ScopeNameHierarchy::const_iterator it = m_vpiScopeHierarchy.begin(); it != m_vpiScopeHierarchy.end(); ++it) { - for (ScopeNameList::const_iterator lit = it->second.begin(); - lit != it->second.end(); ++lit) { + for (ScopeNameList::const_iterator lit = it->second.begin(); lit != it->second.end(); + ++lit) { string fromname = scopeSymString(it->first); string toname = scopeSymString(*lit); ScopeNames::const_iterator from = m_scopeNames.find(fromname); ScopeNames::const_iterator to = m_scopeNames.find(toname); - UASSERT(from != m_scopeNames.end(), fromname+" not in m_scopeNames"); - UASSERT(to != m_scopeNames.end(), toname+" not in m_scopeNames"); + UASSERT(from != m_scopeNames.end(), fromname + " not in m_scopeNames"); + UASSERT(to != m_scopeNames.end(), toname + " not in m_scopeNames"); puts("__Vhier.add("); - puts("&"+protect("__Vscope_"+from->second.m_symName)+", "); - puts("&"+protect("__Vscope_"+to->second.m_symName)+");\n"); + puts("&" + protect("__Vscope_" + from->second.m_symName) + ", "); + puts("&" + protect("__Vscope_" + to->second.m_symName) + ");\n"); } } puts("\n"); @@ -716,7 +730,7 @@ void EmitCSyms::emitSymImp() { AstNodeModule* modp = it->second.m_modp; if (funcp->dpiExport()) { checkSplit(true); - puts(protect("__Vscope_"+scopep->scopeSymName())+".exportInsert(__Vfinal, "); + puts(protect("__Vscope_" + scopep->scopeSymName()) + ".exportInsert(__Vfinal, "); putsQuoted(funcp->cname()); // Not protected - user asked for import/export puts(", (void*)(&"); puts(prefixNameProtect(modp)); @@ -740,30 +754,40 @@ void EmitCSyms::emitSymImp() { if (AstBasicDType* basicp = varp->basicp()) { // Range is always first, it's not in "C" order if (basicp->isRanged()) { - bounds += " ,"; bounds += cvtToStr(basicp->msb()); - bounds += ","; bounds += cvtToStr(basicp->lsb()); + bounds += " ,"; + bounds += cvtToStr(basicp->msb()); + bounds += ","; + bounds += cvtToStr(basicp->lsb()); pdim++; } - for (AstNodeDType* dtypep = varp->dtypep(); dtypep; ) { - dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node + for (AstNodeDType* dtypep = varp->dtypep(); dtypep;) { + dtypep + = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) { - bounds += " ,"; bounds += cvtToStr(adtypep->msb()); - bounds += ","; bounds += cvtToStr(adtypep->lsb()); - if (VN_IS(dtypep, PackArrayDType)) pdim++; else udim++; + bounds += " ,"; + bounds += cvtToStr(adtypep->msb()); + bounds += ","; + bounds += cvtToStr(adtypep->lsb()); + if (VN_IS(dtypep, PackArrayDType)) { + pdim++; + } else { + udim++; + } dtypep = adtypep->subDTypep(); + } else { + break; // AstBasicDType - nothing below, 1 } - else break; // AstBasicDType - nothing below, 1 } } // - if (pdim>1 || udim>1) { + if (pdim > 1 || udim > 1) { puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays } - puts(protect("__Vscope_"+it->second.m_scopeName)+".varInsert(__Vfinal,"); + puts(protect("__Vscope_" + it->second.m_scopeName) + ".varInsert(__Vfinal,"); putsQuoted(protect(it->second.m_varBasePretty)); puts(", &("); if (modp->isTop()) { - puts(protectIf(scopep->nameDotless()+"p", scopep->protect())); + puts(protectIf(scopep->nameDotless() + "p", scopep->protect())); puts("->"); } else { puts(protectIf(scopep->nameDotless(), scopep->protect())); @@ -775,7 +799,7 @@ void EmitCSyms::emitSymImp() { puts(","); puts(varp->vlEnumDir()); // VLVD_IN etc puts(","); - puts(cvtToStr(pdim+udim)); + puts(cvtToStr(pdim + udim)); puts(bounds); puts(");\n"); ++m_numStmts; @@ -791,15 +815,16 @@ void EmitCSyms::emitSymImp() { //###################################################################### void EmitCSyms::emitDpiHdr() { - UINFO(6,__FUNCTION__<<": "<support(true); - V3OutCFile hf (filename); + V3OutCFile hf(filename); m_ofp = &hf; m_ofp->putsHeader(); - puts("// DESCR" "IPTION: Verilator output: Prototypes for DPI import and export functions.\n"); + puts("// DESCR" + "IPTION: Verilator output: Prototypes for DPI import and export functions.\n"); puts("//\n"); puts("// Verilator includes this file in all generated .cpp files that use DPI functions.\n"); puts("// Manually include this file where DPI .c import functions are declared to ensure\n"); @@ -818,15 +843,14 @@ void EmitCSyms::emitDpiHdr() { AstCFunc* nodep = *it; if (nodep->dpiExportWrapper()) { if (!firstExp++) puts("\n// DPI EXPORTS\n"); - puts("// DPI export"+ifNoProtect(" at "+nodep->fileline()->ascii())+"\n"); - puts("extern "+nodep->rtnTypeVoid()+" "+nodep->nameProtect() - +"("+cFuncArgs(nodep)+");\n"); - } - else if (nodep->dpiImport()) { + puts("// DPI export" + ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n"); + puts("extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "(" + + cFuncArgs(nodep) + ");\n"); + } else if (nodep->dpiImport()) { if (!firstImp++) puts("\n// DPI IMPORTS\n"); - puts("// DPI import"+ifNoProtect(" at "+nodep->fileline()->ascii())+"\n"); - puts("extern "+nodep->rtnTypeVoid()+" "+nodep->nameProtect() - +"("+cFuncArgs(nodep)+");\n"); + puts("// DPI import" + ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n"); + puts("extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "(" + + cFuncArgs(nodep) + ");\n"); } } @@ -839,49 +863,50 @@ void EmitCSyms::emitDpiHdr() { //###################################################################### void EmitCSyms::emitDpiImp() { - UINFO(6,__FUNCTION__<<": "<support(true); - V3OutCFile hf (filename); + V3OutCFile hf(filename); m_ofp = &hf; m_ofp->putsHeader(); - puts("// DESCR" "IPTION: Verilator output: Implementation of DPI export functions.\n"); + puts("// DESCR" + "IPTION: Verilator output: Implementation of DPI export functions.\n"); puts("//\n"); puts("// Verilator compiles this file in when DPI functions are used.\n"); puts("// If you have multiple Verilated designs with the same DPI exported\n"); puts("// function names, you will get multiple definition link errors from here.\n"); puts("// This is an unfortunate result of the DPI specification.\n"); puts("// To solve this, either\n"); - puts("// 1. Call "+topClassName()+"::{export_function} instead,\n"); + puts("// 1. Call " + topClassName() + "::{export_function} instead,\n"); puts("// and do not even bother to compile this file\n"); puts("// or 2. Compile all __Dpi.cpp files in the same compiler run,\n"); puts("// and #ifdefs already inserted here will sort everything out.\n"); puts("\n"); - puts("#include \""+topClassName()+"__Dpi.h\"\n"); - puts("#include \""+topClassName()+".h\"\n"); + puts("#include \"" + topClassName() + "__Dpi.h\"\n"); + puts("#include \"" + topClassName() + ".h\"\n"); puts("\n"); for (std::vector::iterator it = m_dpis.begin(); it != m_dpis.end(); ++it) { AstCFunc* nodep = *it; if (nodep->dpiExportWrapper()) { - puts("#ifndef _VL_DPIDECL_"+nodep->name()+"\n"); - puts("#define _VL_DPIDECL_"+nodep->name()+"\n"); - puts(nodep->rtnTypeVoid()+" "+nodep->name()+"("+cFuncArgs(nodep)+") {\n"); - puts("// DPI export"+ifNoProtect(" at "+nodep->fileline()->ascii())+"\n"); - puts("return "+topClassName()+"::"+nodep->name()+"("); + puts("#ifndef _VL_DPIDECL_" + nodep->name() + "\n"); + puts("#define _VL_DPIDECL_" + nodep->name() + "\n"); + puts(nodep->rtnTypeVoid() + " " + nodep->name() + "(" + cFuncArgs(nodep) + ") {\n"); + puts("// DPI export" + ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n"); + puts("return " + topClassName() + "::" + nodep->name() + "("); string args; - for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) { if (const AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO() && !portp->isFuncReturn()) { - if (args != "") args+= ", "; + if (args != "") args += ", "; args += portp->name(); } } } - puts(args+");\n"); + puts(args + ");\n"); puts("}\n"); puts("#endif\n"); puts("\n"); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 28a0a6acc..36a54708b 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -25,6 +25,7 @@ #include "V3File.h" #include "V3PreShell.h" +// clang-format off #include #include #ifndef _WIN32 @@ -43,6 +44,7 @@ #if defined(_WIN32) || defined(__MINGW32__) # include // open, close #endif +// clang-format on //###################################################################### // V3 Internal state @@ -50,18 +52,18 @@ class V3OptionsImp { public: // TYPES - typedef std::map > DirMap; // Directory listing + typedef std::map > DirMap; // Directory listing // STATE - std::list m_allArgs; // List of every argument encountered - std::list m_incDirUsers; // Include directories (ordered) - std::set m_incDirUserSet; // Include directories (for removing duplicates) - std::list m_incDirFallbacks; // Include directories (ordered) - std::set m_incDirFallbackSet; // Include directories (for removing duplicates) - std::map m_langExts; // Language extension map - std::list m_libExtVs; // Library extensions (ordered) - std::set m_libExtVSet; // Library extensions (for removing duplicates) - DirMap m_dirMap; // Directory listing + std::list m_allArgs; // List of every argument encountered + std::list m_incDirUsers; // Include directories (ordered) + std::set m_incDirUserSet; // Include directories (for removing duplicates) + std::list m_incDirFallbacks; // Include directories (ordered) + std::set m_incDirFallbackSet; // Include directories (for removing duplicates) + std::map m_langExts; // Language extension map + std::list m_libExtVs; // Library extensions (ordered) + std::set m_libExtVSet; // Library extensions (for removing duplicates) + DirMap m_dirMap; // Directory listing // ACCESSOR METHODS void addIncDirUser(const string& incdir) { @@ -74,7 +76,8 @@ public: } } void addIncDirFallback(const string& incdir) { - if (m_incDirUserSet.find(incdir) == m_incDirUserSet.end()) { // User has priority over Fallback + if (m_incDirUserSet.find(incdir) + == m_incDirUserSet.end()) { // User has priority over Fallback if (m_incDirFallbackSet.find(incdir) == m_incDirFallbackSet.end()) { // cppcheck-suppress stlFindInsert // cppcheck 1.90 bug m_incDirFallbackSet.insert(incdir); @@ -117,18 +120,12 @@ V3LangCode::V3LangCode(const char* textp) { //###################################################################### // V3Options class functions -void V3Options::addIncDirUser(const string& incdir) { - m_impp->addIncDirUser(incdir); -} -void V3Options::addIncDirFallback(const string& incdir) { - m_impp->addIncDirFallback(incdir); -} +void V3Options::addIncDirUser(const string& incdir) { m_impp->addIncDirUser(incdir); } +void V3Options::addIncDirFallback(const string& incdir) { m_impp->addIncDirFallback(incdir); } void V3Options::addLangExt(const string& langext, const V3LangCode& lc) { m_impp->addLangExt(langext, lc); } -void V3Options::addLibExtV(const string& libext) { - m_impp->addLibExtV(libext); -} +void V3Options::addLibExtV(const string& libext) { m_impp->addLibExtV(libext); } void V3Options::addDefine(const string& defline, bool allowPlus) { // Split +define+foo=value into the appropriate parts and parse // Optional + says to allow multiple defines on the line @@ -138,14 +135,14 @@ void V3Options::addDefine(const string& defline, bool allowPlus) { string def = left; string::size_type pos; if (allowPlus && ((pos = left.find('+')) != string::npos)) { - left = left.substr(pos+1); + left = left.substr(pos + 1); def.erase(pos); } else { left = ""; } string value; if ((pos = def.find('=')) != string::npos) { - value = def.substr(pos+1); + value = def.substr(pos + 1); def.erase(pos); } V3PreShell::defineCmdLine(def, value); @@ -160,17 +157,17 @@ void V3Options::addParameter(const string& paramline, bool allowPlus) { string param = left; string::size_type pos; if (allowPlus && ((pos = left.find('+')) != string::npos)) { - left = left.substr(pos+1); + left = left.substr(pos + 1); param.erase(pos); } else { left = ""; } string value; if ((pos = param.find('=')) != string::npos) { - value = param.substr(pos+1); + value = param.substr(pos + 1); param.erase(pos); } - UINFO(4,"Add parameter"<::iterator it = m_parameters.begin(); - it != m_parameters.end(); ++it) { + for (std::map::iterator it = m_parameters.begin(); + it != m_parameters.end(); ++it) { msg << " " << it->first; } v3error(msg.str()); } } -void V3Options::addCppFile(const string& filename) { - m_cppFiles.insert(filename); -} -void V3Options::addCFlags(const string& filename) { - m_cFlags.push_back(filename); -} -void V3Options::addLdLibs(const string& filename) { - m_ldLibs.push_back(filename); -} -void V3Options::addFuture(const string& flag) { - m_futures.insert(flag); -} +void V3Options::addCppFile(const string& filename) { m_cppFiles.insert(filename); } +void V3Options::addCFlags(const string& filename) { m_cFlags.push_back(filename); } +void V3Options::addLdLibs(const string& filename) { m_ldLibs.push_back(filename); } +void V3Options::addFuture(const string& flag) { m_futures.insert(flag); } bool V3Options::isFuture(const string& flag) const { return m_futures.find(flag) != m_futures.end(); } bool V3Options::isLibraryFile(const string& filename) const { return m_libraryFiles.find(filename) != m_libraryFiles.end(); } -void V3Options::addLibraryFile(const string& filename) { - m_libraryFiles.insert(filename); -} +void V3Options::addLibraryFile(const string& filename) { m_libraryFiles.insert(filename); } bool V3Options::isClocker(const string& signame) const { return m_clockers.find(signame) != m_clockers.end(); } -void V3Options::addClocker(const string& signame) { - m_clockers.insert(signame); -} +void V3Options::addClocker(const string& signame) { m_clockers.insert(signame); } bool V3Options::isNoClocker(const string& signame) const { return m_noClockers.find(signame) != m_noClockers.end(); } -void V3Options::addNoClocker(const string& signame) { - m_noClockers.insert(signame); -} +void V3Options::addNoClocker(const string& signame) { m_noClockers.insert(signame); } void V3Options::addVFile(const string& filename) { // We use a list for v files, because it's legal to have includes // in a specific order and multiple of them. m_vFiles.push_back(filename); } -void V3Options::addForceInc(const string& filename) { - m_forceIncs.push_back(filename); -} +void V3Options::addForceInc(const string& filename) { m_forceIncs.push_back(filename); } -void V3Options::addArg(const string& arg) { - m_impp->m_allArgs.push_back(arg); -} +void V3Options::addArg(const string& arg) { m_impp->m_allArgs.push_back(arg); } string V3Options::allArgsString() { string out; @@ -261,7 +240,7 @@ bool V3Options::fileStatDir(const string& filename) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) struct stat sstat; // Stat information int err = stat(filename.c_str(), &sstat); - if (err!=0) return false; + if (err != 0) return false; if (!S_ISDIR(sstat.st_mode)) return false; return true; } @@ -270,7 +249,7 @@ bool V3Options::fileStatNormal(const string& filename) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) struct stat sstat; // Stat information int err = stat(filename.c_str(), &sstat); - if (err!=0) return false; + if (err != 0) return false; if (S_ISDIR(sstat.st_mode)) return false; return true; } @@ -282,7 +261,7 @@ void V3Options::fileNfsFlush(const string& filename) { if (DIR* dirp = opendir(filename.c_str())) { closedir(dirp); } else if (int fd = ::open(filename.c_str(), O_RDONLY)) { - if (fd>0) ::close(fd); + if (fd > 0) ::close(fd); } } @@ -297,16 +276,13 @@ string V3Options::fileExists(const string& filename) { V3OptionsImp::DirMap::iterator diriter = m_impp->m_dirMap.find(dir); if (diriter == m_impp->m_dirMap.end()) { // Read the listing - m_impp->m_dirMap.insert(std::make_pair(dir, std::set() )); + m_impp->m_dirMap.insert(std::make_pair(dir, std::set())); diriter = m_impp->m_dirMap.find(dir); std::set* setp = &(diriter->second); if (DIR* dirp = opendir(dir.c_str())) { - while (struct dirent* direntp = readdir(dirp)) { - - setp->insert(direntp->d_name); - } + while (struct dirent* direntp = readdir(dirp)) setp->insert(direntp->d_name); closedir(dirp); } } @@ -323,13 +299,13 @@ string V3Options::fileExists(const string& filename) { } string V3Options::filePathCheckOneDir(const string& modname, const string& dirname) { - for (std::list::iterator extIter=m_impp->m_libExtVs.begin(); + for (std::list::iterator extIter = m_impp->m_libExtVs.begin(); extIter != m_impp->m_libExtVs.end(); ++extIter) { - string fn = V3Os::filenameFromDirBase(dirname, modname+*extIter); + string fn = V3Os::filenameFromDirBase(dirname, modname + *extIter); string exists = fileExists(fn); - if (exists!="") { + if (exists != "") { // Strip ./, it just looks ugly - if (exists.substr(0, 2)=="./") exists.erase(0, 2); + if (exists.substr(0, 2) == "./") exists.erase(0, 2); return exists; } } @@ -341,25 +317,25 @@ string V3Options::filePath(FileLine* fl, const string& modname, const string& la // Find a filename to read the specified module name, // using the incdir and libext's. // Return "" if not found. - for (std::list::iterator dirIter=m_impp->m_incDirUsers.begin(); - dirIter!=m_impp->m_incDirUsers.end(); ++dirIter) { + for (std::list::iterator dirIter = m_impp->m_incDirUsers.begin(); + dirIter != m_impp->m_incDirUsers.end(); ++dirIter) { string exists = filePathCheckOneDir(modname, *dirIter); - if (exists!="") return exists; + if (exists != "") return exists; } - for (std::list::iterator dirIter=m_impp->m_incDirFallbacks.begin(); - dirIter!=m_impp->m_incDirFallbacks.end(); ++dirIter) { + for (std::list::iterator dirIter = m_impp->m_incDirFallbacks.begin(); + dirIter != m_impp->m_incDirFallbacks.end(); ++dirIter) { string exists = filePathCheckOneDir(modname, *dirIter); - if (exists!="") return exists; + if (exists != "") return exists; } if (m_relativeIncludes) { string exists = filePathCheckOneDir(modname, lastpath); - if (exists!="") return V3Os::filenameRealPath(exists); + if (exists != "") return V3Os::filenameRealPath(exists); } // Warn and return not found if (errmsg != "") { - fl->v3error(errmsg+modname); + fl->v3error(errmsg + modname); filePathLookedMsg(fl, modname); } return ""; @@ -375,23 +351,24 @@ void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) { } else if (!shown_notfound_msg) { shown_notfound_msg = true; if (m_impp->m_incDirUsers.empty()) { - fl->v3error("This may be because there's no search path specified with -I."<v3error("This may be because there's no search path specified with -I." + << endl); } - std::cerr<::iterator dirIter=m_impp->m_incDirUsers.begin(); - dirIter!=m_impp->m_incDirUsers.end(); ++dirIter) { - for (std::list::iterator extIter=m_impp->m_libExtVs.begin(); + std::cerr << V3Error::warnMore() << "... Looked in:" << endl; + for (std::list::iterator dirIter = m_impp->m_incDirUsers.begin(); + dirIter != m_impp->m_incDirUsers.end(); ++dirIter) { + for (std::list::iterator extIter = m_impp->m_libExtVs.begin(); extIter != m_impp->m_libExtVs.end(); ++extIter) { - string fn = V3Os::filenameFromDirBase(*dirIter, modname+*extIter); - std::cerr<::iterator dirIter=m_impp->m_incDirFallbacks.begin(); - dirIter!=m_impp->m_incDirFallbacks.end(); ++dirIter) { - for (std::list::iterator extIter=m_impp->m_libExtVs.begin(); + for (std::list::iterator dirIter = m_impp->m_incDirFallbacks.begin(); + dirIter != m_impp->m_incDirFallbacks.end(); ++dirIter) { + for (std::list::iterator extIter = m_impp->m_libExtVs.begin(); extIter != m_impp->m_libExtVs.end(); ++extIter) { - string fn = V3Os::filenameFromDirBase(*dirIter, modname+*extIter); - std::cerr<::iterator it = m_impp->m_langExts.find(ext); - if (it != m_impp->m_langExts.end()) { - return it->second; - } + std::map::iterator it = m_impp->m_langExts.find(ext); + if (it != m_impp->m_langExts.end()) return it->second; } return m_defaultLanguage; } - //###################################################################### // Environment string V3Options::getenvBuiltins(const string& var) { - if (var == "PERL") return getenvPERL(); - else if (var == "SYSTEMC") return getenvSYSTEMC(); - else if (var == "SYSTEMC_ARCH") return getenvSYSTEMC_ARCH(); - else if (var == "SYSTEMC_INCLUDE") return getenvSYSTEMC_INCLUDE(); - else if (var == "SYSTEMC_LIBDIR") return getenvSYSTEMC_LIBDIR(); - else if (var == "VERILATOR_ROOT") return getenvVERILATOR_ROOT(); - else { + if (var == "PERL") { + return getenvPERL(); + } else if (var == "SYSTEMC") { + return getenvSYSTEMC(); + } else if (var == "SYSTEMC_ARCH") { + return getenvSYSTEMC_ARCH(); + } else if (var == "SYSTEMC_INCLUDE") { + return getenvSYSTEMC_INCLUDE(); + } else if (var == "SYSTEMC_LIBDIR") { + return getenvSYSTEMC_LIBDIR(); + } else if (var == "VERILATOR_ROOT") { + return getenvVERILATOR_ROOT(); + } else { return V3Os::getenvStr(var, ""); } } -string V3Options::getenvPERL() { +string V3Options::getenvPERL() { // return V3Os::getenvStr("PERL", "perl"); } @@ -450,11 +430,11 @@ string V3Options::getenvSYSTEMC_ARCH() { V3Os::setenvStr("SYSTEMC_ARCH", var, "Hardcoded at build time"); } if (var == "") { -#if defined (__MINGW32__) +#if defined(__MINGW32__) // Hardcoded with MINGW current version. Would like a better way. string sysname = "MINGW32_NT-5.0"; var = "mingw32"; -#elif defined (_WIN32) +#elif defined(_WIN32) string sysname = "WIN32"; var = "win32"; #else @@ -462,11 +442,15 @@ string V3Options::getenvSYSTEMC_ARCH() { struct utsname uts; uname(&uts); string sysname = VString::downcase(uts.sysname); // aka 'uname -s' - if (VString::wildmatch(sysname.c_str(), "*solaris*")) { var = "gccsparcOS5"; } - else if (VString::wildmatch(sysname.c_str(), "*cygwin*")) { var = "cygwin"; } - else { var = "linux"; } + if (VString::wildmatch(sysname.c_str(), "*solaris*")) { + var = "gccsparcOS5"; + } else if (VString::wildmatch(sysname.c_str(), "*cygwin*")) { + var = "cygwin"; + } else { + var = "linux"; + } #endif - V3Os::setenvStr("SYSTEMC_ARCH", var, "From sysname '"+sysname+"'"); + V3Os::setenvStr("SYSTEMC_ARCH", var, "From sysname '" + sysname + "'"); } return var; } @@ -479,7 +463,7 @@ string V3Options::getenvSYSTEMC_INCLUDE() { } if (var == "") { string sc = getenvSYSTEMC(); - if (sc != "") var = sc+"/include"; + if (sc != "") var = sc + "/include"; } // Only correct or check it if we really need the value if (v3Global.opt.usingSystemCLibs()) { @@ -500,7 +484,7 @@ string V3Options::getenvSYSTEMC_LIBDIR() { if (var == "") { string sc = getenvSYSTEMC(); string arch = getenvSYSTEMC_ARCH(); - if (sc != "" && arch != "") var = sc+"/lib-"+arch; + if (sc != "" && arch != "") var = sc + "/lib-" + arch; } // Only correct or check it if we really need the value if (v3Global.opt.usingSystemCLibs()) { @@ -518,9 +502,7 @@ string V3Options::getenvVERILATOR_ROOT() { var = DEFENV_VERILATOR_ROOT; V3Os::setenvStr("VERILATOR_ROOT", var, "Hardcoded at build time"); } - if (var == "") { - v3fatal("$VERILATOR_ROOT needs to be in environment\n"); - } + if (var == "") v3fatal("$VERILATOR_ROOT needs to be in environment\n"); return var; } @@ -529,55 +511,49 @@ string V3Options::getenvVERILATOR_ROOT() { void V3Options::notify() { // Notify that all arguments have been passed and final modification can be made. - if (!outFormatOk() - && !cdc() - && !dpiHdrOnly() - && !lintOnly() - && !preprocOnly() - && !xmlOnly()) { - v3fatal("verilator: Need --cc, --sc, --cdc, --dpi-hdr-only, --lint-only, --xml-only or --E option"); + if (!outFormatOk() && !cdc() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !xmlOnly()) { + v3fatal("verilator: Need --cc, --sc, --cdc, --dpi-hdr-only, --lint-only, " + "--xml-only or --E option"); } // Make sure at least one make system is enabled - if (!m_gmake && !m_cmake) { - m_gmake = true; - } + if (!m_gmake && !m_cmake) m_gmake = true; if (protectIds()) { FileLine* cmdfl = new FileLine(FileLine::commandLineFilename()); if (allPublic()) { // We always call protect() on names, we don't check if public or not // Hence any external references wouldn't be able to find the refed public object. - cmdfl->v3error("Unsupported: Using --protect-ids with --public\n" - +V3Error::warnMore()+"... Suggest remove --public."); + cmdfl->v3error("Unsupported: Using --protect-ids with --public\n" // + + V3Error::warnMore() + "... Suggest remove --public."); } if (trace()) { cmdfl->v3warn(INSECURE, "Using --protect-ids with --trace may expose private design details\n" - +V3Error::warnMore()+"... Suggest remove --trace."); + + V3Error::warnMore() + "... Suggest remove --trace."); } if (vpi()) { cmdfl->v3warn(INSECURE, "Using --protect-ids with --vpi may expose private design details\n" - +V3Error::warnMore()+"... Suggest remove --vpi."); + + V3Error::warnMore() + "... Suggest remove --vpi."); } } // Default some options if not turned on or off if (v3Global.opt.skipIdentical().isDefault()) { - v3Global.opt.m_skipIdentical.setTrueOrFalse( - !v3Global.opt.cdc() - && !v3Global.opt.dpiHdrOnly() - && !v3Global.opt.lintOnly() - && !v3Global.opt.preprocOnly() + v3Global.opt.m_skipIdentical.setTrueOrFalse( // + !v3Global.opt.cdc() // + && !v3Global.opt.dpiHdrOnly() // + && !v3Global.opt.lintOnly() // + && !v3Global.opt.preprocOnly() // && !v3Global.opt.xmlOnly()); } if (v3Global.opt.makeDepend().isDefault()) { - v3Global.opt.m_makeDepend.setTrueOrFalse( - !v3Global.opt.cdc() - && !v3Global.opt.dpiHdrOnly() - && !v3Global.opt.lintOnly() - && !v3Global.opt.preprocOnly() + v3Global.opt.m_makeDepend.setTrueOrFalse( // + !v3Global.opt.cdc() // + && !v3Global.opt.dpiHdrOnly() // + && !v3Global.opt.lintOnly() // + && !v3Global.opt.preprocOnly() // && !v3Global.opt.xmlOnly()); } } @@ -587,7 +563,7 @@ void V3Options::notify() { string V3Options::version() { string ver = DTVERSION; - ver += " rev "+cvtToStr(DTVERSION_rev); + ver += " rev " + cvtToStr(DTVERSION_rev); return ver; } @@ -595,15 +571,17 @@ string V3Options::protectKeyDefaulted() { if (m_protectKey.empty()) { // Create a key with a human-readable symbol-like name. // This conversion drops ~2 bits of entropy out of 256, shouldn't matter. - VHashSha256 digest (V3Os::trueRandom(32)); - m_protectKey = "VL-KEY-"+digest.digestSymbol(); + VHashSha256 digest(V3Os::trueRandom(32)); + m_protectKey = "VL-KEY-" + digest.digestSymbol(); } return m_protectKey; } void V3Options::throwSigsegv() { #if !(defined(VL_CPPCHECK) || defined(__clang_analyzer__)) - char* zp=NULL; *zp=0; // Intentional core dump, ignore warnings here + // clang-format off + { char* zp = NULL; *zp = 0; } // Intentional core dump, ignore warnings here + // clang-format on #endif } @@ -613,8 +591,8 @@ void V3Options::throwSigsegv() { string V3Options::argString(int argc, char** argv) { // Return list of arguments as simple string string opts; - for (int i=0; i=1) { - m_prefix = string("V")+V3Os::filenameNonExt(*(vFilesList.begin())); + if (prefix() == "" && topModule() != "") m_prefix = string("V") + topModule(); + if (prefix() == "" && vFilesList.size() >= 1) { + m_prefix = string("V") + V3Os::filenameNonExt(*(vFilesList.begin())); } - if (modPrefix()=="") m_modPrefix = prefix(); + if (modPrefix() == "") m_modPrefix = prefix(); // Find files in makedir addIncDirFallback(makeDir()); @@ -653,10 +632,17 @@ bool V3Options::onoff(const char* sw, const char* arg, bool& flag) { // if sw=="-no-arg", then return true (found it), and flag=false // if sw=="-noarg", then return true (found it), and flag=false // else return false - if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash"); - if (0==strcmp(sw, arg)) { flag = true; return true; } - else if (0==strncmp(sw, "-no", 3) && (0==strcmp(sw+3, arg+1))) { flag = false; return true; } - else if (0==strncmp(sw, "-no-", 4) && (0==strcmp(sw+4, arg+1))) { flag = false; return true; } + if (arg[0] != '-') v3fatalSrc("OnOff switches must have leading dash"); + if (0 == strcmp(sw, arg)) { + flag = true; + return true; + } else if (0 == strncmp(sw, "-no", 3) && (0 == strcmp(sw + 3, arg + 1))) { + flag = false; + return true; + } else if (0 == strncmp(sw, "-no-", 4) && (0 == strcmp(sw + 4, arg + 1))) { + flag = false; + return true; + } return false; } bool V3Options::onoffb(const char* sw, const char* arg, VOptionBool& flagr) { @@ -671,66 +657,64 @@ bool V3Options::onoffb(const char* sw, const char* arg, VOptionBool& flagr) { bool V3Options::suffixed(const string& sw, const char* arg) { if (strlen(arg) > sw.length()) return false; - return (0==strcmp(sw.c_str()+sw.length()-strlen(arg), arg)); + return (0 == strcmp(sw.c_str() + sw.length() - strlen(arg), arg)); } void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv) { // Parse parameters // Note argc and argv DO NOT INCLUDE the filename in [0]!!! // May be called recursively when there are -f files. - for (int i=0; iv3fatal("Invalid Option: "<v3fatal("Invalid Option: " << argv[i]); } shift; - } // + options - else if (argv[i][0]=='-') { + } + // - options + else if (argv[i][0] == '-') { const char* sw = argv[i]; bool flag = true; VOptionBool bflag; // Allow gnu -- switches - if (sw[0]=='-' && sw[1]=='-') ++sw; + if (sw[0] == '-' && sw[1] == '-') ++sw; bool hadSwitchPart1 = true; // Single switches + // clang-format off if (!strcmp(sw, "-E")) { m_preprocOnly = true; } else if ( onoffb(sw, "-MMD", bflag/*ref*/)) { m_makeDepend = bflag; } else if ( onoff (sw, "-MP", flag/*ref*/)) { m_makePhony = flag; } @@ -804,10 +788,12 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if ( onoff (sw, "-x-initial-edge", flag/*ref*/)) { m_xInitialEdge = flag; } else if ( onoff (sw, "-xml-only", flag/*ref*/)) { m_xmlOnly = flag; } // Undocumented, still experimental else { hadSwitchPart1 = false; } - if (hadSwitchPart1) {} - // Optimization - else if (!strncmp (sw, "-O", 2)) { - for (const char* cp=sw+strlen("-O"); *cp; ++cp) { + // clang-format on + + if (hadSwitchPart1) { + } else if (!strncmp(sw, "-O", 2)) { + // Optimization + for (const char* cp = sw + strlen("-O"); *cp; ++cp) { flag = isupper(*cp); switch (tolower(*cp)) { case '0': optimize(0); break; // 0=all off @@ -824,7 +810,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char case 'i': m_oInline = flag; break; case 'k': m_oSubstConst = flag; break; case 'l': m_oLife = flag; break; - case 'p': m_public = !flag; break; // With -Op so flag=0, we want public on so few optimizations done + case 'p': + m_public = !flag; + break; // With -Op so flag=0, we want public on so few optimizations done case 'r': m_oReorder = flag; break; case 's': m_oSplit = flag; break; case 't': m_oLifePost = flag; break; @@ -833,277 +821,219 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char case 'x': m_oExpand = flag; break; case 'y': m_oAcycSimp = flag; break; case 'z': m_oLocalize = flag; break; - default: break; // No error, just ignore + default: break; // No error, just ignore } } } // Parameterized switches - else if (!strcmp(sw, "-CFLAGS") && (i+1)v3fatal("Unknown --make system specified: '"<v3fatal("Unknown --make system specified: '" << argv[i] << "'"); } - } - else if (!strcmp(sw, "-max-num-width")) { + } else if (!strcmp(sw, "-max-num-width")) { shift; m_maxNumWidth = atoi(argv[i]); - } - else if (!strcmp(sw, "-no-l2name")) { // Historical and undocumented + } else if (!strcmp(sw, "-no-l2name")) { // Historical and undocumented m_l2Name = ""; - } - else if ((!strcmp(sw, "-language") && (i+1)v3fatal("Unknown language specified: "<v3fatal("Unknown language specified: " << argv[i]); } - } - else if (!strcmp(sw, "-Mdir") && (i+1)m_outputSplitCFuncs)) { + if (m_outputSplitCFuncs + && (!m_outputSplitCTrace || m_outputSplitCTrace > m_outputSplitCFuncs)) { m_outputSplitCTrace = m_outputSplitCFuncs; } - } - else if (!strcmp(sw, "-output-split-ctrace")) { // Undocumented optimization tweak + } else if (!strcmp(sw, "-output-split-ctrace")) { // Undocumented optimization tweak shift; m_outputSplitCTrace = atoi(argv[i]); - } - else if (!strcmp(sw, "-protect-lib") && (i+1)v3fatal("Unknown warning specified: "<v3fatal("Unknown warning specified: " << sw); } } else { V3Error::pretendError(code, true); } - } - else if (!strncmp (sw, "-Wfuture-", strlen("-Wfuture-"))) { - string msg = sw+strlen("-Wfuture-"); + } else if (!strncmp(sw, "-Wfuture-", strlen("-Wfuture-"))) { + string msg = sw + strlen("-Wfuture-"); // Note it may not be a future option, but one that is currently implemented. addFuture(msg); - } - else if (!strncmp (sw, "-Wno-", 5)) { + } else if (!strncmp(sw, "-Wno-", 5)) { if (!strcmp(sw, "-Wno-context")) { m_context = false; - } - else if (!strcmp(sw, "-Wno-fatal")) { + } else if (!strcmp(sw, "-Wno-fatal")) { V3Error::warnFatal(false); - } - else if (!strcmp(sw, "-Wno-lint")) { + } else if (!strcmp(sw, "-Wno-lint")) { FileLine::globalWarnLintOff(true); FileLine::globalWarnStyleOff(true); - } - else if (!strcmp(sw, "-Wno-style")) { + } else if (!strcmp(sw, "-Wno-style")) { FileLine::globalWarnStyleOff(true); - } - else { - string msg = sw+strlen("-Wno-"); + } else { + string msg = sw + strlen("-Wno-"); if (!(FileLine::globalWarnOff(msg, true))) { - fl->v3fatal("Unknown warning specified: "<v3fatal("Unknown warning specified: " << sw); } } - } - else if (!strncmp (sw, "-Wwarn-", 5)) { + } else if (!strncmp(sw, "-Wwarn-", 5)) { if (!strcmp(sw, "-Wwarn-lint")) { FileLine::globalWarnLintOff(false); - } - else if (!strcmp(sw, "-Wwarn-style")) { + } else if (!strcmp(sw, "-Wwarn-style")) { FileLine::globalWarnStyleOff(false); - } - else { - string msg = sw+strlen("-Wwarn-"); - V3ErrorCode code (msg.c_str()); + } else { + string msg = sw + strlen("-Wwarn-"); + V3ErrorCode code(msg.c_str()); if (code == V3ErrorCode::EC_ERROR) { - if (!isFuture(msg)) { - fl->v3fatal("Unknown warning specified: "<v3fatal("Unknown warning specified: " << sw); } } else { FileLine::globalWarnOff(code, false); V3Error::pretendError(code, false); } } - } - else if (!strcmp(sw, "-bin") && (i+1)v3fatal("Unknown setting for --compiler: "<v3fatal("Unknown setting for --compiler: " << argv[i]); } - } - else if (!strcmp(sw, "-F") && (i+1) 65) fl->v3fatal("--pins-bv maximum is 65: "<v3fatal("--threads must be >= 0: "< 65) fl->v3fatal("--pins-bv maximum is 65: " << argv[i]); + } else if (!strcmp(sw, "-pipe-filter") && (i + 1) < argc) { + shift; + m_pipeFilter = argv[i]; + } else if (!strcmp(sw, "-prefix") && (i + 1) < argc) { + shift; + m_prefix = argv[i]; + if (m_modPrefix == "") m_modPrefix = m_prefix; + } else if (!strcmp(sw, "-protect-key") && (i + 1) < argc) { + shift; + m_protectKey = argv[i]; + } else if (!strcmp(sw, "-no-threads")) { + m_threads = 0; + } else if (!strcmp(sw, "-threads") && (i + 1) < argc) { + shift; + m_threads = atoi(argv[i]); + if (m_threads < 0) fl->v3fatal("--threads must be >= 0: " << argv[i]); + } else if (!strcmp(sw, "-threads-dpi") && (i + 1) < argc) { shift; if (!strcmp(argv[i], "all")) { - m_threadsDpiPure = true; m_threadsDpiUnpure = true; + m_threadsDpiPure = true; + m_threadsDpiUnpure = true; } else if (!strcmp(argv[i], "none")) { - m_threadsDpiPure = false; m_threadsDpiUnpure = false; + m_threadsDpiPure = false; + m_threadsDpiUnpure = false; } else if (!strcmp(argv[i], "pure")) { - m_threadsDpiPure = true; m_threadsDpiUnpure = false; + m_threadsDpiPure = true; + m_threadsDpiUnpure = false; } else { - fl->v3fatal("Unknown setting for --threads-dpi: "<v3fatal("Unknown setting for --threads-dpi: " << argv[i]); } - } - else if (!strcmp(sw, "-threads-max-mtasks")) { - shift; m_threadsMaxMTasks = atoi(argv[i]); + } else if (!strcmp(sw, "-threads-max-mtasks")) { + shift; + m_threadsMaxMTasks = atoi(argv[i]); if (m_threadsMaxMTasks < 1) - fl->v3fatal("--threads-max-mtasks must be >= 1: "<v3fatal("--threads-max-mtasks must be >= 1: " << argv[i]); + } else if (!strcmp(sw, "-top-module") && (i + 1) < argc) { shift; - if (!strcmp(argv[i], "0")) { m_xAssign = "0"; } - else if (!strcmp(argv[i], "1")) { m_xAssign = "1"; } - else if (!strcmp(argv[i], "fast")) { m_xAssign = "fast"; } - else if (!strcmp(argv[i], "unique")) { m_xAssign = "unique"; } - else { - fl->v3fatal("Unknown setting for --x-assign: "<v3fatal("Unknown setting for --x-initial: "<v3fatal("Unknown setting for --x-assign: " << argv[i]); } - } - else if (!strcmp(sw, "-xml-output") && (i+1)v3fatal("Unknown setting for --x-initial: " << argv[i]); + } + } else if (!strcmp(sw, "-xml-output") && (i + 1) < argc) { + shift; + m_xmlOutput = argv[i]; m_xmlOnly = true; - } - else if (!strcmp(sw, "-y") && (i+1)v3fatal("Invalid Option: "<v3fatal("Invalid Option: " << argv[i]); } shift; } // - options else { // Filename string filename = parseFileArg(optdir, argv[i]); - if (suffixed(filename, ".cpp") - || suffixed(filename, ".cxx") - || suffixed(filename, ".cc") - || suffixed(filename, ".c") + if (suffixed(filename, ".cpp") // + || suffixed(filename, ".cxx") // + || suffixed(filename, ".cc") // + || suffixed(filename, ".c") // || suffixed(filename, ".sp")) { V3Options::addCppFile(filename); - } - else if (suffixed(filename, ".a") - || suffixed(filename, ".o") - || suffixed(filename, ".so")) { + } else if (suffixed(filename, ".a") // + || suffixed(filename, ".o") // + || suffixed(filename, ".so")) { V3Options::addLdLibs(filename); - } - else { + } else { V3Options::addVFile(filename); } shift; @@ -1245,11 +1174,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { // Read the specified -f filename and process as arguments - UINFO(1,"Reading Options File "< ifp (V3File::new_ifstream(filename)); + const vl_unique_ptr ifp(V3File::new_ifstream(filename)); if (ifp->fail()) { - fl->v3error("Cannot open -f command file: "+filename); + fl->v3error("Cannot open -f command file: " + filename); return; } @@ -1263,14 +1192,14 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { char lastch = ' '; for (string::const_iterator pos = line.begin(); pos != line.end(); lastch = *pos++) { if (inCmt) { - if (*pos=='*' && *(pos+1)=='/') { + if (*pos == '*' && *(pos + 1) == '/') { inCmt = false; ++pos; } - } else if (*pos=='/' && *(pos+1)=='/' - && (pos == line.begin() || isspace(lastch))) { // But allow /file//path + } else if (*pos == '/' && *(pos + 1) == '/' + && (pos == line.begin() || isspace(lastch))) { // But allow /file//path break; // Ignore to EOL - } else if (*pos=='/' && *(pos+1)=='*') { + } else if (*pos == '/' && *(pos + 1) == '*') { inCmt = true; // cppcheck-suppress StlMissingComparison ++pos; @@ -1293,16 +1222,12 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { std::vector args; // Parse file using a state machine, taking into account quoted strings and escaped chars - enum state {ST_IN_OPTION, - ST_ESCAPED_CHAR, - ST_IN_QUOTED_STR, - ST_IN_DOUBLE_QUOTED_STR}; + enum state { ST_IN_OPTION, ST_ESCAPED_CHAR, ST_IN_QUOTED_STR, ST_IN_DOUBLE_QUOTED_STR }; state st = ST_IN_OPTION; state last_st = ST_IN_OPTION; string arg; - for (string::size_type pos = 0; - pos < whole_file.length(); ++pos) { + for (string::size_type pos = 0; pos < whole_file.length(); ++pos) { char curr_char = whole_file[pos]; switch (st) { case ST_IN_OPTION: // Get all chars up to a white space or a "=" @@ -1328,7 +1253,7 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { } else { // Base specifier arg += '\''; } - arg += curr_char; + arg += curr_char; break; } if (curr_char == '"') { // Find begin of double quoted string @@ -1371,21 +1296,20 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { string optdir = (rel ? V3Os::filenameDir(filename) : "."); // Convert to argv style arg list and parse them - std::vector argv; argv.reserve(args.size()+1); + std::vector argv; + argv.reserve(args.size() + 1); for (std::vector::const_iterator it = args.begin(); it != args.end(); ++it) { argv.push_back(const_cast(it->c_str())); } - argv.push_back(NULL); // argv is NULL-terminated - parseOptsList(fl, optdir, static_cast(argv.size()-1), argv.data()); + argv.push_back(NULL); // argv is NULL-terminated + parseOptsList(fl, optdir, static_cast(argv.size() - 1), argv.data()); } //====================================================================== string V3Options::parseFileArg(const string& optdir, const string& relfilename) { string filename = V3Os::filenameSubstitute(relfilename); - if (optdir != "." && V3Os::filenameIsRel(filename)) { - filename = optdir + "/" + filename; - } + if (optdir != "." && V3Os::filenameIsRel(filename)) filename = optdir + "/" + filename; return filename; } @@ -1407,37 +1331,38 @@ bool V3Options::parseLangExt(const char* swp, //!< argument text //====================================================================== void V3Options::showVersion(bool verbose) { - cout <second = level; } else { m_debugSrcs.insert(make_pair(srcfile, level)); @@ -1579,7 +1502,7 @@ int V3Options::debugSrcLevel(const string& srcfile_path, int default_level) { // That means though we need to cleanup the filename from ../Foo.cpp -> Foo string srcfile = V3Os::filenameNonDirExt(srcfile_path); DebugSrcMap::iterator iter = m_debugSrcs.find(srcfile); - if (iter!=m_debugSrcs.end()) { + if (iter != m_debugSrcs.end()) { return iter->second; } else { return default_level; @@ -1588,7 +1511,7 @@ int V3Options::debugSrcLevel(const string& srcfile_path, int default_level) { void V3Options::setDumpTreeLevel(const string& srcfile, int level) { DebugSrcMap::iterator iter = m_dumpTrees.find(srcfile); - if (iter!=m_dumpTrees.end()) { + if (iter != m_dumpTrees.end()) { iter->second = level; } else { m_dumpTrees.insert(make_pair(srcfile, level)); @@ -1600,7 +1523,7 @@ int V3Options::dumpTreeLevel(const string& srcfile_path) { // That means though we need to cleanup the filename from ../Foo.cpp -> Foo string srcfile = V3Os::filenameNonDirExt(srcfile_path); DebugSrcMap::iterator iter = m_dumpTrees.find(srcfile); - if (iter!=m_dumpTrees.end()) { + if (iter != m_dumpTrees.end()) { return iter->second; } else { return m_dumpTree; diff --git a/src/V3Options.h b/src/V3Options.h index dff2275e2..b51d4e48f 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -37,18 +37,15 @@ class VOptionBool { // Class to track options that are either not specified (and default // true/false), versus user setting the option to true or false public: - enum en { - OPT_DEFAULT_FALSE = 0, - OPT_DEFAULT_TRUE, - OPT_TRUE, - OPT_FALSE, - _ENUM_END - }; + enum en { OPT_DEFAULT_FALSE = 0, OPT_DEFAULT_TRUE, OPT_TRUE, OPT_FALSE, _ENUM_END }; enum en m_e; - inline VOptionBool() : m_e(OPT_DEFAULT_FALSE) {} + inline VOptionBool() + : m_e(OPT_DEFAULT_FALSE) {} // cppcheck-suppress noExplicitConstructor - inline VOptionBool(en _e) : m_e(_e) {} - explicit inline VOptionBool(int _e) : m_e(static_cast(_e)) {} + inline VOptionBool(en _e) + : m_e(_e) {} + explicit inline VOptionBool(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } bool isDefault() const { return m_e == OPT_DEFAULT_FALSE || m_e == OPT_DEFAULT_TRUE; } bool isTrue() const { return m_e == OPT_TRUE || m_e == OPT_DEFAULT_TRUE; } @@ -57,9 +54,9 @@ public: bool isSetFalse() const { return m_e == OPT_FALSE; } void setTrueOrFalse(bool flag) { m_e = flag ? OPT_TRUE : OPT_FALSE; } const char* ascii() const { - static const char* const names[] = { - "DEFAULT_FALSE", "DEFAULT_TRUE", "TRUE", "FALSE"}; - return names[m_e]; } + static const char* const names[] = {"DEFAULT_FALSE", "DEFAULT_TRUE", "TRUE", "FALSE"}; + return names[m_e]; + } }; inline bool operator==(const VOptionBool& lhs, const VOptionBool& rhs) { return lhs.m_e == rhs.m_e; @@ -74,31 +71,21 @@ inline std::ostream& operator<<(std::ostream& os, const VOptionBool& rhs) { class TraceFormat { public: - enum en { - VCD = 0, - FST, - FST_THREAD - } m_e; + enum en { VCD = 0, FST, FST_THREAD } m_e; // cppcheck-suppress noExplicitConstructor - inline TraceFormat(en _e = VCD) : m_e(_e) {} - explicit inline TraceFormat(int _e) : m_e(static_cast(_e)) {} + inline TraceFormat(en _e = VCD) + : m_e(_e) {} + explicit inline TraceFormat(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } bool fstFlavor() const { return m_e == FST || m_e == FST_THREAD; } bool threaded() const { return m_e == FST_THREAD; } string classBase() const { - static const char* const names[] = { - "VerilatedVcd", - "VerilatedFst", - "VerilatedFst" - }; + static const char* const names[] = {"VerilatedVcd", "VerilatedFst", "VerilatedFst"}; return names[m_e]; } string sourceName() const { - static const char* const names[] = { - "verilated_vcd", - "verilated_fst", - "verilated_fst" - }; + static const char* const names[] = {"verilated_vcd", "verilated_fst", "verilated_fst"}; return names[m_e]; } }; @@ -115,15 +102,15 @@ typedef std::set V3StringSet; // V3Options - Command line options class V3Options { - public: - - private: +public: +private: // TYPES - typedef std::map DebugSrcMap; + typedef std::map DebugSrcMap; // MEMBERS (general options) - V3OptionsImp* m_impp; // Slow hidden options + V3OptionsImp* m_impp; // Slow hidden options + // clang-format off V3StringSet m_cppFiles; // argument: C++ files to link against V3StringList m_cFlags; // argument: user CFLAGS V3StringList m_ldLibs; // argument: user LDFLAGS @@ -137,7 +124,6 @@ class V3Options { DebugSrcMap m_dumpTrees; // argument: --dump-treei-= std::map m_parameters; // Parameters - bool m_preprocOnly; // main switch: -E bool m_makePhony; // main switch: -MP bool m_preprocNoLine;// main switch: -P @@ -268,8 +254,9 @@ class V3Options { bool m_oSubst; // main switch: -Ou: substitute expression temp values bool m_oSubstConst; // main switch: -Ok: final constant substitution bool m_oTable; // main switch: -Oa: lookup table creation + // clang-format on - private: +private: // METHODS void addArg(const string& arg); void addDefine(const string& defline, bool allowPlus); @@ -291,12 +278,13 @@ class V3Options { // CONSTRUCTORS VL_UNCOPYABLE(V3Options); - public: + +public: V3Options(); ~V3Options(); void setDebugMode(int level); void setDebugSrcLevel(const string& srcfile, int level); - int debugSrcLevel(const string& srcfile_path, int default_level=V3Error::debugDefault()); + int debugSrcLevel(const string& srcfile_path, int default_level = V3Error::debugDefault()); void setDumpTreeLevel(const string& srcfile, int level); int dumpTreeLevel(const string& srcfile_path); @@ -359,7 +347,7 @@ class V3Options { bool traceUnderscore() const { return m_traceUnderscore; } bool orderClockDly() const { return m_orderClockDly; } bool outFormatOk() const { return m_outFormatOk; } - bool keepTempFiles() const { return (V3Error::debugDefault()!=0); } + bool keepTempFiles() const { return (V3Error::debugDefault() != 0); } bool pedantic() const { return m_pedantic; } bool pinsScUint() const { return m_pinsScUint; } bool pinsScBigUint() const { return m_pinsScBigUint; } @@ -407,7 +395,7 @@ class V3Options { int compLimitMembers() const { return m_compLimitMembers; } int compLimitParens() const { return m_compLimitParens; } - string exeName() const { return m_exeName!="" ? m_exeName : prefix(); } + string exeName() const { return m_exeName != "" ? m_exeName : prefix(); } string l2Name() const { return m_l2Name; } string makeDir() const { return m_makeDir; } string modPrefix() const { return m_modPrefix; } @@ -417,7 +405,7 @@ class V3Options { string protectKeyDefaulted(); // Set default key if not set by user string protectLib() const { return m_protectLib; } string protectLibName(bool shared) { - string libName = "lib"+protectLib(); + string libName = "lib" + protectLib(); if (shared) { libName += ".so"; } else { @@ -499,10 +487,10 @@ class V3Options { // METHODS (file utilities using these options) string fileExists(const string& filename); - string filePath(FileLine* fl, const string& modname, - const string& lastpath, const string& errmsg); + string filePath(FileLine* fl, const string& modname, const string& lastpath, + const string& errmsg); void filePathLookedMsg(FileLine* fl, const string& modname); - V3LangCode fileLanguage(const string &filename); + V3LangCode fileLanguage(const string& filename); static bool fileStatDir(const string& filename); static bool fileStatNormal(const string& filename); static void fileNfsFlush(const string& filename); diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 06b7ede3d..03f7dc142 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -14,6 +14,7 @@ // //************************************************************************* +// clang-format off #if defined(_WIN32) || defined(__MINGW32__) # ifndef PSAPI_VERSION # define PSAPI_VERSION 1 // Needed for compatibility with Windows 7 @@ -22,6 +23,7 @@ #if defined(__MINGW32__) # define MINGW_HAS_SECURE_API 1 // Needed to expose a "secure" POSIX-like API #endif +// clang-format on #include "config_build.h" #include "verilatedos.h" @@ -42,6 +44,7 @@ #include #include +// clang-format off #if defined(_WIN32) || defined(__MINGW32__) # include // LONG for bcrypt.h on MINGW # include // BCryptGenRandom @@ -53,7 +56,7 @@ # include # include // usleep #endif - +// clang-format on //###################################################################### // Environment @@ -80,17 +83,17 @@ string V3Os::getenvStr(const string& envvar, const string& defaultValue) { void V3Os::setenvStr(const string& envvar, const string& value, const string& why) { if (why != "") { - UINFO(1,"export "<(vareq.c_str())); #endif @@ -101,8 +104,11 @@ void V3Os::setenvStr(const string& envvar, const string& value, const string& wh string V3Os::filenameFromDirBase(const string& dir, const string& basename) { // Don't return ./{filename} because if filename was absolute, that makes it relative - if (dir == ".") return basename; - else return dir+"/"+basename; + if (dir == ".") { + return basename; + } else { + return dir + "/" + basename; + } } string V3Os::filenameDir(const string& filename) { @@ -117,7 +123,7 @@ string V3Os::filenameDir(const string& filename) { string V3Os::filenameNonDir(const string& filename) { string::size_type pos; if ((pos = filename.rfind('/')) != string::npos) { - return filename.substr(pos+1); + return filename.substr(pos + 1); } else { return filename; } @@ -126,9 +132,7 @@ string V3Os::filenameNonDir(const string& filename) { string V3Os::filenameNonExt(const string& filename) { string base = filenameNonDir(filename); string::size_type pos; - if ((pos = base.find('.')) != string::npos) { - base.erase(pos); - } + if ((pos = base.find('.')) != string::npos) base.erase(pos); return base; } @@ -136,32 +140,35 @@ string V3Os::filenameSubstitute(const string& filename) { string out; enum { NONE, PAREN, CURLY } brackets = NONE; for (string::size_type pos = 0; pos < filename.length(); ++pos) { - if ((filename[pos] == '$') && (pos+1 < filename.length())) { - switch (filename[pos+1]) { - case '{': brackets = CURLY; break; - case '(': brackets = PAREN; break; - default: brackets = NONE; break; + if ((filename[pos] == '$') && (pos + 1 < filename.length())) { + switch (filename[pos + 1]) { + case '{': brackets = CURLY; break; + case '(': brackets = PAREN; break; + default: brackets = NONE; break; } - if (brackets != NONE) pos = pos+1; - string::size_type endpos = pos+1; - while (((endpos+1) < filename.length()) && - (((brackets==NONE) && (isalnum(filename[endpos+1]) - || filename[endpos+1]=='_')) - || ((brackets==CURLY) && (filename[endpos+1]!='}')) - || ((brackets==PAREN) && (filename[endpos+1]!=')')))) + if (brackets != NONE) pos = pos + 1; + string::size_type endpos = pos + 1; + while (((endpos + 1) < filename.length()) + && (((brackets == NONE) + && (isalnum(filename[endpos + 1]) || filename[endpos + 1] == '_')) + || ((brackets == CURLY) && (filename[endpos + 1] != '}')) + || ((brackets == PAREN) && (filename[endpos + 1] != ')')))) ++endpos; // Catch bracket errors - if (((brackets==CURLY) && (filename[endpos+1]!='}')) || - ((brackets==PAREN) && (filename[endpos+1]!=')'))) { - v3fatal("Unmatched brackets in variable substitution in file: "+filename); + if (((brackets == CURLY) && (filename[endpos + 1] != '}')) + || ((brackets == PAREN) && (filename[endpos + 1] != ')'))) { + v3fatal("Unmatched brackets in variable substitution in file: " + filename); } - string envvar = filename.substr(pos+1, endpos-pos); + string envvar = filename.substr(pos + 1, endpos - pos); string envvalue; if (!envvar.empty()) envvalue = getenvStr(envvar, ""); if (!envvalue.empty()) { out += envvalue; - if (brackets==NONE) pos = endpos; - else pos = endpos+1; + if (brackets == NONE) { + pos = endpos; + } else { + pos = endpos + 1; + } } else { out += filename[pos]; // *pos == '$' } @@ -170,7 +177,6 @@ string V3Os::filenameSubstitute(const string& filename) { } } return out; - } string V3Os::filenameRealPath(const string& filename) { @@ -183,7 +189,7 @@ string V3Os::filenameRealPath(const string& filename) { #else realpath(filename.c_str(), retpath) #endif - ) { + ) { return string(retpath); } else { return filename; @@ -191,7 +197,7 @@ string V3Os::filenameRealPath(const string& filename) { } bool V3Os::filenameIsRel(const string& filename) { - return (filename.length()>0 && filename[0] != '/'); + return (filename.length() > 0 && filename[0] != '/'); } //###################################################################### @@ -243,28 +249,27 @@ vluint64_t V3Os::rand64(vluint64_t* statep) { // Xoroshiro128+ algorithm vluint64_t result = statep[0] + statep[1]; statep[1] ^= statep[0]; - statep[0] = (((statep[0] << 55) | (statep[0] >> 9)) - ^ statep[1] ^ (statep[1] << 14)); + statep[0] = (((statep[0] << 55) | (statep[0] >> 9)) ^ statep[1] ^ (statep[1] << 14)); statep[1] = (statep[1] << 36) | (statep[1] >> 28); return result; } string V3Os::trueRandom(size_t size) { string result(size, '\xFF'); - char *const data = const_cast(result.data()); + char* const data = const_cast(result.data()); // Note: std::string.data() returns a non-const Char* from C++17 onwards. // For pre-C++17, this cast is OK in practice, even though it's UB. #if defined(_WIN32) || defined(__MINGW32__) - NTSTATUS hr = BCryptGenRandom(NULL, reinterpret_cast(data), size, BCRYPT_USE_SYSTEM_PREFERRED_RNG); - if (!BCRYPT_SUCCESS(hr)) { - v3fatal("Could not acquire random data."); - } + NTSTATUS hr = BCryptGenRandom(NULL, reinterpret_cast(data), size, + BCRYPT_USE_SYSTEM_PREFERRED_RNG); + if (!BCRYPT_SUCCESS(hr)) { v3fatal("Could not acquire random data."); } #else - std::ifstream is ("/dev/urandom", std::ios::in | std::ios::binary); + std::ifstream is("/dev/urandom", std::ios::in | std::ios::binary); // This read uses the size of the buffer. // Flawfinder: ignore if (!is.read(data, size)) { - v3fatal("Could not open /dev/urandom, no source of randomness. Try specifying a key instead."); + v3fatal("Could not open /dev/urandom, no source of randomness. " + "Try specifying a key instead."); } #endif return result; @@ -278,15 +283,16 @@ uint64_t V3Os::timeUsecs() { // Microseconds between 1601-01-01 00:00:00 UTC and 1970-01-01 00:00:00 UTC static const uint64_t EPOCH_DIFFERENCE_USECS = 11644473600000000ull; - FILETIME ft; // contains number of 0.1us intervals since the beginning of 1601 UTC. + FILETIME ft; // contains number of 0.1us intervals since the beginning of 1601 UTC. GetSystemTimeAsFileTime(&ft); - uint64_t us = ((static_cast(ft.dwHighDateTime) << 32) + ft.dwLowDateTime + 5ull) / 10ull; + uint64_t us + = ((static_cast(ft.dwHighDateTime) << 32) + ft.dwLowDateTime + 5ull) / 10ull; return us - EPOCH_DIFFERENCE_USECS; #else // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) timeval tv; if (gettimeofday(&tv, NULL) < 0) return 0; - return static_cast(tv.tv_sec)*1000000 + tv.tv_usec; + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; #endif } @@ -303,13 +309,13 @@ uint64_t V3Os::memUsageBytes() { // Highly unportable. Sorry const char* const statmFilename = "/proc/self/statm"; FILE* fp = fopen(statmFilename, "r"); - if (!fp) { - return 0; - } + if (!fp) return 0; vluint64_t size, resident, share, text, lib, data, dt; // All in pages - if (7 != fscanf(fp, "%" VL_PRI64 "u %" VL_PRI64 "u %" VL_PRI64 "u %" - VL_PRI64 "u %" VL_PRI64 "u %" VL_PRI64 "u %" VL_PRI64 "u", - &size, &resident, &share, &text, &lib, &data, &dt)) { + if (7 + != fscanf(fp, + "%" VL_PRI64 "u %" VL_PRI64 "u %" VL_PRI64 "u %" VL_PRI64 "u %" VL_PRI64 + "u %" VL_PRI64 "u %" VL_PRI64 "u", + &size, &resident, &share, &text, &lib, &data, &dt)) { fclose(fp); return 0; } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 5cfbc3115..d27137487 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -144,9 +144,7 @@ static void process() { // Coverage insertion // Before we do dead code elimination and inlining, or we'll lose it. - if (v3Global.opt.coverage()) { - V3Coverage::coverage(v3Global.rootp()); - } + if (v3Global.opt.coverage()) V3Coverage::coverage(v3Global.rootp()); // Push constants, but only true constants preserving liveness // so V3Undriven sees variables to be eliminated, ie "if (0 && foo) ..." @@ -262,9 +260,7 @@ static void process() { // Push constants across variables and remove redundant assignments V3Const::constifyAll(v3Global.rootp()); - if (v3Global.opt.oLife()) { - V3Life::lifeAll(v3Global.rootp()); - } + if (v3Global.opt.oLife()) V3Life::lifeAll(v3Global.rootp()); // Make large low-fanin logic blocks into lookup tables // This should probably be done much later, once we have common logic elimination. @@ -282,15 +278,11 @@ static void process() { V3Active::activeAll(v3Global.rootp()); // Split single ALWAYS blocks into multiple blocks for better ordering chances - if (v3Global.opt.oSplit()) { - V3Split::splitAlwaysAll(v3Global.rootp()); - } + if (v3Global.opt.oSplit()) V3Split::splitAlwaysAll(v3Global.rootp()); V3SplitAs::splitAsAll(v3Global.rootp()); // Create tracing sample points, before we start eliminating signals - if (v3Global.opt.trace()) { - V3TraceDecl::traceDeclAll(v3Global.rootp()); - } + if (v3Global.opt.trace()) V3TraceDecl::traceDeclAll(v3Global.rootp()); // Gate-based logic elimination; eliminate signals and push constant across cell boundaries // Instant propagation makes lots-o-constant reduction possibilities. @@ -298,13 +290,12 @@ static void process() { V3Gate::gateAll(v3Global.rootp()); // V3Gate calls constant propagation itself. } else { - v3info("Command Line disabled gate optimization with -Og/-O0. This may cause ordering problems."); + v3info("Command Line disabled gate optimization with -Og/-O0. " + "This may cause ordering problems."); } // Combine COVERINCs with duplicate terms - if (v3Global.opt.coverage()) { - V3CoverageJoin::coverageJoin(v3Global.rootp()); - } + if (v3Global.opt.coverage()) V3CoverageJoin::coverageJoin(v3Global.rootp()); // Remove unused vars V3Const::constifyAll(v3Global.rootp()); @@ -318,9 +309,7 @@ static void process() { } // Reorder assignments in pipelined blocks - if (v3Global.opt.oReorder()) { - V3Split::splitReorderAll(v3Global.rootp()); - } + if (v3Global.opt.oReorder()) V3Split::splitReorderAll(v3Global.rootp()); // Create delayed assignments // This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step @@ -349,9 +338,7 @@ static void process() { V3Const::constifyAll(v3Global.rootp()); V3Life::lifeAll(v3Global.rootp()); } - if (v3Global.opt.oLifePost()) { - V3LifePost::lifepostAll(v3Global.rootp()); - } + if (v3Global.opt.oLifePost()) V3LifePost::lifepostAll(v3Global.rootp()); // Remove unused vars V3Const::constifyAll(v3Global.rootp()); @@ -364,9 +351,7 @@ static void process() { // Note past this point, we presume traced variables won't move between CFuncs // (It's OK if untraced temporaries move around, or vars // "effectively" activate the same way.) - if (v3Global.opt.trace()) { - V3Trace::traceAll(v3Global.rootp()); - } + if (v3Global.opt.trace()) V3Trace::traceAll(v3Global.rootp()); if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Scoped"); @@ -383,14 +368,10 @@ static void process() { } // Move BLOCKTEMPS from class to local variables - if (v3Global.opt.oLocalize()) { - V3Localize::localizeAll(v3Global.rootp()); - } + if (v3Global.opt.oLocalize()) V3Localize::localizeAll(v3Global.rootp()); // Icache packing; combine common code in each module's functions into subroutines - if (v3Global.opt.oCombine()) { - V3Combine::combineAll(v3Global.rootp()); - } + if (v3Global.opt.oCombine()) V3Combine::combineAll(v3Global.rootp()); } V3Error::abortIfErrors(); @@ -414,38 +395,30 @@ static void process() { } // Expand macros and wide operators into C++ primitives - if (!v3Global.opt.lintOnly() - && !v3Global.opt.xmlOnly() - && v3Global.opt.oExpand()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.oExpand()) { V3Expand::expandAll(v3Global.rootp()); } // Propagate constants across WORDSEL arrayed temporaries - if (!v3Global.opt.xmlOnly() - && v3Global.opt.oSubst()) { + if (!v3Global.opt.xmlOnly() && v3Global.opt.oSubst()) { // Constant folding of expanded stuff V3Const::constifyCpp(v3Global.rootp()); V3Subst::substituteAll(v3Global.rootp()); } - if (!v3Global.opt.xmlOnly() - && v3Global.opt.oSubstConst()) { + if (!v3Global.opt.xmlOnly() && v3Global.opt.oSubstConst()) { // Constant folding of substitutions V3Const::constifyCpp(v3Global.rootp()); - V3Dead::deadifyAll(v3Global.rootp()); } - if (!v3Global.opt.lintOnly() - && !v3Global.opt.xmlOnly() - && v3Global.opt.oReloop()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.oReloop()) { // Reform loops to reduce code size // Must be after all Sel/array index based optimizations V3Reloop::reloopAll(v3Global.rootp()); } - if (!v3Global.opt.lintOnly() - && !v3Global.opt.xmlOnly()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) { // Fix very deep expressions // Mark evaluation functions as member functions, if needed. V3Depth::depthAll(v3Global.rootp()); @@ -459,15 +432,12 @@ static void process() { } V3Error::abortIfErrors(); - if (!v3Global.opt.lintOnly() - && !v3Global.opt.xmlOnly()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) { // V3CCtors::cctorsAll(); } // Output the text - if (!v3Global.opt.lintOnly() - && !v3Global.opt.xmlOnly() - && !v3Global.opt.dpiHdrOnly()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { // Create AstCUse to determine what class forward declarations/#includes needed in C // Must be before V3EmitC V3CUse::cUseAll(v3Global.rootp()); @@ -479,8 +449,7 @@ static void process() { } else if (v3Global.opt.dpiHdrOnly()) { V3EmitC::emitcSyms(true); } - if (!v3Global.opt.xmlOnly() - && v3Global.opt.mtasks()) { + if (!v3Global.opt.xmlOnly() && v3Global.opt.mtasks()) { // Finalize our MTask cost estimates and pack the mtasks into // threads. Must happen pre-EmitC which relies on the packing // order. Must happen post-V3LifePost which changes the relative @@ -493,8 +462,7 @@ static void process() { } if (v3Global.opt.xmlOnly() // Check XML when debugging to make sure no missing node types - || (v3Global.opt.debugCheck() && !v3Global.opt.lintOnly() - && !v3Global.opt.dpiHdrOnly())) { + || (v3Global.opt.debugCheck() && !v3Global.opt.lintOnly() && !v3Global.opt.dpiHdrOnly())) { V3EmitXml::emitxml(); } @@ -511,14 +479,12 @@ static void process() { V3Stats::statsReport(); } - if (!v3Global.opt.lintOnly() - && !v3Global.opt.xmlOnly() - && !v3Global.opt.dpiHdrOnly()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { // Makefile must be after all other emitters - if (v3Global.opt.cmake()) { + if (v3Global.opt.cmake()) { // V3EmitCMake::emit(); } - if (v3Global.opt.gmake()) { + if (v3Global.opt.gmake()) { // V3EmitMk::emitmk(); } } @@ -545,9 +511,8 @@ int main(int argc, char** argv, char** env) { // Command option parsing v3Global.opt.bin(argv[0]); - string argString = V3Options::argString(argc-1, argv+1); - v3Global.opt.parseOpts(new FileLine(FileLine::commandLineFilename()), - argc-1, argv+1); + string argString = V3Options::argString(argc - 1, argv + 1); + v3Global.opt.parseOpts(new FileLine(FileLine::commandLineFilename()), argc - 1, argv + 1); // Validate settings (aka Boost.Program_options) v3Global.opt.notify(); @@ -558,8 +523,9 @@ int main(int argc, char** argv, char** env) { V3File::addSrcDepend(v3Global.opt.bin()); if (v3Global.opt.skipIdentical().isTrue() && V3File::checkTimes(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() - + "__verFiles.dat", argString)) { - UINFO(1,"--skip-identical: No change to any source files, exiting\n"); + + "__verFiles.dat", + argString)) { + UINFO(1, "--skip-identical: No change to any source files, exiting\n"); exit(0); } // Undocumented debugging - cannot be a switch as then command line @@ -571,9 +537,9 @@ int main(int argc, char** argv, char** env) { //--FRONTEND------------------ // Cleanup - V3Os::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix()+"_*.tree"); - V3Os::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix()+"_*.dot"); - V3Os::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix()+"_*.txt"); + V3Os::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix() + "_*.tree"); + V3Os::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix() + "_*.dot"); + V3Os::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix() + "_*.txt"); // Internal tests (after option parsing as need debug() setting, // and after removing files as may make debug output) @@ -591,7 +557,7 @@ int main(int argc, char** argv, char** env) { v3Global.readFiles(); // Link, etc, if needed - if (!v3Global.opt.preprocOnly()) { + if (!v3Global.opt.preprocOnly()) { // process(); } @@ -600,10 +566,11 @@ int main(int argc, char** argv, char** env) { V3Error::abortIfWarnings(); if (v3Global.opt.makeDepend().isTrue()) { - V3File::writeDepend(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__ver.d"); + V3File::writeDepend(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__ver.d"); } if (v3Global.opt.protectIds()) { - VIdProtect::writeMapFile(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__idmap.xml"); + VIdProtect::writeMapFile(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + + "__idmap.xml"); } if (v3Global.opt.skipIdentical().isTrue() || v3Global.opt.makeDepend().isTrue()) { V3File::writeTimes(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__verFiles.dat", @@ -618,5 +585,5 @@ int main(int argc, char** argv, char** env) { #endif FileLine::deleteAllRemaining(); - UINFO(1,"Done, Exiting...\n"); + UINFO(1, "Done, Exiting...\n"); } From f3308d236b5ae329241f4b16c3b39c282c351d9a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Apr 2020 07:58:34 -0400 Subject: [PATCH 053/127] clang-format remaining sources. No functional change. --- Makefile.in | 6 + nodist/clang_formatter | 236 --- src/V3Active.cpp | 4 +- src/V3Assert.cpp | 2 +- src/V3Ast.cpp | 490 ++++--- src/V3Ast.h | 1568 +++++++++++--------- src/V3AstNodes.cpp | 854 ++++++----- src/V3AstNodes.h | 3101 +++++++++++++++++++++++++++------------- src/V3Begin.cpp | 117 +- src/V3Broken.cpp | 94 +- src/V3CCtors.cpp | 57 +- src/V3Case.cpp | 218 +-- src/V3Cast.cpp | 51 +- src/V3Cdc.cpp | 368 ++--- src/V3Changed.cpp | 122 +- src/V3Clean.cpp | 95 +- src/V3Clock.cpp | 150 +- src/V3Combine.cpp | 191 ++- src/V3Config.cpp | 4 +- src/V3Const.cpp | 1056 +++++++------- src/V3Dead.cpp | 199 ++- src/V3Delayed.cpp | 211 +-- src/V3Depth.cpp | 2 +- src/V3Descope.cpp | 2 +- src/V3EmitC.cpp | 1509 ++++++++++--------- src/V3EmitCBase.h | 40 +- src/V3EmitCMake.cpp | 66 +- src/V3EmitMk.cpp | 174 +-- src/V3EmitV.cpp | 264 ++-- src/V3EmitXml.cpp | 189 ++- src/V3Error.cpp | 152 +- src/V3Error.h | 215 +-- src/V3Expand.cpp | 545 +++---- src/V3File.cpp | 591 ++++---- src/V3File.h | 59 +- src/V3FileLine.cpp | 136 +- src/V3FileLine.h | 91 +- src/V3Gate.cpp | 602 ++++---- src/V3GenClk.cpp | 55 +- src/V3Graph.cpp | 184 ++- src/V3GraphAcyc.cpp | 196 +-- src/V3GraphAlg.cpp | 168 +-- src/V3GraphTest.cpp | 136 +- src/V3Hashed.cpp | 77 +- src/V3Inline.cpp | 63 +- src/V3Inst.cpp | 243 ++-- src/V3Life.cpp | 124 +- src/V3LifePost.cpp | 61 +- src/V3LinkCells.cpp | 177 +-- src/V3LinkDot.cpp | 1284 +++++++++-------- src/V3LinkJump.cpp | 132 +- src/V3LinkLevel.cpp | 67 +- src/V3LinkParse.cpp | 228 ++- src/V3LinkResolve.cpp | 132 +- src/V3Number.cpp | 1165 ++++++++------- src/V3Number.h | 402 +++--- src/V3Order.cpp | 776 +++++----- src/V3Param.cpp | 365 ++--- src/V3ParseGrammar.cpp | 121 +- src/V3ParseImp.cpp | 81 +- src/V3ParseImp.h | 127 +- src/V3Partition.cpp | 702 ++++----- src/V3PreLex.l | 4 +- src/V3PreProc.cpp | 857 +++++------ src/V3Premit.cpp | 154 +- src/V3ProtectLib.cpp | 280 ++-- src/V3Scope.cpp | 135 +- src/V3SenTree.h | 5 +- src/V3Simulate.h | 303 ++-- src/V3Slice.cpp | 143 +- src/V3Split.cpp | 245 ++-- src/V3SplitAs.cpp | 62 +- src/V3SplitVar.cpp | 47 +- src/V3Subst.cpp | 162 +-- src/V3TSP.cpp | 204 ++- src/V3Table.cpp | 184 ++- src/V3Task.cpp | 526 ++++--- src/V3Trace.cpp | 2 +- src/V3Tristate.cpp | 549 ++++--- src/V3Undriven.cpp | 168 ++- src/V3Unknown.cpp | 210 ++- src/V3Unroll.cpp | 209 +-- src/V3Width.cpp | 2027 +++++++++++++------------- src/V3WidthCommit.h | 8 +- src/V3WidthSel.cpp | 358 +++-- 85 files changed, 14640 insertions(+), 13099 deletions(-) delete mode 100755 nodist/clang_formatter diff --git a/Makefile.in b/Makefile.in index dfb5d3c0f..f96f4c85c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -456,6 +456,12 @@ analyzer-include: -rm -rf examples/*/obj* scan-build $(MAKE) -k examples +CLANGFORMAT = clang-format +CLANGFORMAT_FLAGS = -i + +clang-format: + $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) + ftp: info install-msg: diff --git a/nodist/clang_formatter b/nodist/clang_formatter deleted file mode 100755 index c9ee2b72a..000000000 --- a/nodist/clang_formatter +++ /dev/null @@ -1,236 +0,0 @@ -#!/bin/bash -# -# clang-format is used to standardize the indentation of the internal C++ -# code. -# -# For the most part clang-format changes provide good consistency, the two -# main exceptions being the indentation of preprocessor directives, and -# tables of statements. Reformatting is generally performed only before -# other large changes are to be made to a file. -# -# "##" files commented out below are not yet clang-format clean. -# "#" files commented out hit a clang-format limitation with ifdefs. - -clang-format -i examples/make_hello_c/sim_main.cpp -clang-format -i examples/make_hello_sc/sc_main.cpp -#clang-format -i examples/make_protect_lib/sim_main.cpp -clang-format -i examples/make_tracing_c/sim_main.cpp -clang-format -i examples/make_tracing_sc/sc_main.cpp -clang-format -i include/*.cpp -clang-format -i include/*.h -clang-format -i include/verilated_config.h.in -clang-format -i nodist/fuzzer/wrapper.cpp -clang-format -i src/V3Active.cpp -clang-format -i src/V3Active.h -clang-format -i src/V3ActiveTop.cpp -clang-format -i src/V3ActiveTop.h -clang-format -i src/V3Assert.cpp -clang-format -i src/V3Assert.h -clang-format -i src/V3AssertPre.cpp -clang-format -i src/V3AssertPre.h -##clang-format -i src/V3Ast.cpp -##clang-format -i src/V3Ast.h -clang-format -i src/V3AstConstOnly.h -##clang-format -i src/V3AstNodes.cpp -##clang-format -i src/V3AstNodes.h -##clang-format -i src/V3Begin.cpp -clang-format -i src/V3Begin.h -clang-format -i src/V3Branch.cpp -clang-format -i src/V3Branch.h -##clang-format -i src/V3Broken.cpp -clang-format -i src/V3Broken.h -##clang-format -i src/V3CCtors.cpp -clang-format -i src/V3CCtors.h -clang-format -i src/V3CUse.cpp -clang-format -i src/V3CUse.h -##clang-format -i src/V3Case.cpp -clang-format -i src/V3Case.h -##clang-format -i src/V3Cast.cpp -clang-format -i src/V3Cast.h -##clang-format -i src/V3Cdc.cpp -clang-format -i src/V3Cdc.h -##clang-format -i src/V3Changed.cpp -clang-format -i src/V3Changed.h -clang-format -i src/V3Class.cpp -clang-format -i src/V3Class.h -##clang-format -i src/V3Clean.cpp -clang-format -i src/V3Clean.h -##clang-format -i src/V3Clock.cpp -clang-format -i src/V3Clock.h -##clang-format -i src/V3Combine.cpp -clang-format -i src/V3Combine.h -clang-format -i src/V3Config.cpp -clang-format -i src/V3Config.h -##clang-format -i src/V3Const.cpp -clang-format -i src/V3Const.h -clang-format -i src/V3Coverage.cpp -clang-format -i src/V3Coverage.h -clang-format -i src/V3CoverageJoin.cpp -clang-format -i src/V3CoverageJoin.h -##clang-format -i src/V3Dead.cpp -clang-format -i src/V3Dead.h -##clang-format -i src/V3Delayed.cpp -clang-format -i src/V3Delayed.h -clang-format -i src/V3Depth.cpp -clang-format -i src/V3Depth.h -clang-format -i src/V3DepthBlock.cpp -clang-format -i src/V3DepthBlock.h -clang-format -i src/V3Descope.cpp -clang-format -i src/V3Descope.h -##clang-format -i src/V3EmitC.cpp -clang-format -i src/V3EmitC.h -##clang-format -i src/V3EmitCBase.h -clang-format -i src/V3EmitCInlines.cpp -##clang-format -i src/V3EmitCMake.cpp -clang-format -i src/V3EmitCMake.h -clang-format -i src/V3EmitCSyms.cpp -##clang-format -i src/V3EmitMk.cpp -clang-format -i src/V3EmitMk.h -##clang-format -i src/V3EmitV.cpp -clang-format -i src/V3EmitV.h -##clang-format -i src/V3EmitXml.cpp -clang-format -i src/V3EmitXml.h -##clang-format -i src/V3Error.cpp -##clang-format -i src/V3Error.h -##clang-format -i src/V3Expand.cpp -clang-format -i src/V3Expand.h -##clang-format -i src/V3File.cpp -##clang-format -i src/V3File.h -##clang-format -i src/V3FileLine.cpp -##clang-format -i src/V3FileLine.h -##clang-format -i src/V3Gate.cpp -clang-format -i src/V3Gate.h -##clang-format -i src/V3GenClk.cpp -clang-format -i src/V3GenClk.h -clang-format -i src/V3Global.cpp -clang-format -i src/V3Global.h -##clang-format -i src/V3Graph.cpp -clang-format -i src/V3Graph.h -##clang-format -i src/V3GraphAcyc.cpp -##clang-format -i src/V3GraphAlg.cpp -clang-format -i src/V3GraphAlg.h -clang-format -i src/V3GraphDfa.cpp -clang-format -i src/V3GraphDfa.h -clang-format -i src/V3GraphPathChecker.cpp -clang-format -i src/V3GraphPathChecker.h -clang-format -i src/V3GraphStream.h -##clang-format -i src/V3GraphTest.cpp -##clang-format -i src/V3Hashed.cpp -clang-format -i src/V3Hashed.h -##clang-format -i src/V3Inline.cpp -clang-format -i src/V3Inline.h -##clang-format -i src/V3Inst.cpp -clang-format -i src/V3Inst.h -clang-format -i src/V3InstrCount.cpp -clang-format -i src/V3InstrCount.h -clang-format -i src/V3LangCode.h -clang-format -i src/V3LanguageWords.h -##clang-format -i src/V3Life.cpp -clang-format -i src/V3Life.h -##clang-format -i src/V3LifePost.cpp -clang-format -i src/V3LifePost.h -##clang-format -i src/V3LinkCells.cpp -clang-format -i src/V3LinkCells.h -##clang-format -i src/V3LinkDot.cpp -clang-format -i src/V3LinkDot.h -##clang-format -i src/V3LinkJump.cpp -clang-format -i src/V3LinkJump.h -clang-format -i src/V3LinkLValue.cpp -clang-format -i src/V3LinkLValue.h -##clang-format -i src/V3LinkLevel.cpp -clang-format -i src/V3LinkLevel.h -##clang-format -i src/V3LinkParse.cpp -clang-format -i src/V3LinkParse.h -##clang-format -i src/V3LinkResolve.cpp -clang-format -i src/V3LinkResolve.h -clang-format -i src/V3List.h -clang-format -i src/V3Localize.cpp -clang-format -i src/V3Localize.h -clang-format -i src/V3Name.cpp -clang-format -i src/V3Name.h -##clang-format -i src/V3Number.cpp -##clang-format -i src/V3Number.h -clang-format -i src/V3Number_test.cpp -clang-format -i src/V3Options.cpp -clang-format -i src/V3Options.h -##clang-format -i src/V3Order.cpp -clang-format -i src/V3Order.h -clang-format -i src/V3OrderGraph.h -clang-format -i src/V3Os.cpp -clang-format -i src/V3Os.h -##clang-format -i src/V3Param.cpp -clang-format -i src/V3Param.h -clang-format -i src/V3Parse.h -##clang-format -i src/V3ParseGrammar.cpp -##clang-format -i src/V3ParseImp.cpp -##clang-format -i src/V3ParseImp.h -clang-format -i src/V3ParseLex.cpp -clang-format -i src/V3ParseSym.h -##clang-format -i src/V3Partition.cpp -clang-format -i src/V3Partition.h -clang-format -i src/V3PartitionGraph.h -clang-format -i src/V3PreLex.h -##clang-format -i src/V3PreProc.cpp -clang-format -i src/V3PreProc.h -clang-format -i src/V3PreShell.cpp -clang-format -i src/V3PreShell.h -##clang-format -i src/V3Premit.cpp -clang-format -i src/V3Premit.h -##clang-format -i src/V3ProtectLib.cpp -clang-format -i src/V3ProtectLib.h -clang-format -i src/V3Reloop.cpp -clang-format -i src/V3Reloop.h -##clang-format -i src/V3Scope.cpp -clang-format -i src/V3Scope.h -clang-format -i src/V3Scoreboard.cpp -clang-format -i src/V3Scoreboard.h -clang-format -i src/V3SenTree.h -##clang-format -i src/V3Simulate.h -##clang-format -i src/V3Slice.cpp -clang-format -i src/V3Slice.h -##clang-format -i src/V3Split.cpp -clang-format -i src/V3Split.h -##clang-format -i src/V3SplitAs.cpp -clang-format -i src/V3SplitAs.h -##clang-format -i src/V3SplitVar.cpp -clang-format -i src/V3SplitVar.h -clang-format -i src/V3Stats.cpp -clang-format -i src/V3Stats.h -clang-format -i src/V3StatsReport.cpp -clang-format -i src/V3String.cpp -clang-format -i src/V3String.h -##clang-format -i src/V3Subst.cpp -clang-format -i src/V3Subst.h -clang-format -i src/V3SymTable.h -##clang-format -i src/V3TSP.cpp -clang-format -i src/V3TSP.h -##clang-format -i src/V3Table.cpp -clang-format -i src/V3Table.h -##clang-format -i src/V3Task.cpp -clang-format -i src/V3Task.h -clang-format -i src/V3Trace.cpp -clang-format -i src/V3Trace.h -clang-format -i src/V3TraceDecl.cpp -clang-format -i src/V3TraceDecl.h -##clang-format -i src/V3Tristate.cpp -clang-format -i src/V3Tristate.h -##clang-format -i src/V3Undriven.cpp -clang-format -i src/V3Undriven.h -##clang-format -i src/V3Unknown.cpp -clang-format -i src/V3Unknown.h -##clang-format -i src/V3Unroll.cpp -clang-format -i src/V3Unroll.h -##clang-format -i src/V3Width.cpp -clang-format -i src/V3Width.h -clang-format -i src/V3WidthCommit.h -##clang-format -i src/V3WidthSel.cpp -clang-format -i src/Verilator.cpp -clang-format -i src/VlcBucket.h -clang-format -i src/VlcMain.cpp -clang-format -i src/VlcOptions.h -clang-format -i src/VlcPoint.h -clang-format -i src/VlcSource.h -clang-format -i src/VlcTest.h -clang-format -i src/VlcTop.cpp -clang-format -i src/VlcTop.h -clang-format -i src/config_build.h.in diff --git a/src/V3Active.cpp b/src/V3Active.cpp index efc8eef8e..42c3ea5d1 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -364,7 +364,7 @@ private: virtual void visit(AstAlways* nodep) VL_OVERRIDE { // Move always to appropriate ACTIVE based on its sense list UINFO(4, " ALW " << nodep << endl); - // if (debug()>=9) nodep->dumpTree(cout, " Alw: "); + // if (debug() >= 9) nodep->dumpTree(cout, " Alw: "); if (!nodep->bodysp()) { // Empty always. Kill it. @@ -376,7 +376,7 @@ private: virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // Move always to appropriate ACTIVE based on its sense list UINFO(4, " ALWPub " << nodep << endl); - // if (debug()>=9) nodep->dumpTree(cout, " Alw: "); + // if (debug() >= 9) nodep->dumpTree(cout, " Alw: "); visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS); } virtual void visit(AstSenGate* nodep) VL_OVERRIDE { diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 37377ac38..1dd64a7da 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -322,7 +322,7 @@ private: AstNode* assp = new AstAssignDly(nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, true), inp); alwaysp->addStmtp(assp); - // if (debug()>-9) assp->dumpTree(cout, "-ass: "); + // if (debug() >= 9) assp->dumpTree(cout, "-ass: "); invarp = outvarp; inp = new AstVarRef(nodep->fileline(), invarp, false); } diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 7d7e1b1f4..8f0a5373e 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -51,7 +51,6 @@ bool AstUser5InUse::s_userBusy = false; int AstNodeDType::s_uniqueNum = 0; - //###################################################################### // V3AstType @@ -102,15 +101,16 @@ AstNode* AstNode::abovep() const { string AstNode::encodeName(const string& namein) { // Encode signal name raw from parser, then not called again on same signal string out; - for (string::const_iterator pos = namein.begin(); pos!=namein.end(); ++pos) { - if ((pos==namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers - : isalnum(pos[0])) { + for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) { + if ((pos == namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers + : isalnum(pos[0])) { out += pos[0]; - } else if (pos[0]=='_') { - if (pos[1]=='_') { - out += "_"; out += "__05F"; // hex(_) = 0x5F + } else if (pos[0] == '_') { + if (pos[1] == '_') { + out += "_"; + out += "__05F"; // hex(_) = 0x5F ++pos; - if (pos==namein.end()) break; + if (pos == namein.end()) break; } else { out += pos[0]; } @@ -120,7 +120,8 @@ string AstNode::encodeName(const string& namein) { // We also do *NOT* use __DOT__ etc, as we search for those // in some replacements, and don't want to mangle the user's names. unsigned val = pos[0] & 0xff; // Mask to avoid sign extension - char hex[10]; sprintf(hex, "__0%02X", val); + char hex[10]; + sprintf(hex, "__0%02X", val); out += hex; } } @@ -133,34 +134,26 @@ string AstNode::encodeName(const string& namein) { string AstNode::encodeNumber(vlsint64_t num) { if (num < 0) { - return "__02D"+cvtToStr(-num); // 2D=- + return "__02D" + cvtToStr(-num); // 2D=- } else { return cvtToStr(num); } } -string AstNode::nameProtect() const { - return VIdProtect::protectIf(name(), protect()); -} -string AstNode::origNameProtect() const { - return VIdProtect::protectIf(origName(), protect()); -} +string AstNode::nameProtect() const { return VIdProtect::protectIf(name(), protect()); } +string AstNode::origNameProtect() const { return VIdProtect::protectIf(origName(), protect()); } string AstNode::shortName() const { string pretty = name(); string::size_type pos; - while ((pos = pretty.find("__PVT__")) != string::npos) { - pretty.replace(pos, 7, ""); - } + while ((pos = pretty.find("__PVT__")) != string::npos) pretty.replace(pos, 7, ""); return pretty; } string AstNode::dedotName(const string& namein) { string pretty = namein; string::size_type pos; - while ((pos = pretty.find("__DOT__")) != string::npos) { - pretty.replace(pos, 7, "."); - } + while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, "."); if (pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, ""); return pretty; } @@ -170,12 +163,8 @@ string AstNode::vcdName(const string& namein) { // Dots are reserved for dots the user put in the name string pretty = namein; string::size_type pos; - while ((pos = pretty.find("__DOT__")) != string::npos) { - pretty.replace(pos, 7, " "); - } - while ((pos = pretty.find('.')) != string::npos) { - pretty.replace(pos, 1, " "); - } + while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, " "); + while ((pos = pretty.find('.')) != string::npos) pretty.replace(pos, 1, " "); // Now convert escaped special characters, etc return prettyName(pretty); } @@ -185,38 +174,38 @@ string AstNode::prettyName(const string& namein) { string pretty; pretty = ""; pretty.reserve(namein.length()); - for (const char* pos = namein.c_str(); *pos; ) { - if (pos[0]=='-' && pos[1]=='>') { // -> + for (const char* pos = namein.c_str(); *pos;) { + if (pos[0] == '-' && pos[1] == '>') { // -> pretty += "."; pos += 2; continue; } - if (pos[0]=='_' && pos[1]=='_') { // Short-circuit - if (0==strncmp(pos, "__BRA__", 7)) { + if (pos[0] == '_' && pos[1] == '_') { // Short-circuit + if (0 == strncmp(pos, "__BRA__", 7)) { pretty += "["; pos += 7; continue; } - if (0==strncmp(pos, "__KET__", 7)) { + if (0 == strncmp(pos, "__KET__", 7)) { pretty += "]"; pos += 7; continue; } - if (0==strncmp(pos, "__DOT__", 7)) { + if (0 == strncmp(pos, "__DOT__", 7)) { pretty += "."; pos += 7; continue; } - if (0==strncmp(pos, "__PVT__", 7)) { + if (0 == strncmp(pos, "__PVT__", 7)) { pretty += ""; pos += 7; continue; } - if (pos[0]=='_' && pos[1]=='_' && pos[2]=='0' - && isxdigit(pos[3]) && isxdigit(pos[4])) { + if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && isxdigit(pos[3]) + && isxdigit(pos[4])) { char value = 0; - value += 16*(isdigit(pos[3]) ? (pos[3]-'0') : (tolower(pos[3])-'a'+10)); - value += (isdigit(pos[4]) ? (pos[4]-'0') : (tolower(pos[4])-'a'+10)); + value += 16 * (isdigit(pos[3]) ? (pos[3] - '0') : (tolower(pos[3]) - 'a' + 10)); + value += (isdigit(pos[4]) ? (pos[4] - '0') : (tolower(pos[4]) - 'a' + 10)); pretty += value; pos += 5; continue; @@ -226,37 +215,37 @@ string AstNode::prettyName(const string& namein) { pretty += pos[0]; ++pos; } - if (pretty[0]=='T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, ""); - if (pretty[0]=='T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, ""); + if (pretty[0] == 'T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, ""); + if (pretty[0] == 'T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, ""); return pretty; } string AstNode::prettyTypeName() const { - if (name()=="") return typeName(); - return string(typeName())+" '"+prettyName()+"'"; + if (name() == "") return typeName(); + return string(typeName()) + " '" + prettyName() + "'"; } //###################################################################### // Insertion -inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next) { +inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next){ #ifdef VL_DEBUG - // Called on all major tree changers. - // Only for use for those really nasty bugs relating to internals - // Note this may be null. - //if (debug()) cout<<"-treeChange: V3Ast.cpp:"<"<dumpTree(cout, "-treeChange: "); - // if (next||1) this->dumpTreeAndNext(cout, prefix); - // else this->dumpTree(cout, prefix); - // this->checkTree(); - // v3Global.rootp()->checkTree(); - //} +// Called on all major tree changers. +// Only for use for those really nasty bugs relating to internals +// Note this may be null. +// if (debug()) cout<<"-treeChange: V3Ast.cpp:"<"<dumpTree(cout, "-treeChange: "); +// if (next||1) this->dumpTreeAndNext(cout, prefix); +// else this->dumpTree(cout, prefix); +// this->checkTree(); +// v3Global.rootp()->checkTree(); +//} #endif } @@ -276,8 +265,9 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) { UDEBUGONLY(UASSERT_OBJ(!oldtailp->m_nextp, nodep, "Node had next, but headtail says it shouldn't");); } else { - // Though inefficient, we are occasionally passed a addNext in the middle of a list. - while (oldtailp->m_nextp != NULL) oldtailp = oldtailp->m_nextp; + // Though inefficient, we are occasionally passed an + // addNext in the middle of a list. + while (oldtailp->m_nextp) oldtailp = oldtailp->m_nextp; } } // Link it in @@ -328,15 +318,15 @@ void AstNode::addNextHere(AstNode* newp) { AstNode* oldheadtailp = this->m_headtailp; // (!oldheadtailp) // this was&is middle of list // (oldheadtailp==this && !oldnext)// this was head AND tail (one node long list) - // (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not tail - // (oldheadtailp && !oldnextp) // this was tail of list, might also + // (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not + // tail (oldheadtailp && !oldnextp) // this was tail of list, might also // be head of one-node list // newp->m_headtailp = NULL; // Not at head any longer addlastp->m_headtailp = NULL; // Presume middle of list // newp might happen to be head/tail after all, if so will be set again below if (oldheadtailp) { // else in middle of list, no change - if (oldheadtailp==this) { // this was one node + if (oldheadtailp == this) { // this was one node this->m_headtailp = addlastp; // Was head/tail, now a tail addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or NULL) } else if (!oldnextp) { // this was tail @@ -404,26 +394,38 @@ void AstNode::setOp4p(AstNode* newp) { void AstNode::addOp1p(AstNode* newp) { UASSERT(newp, "Null item passed to addOp1p"); - if (!m_op1p) { op1p(newp); } - else { m_op1p->addNext(newp); } + if (!m_op1p) { + op1p(newp); + } else { + m_op1p->addNext(newp); + } } void AstNode::addOp2p(AstNode* newp) { UASSERT(newp, "Null item passed to addOp2p"); - if (!m_op2p) { op2p(newp); } - else { m_op2p->addNext(newp); } + if (!m_op2p) { + op2p(newp); + } else { + m_op2p->addNext(newp); + } } void AstNode::addOp3p(AstNode* newp) { UASSERT(newp, "Null item passed to addOp3p"); - if (!m_op3p) { op3p(newp); } - else { m_op3p->addNext(newp); } + if (!m_op3p) { + op3p(newp); + } else { + m_op3p->addNext(newp); + } } void AstNode::addOp4p(AstNode* newp) { UASSERT(newp, "Null item passed to addOp4p"); - if (!m_op4p) { op4p(newp); } - else { m_op4p->addNext(newp); } + if (!m_op4p) { + op4p(newp); + } else { + m_op4p->addNext(newp); + } } void AstNode::replaceWith(AstNode* newp) { @@ -435,13 +437,13 @@ void AstNode::replaceWith(AstNode* newp) { } void AstNRelinker::dump(std::ostream& str) const { - str<<" BK="<(m_backp); - str<<" ITER="<(m_iterpp); - str<<" CHG="<<(m_chg==RELINK_NEXT?"[NEXT] ":""); - str<<(m_chg==RELINK_OP1?"[OP1] ":""); - str<<(m_chg==RELINK_OP2?"[OP2] ":""); - str<<(m_chg==RELINK_OP3?"[OP3] ":""); - str<<(m_chg==RELINK_OP4?"[OP4] ":""); + str << " BK=" << reinterpret_cast(m_backp); + str << " ITER=" << reinterpret_cast(m_iterpp); + str << " CHG=" << (m_chg == RELINK_NEXT ? "[NEXT] " : ""); + str << (m_chg == RELINK_OP1 ? "[OP1] " : ""); + str << (m_chg == RELINK_OP2 ? "[OP2] " : ""); + str << (m_chg == RELINK_OP3 ? "[OP3] " : ""); + str << (m_chg == RELINK_OP4 ? "[OP4] " : ""); } AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) { @@ -452,17 +454,24 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) { AstNode* backp = oldp->m_backp; if (linkerp) { linkerp->m_oldp = oldp; - linkerp->m_backp = backp; + linkerp->m_backp = backp; linkerp->m_iterpp = oldp->m_iterpp; - if (backp->m_nextp == oldp) linkerp->m_chg = AstNRelinker::RELINK_NEXT; - else if (backp->m_op1p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP1; - else if (backp->m_op2p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP2; - else if (backp->m_op3p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP3; - else if (backp->m_op4p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP4; - else oldp->v3fatalSrc("Unlink of node with back not pointing to it."); + if (backp->m_nextp == oldp) { + linkerp->m_chg = AstNRelinker::RELINK_NEXT; + } else if (backp->m_op1p == oldp) { + linkerp->m_chg = AstNRelinker::RELINK_OP1; + } else if (backp->m_op2p == oldp) { + linkerp->m_chg = AstNRelinker::RELINK_OP2; + } else if (backp->m_op3p == oldp) { + linkerp->m_chg = AstNRelinker::RELINK_OP3; + } else if (backp->m_op4p == oldp) { + linkerp->m_chg = AstNRelinker::RELINK_OP4; + } else { + oldp->v3fatalSrc("Unlink of node with back not pointing to it."); + } } - if (backp->m_nextp== oldp) { - backp->m_nextp= NULL; + if (backp->m_nextp == oldp) { + backp->m_nextp = NULL; // Old list gets truncated // New list becomes a list upon itself // Most common case is unlinking a entire operand tree @@ -477,12 +486,17 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) { // Create new head/tail of extracted list oldp->m_headtailp = oldtailp; oldp->m_headtailp->m_headtailp = oldp; + } else if (backp->m_op1p == oldp) { + backp->m_op1p = NULL; + } else if (backp->m_op2p == oldp) { + backp->m_op2p = NULL; + } else if (backp->m_op3p == oldp) { + backp->m_op3p = NULL; + } else if (backp->m_op4p == oldp) { + backp->m_op4p = NULL; + } else { + this->v3fatalSrc("Unlink of node with back not pointing to it."); } - else if (backp->m_op1p == oldp) backp->m_op1p = NULL; - else if (backp->m_op2p == oldp) backp->m_op2p = NULL; - else if (backp->m_op3p == oldp) backp->m_op3p = NULL; - else if (backp->m_op4p == oldp) backp->m_op4p = NULL; - else this->v3fatalSrc("Unlink of node with back not pointing to it."); // Relink oldp->m_backp = NULL; // Iterator fixup @@ -500,32 +514,44 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) { AstNode* backp = oldp->m_backp; if (linkerp) { linkerp->m_oldp = oldp; - linkerp->m_backp = backp; + linkerp->m_backp = backp; linkerp->m_iterpp = oldp->m_iterpp; - if (backp->m_nextp == oldp) linkerp->m_chg = AstNRelinker::RELINK_NEXT; - else if (backp->m_op1p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP1; - else if (backp->m_op2p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP2; - else if (backp->m_op3p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP3; - else if (backp->m_op4p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP4; - else this->v3fatalSrc("Unlink of node with back not pointing to it."); + if (backp->m_nextp == oldp) { + linkerp->m_chg = AstNRelinker::RELINK_NEXT; + } else if (backp->m_op1p == oldp) { + linkerp->m_chg = AstNRelinker::RELINK_OP1; + } else if (backp->m_op2p == oldp) { + linkerp->m_chg = AstNRelinker::RELINK_OP2; + } else if (backp->m_op3p == oldp) { + linkerp->m_chg = AstNRelinker::RELINK_OP3; + } else if (backp->m_op4p == oldp) { + linkerp->m_chg = AstNRelinker::RELINK_OP4; + } else { + this->v3fatalSrc("Unlink of node with back not pointing to it."); + } } - if (backp->m_nextp== oldp) { + if (backp->m_nextp == oldp) { // This node gets removed from middle (or tail) of list // Not head, since then oldp wouldn't be a next of backp... - backp->m_nextp= oldp->m_nextp; + backp->m_nextp = oldp->m_nextp; if (backp->m_nextp) backp->m_nextp->m_backp = backp; // If it was a tail, back becomes new tail if (oldp->m_headtailp) { backp->m_headtailp = oldp->m_headtailp; backp->m_headtailp->m_headtailp = backp; } - } - else { - if (backp->m_op1p == oldp) backp->m_op1p = oldp->m_nextp; - else if (backp->m_op2p == oldp) backp->m_op2p = oldp->m_nextp; - else if (backp->m_op3p == oldp) backp->m_op3p = oldp->m_nextp; - else if (backp->m_op4p == oldp) backp->m_op4p = oldp->m_nextp; - else this->v3fatalSrc("Unlink of node with back not pointing to it."); + } else { + if (backp->m_op1p == oldp) { + backp->m_op1p = oldp->m_nextp; + } else if (backp->m_op2p == oldp) { + backp->m_op2p = oldp->m_nextp; + } else if (backp->m_op3p == oldp) { + backp->m_op3p = oldp->m_nextp; + } else if (backp->m_op4p == oldp) { + backp->m_op4p = oldp->m_nextp; + } else { + this->v3fatalSrc("Unlink of node with back not pointing to it."); + } if (oldp->m_nextp) { AstNode* newheadp = oldp->m_nextp; newheadp->m_backp = backp; @@ -545,13 +571,19 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) { } void AstNode::relink(AstNRelinker* linkerp) { - if (debug()>8) { UINFO(0," EDIT: relink: "); dumpPtrs(); } + if (debug() > 8) { + UINFO(0, " EDIT: relink: "); + dumpPtrs(); + } AstNode* newp = this; UASSERT(linkerp && linkerp->m_backp, "Need non-empty linker"); UASSERT(!newp->backp(), "New node already linked?"); newp->editCountInc(); - if (debug()>8) { linkerp->dump(cout); cout< 8) { + linkerp->dump(cout); + cout << endl; + } AstNode* backp = linkerp->m_backp; this->debugTreeChange("-relinkNew: ", __LINE__, true); @@ -563,9 +595,7 @@ void AstNode::relink(AstNRelinker* linkerp) { case AstNRelinker::RELINK_OP2: relinkOneLink(backp->m_op2p /*ref*/, newp); break; case AstNRelinker::RELINK_OP3: relinkOneLink(backp->m_op3p /*ref*/, newp); break; case AstNRelinker::RELINK_OP4: relinkOneLink(backp->m_op4p /*ref*/, newp); break; - default: - this->v3fatalSrc("Relink of node without any link to change."); - break; + default: this->v3fatalSrc("Relink of node without any link to change."); break; } // Relink newp->m_backp = backp; @@ -595,10 +625,10 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set // Insert the whole old list following the new node's list. // Thus a unlink without next, followed by relink, gives the same list. AstNode* newlistlastp = newp->m_headtailp; - UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp!=newp), newp, + UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp != newp), newp, "Headtailp tail isn't at the tail"); AstNode* oldlistlastp = pointpr->m_headtailp; - UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp!=pointpr), newp, + UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp != pointpr), newp, "Old headtailp tail isn't at the tail"); // Next links newlistlastp->m_nextp = pointpr; @@ -650,7 +680,7 @@ AstNode* AstNode::cloneTreeIterList() { AstNode* newheadp = NULL; AstNode* newtailp = NULL; // Audited to make sure this is never NULL - for (AstNode* oldp = this; oldp; oldp=oldp->m_nextp) { + for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) { AstNode* newp = oldp->cloneTreeIter(); newp->m_headtailp = NULL; newp->m_backp = newtailp; @@ -701,7 +731,7 @@ void AstNode::deleteNode() { #else !v3Global.opt.debugLeak() #endif - ) { + ) { delete this; } // Else leak massively, so each pointer is unique @@ -711,7 +741,7 @@ void AstNode::deleteNode() { void AstNode::deleteTreeIter() { // private: Delete list of nodes. Publicly call deleteTree() instead. // Audited to make sure this is never NULL - for (AstNode* nodep=this, *nnextp; nodep; nodep=nnextp) { + for (AstNode *nodep = this, *nnextp; nodep; nodep = nnextp) { nnextp = nodep->m_nextp; // MUST be depth first! if (nodep->m_op1p) nodep->m_op1p->deleteTreeIter(); @@ -789,26 +819,25 @@ void AstNode::iterateAndNext(AstNVisitor& v) { // there's no lower level reason yet though the back must exist. AstNode* nodep = this; #ifdef VL_DEBUG // Otherwise too hot of a function for debug - UASSERT_OBJ(!(nodep && !nodep->m_backp), nodep, - "iterateAndNext node has no back"); + UASSERT_OBJ(!(nodep && !nodep->m_backp), nodep, "iterateAndNext node has no back"); #endif if (nodep) ASTNODE_PREFETCH(nodep->m_nextp); - while (nodep) { // effectively: if (!this) return; // Callers rely on this + while (nodep) { // effectively: if (!this) return; // Callers rely on this if (nodep->m_nextp) ASTNODE_PREFETCH(nodep->m_nextp->m_nextp); - AstNode* niterp = nodep; // This address may get stomped via m_iterpp if the node is edited + AstNode* niterp = nodep; // Pointer may get stomped via m_iterpp if the node is edited // Desirable check, but many places where multiple iterations are OK - // UASSERT_OBJ(!niterp->m_iterpp, niterp, "IterateAndNext under iterateAndNext may miss edits"); - // Optimization note: Doing PREFETCH_RW on m_iterpp is a net even + // UASSERT_OBJ(!niterp->m_iterpp, niterp, "IterateAndNext under iterateAndNext may miss + // edits"); Optimization note: Doing PREFETCH_RW on m_iterpp is a net even // cppcheck-suppress nullPointer niterp->m_iterpp = &niterp; niterp->accept(v); // accept may do a replaceNode and change niterp on us... // niterp maybe NULL, so need cast if printing - //if (niterp != nodep) UINFO(1,"iterateAndNext edited "<m_iterpp = NULL; - if (VL_UNLIKELY(niterp!=nodep)) { // Edited node inside accept + if (VL_UNLIKELY(niterp != nodep)) { // Edited node inside accept nodep = niterp; } else { // Unchanged node, just continue loop nodep = niterp->m_nextp; @@ -822,8 +851,11 @@ void AstNode::iterateListBackwards(AstNVisitor& v) { while (nodep) { // Edits not supported: nodep->m_iterpp = &nodep; nodep->accept(v); - if (nodep->backp()->m_nextp == nodep) nodep = nodep->backp(); - else nodep = NULL; // else: backp points up the tree. + if (nodep->backp()->m_nextp == nodep) { + nodep = nodep->backp(); + } else { + nodep = NULL; + } // else: backp points up the tree. } } @@ -861,7 +893,8 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) { // track, then delete it on completion AstBegin* tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep); { - VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep); // nodep to null as may be replaced + VL_DO_DANGLING(tempp->stmtsp()->accept(v), + nodep); // nodep to null as may be replaced } nodep = tempp->stmtsp()->unlinkFrBackWithNext(); VL_DO_DANGLING(tempp->deleteTree(), tempp); @@ -869,11 +902,17 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) { // Use back to determine who's pointing at us (IE assume new node // grafts into same place as old one) AstNode** nextnodepp = NULL; - if (this->m_backp->m_op1p == this) nextnodepp = &(this->m_backp->m_op1p); - else if (this->m_backp->m_op2p == this) nextnodepp = &(this->m_backp->m_op2p); - else if (this->m_backp->m_op3p == this) nextnodepp = &(this->m_backp->m_op3p); - else if (this->m_backp->m_op4p == this) nextnodepp = &(this->m_backp->m_op4p); - else if (this->m_backp->m_nextp == this) nextnodepp = &(this->m_backp->m_nextp); + if (this->m_backp->m_op1p == this) { + nextnodepp = &(this->m_backp->m_op1p); + } else if (this->m_backp->m_op2p == this) { + nextnodepp = &(this->m_backp->m_op2p); + } else if (this->m_backp->m_op3p == this) { + nextnodepp = &(this->m_backp->m_op3p); + } else if (this->m_backp->m_op4p == this) { + nextnodepp = &(this->m_backp->m_op4p); + } else if (this->m_backp->m_nextp == this) { + nextnodepp = &(this->m_backp->m_nextp); + } UASSERT_OBJ(nextnodepp, this, "Node's back doesn't point to forward to node itself"); { VL_DO_DANGLING(nodep->accept(v), nodep); // nodep to null as may be replaced @@ -887,10 +926,8 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) { void AstNode::cloneRelinkTree() { // private: Cleanup clone() operation on whole tree. Publicly call cloneTree() instead. - for (AstNode* nodep=this; nodep; nodep = nodep->m_nextp) { - if (m_dtypep && m_dtypep->clonep()) { - m_dtypep = m_dtypep->clonep(); - } + for (AstNode* nodep = this; nodep; nodep = nodep->m_nextp) { + if (m_dtypep && m_dtypep->clonep()) m_dtypep = m_dtypep->clonep(); nodep->cloneRelink(); if (nodep->m_op1p) nodep->m_op1p->cloneRelinkTree(); if (nodep->m_op2p) nodep->m_op2p->cloneRelinkTree(); @@ -912,37 +949,34 @@ bool AstNode::gateTreeIter() const { return true; } -bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, - bool ignNext, bool gateOnly) { +bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext, + bool gateOnly) { // private: Return true if the two trees are identical if (!node1p && !node2p) return true; if (!node1p || !node2p) return false; - if (node1p->type() != node2p->type() - || node1p->dtypep() != node2p->dtypep() - || !node1p->same(node2p) - || (gateOnly && !node1p->isGateOptimizable())) { + if (node1p->type() != node2p->type() || node1p->dtypep() != node2p->dtypep() + || !node1p->same(node2p) || (gateOnly && !node1p->isGateOptimizable())) { return false; } return (sameTreeIter(node1p->m_op1p, node2p->m_op1p, false, gateOnly) && sameTreeIter(node1p->m_op2p, node2p->m_op2p, false, gateOnly) && sameTreeIter(node1p->m_op3p, node2p->m_op3p, false, gateOnly) && sameTreeIter(node1p->m_op4p, node2p->m_op4p, false, gateOnly) - && (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp, false, gateOnly)) - ); + && (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp, false, gateOnly))); } //====================================================================== // Static utilities std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) { - return os<backp(), this, "Back node inconsistent"); if (VN_IS(this, NodeTermop) || VN_IS(this, NodeVarRef)) { // Termops have a short-circuited iterateChildren, so check usage - UASSERT_OBJ(!(op1p()||op2p()||op3p()||op4p()), this, + UASSERT_OBJ(!(op1p() || op2p() || op3p() || op4p()), this, "Terminal operation with non-terminals"); } if (m_op1p) m_op1p->checkTreeIterList(this); @@ -969,9 +1003,9 @@ void AstNode::checkTreeIterList(AstNode* backp) { // Audited to make sure this is never NULL AstNode* headp = this; AstNode* tailp = this; - for (AstNode* nodep=headp; nodep; nodep=nodep->nextp()) { + for (AstNode* nodep = headp; nodep; nodep = nodep->nextp()) { nodep->checkTreeIter(backp); - UASSERT_OBJ(headp==this || !nextp(), this, + UASSERT_OBJ(headp == this || !nextp(), this, "Headtailp should be null in middle of lists"); tailp = nodep; backp = nodep; @@ -993,12 +1027,14 @@ void AstNode::checkTree() { // cppcheck-suppress unusedFunction // Debug only void AstNode::dumpGdb() { // For GDB only // LCOV_EXCL_LINE dumpGdbHeader(); // LCOV_EXCL_LINE - cout<<" "; dump(cout); cout<dumpTreeFile(filename); // LCOV_EXCL_LINE } @@ -1021,45 +1058,53 @@ void AstNode::checkIter() const { } void AstNode::dumpPtrs(std::ostream& os) const { - os<<"This="<8) { os<= 9) { - os<warnContextSecondary(); + os << indent << " " << this << endl; + if (debug() > 8) { + os << indent << " "; + dumpPtrs(os); } - if (maxDepth==1) { - if (op1p()||op2p()||op3p()||op4p()) { os<= 9) { os << fileline()->warnContextSecondary(); } + if (maxDepth == 1) { + if (op1p() || op2p() || op3p() || op4p()) { os << indent << "1: ...(maxDepth)" << endl; } } else { - for (const AstNode* nodep=op1p(); nodep; nodep=nodep->nextp()) { - nodep->dumpTree(os, indent+"1:", maxDepth-1); } - for (const AstNode* nodep=op2p(); nodep; nodep=nodep->nextp()) { - nodep->dumpTree(os, indent+"2:", maxDepth-1); } - for (const AstNode* nodep=op3p(); nodep; nodep=nodep->nextp()) { - nodep->dumpTree(os, indent+"3:", maxDepth-1); } - for (const AstNode* nodep=op4p(); nodep; nodep=nodep->nextp()) { - nodep->dumpTree(os, indent+"4:", maxDepth-1); } + for (const AstNode* nodep = op1p(); nodep; nodep = nodep->nextp()) { + nodep->dumpTree(os, indent + "1:", maxDepth - 1); + } + for (const AstNode* nodep = op2p(); nodep; nodep = nodep->nextp()) { + nodep->dumpTree(os, indent + "2:", maxDepth - 1); + } + for (const AstNode* nodep = op3p(); nodep; nodep = nodep->nextp()) { + nodep->dumpTree(os, indent + "3:", maxDepth - 1); + } + for (const AstNode* nodep = op4p(); nodep; nodep = nodep->nextp()) { + nodep->dumpTree(os, indent + "4:", maxDepth - 1); + } } } @@ -1073,16 +1118,15 @@ void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDep void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) { // Not const function as calls checkTree if (doDump) { - { // Write log & close - UINFO(2,"Dumping "< logsp (V3File::new_ofstream(filename, append)); - if (logsp->fail()) v3fatal("Can't write "<"; - *logsp<<" to "<=9)) { - *logsp< logsp(V3File::new_ofstream(filename, append)); + if (logsp->fail()) v3fatal("Can't write " << filename); + *logsp << "Verilator Tree Dump (format 0x3900) from to " << endl; + if (editCountGbl() == editCountLast() && !(v3Global.opt.dumpTree() >= 9)) { + *logsp << endl; + *logsp << "No changes since last dump!\n"; } else { dumpTree(*logsp); } @@ -1100,7 +1144,9 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) { } void AstNode::v3errorEndFatal(std::ostringstream& str) const { - v3errorEnd(str); assert(0); VL_UNREACHABLE + v3errorEnd(str); + assert(0); + VL_UNREACHABLE } string AstNode::locationStr() const { @@ -1148,12 +1194,12 @@ void AstNode::v3errorEnd(std::ostringstream& str) const { V3Error::v3errorEnd(str, locationStr()); } else { std::ostringstream nsstr; - nsstr<(this)->dump(nsstr); - nsstr<v3errorEnd(nsstr, locationStr()); } @@ -1164,8 +1210,7 @@ void AstNode::v3errorEnd(std::ostringstream& str) const { void AstNode::dtypeChgSigned(bool flag) { UASSERT_OBJ(dtypep(), this, "No dtype when changing to (un)signed"); - dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(), - AstNumeric::fromBool(flag)); + dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(), AstNumeric::fromBool(flag)); } void AstNode::dtypeChgWidth(int width, int widthMin) { UASSERT_OBJ(dtypep(), this, @@ -1178,9 +1223,9 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) { // We allow dtypep() to be null, as before/during widthing dtypes are not resolved dtypeSetLogicUnsized(width, widthMin, numeric); } else { - if (width==dtypep()->width() - && widthMin==dtypep()->widthMin() - && numeric==dtypep()->numeric()) return; // Correct already + if (width == dtypep()->width() && widthMin == dtypep()->widthMin() + && numeric == dtypep()->numeric()) + return; // Correct already // FUTURE: We may be pointing at a two state data type, and this may // convert it to logic. Since the AstVar remains correct, we // work OK but this assumption may break in the future. @@ -1193,34 +1238,31 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) { AstNodeDType* AstNode::findBasicDType(AstBasicDTypeKwd kwd) const { // For 'simple' types we use the global directory. These are all unsized. // More advanced types land under the module/task/etc - return v3Global.rootp()->typeTablep() - ->findBasicDType(fileline(), kwd); + return v3Global.rootp()->typeTablep()->findBasicDType(fileline(), kwd); } AstNodeDType* AstNode::findBitDType(int width, int widthMin, AstNumeric numeric) const { - return v3Global.rootp()->typeTablep() - ->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, width, widthMin, numeric); + return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, + width, widthMin, numeric); } AstNodeDType* AstNode::findLogicDType(int width, int widthMin, AstNumeric numeric) const { - return v3Global.rootp()->typeTablep() - ->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, width, widthMin, numeric); + return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, + width, widthMin, numeric); } AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin, AstNumeric numeric) const { - return v3Global.rootp()->typeTablep() - ->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, range, widthMin, numeric); + return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, + range, widthMin, numeric); } AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin, AstNumeric numeric) const { - return v3Global.rootp()->typeTablep() - ->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, range, widthMin, numeric); + return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, + range, widthMin, numeric); } AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) { - return v3Global.rootp()->typeTablep() - ->findInsertSameDType(nodep); + return v3Global.rootp()->typeTablep()->findInsertSameDType(nodep); } AstNodeDType* AstNode::findVoidDType() const { - return v3Global.rootp()->typeTablep() - ->findVoidDType(fileline()); + return v3Global.rootp()->typeTablep()->findVoidDType(fileline()); } //###################################################################### diff --git a/src/V3Ast.h b/src/V3Ast.h index b73b1840e..3f461b777 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -59,12 +59,12 @@ typedef std::set MTaskIdSet; // Set of mtaskIds for Var sorting } while (false) // (V)erilator (N)ode is: True if AstNode is of a a given AstType -#define VN_IS(nodep,nodetypename) (AstNode::privateIs(nodep)) +#define VN_IS(nodep, nodetypename) (AstNode::privateIs(nodep)) // (V)erilator (N)ode cast: Cast to given type if can; effectively // dynamic_cast(nodep) -#define VN_CAST(nodep,nodetypename) (AstNode::privateCast(nodep)) -#define VN_CAST_CONST(nodep,nodetypename) (AstNode::privateConstCast(nodep)) +#define VN_CAST(nodep, nodetypename) (AstNode::privateCast(nodep)) +#define VN_CAST_CONST(nodep, nodetypename) (AstNode::privateConstCast(nodep)) // (V)erilator (N)ode deleted: Reference to deleted child (for assertions only) #define VN_DELETED(nodep) VL_UNLIKELY((vluint64_t)(nodep) == 0x1) @@ -81,8 +81,10 @@ public: // cppcheck-suppress uninitVar // responsibility of each subclass inline AstType() {} // cppcheck-suppress noExplicitConstructor - inline AstType(en _e) : m_e(_e) {} - explicit inline AstType(int _e) : m_e(static_cast(_e)) {} + inline AstType(en _e) + : m_e(_e) {} + explicit inline AstType(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } }; inline bool operator==(const AstType& lhs, const AstType& rhs) { return lhs.m_e == rhs.m_e; } @@ -94,7 +96,9 @@ inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return o enum VSignedState { // This can't be in the fancy class as the lexer union will get upset - signedst_UNSIGNED = 0, signedst_SIGNED = 1, signedst_NOSIGN = 2 + signedst_UNSIGNED = 0, + signedst_SIGNED = 1, + signedst_NOSIGN = 2 }; //###################################################################### @@ -109,26 +113,32 @@ public: }; enum en m_e; const char* ascii() const { - static const char* const names[] = { - "UNSIGNED", "SIGNED", "NOSIGN" - }; + static const char* const names[] = {"UNSIGNED", "SIGNED", "NOSIGN"}; return names[m_e]; } - inline AstNumeric() : m_e(UNSIGNED) {} + inline AstNumeric() + : m_e(UNSIGNED) {} // cppcheck-suppress noExplicitConstructor - inline AstNumeric(en _e) : m_e(_e) {} + inline AstNumeric(en _e) + : m_e(_e) {} // cppcheck-suppress noExplicitConstructor inline AstNumeric(VSignedState signst) { - if (signst==signedst_UNSIGNED) m_e = UNSIGNED; - else if (signst==signedst_SIGNED) m_e = SIGNED; - else m_e = NOSIGN; + if (signst == signedst_UNSIGNED) { + m_e = UNSIGNED; + } else if (signst == signedst_SIGNED) { + m_e = SIGNED; + } else { + m_e = NOSIGN; + } } static inline AstNumeric fromBool(bool isSigned) { // Factory method - return isSigned ? AstNumeric(SIGNED) : AstNumeric(UNSIGNED); } - explicit inline AstNumeric(int _e) : m_e(static_cast(_e)) {} + return isSigned ? AstNumeric(SIGNED) : AstNumeric(UNSIGNED); + } + explicit inline AstNumeric(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } - inline bool isSigned() const { return m_e==SIGNED; } - inline bool isNosign() const { return m_e==NOSIGN; } + inline bool isSigned() const { return m_e == SIGNED; } + inline bool isNosign() const { return m_e == NOSIGN; } // No isUnsigned() as it's ambiguous if NOSIGN should be included or not. }; inline bool operator==(const AstNumeric& lhs, const AstNumeric& rhs) { return lhs.m_e == rhs.m_e; } @@ -155,10 +165,13 @@ public: ENUM_SIZE }; enum en m_e; - inline AstPragmaType() : m_e(ILLEGAL) {} + inline AstPragmaType() + : m_e(ILLEGAL) {} // cppcheck-suppress noExplicitConstructor - inline AstPragmaType(en _e) : m_e(_e) {} - explicit inline AstPragmaType(int _e) : m_e(static_cast(_e)) {} + inline AstPragmaType(en _e) + : m_e(_e) {} + explicit inline AstPragmaType(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } }; inline bool operator==(const AstPragmaType& lhs, const AstPragmaType& rhs) { @@ -181,15 +194,19 @@ public: TRACE_CHANGE_SUB }; enum en m_e; - inline AstCFuncType() : m_e(FT_NORMAL) {} + inline AstCFuncType() + : m_e(FT_NORMAL) {} // cppcheck-suppress noExplicitConstructor - inline AstCFuncType(en _e) : m_e(_e) {} - explicit inline AstCFuncType(int _e) : m_e(static_cast(_e)) {} + inline AstCFuncType(en _e) + : m_e(_e) {} + explicit inline AstCFuncType(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } // METHODS - bool isTrace() const { return (m_e==TRACE_INIT || m_e==TRACE_INIT_SUB - || m_e==TRACE_FULL || m_e==TRACE_FULL_SUB - || m_e==TRACE_CHANGE || m_e==TRACE_CHANGE_SUB); } + bool isTrace() const { + return (m_e == TRACE_INIT || m_e == TRACE_INIT_SUB || m_e == TRACE_FULL + || m_e == TRACE_FULL_SUB || m_e == TRACE_CHANGE || m_e == TRACE_CHANGE_SUB); + } }; inline bool operator==(const AstCFuncType& lhs, const AstCFuncType& rhs) { return lhs.m_e == rhs.m_e; @@ -201,56 +218,52 @@ inline bool operator==(AstCFuncType::en lhs, const AstCFuncType& rhs) { return l class VEdgeType { public: -// REMEMBER to edit the strings below too + // REMEMBER to edit the strings below too enum en { // These must be in general -> most specific order, as we sort by it // in V3Const::visit AstSenTree ET_ILLEGAL, // Involving a variable - ET_ANYEDGE, // Default for sensitivities; rip them out - ET_BOTHEDGE, // POSEDGE | NEGEDGE + ET_ANYEDGE, // Default for sensitivities; rip them out + ET_BOTHEDGE, // POSEDGE | NEGEDGE ET_POSEDGE, ET_NEGEDGE, - ET_HIGHEDGE, // Is high now (latches) - ET_LOWEDGE, // Is low now (latches) + ET_HIGHEDGE, // Is high now (latches) + ET_LOWEDGE, // Is low now (latches) // Not involving anything - ET_COMBO, // Sensitive to all combo inputs to this block - ET_INITIAL, // User initial statements - ET_SETTLE, // Like combo but for initial wire resolutions after initial statement - ET_NEVER // Never occurs (optimized away) + ET_COMBO, // Sensitive to all combo inputs to this block + ET_INITIAL, // User initial statements + ET_SETTLE, // Like combo but for initial wire resolutions after initial statement + ET_NEVER // Never occurs (optimized away) }; enum en m_e; bool clockedStmt() const { - static const bool clocked[] = { - false, false, true, true, true, true, true, - false, false, false - }; + static const bool clocked[] + = {false, false, true, true, true, true, true, false, false, false}; return clocked[m_e]; } VEdgeType invert() const { switch (m_e) { - case ET_ANYEDGE: return ET_ANYEDGE; - case ET_BOTHEDGE: return ET_BOTHEDGE; - case ET_POSEDGE: return ET_NEGEDGE; - case ET_NEGEDGE: return ET_POSEDGE; - case ET_HIGHEDGE: return ET_LOWEDGE; - case ET_LOWEDGE: return ET_HIGHEDGE; + case ET_ANYEDGE: return ET_ANYEDGE; + case ET_BOTHEDGE: return ET_BOTHEDGE; + case ET_POSEDGE: return ET_NEGEDGE; + case ET_NEGEDGE: return ET_POSEDGE; + case ET_HIGHEDGE: return ET_LOWEDGE; + case ET_LOWEDGE: return ET_HIGHEDGE; default: UASSERT_STATIC(0, "Inverting bad edgeType()"); }; return VEdgeType::ET_ILLEGAL; } const char* ascii() const { - static const char* const names[] = { - "%E-edge", "ANY", "BOTH", "POS", "NEG", "HIGH", "LOW", - "COMBO", "INITIAL", "SETTLE", "NEVER" - }; + static const char* const names[] + = {"%E-edge", "ANY", "BOTH", "POS", "NEG", "HIGH", + "LOW", "COMBO", "INITIAL", "SETTLE", "NEVER"}; return names[m_e]; } const char* verilogKwd() const { - static const char* const names[] = { - "%E-edge", "[any]", "edge", "posedge", "negedge", "[high]", "[low]", - "*", "[initial]", "[settle]", "[never]" - }; + static const char* const names[] + = {"%E-edge", "[any]", "edge", "posedge", "negedge", "[high]", + "[low]", "*", "[initial]", "[settle]", "[never]"}; return names[m_e]; } // Return true iff this and the other have mutually exclusive transitions @@ -259,16 +272,14 @@ public: case VEdgeType::ET_POSEDGE: switch (other.m_e) { case VEdgeType::ET_NEGEDGE: // FALLTHRU - case VEdgeType::ET_LOWEDGE: - return true; + case VEdgeType::ET_LOWEDGE: return true; default: {} } break; case VEdgeType::ET_NEGEDGE: switch (other.m_e) { case VEdgeType::ET_POSEDGE: // FALLTHRU - case VEdgeType::ET_HIGHEDGE: - return true; + case VEdgeType::ET_HIGHEDGE: return true; default: {} } break; @@ -276,10 +287,13 @@ public: } return false; } - inline VEdgeType() : m_e(ET_ILLEGAL) {} + inline VEdgeType() + : m_e(ET_ILLEGAL) {} // cppcheck-suppress noExplicitConstructor - inline VEdgeType(en _e) : m_e(_e) {} - explicit inline VEdgeType(int _e) : m_e(static_cast(_e)) {} + inline VEdgeType(en _e) + : m_e(_e) {} + explicit inline VEdgeType(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } }; inline bool operator==(const VEdgeType& lhs, const VEdgeType& rhs) { return lhs.m_e == rhs.m_e; } @@ -290,6 +304,7 @@ inline bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs == class AstAttrType { public: + // clang-format off enum en { ILLEGAL, // @@ -331,8 +346,10 @@ public: VAR_NO_CLOCKER, // V3LinkParse moves to AstVar::attrClocker VAR_SPLIT_VAR // V3LinkParse moves to AstVar::attrSplitVar }; + // clang-format on enum en m_e; const char* ascii() const { + // clang-format off static const char* const names[] = { "%E-AT", "DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT", @@ -347,12 +364,16 @@ public: "VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER", "VAR_NO_CLOCKER", "VAR_SPLIT_VAR" }; + // clang-format on return names[m_e]; } - inline AstAttrType() : m_e(ILLEGAL) {} + inline AstAttrType() + : m_e(ILLEGAL) {} // cppcheck-suppress noExplicitConstructor - inline AstAttrType(en _e) : m_e(_e) {} - explicit inline AstAttrType(int _e) : m_e(static_cast(_e)) {} + inline AstAttrType(en _e) + : m_e(_e) {} + explicit inline AstAttrType(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } }; inline bool operator==(const AstAttrType& lhs, const AstAttrType& rhs) { @@ -367,14 +388,25 @@ class AstBasicDTypeKwd { public: enum en { UNKNOWN, - BIT, BYTE, CHANDLE, INT, INTEGER, LOGIC, LONGINT, - DOUBLE, SHORTINT, FLOAT, TIME, + BIT, + BYTE, + CHANDLE, + INT, + INTEGER, + LOGIC, + LONGINT, + DOUBLE, + SHORTINT, + FLOAT, + TIME, // Closer to a class type, but limited usage STRING, // Internal types for mid-steps - SCOPEPTR, CHARPTR, + SCOPEPTR, + CHARPTR, // Unsigned and two state; fundamental types - UINT32, UINT64, + UINT32, + UINT64, // Internal types, eliminated after parsing LOGIC_IMPLICIT, // Leave last @@ -383,97 +415,92 @@ public: enum en m_e; const char* ascii() const { static const char* const names[] = { - "%E-unk", - "bit", "byte", "chandle", "int", "integer", "logic", "longint", - "real", "shortint", "shortreal", "time", - "string", - "VerilatedScope*", "char*", - "IData", "QData", - "LOGIC_IMPLICIT", - " MAX" - }; + "%E-unk", "bit", "byte", "chandle", "int", "integer", "logic", + "longint", "real", "shortint", "shortreal", "time", "string", "VerilatedScope*", + "char*", "IData", "QData", "LOGIC_IMPLICIT", " MAX"}; return names[m_e]; } const char* dpiType() const { - static const char* const names[] = { - "%E-unk", - "svBit", "char", "void*", "int", "%E-integer", "svLogic", "long long", - "double", "short", "float", "%E-time", - "const char*", - "dpiScope", "const char*", - "IData", "QData", - "%E-logic-implicit", - " MAX" - }; + static const char* const names[] + = {"%E-unk", "svBit", "char", "void*", "int", "%E-integer", + "svLogic", "long long", "double", "short", "float", "%E-time", + "const char*", "dpiScope", "const char*", "IData", "QData", "%E-logic-implicit", + " MAX"}; return names[m_e]; } static void selfTest() { - UASSERT(0==strcmp(AstBasicDTypeKwd(_ENUM_MAX).ascii(), " MAX"), "SelfTest: Enum mismatch"); - UASSERT(0==strcmp(AstBasicDTypeKwd(_ENUM_MAX).dpiType(), " MAX"), "SelfTest: Enum mismatch"); + UASSERT(0 == strcmp(AstBasicDTypeKwd(_ENUM_MAX).ascii(), " MAX"), + "SelfTest: Enum mismatch"); + UASSERT(0 == strcmp(AstBasicDTypeKwd(_ENUM_MAX).dpiType(), " MAX"), + "SelfTest: Enum mismatch"); } - inline AstBasicDTypeKwd() : m_e(UNKNOWN) {} + inline AstBasicDTypeKwd() + : m_e(UNKNOWN) {} // cppcheck-suppress noExplicitConstructor - inline AstBasicDTypeKwd(en _e) : m_e(_e) {} - explicit inline AstBasicDTypeKwd(int _e) : m_e(static_cast(_e)) {} + inline AstBasicDTypeKwd(en _e) + : m_e(_e) {} + explicit inline AstBasicDTypeKwd(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } int width() const { switch (m_e) { - case BIT: return 1; // scalar, can't bit extract unless ranged - case BYTE: return 8; - case CHANDLE: return 64; - case INT: return 32; - case INTEGER: return 32; - case LOGIC: return 1; // scalar, can't bit extract unless ranged - case LONGINT: return 64; - case DOUBLE: return 64; // opaque - case FLOAT: return 32; // opaque - case SHORTINT: return 16; - case TIME: return 64; - case STRING: return 64; // opaque // Just the pointer, for today - case SCOPEPTR: return 0; // opaque - case CHARPTR: return 0; // opaque - case UINT32: return 32; - case UINT64: return 64; + case BIT: return 1; // scalar, can't bit extract unless ranged + case BYTE: return 8; + case CHANDLE: return 64; + case INT: return 32; + case INTEGER: return 32; + case LOGIC: return 1; // scalar, can't bit extract unless ranged + case LONGINT: return 64; + case DOUBLE: return 64; // opaque + case FLOAT: return 32; // opaque + case SHORTINT: return 16; + case TIME: return 64; + case STRING: return 64; // opaque // Just the pointer, for today + case SCOPEPTR: return 0; // opaque + case CHARPTR: return 0; // opaque + case UINT32: return 32; + case UINT64: return 64; default: return 0; } } bool isSigned() const { - return m_e==BYTE || m_e==SHORTINT || m_e==INT || m_e==LONGINT || m_e==INTEGER - || m_e==DOUBLE || m_e==FLOAT; + return m_e == BYTE || m_e == SHORTINT || m_e == INT || m_e == LONGINT || m_e == INTEGER + || m_e == DOUBLE || m_e == FLOAT; } bool isUnsigned() const { - return m_e==CHANDLE || m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR - || m_e==UINT32 || m_e==UINT64; + return m_e == CHANDLE || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR + || m_e == UINT32 || m_e == UINT64; } bool isFourstate() const { return m_e == INTEGER || m_e == LOGIC || m_e == LOGIC_IMPLICIT || m_e == TIME; } bool isZeroInit() const { // Otherwise initializes to X - return (m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT || m_e==LONGINT || m_e==SHORTINT - || m_e==STRING || m_e==DOUBLE || m_e==FLOAT); + return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == INT || m_e == LONGINT + || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE || m_e == FLOAT); } bool isIntNumeric() const { // Enum increment supported - return (m_e==BIT || m_e==BYTE || m_e==INT || m_e==INTEGER || m_e==LOGIC - || m_e==LONGINT || m_e==SHORTINT || m_e==UINT32 || m_e==UINT64); + return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC + || m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64); } bool isSloppy() const { // Don't be as anal about width warnings - return !(m_e==LOGIC || m_e==BIT); + return !(m_e == LOGIC || m_e == BIT); } bool isBitLogic() const { // Bit/logic vector types; can form a packed array - return (m_e==LOGIC || m_e==BIT); + return (m_e == LOGIC || m_e == BIT); } bool isDpiUnsignable() const { // Can add "unsigned" to DPI - return (m_e==BYTE || m_e==SHORTINT || m_e==INT || m_e==LONGINT || m_e==INTEGER); + return (m_e == BYTE || m_e == SHORTINT || m_e == INT || m_e == LONGINT || m_e == INTEGER); } bool isDpiCLayout() const { // Uses standard C layout, for DPI runtime access - return (m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT - || m_e==LONGINT || m_e==DOUBLE || m_e==SHORTINT || m_e==UINT32 || m_e==UINT64); + return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == INT || m_e == LONGINT + || m_e == DOUBLE || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64); } bool isOpaque() const { // IE not a simple number we can bit optimize - return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR || m_e==DOUBLE || m_e==FLOAT); + return (m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR || m_e == DOUBLE + || m_e == FLOAT); } - bool isDouble() const { return m_e==DOUBLE; } - bool isString() const { return m_e==STRING; } + bool isDouble() const { return m_e == DOUBLE; } + bool isString() const { return m_e == STRING; } }; inline bool operator==(const AstBasicDTypeKwd& lhs, const AstBasicDTypeKwd& rhs) { return lhs.m_e == rhs.m_e; @@ -489,41 +516,37 @@ inline bool operator==(AstBasicDTypeKwd::en lhs, const AstBasicDTypeKwd& rhs) { class VDirection { public: - enum en { - NONE, - INPUT, - OUTPUT, - INOUT, - REF, - CONSTREF - }; + enum en { NONE, INPUT, OUTPUT, INOUT, REF, CONSTREF }; enum en m_e; - inline VDirection() : m_e(NONE) {} + inline VDirection() + : m_e(NONE) {} // cppcheck-suppress noExplicitConstructor - inline VDirection(en _e) : m_e(_e) {} - explicit inline VDirection(int _e) : m_e(static_cast(_e)) {} + inline VDirection(en _e) + : m_e(_e) {} + explicit inline VDirection(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } const char* ascii() const { - static const char* const names[] = { - "NONE", "INPUT", "OUTPUT", "INOUT", "REF", "CONSTREF"}; - return names[m_e]; } + static const char* const names[] = {"NONE", "INPUT", "OUTPUT", "INOUT", "REF", "CONSTREF"}; + return names[m_e]; + } string verilogKwd() const { - static const char* const names[] = { - "", "input", "output", "inout", "ref", "const ref"}; - return names[m_e]; } + static const char* const names[] = {"", "input", "output", "inout", "ref", "const ref"}; + return names[m_e]; + } string xmlKwd() const { // For historical reasons no "put" suffix - static const char* const names[] = { - "", "in", "out", "inout", "ref", "const ref"}; - return names[m_e]; } + static const char* const names[] = {"", "in", "out", "inout", "ref", "const ref"}; + return names[m_e]; + } string prettyName() const { return verilogKwd(); } bool isAny() const { return m_e != NONE; } // Looks like inout - "ish" because not identical to being an INOUT bool isInoutish() const { return m_e == INOUT; } - bool isNonOutput() const { return m_e == INPUT || m_e == INOUT - || m_e == REF || m_e == CONSTREF; } + bool isNonOutput() const { + return m_e == INPUT || m_e == INOUT || m_e == REF || m_e == CONSTREF; + } bool isReadOnly() const { return m_e == INPUT || m_e == CONSTREF; } - bool isWritable() const { return m_e == OUTPUT || m_e == INOUT - || m_e == REF; } + bool isWritable() const { return m_e == OUTPUT || m_e == INOUT || m_e == REF; } bool isRefOrConstRef() const { return m_e == REF || m_e == CONSTREF; } }; inline bool operator==(const VDirection& lhs, const VDirection& rhs) { return lhs.m_e == rhs.m_e; } @@ -538,22 +561,20 @@ inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) { /// Boolean or unknown class VBoolOrUnknown { public: - enum en { - BU_FALSE=0, - BU_TRUE=1, - BU_UNKNOWN=2, - _ENUM_END - }; + enum en { BU_FALSE = 0, BU_TRUE = 1, BU_UNKNOWN = 2, _ENUM_END }; enum en m_e; // CONSTRUCTOR - note defaults to *UNKNOWN* - inline VBoolOrUnknown() : m_e(BU_UNKNOWN) {} + inline VBoolOrUnknown() + : m_e(BU_UNKNOWN) {} // cppcheck-suppress noExplicitConstructor - inline VBoolOrUnknown(en _e) : m_e(_e) {} - explicit inline VBoolOrUnknown(int _e) : m_e(static_cast(_e)) {} + inline VBoolOrUnknown(en _e) + : m_e(_e) {} + explicit inline VBoolOrUnknown(int _e) + : m_e(static_cast(_e)) {} const char* ascii() const { - static const char* const names[] = { - "FALSE", "TRUE", "UNK"}; - return names[m_e]; } + static const char* const names[] = {"FALSE", "TRUE", "UNK"}; + return names[m_e]; + } bool trueKnown() const { return m_e == BU_TRUE; } bool trueUnknown() const { return m_e == BU_TRUE || m_e == BU_UNKNOWN; } bool falseKnown() const { return m_e == BU_FALSE; } @@ -592,7 +613,7 @@ public: TRIWIRE, TRI0, TRI1, - PORT, // Temp type used in parser only + PORT, // Temp type used in parser only BLOCKTEMP, MODULETEMP, STMTTEMP, @@ -601,42 +622,38 @@ public: MEMBER }; enum en m_e; - inline AstVarType() : m_e(UNKNOWN) {} + inline AstVarType() + : m_e(UNKNOWN) {} // cppcheck-suppress noExplicitConstructor - inline AstVarType(en _e) : m_e(_e) {} - explicit inline AstVarType(int _e) : m_e(static_cast(_e)) {} + inline AstVarType(en _e) + : m_e(_e) {} + explicit inline AstVarType(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } const char* ascii() const { static const char* const names[] = { - "?", "GPARAM", "LPARAM", "GENVAR", "VAR", - "SUPPLY0", "SUPPLY1", "WIRE", "WREAL", "IMPLICITWIRE", - "TRIWIRE", "TRI0", "TRI1", - "PORT", - "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", - "IFACEREF", "MEMBER"}; - return names[m_e]; } + "?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1", + "WIRE", "WREAL", "IMPLICITWIRE", "TRIWIRE", "TRI0", "TRI1", "PORT", + "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"}; + return names[m_e]; + } bool isSignal() const { - return (m_e==WIRE || m_e==WREAL || m_e==IMPLICITWIRE - || m_e==TRIWIRE - || m_e==TRI0 || m_e==TRI1 || m_e==PORT - || m_e==SUPPLY0 || m_e==SUPPLY1 - || m_e==VAR); + return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 + || m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR); } bool isContAssignable() const { // In Verilog, always ok in SystemVerilog - return (m_e==SUPPLY0 || m_e==SUPPLY1 - || m_e==WIRE || m_e==WREAL || m_e==IMPLICITWIRE - || m_e==TRIWIRE || m_e==TRI0 || m_e==TRI1 || m_e==PORT - || m_e==BLOCKTEMP || m_e==MODULETEMP || m_e==STMTTEMP - || m_e==XTEMP || m_e==IFACEREF); + return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL + || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 + || m_e == PORT || m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP + || m_e == XTEMP || m_e == IFACEREF); } bool isProcAssignable() const { - return (m_e==GPARAM || m_e==LPARAM || m_e==GENVAR - || m_e==VAR - || m_e==BLOCKTEMP || m_e==MODULETEMP || m_e==STMTTEMP - || m_e==XTEMP || m_e==IFACEREF || m_e==MEMBER); + return (m_e == GPARAM || m_e == LPARAM || m_e == GENVAR || m_e == VAR || m_e == BLOCKTEMP + || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP || m_e == IFACEREF + || m_e == MEMBER); } bool isTemp() const { - return (m_e==BLOCKTEMP || m_e==MODULETEMP || m_e==STMTTEMP || m_e==XTEMP); + return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP); } }; inline bool operator==(const AstVarType& lhs, const AstVarType& rhs) { return lhs.m_e == rhs.m_e; } @@ -650,31 +667,33 @@ inline std::ostream& operator<<(std::ostream& os, const AstVarType& rhs) { class VBranchPred { public: - enum en { - BP_UNKNOWN=0, - BP_LIKELY, - BP_UNLIKELY, - _ENUM_END - }; + enum en { BP_UNKNOWN = 0, BP_LIKELY, BP_UNLIKELY, _ENUM_END }; enum en m_e; // CONSTRUCTOR - note defaults to *UNKNOWN* - inline VBranchPred() : m_e(BP_UNKNOWN) {} + inline VBranchPred() + : m_e(BP_UNKNOWN) {} // cppcheck-suppress noExplicitConstructor - inline VBranchPred(en _e) : m_e(_e) {} - explicit inline VBranchPred(int _e) : m_e(static_cast(_e)) {} + inline VBranchPred(en _e) + : m_e(_e) {} + explicit inline VBranchPred(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } bool unknown() const { return m_e == BP_UNKNOWN; } bool likely() const { return m_e == BP_LIKELY; } bool unlikely() const { return m_e == BP_UNLIKELY; } VBranchPred invert() const { - if (m_e==BP_UNLIKELY) return BP_LIKELY; - else if (m_e==BP_LIKELY) return BP_UNLIKELY; - else return m_e; + if (m_e == BP_UNLIKELY) { + return BP_LIKELY; + } else if (m_e == BP_LIKELY) { + return BP_UNLIKELY; + } else { + return m_e; + } } const char* ascii() const { - static const char* const names[] = { - "", "VL_LIKELY", "VL_UNLIKELY"}; - return names[m_e]; } + static const char* const names[] = {"", "VL_LIKELY", "VL_UNLIKELY"}; + return names[m_e]; + } }; inline bool operator==(const VBranchPred& lhs, const VBranchPred& rhs) { return lhs.m_e == rhs.m_e; @@ -689,29 +708,31 @@ inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) { class VVarAttrClocker { public: - enum en { - CLOCKER_UNKNOWN=0, - CLOCKER_YES, - CLOCKER_NO, - _ENUM_END - }; + enum en { CLOCKER_UNKNOWN = 0, CLOCKER_YES, CLOCKER_NO, _ENUM_END }; enum en m_e; // CONSTRUCTOR - note defaults to *UNKNOWN* - inline VVarAttrClocker() : m_e(CLOCKER_UNKNOWN) {} + inline VVarAttrClocker() + : m_e(CLOCKER_UNKNOWN) {} // cppcheck-suppress noExplicitConstructor - inline VVarAttrClocker(en _e) : m_e(_e) {} - explicit inline VVarAttrClocker(int _e) : m_e(static_cast(_e)) {} + inline VVarAttrClocker(en _e) + : m_e(_e) {} + explicit inline VVarAttrClocker(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } - bool unknown() const { return m_e==CLOCKER_UNKNOWN; } + bool unknown() const { return m_e == CLOCKER_UNKNOWN; } VVarAttrClocker invert() const { - if (m_e==CLOCKER_YES) return CLOCKER_NO; - else if (m_e==CLOCKER_NO) return CLOCKER_YES; - else return m_e; + if (m_e == CLOCKER_YES) { + return CLOCKER_NO; + } else if (m_e == CLOCKER_NO) { + return CLOCKER_YES; + } else { + return m_e; + } } const char* ascii() const { - static const char* const names[] = { - "", "clker", "non_clker"}; - return names[m_e]; } + static const char* const names[] = {"", "clker", "non_clker"}; + return names[m_e]; + } }; inline bool operator==(const VVarAttrClocker& lhs, const VVarAttrClocker& rhs) { return lhs.m_e == rhs.m_e; @@ -730,22 +751,20 @@ inline std::ostream& operator<<(std::ostream& os, const VVarAttrClocker& rhs) { class VAlwaysKwd { public: - enum en { - ALWAYS, - ALWAYS_FF, - ALWAYS_LATCH, - ALWAYS_COMB - }; + enum en { ALWAYS, ALWAYS_FF, ALWAYS_LATCH, ALWAYS_COMB }; enum en m_e; - inline VAlwaysKwd() : m_e(ALWAYS) {} + inline VAlwaysKwd() + : m_e(ALWAYS) {} // cppcheck-suppress noExplicitConstructor - inline VAlwaysKwd(en _e) : m_e(_e) {} - explicit inline VAlwaysKwd(int _e) : m_e(static_cast(_e)) {} + inline VAlwaysKwd(en _e) + : m_e(_e) {} + explicit inline VAlwaysKwd(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } const char* ascii() const { - static const char* const names[] = { - "always", "always_ff", "always_latch", "always_comb"}; - return names[m_e]; } + static const char* const names[] = {"always", "always_ff", "always_latch", "always_comb"}; + return names[m_e]; + } }; inline bool operator==(const VAlwaysKwd& lhs, const VAlwaysKwd& rhs) { return lhs.m_e == rhs.m_e; } inline bool operator==(const VAlwaysKwd& lhs, VAlwaysKwd::en rhs) { return lhs.m_e == rhs; } @@ -755,17 +774,15 @@ inline bool operator==(VAlwaysKwd::en lhs, const VAlwaysKwd& rhs) { return lhs = class VCaseType { public: - enum en { - CT_CASE, - CT_CASEX, - CT_CASEZ, - CT_CASEINSIDE - }; + enum en { CT_CASE, CT_CASEX, CT_CASEZ, CT_CASEINSIDE }; enum en m_e; - inline VCaseType() : m_e(CT_CASE) {} + inline VCaseType() + : m_e(CT_CASE) {} // cppcheck-suppress noExplicitConstructor - inline VCaseType(en _e) : m_e(_e) {} - explicit inline VCaseType(int _e) : m_e(static_cast(_e)) {} + inline VCaseType(en _e) + : m_e(_e) {} + explicit inline VCaseType(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } }; inline bool operator==(const VCaseType& lhs, const VCaseType& rhs) { return lhs.m_e == rhs.m_e; } @@ -776,26 +793,23 @@ inline bool operator==(VCaseType::en lhs, const VCaseType& rhs) { return lhs == class AstDisplayType { public: - enum en { - DT_DISPLAY, - DT_WRITE, - DT_INFO, - DT_ERROR, - DT_WARNING, - DT_FATAL - }; + enum en { DT_DISPLAY, DT_WRITE, DT_INFO, DT_ERROR, DT_WARNING, DT_FATAL }; enum en m_e; - inline AstDisplayType() : m_e(DT_DISPLAY) {} + inline AstDisplayType() + : m_e(DT_DISPLAY) {} // cppcheck-suppress noExplicitConstructor - inline AstDisplayType(en _e) : m_e(_e) {} - explicit inline AstDisplayType(int _e) : m_e(static_cast(_e)) {} + inline AstDisplayType(en _e) + : m_e(_e) {} + explicit inline AstDisplayType(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } - bool addNewline() const { return m_e!=DT_WRITE; } - bool needScopeTracking() const { return m_e!=DT_DISPLAY && m_e!=DT_WRITE; } + bool addNewline() const { return m_e != DT_WRITE; } + bool needScopeTracking() const { return m_e != DT_DISPLAY && m_e != DT_WRITE; } const char* ascii() const { - static const char* const names[] = { - "display", "write", "info", "error", "warning", "fatal"}; - return names[m_e]; } + static const char* const names[] + = {"display", "write", "info", "error", "warning", "fatal"}; + return names[m_e]; + } }; inline bool operator==(const AstDisplayType& lhs, const AstDisplayType& rhs) { return lhs.m_e == rhs.m_e; @@ -822,8 +836,8 @@ public: : m_e(static_cast(_e)) {} operator en() const { return m_e; } const char* ascii() const { - static const char* const names[] = {"$dumpfile", "$dumpvars", "$dumpall", "$dumpflush", - "$dumplimit", "$dumpoff", "$dumpon"}; + static const char* const names[] = {"$dumpfile", "$dumpvars", "$dumpall", "$dumpflush", + "$dumplimit", "$dumpoff", "$dumpon"}; return names[m_e]; } }; @@ -838,19 +852,22 @@ inline bool operator==(VDumpCtlType::en lhs, const VDumpCtlType& rhs) { return l class VParseRefExp { public: enum en { - PX_NONE, // Used in V3LinkParse only - PX_TEXT // Unknown ID component + PX_NONE, // Used in V3LinkParse only + PX_TEXT // Unknown ID component }; enum en m_e; - inline VParseRefExp() : m_e(PX_NONE) {} + inline VParseRefExp() + : m_e(PX_NONE) {} // cppcheck-suppress noExplicitConstructor - inline VParseRefExp(en _e) : m_e(_e) {} - explicit inline VParseRefExp(int _e) : m_e(static_cast(_e)) {} + inline VParseRefExp(en _e) + : m_e(_e) {} + explicit inline VParseRefExp(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } const char* ascii() const { - static const char* const names[] = { - "", "TEXT", "PREDOT"}; - return names[m_e]; } + static const char* const names[] = {"", "TEXT", "PREDOT"}; + return names[m_e]; + } }; inline bool operator==(const VParseRefExp& lhs, const VParseRefExp& rhs) { return lhs.m_e == rhs.m_e; @@ -872,52 +889,75 @@ public: union { int mu_flags; struct { - bool m_ranged:1; // Has a range - bool m_littleEndian:1; // Bit vector is little endian + bool m_ranged : 1; // Has a range + bool m_littleEndian : 1; // Bit vector is little endian }; }; inline bool operator==(const VNumRange& rhs) const { - return m_hi == rhs.m_hi - && m_lo == rhs.m_lo - && mu_flags == rhs.mu_flags; } - inline bool operator< (const VNumRange& rhs) const { - if ( (m_hi < rhs.m_hi)) return true; + return m_hi == rhs.m_hi && m_lo == rhs.m_lo && mu_flags == rhs.mu_flags; + } + inline bool operator<(const VNumRange& rhs) const { + if ((m_hi < rhs.m_hi)) return true; if (!(m_hi == rhs.m_hi)) return false; // lhs > rhs - if ( (m_lo < rhs.m_lo)) return true; + if ((m_lo < rhs.m_lo)) return true; if (!(m_lo == rhs.m_lo)) return false; // lhs > rhs - if ( (mu_flags < rhs.mu_flags)) return true; + if ((mu_flags < rhs.mu_flags)) return true; if (!(mu_flags == rhs.mu_flags)) return false; // lhs > rhs return false; } // class LeftRight {}; - VNumRange() : m_hi(0), m_lo(0), mu_flags(0) {} + VNumRange() + : m_hi(0) + , m_lo(0) + , mu_flags(0) {} VNumRange(int hi, int lo, bool littleEndian) - : m_hi(0), m_lo(0), mu_flags(0) - { init(hi, lo, littleEndian); } + : m_hi(0) + , m_lo(0) + , mu_flags(0) { + init(hi, lo, littleEndian); + } VNumRange(LeftRight, int left, int right) - : m_hi(0), m_lo(0), mu_flags(0) - { init((right>left)?right:left, (right>left)?left:right, (right>left)); } + : m_hi(0) + , m_lo(0) + , mu_flags(0) { + init((right > left) ? right : left, (right > left) ? left : right, (right > left)); + } ~VNumRange() {} // MEMBERS void init(int hi, int lo, bool littleEndian) { - m_hi = hi; m_lo = lo; mu_flags = 0; m_ranged = true; m_littleEndian = littleEndian; + m_hi = hi; + m_lo = lo; + mu_flags = 0; + m_ranged = true; + m_littleEndian = littleEndian; } int hi() const { return m_hi; } int lo() const { return m_lo; } - int left() const { return littleEndian()?lo():hi(); } // How to show a declaration - int right() const { return littleEndian()?hi():lo(); } - int leftToRightInc() const { return littleEndian()?1:-1; } - int elements() const { return hi()-lo()+1; } + int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration + int right() const { return littleEndian() ? hi() : lo(); } + int leftToRightInc() const { return littleEndian() ? 1 : -1; } + int elements() const { return hi() - lo() + 1; } bool ranged() const { return m_ranged; } bool littleEndian() const { return m_littleEndian; } - int hiMaxSelect() const { return (lo()<0 ? hi()-lo() : hi()); } // Maximum value a [] select may index + int hiMaxSelect() const { + return (lo() < 0 ? hi() - lo() : hi()); + } // Maximum value a [] select may index bool representableByWidth() const { // Could be represented by just width=1, or [width-1:0] - return (!m_ranged || (m_lo==0 && m_hi>=1 && !m_littleEndian)); } + return (!m_ranged || (m_lo == 0 && m_hi >= 1 && !m_littleEndian)); + } void dump(std::ostream& str) const { - if (ranged()) str<<"["<(_e)) {} + inline VUseType(en _e) + : m_e(_e) {} + explicit inline VUseType(int _e) + : m_e(static_cast(_e)) {} bool isInclude() const { return m_e == IMP_INCLUDE || m_e == INT_INCLUDE; } bool isFwdClass() const { return m_e == IMP_FWD_CLASS || m_e == INT_FWD_CLASS; } operator en() const { return m_e; } @@ -953,33 +996,35 @@ inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) { class VBasicTypeKey { public: - int m_width; // From AstNodeDType: Bit width of operation - int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation - AstNumeric m_numeric; // From AstNodeDType: Node is signed + int m_width; // From AstNodeDType: Bit width of operation + int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation + AstNumeric m_numeric; // From AstNodeDType: Node is signed AstBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type - VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword) + VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword) inline bool operator==(const VBasicTypeKey& rhs) const { - return m_width == rhs.m_width - && m_widthMin == rhs.m_widthMin - && m_numeric == rhs.m_numeric - && m_keyword == rhs.m_keyword - && m_nrange == rhs.m_nrange; } - inline bool operator< (const VBasicTypeKey& rhs) const { - if ( (m_width < rhs.m_width)) return true; + return m_width == rhs.m_width && m_widthMin == rhs.m_widthMin && m_numeric == rhs.m_numeric + && m_keyword == rhs.m_keyword && m_nrange == rhs.m_nrange; + } + inline bool operator<(const VBasicTypeKey& rhs) const { + if ((m_width < rhs.m_width)) return true; if (!(m_width == rhs.m_width)) return false; // lhs > rhs - if ( (m_widthMin < rhs.m_widthMin)) return true; + if ((m_widthMin < rhs.m_widthMin)) return true; if (!(m_widthMin == rhs.m_widthMin)) return false; // lhs > rhs - if ( (m_numeric < rhs.m_numeric)) return true; + if ((m_numeric < rhs.m_numeric)) return true; if (!(m_numeric == rhs.m_numeric)) return false; // lhs > rhs - if ( (m_keyword < rhs.m_keyword)) return true; + if ((m_keyword < rhs.m_keyword)) return true; if (!(m_keyword == rhs.m_keyword)) return false; // lhs > rhs - if ( (m_nrange < rhs.m_nrange)) return true; + if ((m_nrange < rhs.m_nrange)) return true; if (!(m_nrange == rhs.m_nrange)) return false; // lhs > rhs - return false; } + return false; + } VBasicTypeKey(int width, int widthMin, AstNumeric numeric, AstBasicDTypeKwd kwd, const VNumRange& nrange) - : m_width(width), m_widthMin(widthMin), m_numeric(numeric), - m_keyword(kwd), m_nrange(nrange) {} + : m_width(width) + , m_widthMin(widthMin) + , m_numeric(numeric) + , m_keyword(kwd) + , m_nrange(nrange) {} ~VBasicTypeKey() {} }; @@ -999,11 +1044,15 @@ class VNUser { void* up; int ui; } m_u; + public: VNUser() {} // non-explicit: // cppcheck-suppress noExplicitConstructor - VNUser(int i) { m_u.up = 0; m_u.ui = i; } + VNUser(int i) { + m_u.up = 0; + m_u.ui = i; + } explicit VNUser(void* p) { m_u.up = p; } ~VNUser() {} // Casters @@ -1014,9 +1063,7 @@ public: OrderBlockNU* toOrderBlock() { return ((OrderBlockNU*)m_u.up); } OrderVarNU* toOrderVar() { return ((OrderVarNU*)m_u.up); } V3GraphVertex* toGraphVertex() { return ((V3GraphVertex*)m_u.up); } - inline int toInt() { - return m_u.ui; - } + inline int toInt() { return m_u.ui; } static inline VNUser fromZero() { return VNUser(0); } static inline VNUser fromInt(int i) { return VNUser(i); } }; @@ -1036,30 +1083,33 @@ class AstUserInUseBase { protected: static void allocate(int id, uint32_t& cntGblRef, bool& userBusyRef) { // Perhaps there's still a AstUserInUse in scope for this? - UASSERT_STATIC(!userBusyRef, "Conflicting user use; AstUser"+cvtToStr(id)+"InUse request when under another AstUserInUse"); + UASSERT_STATIC(!userBusyRef, "Conflicting user use; AstUser" + cvtToStr(id) + + "InUse request when under another AstUserInUse"); userBusyRef = true; clearcnt(id, cntGblRef, userBusyRef); } static void free(int id, uint32_t& cntGblRef, bool& userBusyRef) { - UASSERT_STATIC(userBusyRef, "Free of User"+cvtToStr(id)+"() not under AstUserInUse"); + UASSERT_STATIC(userBusyRef, "Free of User" + cvtToStr(id) + "() not under AstUserInUse"); clearcnt(id, cntGblRef, userBusyRef); // Includes a checkUse for us userBusyRef = false; } static void clearcnt(int id, uint32_t& cntGblRef, const bool& userBusyRef) { - UASSERT_STATIC(userBusyRef, "Clear of User"+cvtToStr(id)+"() not under AstUserInUse"); + UASSERT_STATIC(userBusyRef, "Clear of User" + cvtToStr(id) + "() not under AstUserInUse"); // If this really fires and is real (after 2^32 edits???) // we could just walk the tree and clear manually ++cntGblRef; UASSERT_STATIC(cntGblRef, "User*() overflowed!"); } static void checkcnt(int id, uint32_t&, const bool& userBusyRef) { - UASSERT_STATIC(userBusyRef, "Check of User"+cvtToStr(id)+"() failed, not under AstUserInUse"); + UASSERT_STATIC(userBusyRef, + "Check of User" + cvtToStr(id) + "() failed, not under AstUserInUse"); } }; // For each user() declare the in use structure // We let AstNode peek into here, because when under low optimization even // an accessor would be way too slow. +// clang-format off class AstUser1InUse : AstUserInUseBase { protected: friend class AstNode; @@ -1115,6 +1165,7 @@ public: static void clear() { clearcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void check() { checkcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } }; +// clang-format on //###################################################################### // AstNVisitor -- Allows new functions to be called on each node @@ -1126,21 +1177,19 @@ private: std::vector m_deleteps; // Nodes to delete when doDeletes() called protected: friend class AstNode; + public: // METHODS /// At the end of the visitor (or doDeletes()), delete this pushed node /// along with all children and next(s). This is often better to use /// than an immediate deleteTree, as any pointers into this node will /// persist for the lifetime of the visitor - void pushDeletep(AstNode* nodep) { - m_deleteps.push_back(nodep); - } + void pushDeletep(AstNode* nodep) { m_deleteps.push_back(nodep); } /// Call deleteTree on all previously pushDeletep()'ed nodes void doDeletes(); + public: - virtual ~AstNVisitor() { - doDeletes(); - } + virtual ~AstNVisitor() { doDeletes(); } /// Call visit()s on nodep void iterate(AstNode* nodep); /// Call visit()s on nodep's children @@ -1169,21 +1218,27 @@ public: class AstNRelinker { protected: friend class AstNode; - enum RelinkWhatEn { - RELINK_BAD, RELINK_NEXT, RELINK_OP1, RELINK_OP2, RELINK_OP3, RELINK_OP4 - }; + enum RelinkWhatEn { RELINK_BAD, RELINK_NEXT, RELINK_OP1, RELINK_OP2, RELINK_OP3, RELINK_OP4 }; AstNode* m_oldp; // The old node that was linked to this point in the tree AstNode* m_backp; RelinkWhatEn m_chg; AstNode** m_iterpp; + public: - AstNRelinker() { m_oldp = NULL; m_backp = NULL; m_chg = RELINK_BAD; m_iterpp = NULL; } + AstNRelinker() { + m_oldp = NULL; + m_backp = NULL; + m_chg = RELINK_BAD; + m_iterpp = NULL; + } void relink(AstNode* newp); AstNode* oldp() const { return m_oldp; } - void dump(std::ostream& str=std::cout) const; + void dump(std::ostream& str = std::cout) const; }; inline std::ostream& operator<<(std::ostream& os, const AstNRelinker& rhs) { - rhs.dump(os); return os; } + rhs.dump(os); + return os; +} //###################################################################### // V3Hash -- Node hashing for V3Combine @@ -1192,32 +1247,34 @@ class V3Hash { // A hash of a tree of nodes, consisting of 8 bits with the number of nodes in the hash // and 24 bit value hash of relevant information about the node. // A value of 0 is illegal - uint32_t m_both; - static const uint32_t M24 = ((1<<24)-1); + uint32_t m_both; + static const uint32_t M24 = ((1 << 24) - 1); void setBoth(uint32_t depth, uint32_t hshval) { - if (depth==0) depth = 1; - if (depth>255) depth = 255; - m_both = (depth<<24) | (hshval & M24); + if (depth == 0) depth = 1; + if (depth > 255) depth = 255; + m_both = (depth << 24) | (hshval & M24); } + public: // METHODS - bool isIllegal() const { return m_both==0; } + bool isIllegal() const { return m_both == 0; } uint32_t fullValue() const { return m_both; } uint32_t depth() const { return (m_both >> 24) & 255; } uint32_t hshval() const { return m_both & M24; } // OPERATORS - inline bool operator==(const V3Hash& rh) const { return m_both==rh.m_both; } - inline bool operator!=(const V3Hash& rh) const { return m_both!=rh.m_both; } - inline bool operator<(const V3Hash& rh) const { return m_bothm_nextp)); VL_PREFETCH_RD(&((nodep)->m_iterpp)); }} + { \ + if (nodep) { \ + VL_PREFETCH_RD(&((nodep)->m_nextp)); \ + VL_PREFETCH_RD(&((nodep)->m_iterpp)); \ + } \ + } class AstNode { // v ASTNODE_PREFETCH depends on below ordering of members - AstNode* m_nextp; // Next peer in the parent's list - AstNode* m_backp; // Node that points to this one (via next/op1/op2/...) - AstNode* m_op1p; // Generic pointer 1 - AstNode* m_op2p; // Generic pointer 2 - AstNode* m_op3p; // Generic pointer 3 - AstNode* m_op4p; // Generic pointer 4 - AstNode** m_iterpp; // Pointer to node iterating on, change it if we replace this node. + AstNode* m_nextp; // Next peer in the parent's list + AstNode* m_backp; // Node that points to this one (via next/op1/op2/...) + AstNode* m_op1p; // Generic pointer 1 + AstNode* m_op2p; // Generic pointer 2 + AstNode* m_op3p; // Generic pointer 3 + AstNode* m_op4p; // Generic pointer 4 + AstNode** m_iterpp; // Pointer to node iterating on, change it if we replace this node. // ^ ASTNODE_PREFETCH depends on above ordering of members - AstNode* m_headtailp; // When at begin/end of list, the opposite end of the list + AstNode* m_headtailp; // When at begin/end of list, the opposite end of the list - const AstType m_type; // Node sub-type identifier + const AstType m_type; // Node sub-type identifier - FileLine* m_fileline; // Where it was declared - vluint64_t m_editCount; // When it was last edited + FileLine* m_fileline; // Where it was declared + vluint64_t m_editCount; // When it was last edited static vluint64_t s_editCntGbl; // Global edit counter - static vluint64_t s_editCntLast; // Global edit counter, last value for printing * near node #s + // Global edit counter, last value for printing * near node #s + static vluint64_t s_editCntLast; - AstNodeDType* m_dtypep; // Data type of output or assignment (etc) + AstNodeDType* m_dtypep; // Data type of output or assignment (etc) - AstNode* m_clonep; // Pointer to clone of/ source of this module (for *LAST* cloneTree() ONLY) - int m_cloneCnt; // Mark of when userp was set - static int s_cloneCntGbl; // Count of which userp is set + AstNode* m_clonep; // Pointer to clone of/ source of this module (for *LAST* cloneTree() ONLY) + int m_cloneCnt; // Mark of when userp was set + static int s_cloneCntGbl; // Count of which userp is set // Attributes - bool m_didWidth:1; // Did V3Width computation - bool m_doingWidth:1; // Inside V3Width - bool m_protect:1; // Protect name if protection is on + bool m_didWidth : 1; // Did V3Width computation + bool m_doingWidth : 1; // Inside V3Width + bool m_protect : 1; // Protect name if protection is on // // Space for more bools here // This member ordering both allows 64 bit alignment and puts associated data together - VNUser m_user1u; // Contains any information the user iteration routine wants - uint32_t m_user1Cnt; // Mark of when userp was set - uint32_t m_user2Cnt; // Mark of when userp was set - VNUser m_user2u; // Contains any information the user iteration routine wants - VNUser m_user3u; // Contains any information the user iteration routine wants - uint32_t m_user3Cnt; // Mark of when userp was set - uint32_t m_user4Cnt; // Mark of when userp was set - VNUser m_user4u; // Contains any information the user iteration routine wants - VNUser m_user5u; // Contains any information the user iteration routine wants - uint32_t m_user5Cnt; // Mark of when userp was set + VNUser m_user1u; // Contains any information the user iteration routine wants + uint32_t m_user1Cnt; // Mark of when userp was set + uint32_t m_user2Cnt; // Mark of when userp was set + VNUser m_user2u; // Contains any information the user iteration routine wants + VNUser m_user3u; // Contains any information the user iteration routine wants + uint32_t m_user3Cnt; // Mark of when userp was set + uint32_t m_user4Cnt; // Mark of when userp was set + VNUser m_user4u; // Contains any information the user iteration routine wants + VNUser m_user5u; // Contains any information the user iteration routine wants + uint32_t m_user5Cnt; // Mark of when userp was set // METHODS - void op1p(AstNode* nodep) { m_op1p = nodep; if (nodep) nodep->m_backp = this; } - void op2p(AstNode* nodep) { m_op2p = nodep; if (nodep) nodep->m_backp = this; } - void op3p(AstNode* nodep) { m_op3p = nodep; if (nodep) nodep->m_backp = this; } - void op4p(AstNode* nodep) { m_op4p = nodep; if (nodep) nodep->m_backp = this; } + void op1p(AstNode* nodep) { + m_op1p = nodep; + if (nodep) nodep->m_backp = this; + } + void op2p(AstNode* nodep) { + m_op2p = nodep; + if (nodep) nodep->m_backp = this; + } + void op3p(AstNode* nodep) { + m_op3p = nodep; + if (nodep) nodep->m_backp = this; + } + void op4p(AstNode* nodep) { + m_op4p = nodep; + if (nodep) nodep->m_backp = this; + } - void init(); // initialize value of AstNode + void init(); // initialize value of AstNode private: - AstNode* cloneTreeIter(); - AstNode* cloneTreeIterList(); - void checkTreeIter(AstNode* backp); - void checkTreeIterList(AstNode* backp); - bool gateTreeIter() const; - static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, - bool ignNext, bool gateOnly); - void deleteTreeIter(); - void deleteNode(); - string locationStr() const; + AstNode* cloneTreeIter(); + AstNode* cloneTreeIterList(); + void checkTreeIter(AstNode* backp); + void checkTreeIterList(AstNode* backp); + bool gateTreeIter() const; + static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext, + bool gateOnly); + void deleteTreeIter(); + void deleteNode(); + string locationStr() const; + public: static void relinkOneLink(AstNode*& pointpr, AstNode* newp); // cppcheck-suppress functionConst - void debugTreeChange(const char* prefix, int lineno, bool next); + void debugTreeChange(const char* prefix, int lineno, bool next); protected: // CONSTRUCTORS AstNode(AstType t) - : m_type(t) { init(); } + : m_type(t) { + init(); + } AstNode(AstType t, FileLine* fl) - : m_type(t) { init(); m_fileline = fl; } + : m_type(t) { + init(); + m_fileline = fl; + } virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead virtual void cloneRelink() {} void cloneRelinkTree(); @@ -1334,23 +1416,31 @@ protected: void setOp3p(AstNode* newp); // Set non-list-type op3 to non-list element void setOp4p(AstNode* newp); // Set non-list-type op4 to non-list element - void setNOp1p(AstNode* newp) { if (newp) setOp1p(newp); } - void setNOp2p(AstNode* newp) { if (newp) setOp2p(newp); } - void setNOp3p(AstNode* newp) { if (newp) setOp3p(newp); } - void setNOp4p(AstNode* newp) { if (newp) setOp4p(newp); } - void addOp1p(AstNode* newp); // Append newp to end of op1 void addOp2p(AstNode* newp); // Append newp to end of op2 void addOp3p(AstNode* newp); // Append newp to end of op3 void addOp4p(AstNode* newp); // Append newp to end of op4 + // clang-format off + void setNOp1p(AstNode* newp) { if (newp) setOp1p(newp); } + void setNOp2p(AstNode* newp) { if (newp) setOp2p(newp); } + void setNOp3p(AstNode* newp) { if (newp) setOp3p(newp); } + void setNOp4p(AstNode* newp) { if (newp) setOp4p(newp); } + void addNOp1p(AstNode* newp) { if (newp) addOp1p(newp); } void addNOp2p(AstNode* newp) { if (newp) addOp2p(newp); } void addNOp3p(AstNode* newp) { if (newp) addOp3p(newp); } void addNOp4p(AstNode* newp) { if (newp) addOp4p(newp); } + // clang-format on - void clonep(AstNode* nodep) { m_clonep = nodep; m_cloneCnt = s_cloneCntGbl; } - static void cloneClearTree() { s_cloneCntGbl++; UASSERT_STATIC(s_cloneCntGbl, "Rollover"); } + void clonep(AstNode* nodep) { + m_clonep = nodep; + m_cloneCnt = s_cloneCntGbl; + } + static void cloneClearTree() { + s_cloneCntGbl++; + UASSERT_STATIC(s_cloneCntGbl, "Rollover"); + } public: // ACCESSORS @@ -1364,9 +1454,10 @@ public: AstNode* op3p() const { return m_op3p; } AstNode* op4p() const { return m_op4p; } AstNodeDType* dtypep() const { return m_dtypep; } - AstNode* clonep() const { return ((m_cloneCnt==s_cloneCntGbl)?m_clonep:NULL); } + AstNode* clonep() const { return ((m_cloneCnt == s_cloneCntGbl) ? m_clonep : NULL); } AstNode* firstAbovep() const { // Returns NULL when second or later in list - return ((backp() && backp()->nextp()!=this) ? backp() : NULL); } + return ((backp() && backp()->nextp() != this) ? backp() : NULL); + } bool brokeExists() const; bool brokeExistsAbove() const; @@ -1378,23 +1469,27 @@ public: #endif // CONSTANT ACCESSORS - static int instrCountBranch() { return 4; } ///< Instruction cycles to branch - static int instrCountDiv() { return 10; } ///< Instruction cycles to divide - static int instrCountDpi() { return 1000; } ///< Instruction cycles to call user function - static int instrCountLd() { return 2; } ///< Instruction cycles to load memory - static int instrCountMul() { return 3; } ///< Instruction cycles to multiply integers - static int instrCountPli() { return 20; } ///< Instruction cycles to call pli routines - static int instrCountDouble() { return 8; } ///< Instruction cycles to convert or do floats - static int instrCountDoubleDiv() { return 40; } ///< Instruction cycles to divide floats + static int instrCountBranch() { return 4; } ///< Instruction cycles to branch + static int instrCountDiv() { return 10; } ///< Instruction cycles to divide + static int instrCountDpi() { return 1000; } ///< Instruction cycles to call user function + static int instrCountLd() { return 2; } ///< Instruction cycles to load memory + static int instrCountMul() { return 3; } ///< Instruction cycles to multiply integers + static int instrCountPli() { return 20; } ///< Instruction cycles to call pli routines + static int instrCountDouble() { return 8; } ///< Instruction cycles to convert or do floats + static int instrCountDoubleDiv() { return 40; } ///< Instruction cycles to divide floats static int instrCountDoubleTrig() { return 200; } ///< Instruction cycles to do trigonomics - static int instrCountString() { return 100; } ///< Instruction cycles to do string ops - static int instrCountCall() { return instrCountBranch()+10; } ///< Instruction cycles to call subroutine - static int instrCountTime() { return instrCountCall()+5; } ///< Instruction cycles to determine simulation time + static int instrCountString() { return 100; } ///< Instruction cycles to do string ops + /// Instruction cycles to call subroutine + static int instrCountCall() { return instrCountBranch() + 10; } + /// Instruction cycles to determine simulation time + static int instrCountTime() { return instrCountCall() + 5; } // ACCESSORS virtual string name() const { return ""; } virtual string origName() const { return ""; } - virtual void name(const string& name) { this->v3fatalSrc("name() called on object without name() method"); } + virtual void name(const string& name) { + this->v3fatalSrc("name() called on object without name() method"); + } virtual void tag(const string& text) {} virtual string tag() const { return ""; } virtual string verilogKwd() const { return ""; } @@ -1404,30 +1499,38 @@ public: static string dedotName(const string& namein); // Name with dots removed static string prettyName(const string& namein); // Name for printing out to the user static string prettyNameQ(const string& namein) { // Quoted pretty name (for errors) - return string("'")+prettyName(namein)+"'"; } - static string encodeName(const string& namein); // Encode user name into internal C representation + return string("'") + prettyName(namein) + "'"; + } + static string + encodeName(const string& namein); // Encode user name into internal C representation static string encodeNumber(vlsint64_t num); // Encode number into internal C representation static string vcdName(const string& namein); // Name for printing out to vcd files string prettyName() const { return prettyName(name()); } string prettyNameQ() const { return prettyNameQ(name()); } string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name) - virtual string prettyOperatorName() const { return "operator "+prettyTypeName(); } + virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); } FileLine* fileline() const { return m_fileline; } void fileline(FileLine* fl) { m_fileline = fl; } bool width1() const; int widthInstrs() const; void didWidth(bool flag) { m_didWidth = flag; } bool didWidth() const { return m_didWidth; } - bool didWidthAndSet() { if (didWidth()) return true; didWidth(true); return false; } + bool didWidthAndSet() { + if (didWidth()) return true; + didWidth(true); + return false; + } bool doingWidth() const { return m_doingWidth; } void doingWidth(bool flag) { m_doingWidth = flag; } bool protect() const { return m_protect; } void protect(bool flag) { m_protect = flag; } - //TODO stomp these width functions out, and call via dtypep() instead + // TODO stomp these width functions out, and call via dtypep() instead int width() const; int widthMin() const; - int widthMinV() const { return v3Global.widthMinUsage()==VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width(); } + int widthMinV() const { + return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width(); + } int widthWords() const { return VL_WORDS_I(width()); } bool isQuad() const { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); } bool isWide() const { return (width() > VL_QUADSIZE); } @@ -1435,6 +1538,7 @@ public: bool isSigned() const; bool isString() const; + // clang-format off VNUser user1u() const { // Slows things down measurably, so disabled by default //UASSERT_STATIC(AstUser1InUse::s_userBusy, "userp set w/o busy"); @@ -1504,9 +1608,12 @@ public: int user5Inc(int val=1) { int v=user5(); user5(v+val); return v; } int user5SetOnce() { int v=user5(); if (!v) user5(1); return v; } // Better for cache than user5Inc() static void user5ClearTree() { AstUser5InUse::clear(); } // Clear userp()'s across the entire tree + // clang-format on vluint64_t editCount() const { return m_editCount; } - void editCountInc() { m_editCount = ++s_editCntGbl; } // Preincrement, so can "watch AstNode::s_editCntGbl=##" + void editCountInc() { + m_editCount = ++s_editCntGbl; // Preincrement, so can "watch AstNode::s_editCntGbl=##" + } static vluint64_t editCountLast() { return s_editCntLast; } static vluint64_t editCountGbl() { return s_editCntGbl; } static void editCountSetLast() { s_editCntLast = editCountGbl(); } @@ -1520,34 +1627,45 @@ public: bool isAllOnesV() const; // Verilog width rules apply // METHODS - data type changes especially for initial creation - void dtypep(AstNodeDType* nodep) { if (m_dtypep != nodep) { m_dtypep = nodep; editCountInc(); } } - void dtypeFrom(AstNode* fromp) { if (fromp) { dtypep(fromp->dtypep()); }} - void dtypeChgSigned(bool flag=true); + void dtypep(AstNodeDType* nodep) { + if (m_dtypep != nodep) { + m_dtypep = nodep; + editCountInc(); + } + } + void dtypeFrom(AstNode* fromp) { + if (fromp) { dtypep(fromp->dtypep()); } + } + void dtypeChgSigned(bool flag = true); void dtypeChgWidth(int width, int widthMin); void dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric); void dtypeSetBitUnsized(int width, int widthMin, AstNumeric numeric) { - dtypep(findBitDType(width, widthMin, numeric)); } + dtypep(findBitDType(width, widthMin, numeric)); + } void dtypeSetBitSized(int width, AstNumeric numeric) { - dtypep(findBitDType(width, width, numeric)); } // Since sized, widthMin is width + dtypep(findBitDType(width, width, numeric)); // Since sized, widthMin is width + } void dtypeSetLogicUnsized(int width, int widthMin, AstNumeric numeric) { - dtypep(findLogicDType(width, widthMin, numeric)); } + dtypep(findLogicDType(width, widthMin, numeric)); + } void dtypeSetLogicSized(int width, AstNumeric numeric) { - dtypep(findLogicDType(width, width, numeric)); } // Since sized, widthMin is width - void dtypeSetLogicBool() { dtypep(findLogicBoolDType()); } - void dtypeSetDouble() { dtypep(findDoubleDType()); } - void dtypeSetString() { dtypep(findStringDType()); } - void dtypeSetSigned32() { dtypep(findSigned32DType()); } - void dtypeSetUInt32() { dtypep(findUInt32DType()); } // Twostate - void dtypeSetUInt64() { dtypep(findUInt64DType()); } // Twostate + dtypep(findLogicDType(width, width, numeric)); // Since sized, widthMin is width + } + void dtypeSetLogicBool() { dtypep(findLogicBoolDType()); } + void dtypeSetDouble() { dtypep(findDoubleDType()); } + void dtypeSetString() { dtypep(findStringDType()); } + void dtypeSetSigned32() { dtypep(findSigned32DType()); } + void dtypeSetUInt32() { dtypep(findUInt32DType()); } // Twostate + void dtypeSetUInt64() { dtypep(findUInt64DType()); } // Twostate void dtypeSetVoid() { dtypep(findVoidDType()); } // Data type locators - AstNodeDType* findLogicBoolDType() { return findBasicDType(AstBasicDTypeKwd::LOGIC); } - AstNodeDType* findDoubleDType() { return findBasicDType(AstBasicDTypeKwd::DOUBLE); } - AstNodeDType* findStringDType() { return findBasicDType(AstBasicDTypeKwd::STRING); } - AstNodeDType* findSigned32DType() { return findBasicDType(AstBasicDTypeKwd::INTEGER); } - AstNodeDType* findUInt32DType() { return findBasicDType(AstBasicDTypeKwd::UINT32); } // Twostate - AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); } // Twostate + AstNodeDType* findLogicBoolDType() { return findBasicDType(AstBasicDTypeKwd::LOGIC); } + AstNodeDType* findDoubleDType() { return findBasicDType(AstBasicDTypeKwd::DOUBLE); } + AstNodeDType* findStringDType() { return findBasicDType(AstBasicDTypeKwd::STRING); } + AstNodeDType* findSigned32DType() { return findBasicDType(AstBasicDTypeKwd::INTEGER); } + AstNodeDType* findUInt32DType() { return findBasicDType(AstBasicDTypeKwd::UINT32); } + AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); } AstNodeDType* findVoidDType() const; AstNodeDType* findBitDType(int width, int widthMin, AstNumeric numeric) const; AstNodeDType* findLogicDType(int width, int widthMin, AstNumeric numeric) const; @@ -1566,66 +1684,89 @@ public: string warnMore() const { return fileline()->warnMore(); } string warnOther() const { return fileline()->warnOther(); } - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; void dumpGdb(); // For GDB only void dumpGdbHeader() const; // METHODS - Tree modifications - static AstNode* addNext(AstNode* nodep, AstNode* newp); // Returns nodep, adds newp to end of nodep's list - static AstNode* addNextNull(AstNode* nodep, AstNode* newp); // Returns nodep, adds newp (maybe NULL) to end of nodep's list + // Returns nodep, adds newp to end of nodep's list + static AstNode* addNext(AstNode* nodep, AstNode* newp); + // Returns nodep, adds newp (maybe NULL) to end of nodep's list + static AstNode* addNextNull(AstNode* nodep, AstNode* newp); inline AstNode* addNext(AstNode* newp) { return addNext(this, newp); } inline AstNode* addNextNull(AstNode* newp) { return addNextNull(this, newp); } void addNextHere(AstNode* newp); // Insert newp at this->nextp - void addPrev(AstNode* newp) { replaceWith(newp); newp->addNext(this); } + void addPrev(AstNode* newp) { + replaceWith(newp); + newp->addNext(this); + } void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next void replaceWith(AstNode* newp); // Replace current node in tree with new node - AstNode* unlinkFrBack(AstNRelinker* linkerp=NULL); // Unlink this from whoever points to it. + AstNode* unlinkFrBack(AstNRelinker* linkerp = NULL); // Unlink this from whoever points to it. // Unlink this from whoever points to it, keep entire next list with unlinked node - AstNode* unlinkFrBackWithNext(AstNRelinker* linkerp=NULL); + AstNode* unlinkFrBackWithNext(AstNRelinker* linkerp = NULL); void swapWith(AstNode* bp); void relink(AstNRelinker* linkerp); // Generally use linker->relink() instead void cloneRelinkNode() { cloneRelink(); } // Iterate and insert - assumes tree format - virtual void addNextStmt(AstNode* newp, AstNode* belowp); // When calling, "this" is second argument - virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // When calling, "this" is second argument + virtual void addNextStmt(AstNode* newp, + AstNode* belowp); // When calling, "this" is second argument + virtual void addBeforeStmt(AstNode* newp, + AstNode* belowp); // When calling, "this" is second argument // METHODS - Iterate on a tree // Clone or return NULL if NULL static AstNode* cloneTreeNull(AstNode* nodep, bool cloneNextLink) { - return nodep ? nodep->cloneTree(cloneNextLink) : NULL; } + return nodep ? nodep->cloneTree(cloneNextLink) : NULL; + } AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable? bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p? - bool sameGateTree(const AstNode* node2p) const; // Does tree of this == node2p?, not allowing non-isGateOptimizable + // Does tree of this == node2p?, not allowing non-isGateOptimizable + bool sameGateTree(const AstNode* node2p) const; void deleteTree(); // Always deletes the next link void checkTree(); // User Interface version void checkIter() const; void clearIter() { m_iterpp = NULL; } - void dumpPtrs(std::ostream& os=std::cout) const; - void dumpTree(std::ostream& os=std::cout, const string& indent=" ", int maxDepth=0) const; - void dumpTree(const string& indent, int maxDepth=0) const { dumpTree(cout, indent, maxDepth); } + void dumpPtrs(std::ostream& os = std::cout) const; + void dumpTree(std::ostream& os = std::cout, const string& indent = " ", + int maxDepth = 0) const; + void dumpTree(const string& indent, int maxDepth = 0) const { + dumpTree(cout, indent, maxDepth); + } void dumpTreeGdb(); // For GDB only - void dumpTreeAndNext(std::ostream& os=std::cout, const string& indent=" ", int maxDepth=0) const; - void dumpTreeFile(const string& filename, bool append=false, bool doDump=true); - static void dumpTreeFileGdb(const char* filenamep=NULL); + void dumpTreeAndNext(std::ostream& os = std::cout, const string& indent = " ", + int maxDepth = 0) const; + void dumpTreeFile(const string& filename, bool append = false, bool doDump = true); + static void dumpTreeFileGdb(const char* filenamep = NULL); // METHODS - queries - virtual bool isPure() const { return true; } // Else a $display, etc, that must be ordered with other displays - virtual bool isBrancher() const { return false; } // Changes control flow, disable some optimizations - virtual bool isGateOptimizable() const { return true; } // Else a AstTime etc that can't be pushed out + // Else a $display, etc, that must be ordered with other displays + virtual bool isPure() const { return true; } + // Changes control flow, disable some optimizations + virtual bool isBrancher() const { return false; } + // Else a AstTime etc that can't be pushed out + virtual bool isGateOptimizable() const { return true; } // GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf) virtual bool isGateDedupable() const { return isGateOptimizable(); } - virtual bool isSubstOptimizable() const { return true; } // Else a AstTime etc that can't be substituted out - virtual bool isPredictOptimizable() const { return true; } // Else a AstTime etc which output can't be predicted from input - virtual bool isOutputter() const { return false; } // Else creates output or exits, etc, not unconsumed + // Else a AstTime etc that can't be substituted out + virtual bool isSubstOptimizable() const { return true; } + // Else a AstTime etc which output can't be predicted from input + virtual bool isPredictOptimizable() const { return true; } + // Else creates output or exits, etc, not unconsumed + virtual bool isOutputter() const { return false; } // isUnlikely handles $stop or similar statement which means an above IF // statement is unlikely to be taken virtual bool isUnlikely() const { return false; } virtual int instrCount() const { return 0; } - virtual V3Hash sameHash() const { return V3Hash(V3Hash::Illegal()); } // Not a node that supports it + virtual V3Hash sameHash() const { + return V3Hash(V3Hash::Illegal()); // Not a node that supports it + } virtual bool same(const AstNode*) const { return true; } - virtual bool hasDType() const { return false; } // Iff has a data type; dtype() must be non null - virtual AstNodeDType* getChildDTypep() const { return NULL; } // Iff has a non-null childDTypep(), as generic node function + // Iff has a data type; dtype() must be non null + virtual bool hasDType() const { return false; } + // Iff has a non-null childDTypep(), as generic node function + virtual AstNodeDType* getChildDTypep() const { return NULL; } // Another AstNode* may have a pointer into this node, other then normal front/back/etc. virtual bool maybePointedTo() const { return false; } virtual const char* broken() const { return NULL; } @@ -1636,35 +1777,44 @@ public: protected: // All AstNVisitor related functions are called as methods off the visitor friend class AstNVisitor; - void iterateChildren(AstNVisitor& v); // Use instead AstNVisitor::iterateChildren - void iterateChildrenBackwards(AstNVisitor& v); // Use instead AstNVisitor::iterateChildrenBackwards - void iterateChildrenConst(AstNVisitor& v); // Use instead AstNVisitor::iterateChildrenConst - void iterateAndNext(AstNVisitor& v); // Use instead AstNVisitor::iterateAndNextNull - void iterateAndNextConst(AstNVisitor& v); // Use instead AstNVisitor::iterateAndNextConstNull - AstNode* iterateSubtreeReturnEdits(AstNVisitor& v); // Use instead AstNVisitor::iterateSubtreeReturnEdits + // Use instead AstNVisitor::iterateChildren + void iterateChildren(AstNVisitor& v); + // Use instead AstNVisitor::iterateChildrenBackwards + void iterateChildrenBackwards(AstNVisitor& v); + // Use instead AstNVisitor::iterateChildrenConst + void iterateChildrenConst(AstNVisitor& v); + // Use instead AstNVisitor::iterateAndNextNull + void iterateAndNext(AstNVisitor& v); + // Use instead AstNVisitor::iterateAndNextConstNull + void iterateAndNextConst(AstNVisitor& v); + // Use instead AstNVisitor::iterateSubtreeReturnEdits + AstNode* iterateSubtreeReturnEdits(AstNVisitor& v); + private: void iterateListBackwards(AstNVisitor& v); // CONVERSION public: // These for use by VN_IS macro only - template - static bool privateIs(const AstNode* nodep); + template static bool privateIs(const AstNode* nodep); // These for use by VN_CAST macro only - template - static T* privateCast(AstNode* nodep); + template static T* privateCast(AstNode* nodep); // These for use by VN_CAST_CONST macro only - template - static const T* privateConstCast(const AstNode* nodep); + template static const T* privateConstCast(const AstNode* nodep); }; // Specialisations of privateIs/privateCast #include "V3Ast__gen_impl.h" // From ./astgen inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) { - if (!rhs) os<<"NULL"; else rhs->dump(os); return os; + if (!rhs) { + os << "NULL"; + } else { + rhs->dump(os); + } + return os; } inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); } @@ -1672,12 +1822,15 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); } //###################################################################### //=== AstNode* : Derived generic node types -#define ASTNODE_BASE_FUNCS(name) \ - virtual ~Ast ##name() {} \ - static Ast ##name * cloneTreeNull(Ast ##name * nodep, bool cloneNextLink) { \ - return nodep ? nodep->cloneTree(cloneNextLink) : NULL; } \ - Ast ##name * cloneTree(bool cloneNext) { return static_cast(AstNode::cloneTree(cloneNext)); } \ - Ast ##name * clonep() const { return static_cast(AstNode::clonep()); } +#define ASTNODE_BASE_FUNCS(name) \ + virtual ~Ast##name() {} \ + static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \ + return nodep ? nodep->cloneTree(cloneNextLink) : NULL; \ + } \ + Ast##name* cloneTree(bool cloneNext) { \ + return static_cast(AstNode::cloneTree(cloneNext)); \ + } \ + Ast##name* clonep() const { return static_cast(AstNode::clonep()); } class AstNodeMath : public AstNode { // Math -- anything that's part of an expression tree @@ -1706,7 +1859,7 @@ public: // Know no children, and hot function, so skip iterator for speed // See checkTreeIter also that asserts no children // cppcheck-suppress functionConst - void iterateChildren(AstNVisitor& v) { } + void iterateChildren(AstNVisitor& v) {} }; class AstNodeUniop : public AstNodeMath { @@ -1715,16 +1868,19 @@ public: AstNodeUniop(AstType t, FileLine* fl, AstNode* lhsp) : AstNodeMath(t, fl) { dtypeFrom(lhsp); - setOp1p(lhsp); } + setOp1p(lhsp); + } ASTNODE_BASE_FUNCS(NodeUniop) AstNode* lhsp() const { return op1p(); } void lhsp(AstNode* nodep) { return setOp1p(nodep); } // METHODS - virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; // Set out to evaluation of a AstConst'ed lhs + // Set out to evaluation of a AstConst'ed lhs + virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; virtual bool cleanLhs() const = 0; virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors? - virtual bool signedFlavor() const { return false; } // Signed flavor of nodes with both flavors? + // Signed flavor of nodes with both flavors? + virtual bool signedFlavor() const { return false; } virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? virtual int instrCount() const { return widthInstrs(); } virtual V3Hash sameHash() const { return V3Hash(); } @@ -1736,22 +1892,27 @@ class AstNodeBiop : public AstNodeMath { public: AstNodeBiop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs) : AstNodeMath(t, fl) { - setOp1p(lhs); setOp2p(rhs); } + setOp1p(lhs); + setOp2p(rhs); + } ASTNODE_BASE_FUNCS(NodeBiop) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; // Clone single node, just get same type back. + // Clone single node, just get same type back. + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; // ACCESSORS AstNode* lhsp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } void lhsp(AstNode* nodep) { return setOp1p(nodep); } void rhsp(AstNode* nodep) { return setOp2p(nodep); } // METHODS - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) = 0; // Set out to evaluation of a AstConst'ed + // Set out to evaluation of a AstConst'ed + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) = 0; virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors? - virtual bool signedFlavor() const { return false; } // Signed flavor of nodes with both flavors? + // Signed flavor of nodes with both flavors? + virtual bool signedFlavor() const { return false; } virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? virtual int instrCount() const { return widthInstrs(); } virtual V3Hash sameHash() const { return V3Hash(); } @@ -1763,7 +1924,10 @@ class AstNodeTriop : public AstNodeMath { public: AstNodeTriop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths) : AstNodeMath(t, fl) { - setOp1p(lhs); setOp2p(rhs); setOp3p(ths); } + setOp1p(lhs); + setOp2p(rhs); + setOp3p(ths); + } ASTNODE_BASE_FUNCS(NodeTriop) AstNode* lhsp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } @@ -1773,8 +1937,9 @@ public: void thsp(AstNode* nodep) { return setOp3p(nodep); } // METHODS // Set out to evaluation of a AstConst'ed - virtual void numberOperate(V3Number& out, const V3Number& lhs, - const V3Number& rhs, const V3Number& ths) = 0; + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) + = 0; virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero @@ -1805,12 +1970,15 @@ class AstNodeCond : public AstNodeTriop { public: AstNodeCond(AstType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) : AstNodeTriop(t, fl, condp, expr1p, expr2p) { - if (expr1p) dtypeFrom(expr1p); - else if (expr2p) dtypeFrom(expr2p); + if (expr1p) { + dtypeFrom(expr1p); + } else if (expr2p) { + dtypeFrom(expr2p); + } } ASTNODE_BASE_FUNCS(NodeCond) - virtual void numberOperate(V3Number& out, const V3Number& lhs, - const V3Number& rhs, const V3Number& ths); + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths); AstNode* condp() const { return op1p(); } // op1 = Condition AstNode* expr1p() const { return op2p(); } // op2 = If true... AstNode* expr2p() const { return op3p(); } // op3 = If false... @@ -1832,7 +2000,10 @@ class AstNodePreSel : public AstNode { public: AstNodePreSel(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths) : AstNode(t, fl) { - setOp1p(lhs); setOp2p(rhs); setNOp3p(ths); } + setOp1p(lhs); + setOp2p(rhs); + setNOp3p(ths); + } ASTNODE_BASE_FUNCS(NodePreSel) AstNode* lhsp() const { return op1p(); } AstNode* fromp() const { return lhsp(); } @@ -1867,11 +2038,13 @@ class AstNodeAssign : public AstNodeStmt { public: AstNodeAssign(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeStmt(t, fl) { - setOp1p(rhsp); setOp2p(lhsp); + setOp1p(rhsp); + setOp2p(lhsp); dtypeFrom(lhsp); } ASTNODE_BASE_FUNCS(NodeAssign) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; // Clone single node, just get same type back. + // Clone single node, just get same type back. + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; // So iteration hits the RHS which is "earlier" in execution order, it's op1, not op2 AstNode* rhsp() const { return op1p(); } // op1 = Assign from AstNode* lhsp() const { return op2p(); } // op2 = Assign to @@ -1888,10 +2061,13 @@ public: class AstNodeFor : public AstNodeStmt { public: - AstNodeFor(AstType t, FileLine* fl, AstNode* initsp, AstNode* condp, - AstNode* incsp, AstNode* bodysp) + AstNodeFor(AstType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, + AstNode* bodysp) : AstNodeStmt(t, fl) { - addNOp1p(initsp); setOp2p(condp); addNOp3p(incsp); addNOp4p(bodysp); + addNOp1p(initsp); + setOp2p(condp); + addNOp3p(incsp); + addNOp4p(bodysp); } ASTNODE_BASE_FUNCS(NodeFor) AstNode* initsp() const { return op1p(); } // op1 = initial statements @@ -1910,7 +2086,9 @@ private: public: AstNodeIf(AstType t, FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) : AstNodeStmt(t, fl) { - setOp1p(condp); addNOp2p(ifsp); addNOp3p(elsesp); + setOp1p(condp); + addNOp2p(ifsp); + addNOp3p(elsesp); } ASTNODE_BASE_FUNCS(NodeIf) AstNode* condp() const { return op1p(); } // op1 = condition @@ -1932,12 +2110,15 @@ class AstNodeCase : public AstNodeStmt { public: AstNodeCase(AstType t, FileLine* fl, AstNode* exprp, AstNode* casesp) : AstNodeStmt(t, fl) { - setOp1p(exprp); addNOp2p(casesp); + setOp1p(exprp); + addNOp2p(casesp); } ASTNODE_BASE_FUNCS(NodeCase) virtual int instrCount() const { return instrCountBranch(); } AstNode* exprp() const { return op1p(); } // op1 = case condition - AstCaseItem* itemsp() const { return VN_CAST(op2p(), CaseItem); } // op2 = list of case expressions + AstCaseItem* itemsp() const { + return VN_CAST(op2p(), CaseItem); + } // op2 = list of case expressions AstNode* notParallelp() const { return op3p(); } // op3 = assertion code for non-full case's void addItemsp(AstNode* nodep) { addOp2p(nodep); } void addNotParallelp(AstNode* nodep) { setOp3p(nodep); } @@ -1959,23 +2140,34 @@ public: class AstNodeVarRef : public AstNodeMath { // An AstVarRef or AstVarXRef private: - bool m_lvalue; // Left hand side assignment - AstVar* m_varp; // [AfterLink] Pointer to variable itself - AstVarScope* m_varScopep; // Varscope for hierarchy + bool m_lvalue; // Left hand side assignment + AstVar* m_varp; // [AfterLink] Pointer to variable itself + AstVarScope* m_varScopep; // Varscope for hierarchy AstNodeModule* m_packagep; // Package hierarchy - string m_name; // Name of variable - string m_hiername; // Scope converted into name-> for emitting - bool m_hierThis; // Hiername points to "this" function + string m_name; // Name of variable + string m_hiername; // Scope converted into name-> for emitting + bool m_hierThis; // Hiername points to "this" function void init(); + public: AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue) - : AstNodeMath(t, fl), m_lvalue(lvalue), m_varp(NULL), m_varScopep(NULL) - , m_packagep(NULL), m_name(name), m_hierThis(false) { + : AstNodeMath(t, fl) + , m_lvalue(lvalue) + , m_varp(NULL) + , m_varScopep(NULL) + , m_packagep(NULL) + , m_name(name) + , m_hierThis(false) { init(); } AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue) - : AstNodeMath(t, fl), m_lvalue(lvalue), m_varp(varp), m_varScopep(NULL) - , m_packagep(NULL), m_name(name), m_hierThis(false) { + : AstNodeMath(t, fl) + , m_lvalue(lvalue) + , m_varp(varp) + , m_varScopep(NULL) + , m_packagep(NULL) + , m_name(name) + , m_hierThis(false) { // May have varp==NULL init(); } @@ -2002,12 +2194,13 @@ public: // Know no children, and hot function, so skip iterator for speed // See checkTreeIter also that asserts no children // cppcheck-suppress functionConst - void iterateChildren(AstNVisitor& v) { } + void iterateChildren(AstNVisitor& v) {} }; class AstNodeText : public AstNode { private: - string m_text; + string m_text; + public: // Node that simply puts text into the output stream AstNodeText(AstType t, FileLine* fl, const string& textp) @@ -2015,11 +2208,12 @@ public: m_text = textp; // Copy it } ASTNODE_BASE_FUNCS(NodeText) - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; virtual V3Hash sameHash() const { return V3Hash(text()); } virtual bool same(const AstNode* samep) const { const AstNodeText* asamep = static_cast(samep); - return text() == asamep->text(); } + return text() == asamep->text(); + } const string& text() const { return m_text; } }; @@ -2028,17 +2222,21 @@ class AstNodeDType : public AstNode { // but it's currently so prevalent in the code we leave it here. // Note the below members are included in AstTypeTable::Key lookups private: - int m_width; // (also in AstTypeTable::Key) Bit width of operation - int m_widthMin; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation - AstNumeric m_numeric; // (also in AstTypeTable::Key) Node is signed + int m_width; // (also in AstTypeTable::Key) Bit width of operation + int m_widthMin; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation + AstNumeric m_numeric; // (also in AstTypeTable::Key) Node is signed // Other members - bool m_generic; // Simple globally referenced type, don't garbage collect - static int s_uniqueNum; // Unique number assigned to each dtype during creation for IEEE matching + bool m_generic; // Simple globally referenced type, don't garbage collect + // Unique number assigned to each dtype during creation for IEEE matching + static int s_uniqueNum; + public: // CONSTRUCTORS AstNodeDType(AstType t, FileLine* fl) : AstNode(t, fl) { - m_width = 0; m_widthMin = 0; m_generic = false; + m_width = 0; + m_widthMin = 0; + m_generic = false; } ASTNODE_BASE_FUNCS(NodeDType) // ACCESSORS @@ -2046,27 +2244,47 @@ public: virtual void dumpSmall(std::ostream& str) const; virtual bool hasDType() const { return true; } virtual AstBasicDType* basicp() const = 0; // (Slow) recurse down to find basic data type - virtual AstNodeDType* skipRefp() const = 0; // recurses over typedefs/const/enum to next non-typeref type - virtual AstNodeDType* skipRefToConstp() const = 0; // recurses over typedefs to next non-typeref-or-const type - virtual AstNodeDType* skipRefToEnump() const = 0; // recurses over typedefs/const to next non-typeref-or-enum/struct type - virtual int widthAlignBytes() const = 0; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthTotalBytes() const = 0; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + // recurses over typedefs/const/enum to next non-typeref type + virtual AstNodeDType* skipRefp() const = 0; + // recurses over typedefs to next non-typeref-or-const type + virtual AstNodeDType* skipRefToConstp() const = 0; + // recurses over typedefs/const to next non-typeref-or-enum/struct type + virtual AstNodeDType* skipRefToEnump() const = 0; + // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + virtual int widthAlignBytes() const = 0; + virtual int + // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + widthTotalBytes() const = 0; virtual bool maybePointedTo() const { return true; } - virtual AstNodeDType* virtRefDTypep() const { return NULL; } // Iff has a non-null refDTypep(), as generic node function - virtual void virtRefDTypep(AstNodeDType* nodep) { } // Iff has refDTypep(), set as generic node function - virtual AstNodeDType* virtRefDType2p() const { return NULL; } // Iff has a non-null second dtypep, as generic node function - virtual void virtRefDType2p(AstNodeDType* nodep) { } // Iff has second dtype, set as generic node function - virtual bool similarDType(AstNodeDType* samep) const = 0; // Assignable equivalence. Call skipRefp() on this and samep before calling - virtual AstNodeDType* subDTypep() const { return NULL; } // Iff has a non-null subDTypep(), as generic node function + // Iff has a non-null refDTypep(), as generic node function + virtual AstNodeDType* virtRefDTypep() const { return NULL; } + // Iff has refDTypep(), set as generic node function + virtual void virtRefDTypep(AstNodeDType* nodep) {} + // Iff has a non-null second dtypep, as generic node function + virtual AstNodeDType* virtRefDType2p() const { return NULL; } + // Iff has second dtype, set as generic node function + virtual void virtRefDType2p(AstNodeDType* nodep) {} + // Assignable equivalence. Call skipRefp() on this and samep before calling + virtual bool similarDType(AstNodeDType* samep) const = 0; + // Iff has a non-null subDTypep(), as generic node function + virtual AstNodeDType* subDTypep() const { return NULL; } virtual bool isFourstate() const; - virtual string prettyDTypeName() const { return prettyTypeName(); } // Ideally an IEEE $typename + // Ideally an IEEE $typename + virtual string prettyDTypeName() const { return prettyTypeName(); } string prettyDTypeNameQ() const { return "'" + prettyDTypeName() + "'"; } // // Changing the width may confuse the data type resolution, so must clear // TypeTable cache after use. - void widthForce(int width, int widthMin) { m_width = width; m_widthMin = widthMin; } + void widthForce(int width, int widthMin) { + m_width = width; + m_widthMin = widthMin; + } // For backward compatibility inherit width and signing from the subDType/base type - void widthFromSub(AstNodeDType* nodep) { m_width = nodep->m_width; m_widthMin = nodep->m_widthMin; m_numeric = nodep->m_numeric; } + void widthFromSub(AstNodeDType* nodep) { + m_width = nodep->m_width; + m_widthMin = nodep->m_widthMin; + m_numeric = nodep->m_numeric; + } // int width() const { return m_width; } void numeric(AstNumeric flag) { m_numeric = flag; } @@ -2075,29 +2293,33 @@ public: AstNumeric numeric() const { return m_numeric; } int widthWords() const { return VL_WORDS_I(width()); } int widthMin() const { // If sized, the size, if unsized the min digits to represent it - return m_widthMin?m_widthMin:m_width; } + return m_widthMin ? m_widthMin : m_width; + } int widthPow2() const; void widthMinFromWidth() { m_widthMin = m_width; } - bool widthSized() const { return !m_widthMin || m_widthMin==m_width; } + bool widthSized() const { return !m_widthMin || m_widthMin == m_width; } bool generic() const { return m_generic; } void generic(bool flag) { m_generic = flag; } AstNodeDType* dtypeDimensionp(int dimension); - std::pair dimensions(bool includeBasic); + std::pair dimensions(bool includeBasic); uint32_t arrayUnpackedElements(); // 1, or total multiplication of all dimensions static int uniqueNumInc() { return ++s_uniqueNum; } - const char* charIQWN() const { return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I"); } + const char* charIQWN() const { + return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I"); + } }; class AstNodeUOrStructDType : public AstNodeDType { // A struct or union; common handling private: // TYPES - typedef std::map MemberNameMap; + typedef std::map MemberNameMap; // MEMBERS string m_name; // Name from upper typedef, if any - bool m_packed; - bool m_isFourstate; - MemberNameMap m_members; + bool m_packed; + bool m_isFourstate; + MemberNameMap m_members; + public: AstNodeUOrStructDType(AstType t, FileLine* fl, AstNumeric numericUnpack) : AstNodeDType(t, fl) { @@ -2121,28 +2343,34 @@ public: virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + virtual int widthAlignBytes() + const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + virtual int + widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... // op1 = members virtual bool similarDType(AstNodeDType* samep) const { - return this==samep; // We don't compare members, require exact equivalence + return this == samep; // We don't compare members, require exact equivalence } virtual string name() const { return m_name; } void name(const string& flag) { m_name = flag; } - AstMemberDType* membersp() const { return VN_CAST(op1p(), MemberDType); } // op1 = AstMember list + AstMemberDType* membersp() const { + return VN_CAST(op1p(), MemberDType); + } // op1 = AstMember list void addMembersp(AstNode* nodep) { addNOp1p(nodep); } bool packed() const { return m_packed; } - bool packedUnsup() const { return true; } // packed() but as don't support unpacked, presently all structs + bool packedUnsup() const { + return true; + } // packed() but as don't support unpacked, presently all structs void isFourstate(bool flag) { m_isFourstate = flag; } virtual bool isFourstate() const { return m_isFourstate; } void clearCache() { m_members.clear(); } void repairMemberCache(); AstMemberDType* findMember(const string& name) const { MemberNameMap::const_iterator it = m_members.find(name); - return (it==m_members.end()) ? NULL : it->second; + return (it == m_members.end()) ? NULL : it->second; } int lsb() const { return 0; } - int msb() const { return dtypep()->width()-1; } // Packed classes look like arrays + int msb() const { return dtypep()->width() - 1; } // Packed classes look like arrays VNumRange declRange() const { return VNumRange(msb(), lsb(), false); } }; @@ -2163,26 +2391,30 @@ public: virtual void dumpSmall(std::ostream& str) const; virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); return NULL; } - virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { - m_refDTypep = m_refDTypep->clonep(); - }} + || (!m_refDTypep && childDTypep()))); + return NULL; + } + virtual void cloneRelink() { + if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + } virtual bool same(const AstNode* samep) const { const AstNodeArrayDType* asamep = static_cast(samep); - return (msb()==asamep->msb() - && subDTypep()==asamep->subDTypep() - && rangenp()->sameTree(asamep->rangenp())); } // HashedDT doesn't recurse, so need to check children + return (msb() == asamep->msb() && subDTypep() == asamep->subDTypep() + && rangenp()->sameTree(asamep->rangenp())); + } // HashedDT doesn't recurse, so need to check children virtual bool similarDType(AstNodeDType* samep) const { const AstNodeArrayDType* asamep = static_cast(samep); - return (asamep - && type() == samep->type() - && msb() == asamep->msb() + return (asamep && type() == samep->type() && msb() == asamep->msb() && rangenp()->sameTree(asamep->rangenp()) && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); } - virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep), V3Hash(msb()), V3Hash(lsb())); } + virtual V3Hash sameHash() const { + return V3Hash(V3Hash(m_refDTypep), V3Hash(msb()), V3Hash(lsb())); + } AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + AstNodeDType* childDTypep() const { + return VN_CAST(op1p(), NodeDType); + } // op1 = Range of variable void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } @@ -2191,12 +2423,16 @@ public: AstRange* rangep() const { return VN_CAST(op2p(), Range); } // op2 = Array(s) of variable void rangep(AstRange* nodep); // METHODS - virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type + virtual AstBasicDType* basicp() const { + return subDTypep()->basicp(); + } // (Slow) recurse down to find basic data type virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const { return elementsConst() * subDTypep()->widthTotalBytes(); } + virtual int widthTotalBytes() const { + return elementsConst() * subDTypep()->widthTotalBytes(); + } int msb() const; int lsb() const; int elementsConst() const; @@ -2222,9 +2458,7 @@ class AstNodeStream : public AstNodeBiop { public: AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(t, fl, lhsp, rhsp) { - if (lhsp->dtypep()) { - dtypeSetLogicSized(lhsp->dtypep()->width(), AstNumeric::UNSIGNED); - } + if (lhsp->dtypep()) { dtypeSetLogicSized(lhsp->dtypep()->width(), AstNumeric::UNSIGNED); } } ASTNODE_BASE_FUNCS(NodeStream) }; @@ -2238,6 +2472,7 @@ class AstNodeCCall : public AstNodeStmt { AstCFunc* m_funcp; string m_hiername; string m_argTypes; + public: AstNodeCCall(AstType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = NULL) : AstNodeStmt(t, fl, true) @@ -2255,7 +2490,7 @@ public: if (oldp->argsp()) addNOp2p(oldp->argsp()->unlinkFrBackWithNext()); } ASTNODE_BASE_FUNCS(NodeCCall) - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; virtual void cloneRelink(); virtual const char* broken() const; virtual int instrCount() const { return instrCountCall(); } @@ -2282,33 +2517,41 @@ public: class AstNodeFTask : public AstNode { private: - string m_name; // Name of task - string m_cname; // Name of task if DPI import - uint64_t m_dpiOpenParent; // DPI import open array, if !=0, how many callees - bool m_taskPublic:1; // Public task - bool m_attrIsolateAssign:1;// User isolate_assignments attribute - bool m_classMethod:1; // Class method - bool m_prototype:1; // Just a prototype - bool m_dpiExport:1; // DPI exported - bool m_dpiImport:1; // DPI imported - bool m_dpiContext:1; // DPI import context - bool m_dpiOpenChild:1; // DPI import open array child wrapper - bool m_dpiTask:1; // DPI import task (vs. void function) - bool m_isConstructor:1; // Class constructor - bool m_pure:1; // DPI import pure (vs. virtual pure) + string m_name; // Name of task + string m_cname; // Name of task if DPI import + uint64_t m_dpiOpenParent; // DPI import open array, if !=0, how many callees + bool m_taskPublic : 1; // Public task + bool m_attrIsolateAssign : 1; // User isolate_assignments attribute + bool m_classMethod : 1; // Class method + bool m_prototype : 1; // Just a prototype + bool m_dpiExport : 1; // DPI exported + bool m_dpiImport : 1; // DPI imported + bool m_dpiContext : 1; // DPI import context + bool m_dpiOpenChild : 1; // DPI import open array child wrapper + bool m_dpiTask : 1; // DPI import task (vs. void function) + bool m_isConstructor : 1; // Class constructor + bool m_pure : 1; // DPI import pure (vs. virtual pure) public: AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) : AstNode(t, fl) , m_name(name) - , m_dpiOpenParent(0), m_taskPublic(false) - , m_attrIsolateAssign(false), m_classMethod(false), m_prototype(false) - , m_dpiExport(false), m_dpiImport(false), m_dpiContext(false) - , m_dpiOpenChild(false), m_dpiTask(false), m_isConstructor(false), m_pure(false) { + , m_dpiOpenParent(0) + , m_taskPublic(false) + , m_attrIsolateAssign(false) + , m_classMethod(false) + , m_prototype(false) + , m_dpiExport(false) + , m_dpiImport(false) + , m_dpiContext(false) + , m_dpiOpenChild(false) + , m_dpiTask(false) + , m_isConstructor(false) + , m_pure(false) { addNOp3p(stmtsp); cname(name); // Might be overridden by dpi import/export } ASTNODE_BASE_FUNCS(NodeFTask) - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; virtual string name() const { return m_name; } // * = Var name virtual bool maybePointedTo() const { return true; } virtual bool isGateOptimizable() const { return !((m_dpiExport || m_dpiImport) && !m_pure); } @@ -2319,7 +2562,7 @@ public: // op1 = Output variable (functions only, NULL for tasks) AstNode* fvarp() const { return op1p(); } void addFvarp(AstNode* nodep) { addNOp1p(nodep); } - bool isFunction() const { return fvarp()!=NULL; } + bool isFunction() const { return fvarp() != NULL; } // op3 = Statements/Ports/Vars AstNode* stmtsp() const { return op3p(); } // op3 = List of statements void addStmtsp(AstNode* nodep) { addNOp3p(nodep); } @@ -2358,28 +2601,35 @@ class AstNodeFTaskRef : public AstNodeStmt { // A reference to a task (or function) // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. private: - AstNodeFTask* m_taskp; // [AfterLink] Pointer to task referenced - string m_name; // Name of variable - string m_dotted; // Dotted part of scope the name()ed task/func is under or "" - string m_inlinedDots; // Dotted hierarchy flattened out + AstNodeFTask* m_taskp; // [AfterLink] Pointer to task referenced + string m_name; // Name of variable + string m_dotted; // Dotted part of scope the name()ed task/func is under or "" + string m_inlinedDots; // Dotted hierarchy flattened out AstNodeModule* m_packagep; // Package hierarchy public: AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) : AstNodeStmt(t, fl, statement) - , m_taskp(NULL), m_packagep(NULL) { - setOp1p(namep); addNOp3p(pinsp); + , m_taskp(NULL) + , m_packagep(NULL) { + setOp1p(namep); + addNOp3p(pinsp); } AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp) : AstNodeStmt(t, fl, statement) - , m_taskp(NULL), m_name(name), m_packagep(NULL) { + , m_taskp(NULL) + , m_name(name) + , m_packagep(NULL) { addNOp3p(pinsp); } ASTNODE_BASE_FUNCS(NodeFTaskRef) - virtual const char* broken() const { BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); return NULL; } - virtual void cloneRelink() { if (m_taskp && m_taskp->clonep()) { - m_taskp = m_taskp->clonep(); - }} - virtual void dump(std::ostream& str=std::cout) const; + virtual const char* broken() const { + BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); + return NULL; + } + virtual void cloneRelink() { + if (m_taskp && m_taskp->clonep()) { m_taskp = m_taskp->clonep(); } + } + virtual void dump(std::ostream& str = std::cout) const; virtual string name() const { return m_name; } // * = Var name virtual bool isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); } string dotted() const { return m_dotted; } // * = Scope name or "" @@ -2408,27 +2658,35 @@ class AstNodeModule : public AstNode { // something that can live directly under the TOP, // excluding $unit package stuff private: - string m_name; // Name of the module - string m_origName; // Name of the module, ignoring name() changes, for dot lookup - string m_hierName; // Hierarchical name for errors, etc. - bool m_modPublic:1; // Module has public references - bool m_modTrace:1; // Tracing this module - bool m_inLibrary:1; // From a library, no error if not used, never top level - bool m_dead:1; // LinkDot believes is dead; will remove in Dead visitors - bool m_internal:1; // Internally created - bool m_recursive:1; // Recursive module - bool m_recursiveClone:1; // If recursive, what module it clones, otherwise NULL - int m_level; // 1=top module, 2=cell off top module, ... - int m_varNum; // Incrementing variable number - int m_typeNum; // Incrementing implicit type number + string m_name; // Name of the module + string m_origName; // Name of the module, ignoring name() changes, for dot lookup + string m_hierName; // Hierarchical name for errors, etc. + bool m_modPublic : 1; // Module has public references + bool m_modTrace : 1; // Tracing this module + bool m_inLibrary : 1; // From a library, no error if not used, never top level + bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors + bool m_internal : 1; // Internally created + bool m_recursive : 1; // Recursive module + bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise NULL + int m_level; // 1=top module, 2=cell off top module, ... + int m_varNum; // Incrementing variable number + int m_typeNum; // Incrementing implicit type number VOptionBool m_unconnectedDrive; // State of `unconnected_drive public: AstNodeModule(AstType t, FileLine* fl, const string& name) : AstNode(t, fl) - , m_name(name), m_origName(name) - , m_modPublic(false), m_modTrace(false), m_inLibrary(false), m_dead(false) - , m_internal(false), m_recursive(false), m_recursiveClone(false) - , m_level(0), m_varNum(0), m_typeNum(0) { } + , m_name(name) + , m_origName(name) + , m_modPublic(false) + , m_modTrace(false) + , m_inLibrary(false) + , m_dead(false) + , m_internal(false) + , m_recursive(false) + , m_recursiveClone(false) + , m_level(0) + , m_varNum(0) + , m_typeNum(0) {} ASTNODE_BASE_FUNCS(NodeModule) virtual void dump(std::ostream& str) const; virtual bool maybePointedTo() const { return true; } @@ -2442,13 +2700,13 @@ public: // ACCESSORS virtual void name(const string& name) { m_name = name; } virtual string origName() const { return m_origName; } - string hierName() const { return m_hierName; } + string hierName() const { return m_hierName; } void hierName(const string& hierName) { m_hierName = hierName; } bool inLibrary() const { return m_inLibrary; } void inLibrary(bool flag) { m_inLibrary = flag; } void level(int level) { m_level = level; } int level() const { return m_level; } - bool isTop() const { return level()==1; } + bool isTop() const { return level() == 1; } int varNumGetInc() { return ++m_varNum; } int typeNumGetInc() { return ++m_typeNum; } void modPublic(bool flag) { m_modPublic = flag; } @@ -2482,12 +2740,8 @@ public: //###################################################################### // Inline AstNVisitor METHODS -inline void AstNVisitor::iterate(AstNode* nodep) { - nodep->accept(*this); -} -inline void AstNVisitor::iterateChildren(AstNode* nodep) { - nodep->iterateChildren(*this); -} +inline void AstNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); } +inline void AstNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); } inline void AstNVisitor::iterateChildrenBackwards(AstNode* nodep) { nodep->iterateChildrenBackwards(*this); } @@ -2510,27 +2764,44 @@ inline AstNode* AstNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) { inline int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; } inline int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; } inline bool AstNode::width1() const { // V3Const uses to know it can optimize - return dtypep() && dtypep()->width()==1; } + return dtypep() && dtypep()->width() == 1; +} inline int AstNode::widthInstrs() const { - return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); } + return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); +} inline bool AstNode::isDouble() const { - return dtypep() && VN_IS(dtypep(), BasicDType) && VN_CAST(dtypep(), BasicDType)->isDouble(); } + return dtypep() && VN_IS(dtypep(), BasicDType) && VN_CAST(dtypep(), BasicDType)->isDouble(); +} inline bool AstNode::isString() const { - return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); } -inline bool AstNode::isSigned() const { - return dtypep() && dtypep()->isSigned(); } + return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); +} +inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); } -inline bool AstNode::isZero() const { return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqZero()); } -inline bool AstNode::isNeqZero() const { return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isNeqZero()); } -inline bool AstNode::isOne() const { return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqOne()); } -inline bool AstNode::isAllOnes() const { return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnes()); } -inline bool AstNode::isAllOnesV() const { return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnesV()); } +inline bool AstNode::isZero() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqZero()); +} +inline bool AstNode::isNeqZero() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isNeqZero()); +} +inline bool AstNode::isOne() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqOne()); +} +inline bool AstNode::isAllOnes() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnes()); +} +inline bool AstNode::isAllOnesV() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnesV()); +} inline bool AstNode::sameTree(const AstNode* node2p) const { - return sameTreeIter(this, node2p, true, false); } + return sameTreeIter(this, node2p, true, false); +} inline bool AstNode::sameGateTree(const AstNode* node2p) const { - return sameTreeIter(this, node2p, true, true); } + return sameTreeIter(this, node2p, true, true); +} -inline void AstNodeVarRef::init() { if (m_varp) dtypep(m_varp->dtypep()); } +inline void AstNodeVarRef::init() { + if (m_varp) dtypep(m_varp->dtypep()); +} inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); } @@ -2538,11 +2809,14 @@ inline void AstNodeArrayDType::rangep(AstRange* nodep) { setOp2p(nodep); } inline int AstNodeArrayDType::msb() const { return rangep()->msbConst(); } inline int AstNodeArrayDType::lsb() const { return rangep()->lsbConst(); } inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); } -inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange(msb(), lsb(), rangep()->littleEndian()); } +inline VNumRange AstNodeArrayDType::declRange() const { + return VNumRange(msb(), lsb(), rangep()->littleEndian()); +} inline void AstIfaceRefDType::cloneRelink() { if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep(); if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep(); - if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep(); } + if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep(); +} #endif // Guard diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index a46a7258d..4ca1f3646 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -64,21 +64,23 @@ int AstNodeSel::bitConst() const { void AstNodeUOrStructDType::repairMemberCache() { clearCache(); - for (AstMemberDType* itemp = membersp(); itemp; itemp=VN_CAST(itemp->nextp(), MemberDType)) { - if (m_members.find(itemp->name())!=m_members.end()) { - itemp->v3error("Duplicate declaration of member name: "<prettyNameQ()); } - else m_members.insert(make_pair(itemp->name(), itemp)); + for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) { + if (m_members.find(itemp->name()) != m_members.end()) { + itemp->v3error("Duplicate declaration of member name: " << itemp->prettyNameQ()); + } else { + m_members.insert(make_pair(itemp->name(), itemp)); + } } } const char* AstNodeUOrStructDType::broken() const { vl_unordered_set exists; - for (AstMemberDType* itemp = membersp(); itemp; itemp=VN_CAST(itemp->nextp(), MemberDType)) { + for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) { exists.insert(itemp); } - for (MemberNameMap::const_iterator it=m_members.begin(); it!=m_members.end(); ++it) { + for (MemberNameMap::const_iterator it = m_members.begin(); it != m_members.end(); ++it) { if (VL_UNCOVERABLE(exists.find(it->second) == exists.end())) { - this->v3error("Internal: Structure member broken: "<first); + this->v3error("Internal: Structure member broken: " << it->first); return "member broken"; } } @@ -106,39 +108,62 @@ string AstNodeCCall::hiernameProtect() const { return VIdProtect::protectWordsIf(hiername(), protect()); } -void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, - const V3Number& rhs, const V3Number& ths) { - if (lhs.isNeqZero()) out.opAssign(rhs); else out.opAssign(ths); +void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) { + if (lhs.isNeqZero()) + out.opAssign(rhs); + else + out.opAssign(ths); } int AstBasicDType::widthAlignBytes() const { - if (width()<=8) return 1; - else if (width()<=16) return 2; - else if (isQuad()) return 8; - else return 4; + if (width() <= 8) { + return 1; + } else if (width() <= 16) { + return 2; + } else if (isQuad()) { + return 8; + } else { + return 4; + } } int AstBasicDType::widthTotalBytes() const { - if (width()<=8) return 1; - else if (width()<=16) return 2; - else if (isQuad()) return 8; - else return widthWords() * (VL_EDATASIZE / 8); + if (width() <= 8) { + return 1; + } else if (width() <= 16) { + return 2; + } else if (isQuad()) { + return 8; + } else { + return widthWords() * (VL_EDATASIZE / 8); + } } int AstNodeUOrStructDType::widthTotalBytes() const { - if (width()<=8) return 1; - else if (width()<=16) return 2; - else if (isQuad()) return 8; - else return widthWords() * (VL_EDATASIZE / 8); + if (width() <= 8) { + return 1; + } else if (width() <= 16) { + return 2; + } else if (isQuad()) { + return 8; + } else { + return widthWords() * (VL_EDATASIZE / 8); + } } int AstNodeUOrStructDType::widthAlignBytes() const { // Could do max across members but that would be slow, // instead intuit based on total structure size - if (width()<=8) return 1; - else if (width()<=16) return 2; - else if (width()<=32) return 4; - else return 8; + if (width() <= 8) { + return 1; + } else if (width() <= 16) { + return 2; + } else if (width() <= 32) { + return 4; + } else { + return 8; + } } AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) { @@ -189,9 +214,7 @@ AstExecGraph::AstExecGraph(FileLine* fileline) : AstNode(AstType::atExecGraph, fileline) { m_depGraphp = new V3Graph; } -AstExecGraph::~AstExecGraph() { - VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); -} +AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); } AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp) { AstNode* ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp); @@ -205,19 +228,16 @@ AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode bool AstVar::isSigPublic() const { return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar())); } -bool AstVar::isScQuad() const { - return (isSc() && isQuad() && !isScBv() && !isScBigUint()); -} +bool AstVar::isScQuad() const { return (isSc() && isQuad() && !isScBv() && !isScBigUint()); } bool AstVar::isScBv() const { return ((isSc() && width() >= v3Global.opt.pinsBv()) || m_attrScBv); } bool AstVar::isScUint() const { - return ((isSc() && v3Global.opt.pinsScUint() - && width() >= 2 && width() <= 64) && !isScBv()); + return ((isSc() && v3Global.opt.pinsScUint() && width() >= 2 && width() <= 64) && !isScBv()); } bool AstVar::isScBigUint() const { - return ((isSc() && v3Global.opt.pinsScBigUint() - && width() >= 65 && width() <= 512) && !isScBv()); + return ((isSc() && v3Global.opt.pinsScBigUint() && width() >= 65 && width() <= 512) + && !isScBv()); } void AstVar::combineType(AstVarType type) { @@ -226,15 +246,11 @@ void AstVar::combineType(AstVarType type) { // when we combine wires cross-hierarchy we need a union of all characteristics. m_varType = type; // These flags get combined with the existing settings of the flags. - if (type==AstVarType::TRIWIRE || type==AstVarType::TRI0 || type==AstVarType::TRI1) { + if (type == AstVarType::TRIWIRE || type == AstVarType::TRI0 || type == AstVarType::TRI1) { m_tristate = true; } - if (type==AstVarType::TRI0) { - m_isPulldown = true; - } - if (type==AstVarType::TRI1) { - m_isPullup = true; - } + if (type == AstVarType::TRI0) m_isPulldown = true; + if (type == AstVarType::TRI1) m_isPullup = true; } string AstVar::verilogKwd() const { @@ -242,11 +258,11 @@ string AstVar::verilogKwd() const { return direction().verilogKwd(); } else if (isTristate()) { return "tri"; - } else if (varType()==AstVarType::WIRE) { + } else if (varType() == AstVarType::WIRE) { return "wire"; - } else if (varType()==AstVarType::WREAL) { + } else if (varType() == AstVarType::WREAL) { return "wreal"; - } else if (varType()==AstVarType::IFACEREF) { + } else if (varType() == AstVarType::IFACEREF) { return "ifaceref"; } else { return dtypep()->name(); @@ -264,7 +280,7 @@ public: m_oprefix.clear(); } string refParen(const string& name) { - return m_oref.empty() ? name : "("+m_oref+" "+name+")"; + return m_oref.empty() ? name : "(" + m_oref + " " + name + ")"; } }; @@ -279,7 +295,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& string oname; if (named) { oname += " "; - if (!namespc.empty()) oname += namespc+"::"; + if (!namespc.empty()) oname += namespc + "::"; oname += VIdProtect::protectIf(name(), protect()); } return ostatic + info.m_oprefix + info.refParen(oname) + info.m_osuffix; @@ -344,11 +360,11 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT if (!bdtypep->isOpaque() && !v3Global.opt.protectIds()) { // We don't print msb()/lsb() as multidim packed would require recursion, // and may confuse users as C++ data is stored always with bit 0 used - bitvec += "/*"+cvtToStr(dtypep->width()-1)+":0*/"; + bitvec += "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"; } - if ((forFunc && isReadOnly()) - || bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR - || bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) otype += "const "; + if ((forFunc && isReadOnly()) || bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR + || bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) + otype += "const "; if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) { otype += "char*"; } else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) { @@ -360,28 +376,27 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT } else if (strtype) { otype += "std::string"; } else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width - otype += "CData"+bitvec; + otype += "CData" + bitvec; } else if (dtypep->widthMin() <= 16) { - otype += "SData"+bitvec; + otype += "SData" + bitvec; } else if (dtypep->widthMin() <= VL_IDATASIZE) { - otype += "IData"+bitvec; + otype += "IData" + bitvec; } else if (dtypep->isQuad()) { - otype += "QData"+bitvec; + otype += "QData" + bitvec; } else if (dtypep->isWide()) { if (arrayed) { - otype += "VlWide<"+cvtToStr(dtypep->widthWords())+"> "; + otype += "VlWide<" + cvtToStr(dtypep->widthWords()) + "> "; } else { - otype += "WData"+bitvec; // []'s added later - oarray += "["+cvtToStr(dtypep->widthWords())+"]"; + otype += "WData" + bitvec; // []'s added later + oarray += "[" + cvtToStr(dtypep->widthWords()) + "]"; } } string oref; if (isDpiOpenArray() - || (forFunc && (isWritable() - || direction() == VDirection::REF - || direction() == VDirection::CONSTREF - || (strtype && isNonOutput())))) { + || (forFunc + && (isWritable() || direction() == VDirection::REF + || direction() == VDirection::CONSTREF || (strtype && isNonOutput())))) { oref = "&"; } @@ -389,21 +404,21 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT info.m_oprefix = otype; info.m_osuffix = oarray; info.m_oref = oref; - //UINFO(9, "vlArgRec "<<"oprefix="<prettyName()); + v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName()); } } string AstVar::vlEnumType() const { string arg; AstBasicDType* bdtypep = basicp(); - bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING; - if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) { + bool strtype = bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::STRING; + if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) { return "VLVT_PTR"; - } else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) { + } else if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) { return "VLVT_PTR"; } else if (strtype) { arg += "VLVT_STRING"; @@ -434,8 +449,11 @@ string AstVar::vlEnumDir() const { out = "VLVD_NODIR"; } // - if (isSigUserRWPublic()) out += "|VLVF_PUB_RW"; - else if (isSigUserRdPublic()) out += "|VLVF_PUB_RD"; + if (isSigUserRWPublic()) { + out += "|VLVF_PUB_RW"; + } else if (isSigUserRdPublic()) { + out += "|VLVF_PUB_RD"; + } // if (AstBasicDType* bdtypep = basicp()) { if (bdtypep->keyword().isDpiCLayout()) out += "|VLVF_DPI_CLAY"; @@ -446,23 +464,25 @@ string AstVar::vlEnumDir() const { string AstVar::vlPropInit() const { string out; out = vlEnumType(); // VLVT_UINT32 etc - out += ", "+vlEnumDir(); // VLVD_IN etc + out += ", " + vlEnumDir(); // VLVD_IN etc if (AstBasicDType* bdtypep = basicp()) { out += ", VerilatedVarProps::Packed()"; - out += ", "+cvtToStr(bdtypep->left())+", "+cvtToStr(bdtypep->right()); + out += ", " + cvtToStr(bdtypep->left()) + ", " + cvtToStr(bdtypep->right()); } bool first = true; - for (AstNodeDType* dtp=dtypep(); dtp; ) { + for (AstNodeDType* dtp = dtypep(); dtp;) { dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node if (AstNodeArrayDType* adtypep = VN_CAST(dtp, NodeArrayDType)) { if (first) { out += ", VerilatedVarProps::Unpacked()"; first = false; } - out += ", "+cvtToStr(adtypep->declRange().left())+", "+cvtToStr(adtypep->declRange().right()); + out += ", " + cvtToStr(adtypep->declRange().left()) + ", " + + cvtToStr(adtypep->declRange().right()); dtp = adtypep->subDTypep(); + } else { + break; // AstBasicDType - nothing below } - else break; // AstBasicDType - nothing below } return out; } @@ -481,13 +501,15 @@ string AstVar::cPubArgType(bool named, bool forReturn) const { arg += "uint32_t"; // []'s added later } if (isWide()) { - if (forReturn) v3error("Unsupported: Public functions with >64 bit outputs; make an output of a public task instead"); - arg += " (& "+name(); - arg += ")["+cvtToStr(widthWords())+"]"; + if (forReturn) { + v3error("Unsupported: Public functions with >64 bit outputs; " + "make an output of a public task instead"); + } + arg += " (& " + name(); + arg += ")[" + cvtToStr(widthWords()) + "]"; } else { - if (!forReturn && (isWritable() - || direction().isRefOrConstRef())) arg += "&"; - if (named) arg += " "+name(); + if (!forReturn && (isWritable() || direction().isRefOrConstRef())) arg += "&"; + if (named) arg += " " + name(); } return arg; } @@ -518,21 +540,23 @@ string AstVar::dpiArgType(bool named, bool forReturn) const { } else { arg = basicp()->keyword().dpiType(); if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) { - arg = "unsigned "+arg; + arg = "unsigned " + arg; } if (!forReturn && isWritable()) arg += "*"; } - if (named) arg += " "+name(); + if (named) arg += " " + name(); return arg; } string AstVar::scType() const { if (isScBigUint()) { - return (string("sc_biguint<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >> + return (string("sc_biguint<") + cvtToStr(widthMin()) + + "> "); // Keep the space so don't get >> } else if (isScUint()) { - return (string("sc_uint<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >> + return (string("sc_uint<") + cvtToStr(widthMin()) + + "> "); // Keep the space so don't get >> } else if (isScBv()) { - return (string("sc_bv<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >> + return (string("sc_bv<") + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >> } else if (widthMin() == 1) { return "bool"; } else if (widthMin() <= VL_IDATASIZE) { @@ -553,28 +577,39 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) { // Historically sc variables are identified by a variable // attribute. TODO it would better be a data type attribute. if (AstVar* anodep = VN_CAST(nodep, Var)) { - if (anodep->isSc()) return anodep; - else return NULL; - } - else if (VN_IS(nodep, VarRef)) { - if (VN_CAST(nodep, VarRef)->varp()->isSc()) return VN_CAST(nodep, VarRef)->varp(); - else return NULL; - } - else if (VN_IS(nodep, ArraySel)) { - if (nodep->op1p()) if (AstVar* p = scVarRecurse(nodep->op1p())) return p; - if (nodep->op2p()) if (AstVar* p = scVarRecurse(nodep->op2p())) return p; - if (nodep->op3p()) if (AstVar* p = scVarRecurse(nodep->op3p())) return p; - if (nodep->op4p()) if (AstVar* p = scVarRecurse(nodep->op4p())) return p; + if (anodep->isSc()) { + return anodep; + } else { + return NULL; + } + } else if (VN_IS(nodep, VarRef)) { + if (VN_CAST(nodep, VarRef)->varp()->isSc()) { + return VN_CAST(nodep, VarRef)->varp(); + } else { + return NULL; + } + } else if (VN_IS(nodep, ArraySel)) { + if (nodep->op1p()) { + if (AstVar* p = scVarRecurse(nodep->op1p())) return p; + } + if (nodep->op2p()) { + if (AstVar* p = scVarRecurse(nodep->op2p())) return p; + } + if (nodep->op3p()) { + if (AstVar* p = scVarRecurse(nodep->op3p())) return p; + } + if (nodep->op4p()) { + if (AstVar* p = scVarRecurse(nodep->op4p())) return p; + } } return NULL; } string AstVar::mtasksString() const { std::ostringstream os; - os<<"all: "; - for (MTaskIdSet::const_iterator it = m_mtaskIds.begin(); - it != m_mtaskIds.end(); ++it) { - os<<*it<<" "; + os << "all: "; + for (MTaskIdSet::const_iterator it = m_mtaskIds.begin(); it != m_mtaskIds.end(); ++it) { + os << *it << " "; } return os.str(); } @@ -594,29 +629,21 @@ AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) { // TODO this function should be removed in favor of recursing the dtype(), // as that allows for more complicated data types. int dim = 0; - for (AstNodeDType* dtypep=this; dtypep; ) { + for (AstNodeDType* dtypep = this; dtypep;) { dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node if (AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) { - if ((dim++)==dimension) { - return dtypep; - } + if ((dim++) == dimension) return dtypep; dtypep = adtypep->subDTypep(); continue; - } - else if (AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) { + } else if (AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) { // AstBasicDType - nothing below, return null if (adtypep->isRanged()) { - if ((dim++) == dimension) { - return adtypep; - } + if ((dim++) == dimension) return adtypep; } return NULL; - } - else if (AstNodeUOrStructDType* adtypep = VN_CAST(dtypep, NodeUOrStructDType)) { + } else if (AstNodeUOrStructDType* adtypep = VN_CAST(dtypep, NodeUOrStructDType)) { if (adtypep->packed()) { - if ((dim++) == dimension) { - return adtypep; - } + if ((dim++) == dimension) return adtypep; } return NULL; } @@ -628,13 +655,12 @@ AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) { uint32_t AstNodeDType::arrayUnpackedElements() { uint32_t entries = 1; - for (AstNodeDType* dtypep=this; dtypep; ) { + for (AstNodeDType* dtypep = this; dtypep;) { dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { entries *= adtypep->elementsConst(); dtypep = adtypep->subDTypep(); - } - else { + } else { // AstBasicDType - nothing below, 1 break; } @@ -642,27 +668,27 @@ uint32_t AstNodeDType::arrayUnpackedElements() { return entries; } -std::pair AstNodeDType::dimensions(bool includeBasic) { +std::pair AstNodeDType::dimensions(bool includeBasic) { // How many array dimensions (packed,unpacked) does this Var have? uint32_t packed = 0; uint32_t unpacked = 0; - for (AstNodeDType* dtypep=this; dtypep; ) { + for (AstNodeDType* dtypep = this; dtypep;) { dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) { - if (VN_IS(adtypep, PackArrayDType)) packed++; - else unpacked++; + if (VN_IS(adtypep, PackArrayDType)) { + ++packed; + } else { + ++unpacked; + } dtypep = adtypep->subDTypep(); continue; - } - else if (const AstQueueDType* qdtypep = VN_CAST(dtypep, QueueDType)) { + } else if (const AstQueueDType* qdtypep = VN_CAST(dtypep, QueueDType)) { unpacked++; dtypep = qdtypep->subDTypep(); continue; - } - else if (const AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) { + } else if (const AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) { if (includeBasic && (adtypep->isRanged() || adtypep->isString())) packed++; - } - else if (VN_IS(dtypep, StructDType)) { + } else if (VN_IS(dtypep, StructDType)) { packed++; } break; @@ -673,29 +699,38 @@ std::pair AstNodeDType::dimensions(bool includeBasic) { int AstNodeDType::widthPow2() const { // I.e. width 30 returns 32, width 32 returns 32. uint32_t width = this->width(); - for (int p2=30; p2>=0; p2--) { - if (width > (1UL<= 0; p2--) { + if (width > (1UL << p2)) return (1UL << (p2 + 1)); } return 1; } -AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences? +/// What is the base variable (or const) this dereferences? +AstNode* AstArraySel::baseFromp(AstNode* nodep) { // Else AstArraySel etc; search for the base while (nodep) { - if (VN_IS(nodep, ArraySel)) { nodep = VN_CAST(nodep, ArraySel)->fromp(); continue; } - else if (VN_IS(nodep, Sel)) { nodep = VN_CAST(nodep, Sel)->fromp(); continue; } + if (VN_IS(nodep, ArraySel)) { + nodep = VN_CAST(nodep, ArraySel)->fromp(); + continue; + } else if (VN_IS(nodep, Sel)) { + nodep = VN_CAST(nodep, Sel)->fromp(); + continue; + } // AstNodeSelPre stashes the associated variable under an ATTROF // of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified - else if (VN_IS(nodep, AttrOf)) { nodep = VN_CAST(nodep, AttrOf)->fromp(); continue; } - else if (VN_IS(nodep, NodePreSel)) { + else if (VN_IS(nodep, AttrOf)) { + nodep = VN_CAST(nodep, AttrOf)->fromp(); + continue; + } else if (VN_IS(nodep, NodePreSel)) { if (VN_CAST(nodep, NodePreSel)->attrp()) { nodep = VN_CAST(nodep, NodePreSel)->attrp(); } else { nodep = VN_CAST(nodep, NodePreSel)->lhsp(); } continue; + } else { + break; } - else break; } return nodep; } @@ -719,15 +754,13 @@ void AstScope::cloneRelink() { string AstScope::nameDotless() const { string out = shortName(); string::size_type pos; - while ((pos = out.find('.')) != string::npos) { - out.replace(pos, 1, "__"); - } + while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__"); return out; } string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const { string out; - for (AstText* textp=scopeTextp; textp; textp=VN_CAST(textp->nextp(), Text)) { + for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) { out += textp->text(); } // TOP will be replaced by top->name() @@ -739,46 +772,42 @@ string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const { string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const { string out; - for (AstText* textp=scopeTextp; textp; textp=VN_CAST(textp->nextp(), Text)) { + for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) { out += textp->text(); } if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, ""); if (out.substr(0, 7) == "__DOT__") out.replace(0, 7, ""); if (out.substr(0, 1) == ".") out.replace(0, 1, ""); string::size_type pos; - while ((pos = out.find('.')) != string::npos) { - out.replace(pos, 1, "__"); - } - while ((pos = out.find("__DOT__")) != string::npos) { - out.replace(pos, 7, "__"); - } + while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__"); + while ((pos = out.find("__DOT__")) != string::npos) out.replace(pos, 7, "__"); return out; } bool AstSenTree::hasClocked() const { UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it"); - for (AstNodeSenItem* senp = sensesp(); senp; senp=VN_CAST(senp->nextp(), NodeSenItem)) { + for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { if (senp->isClocked()) return true; } return false; } bool AstSenTree::hasSettle() const { UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it"); - for (AstNodeSenItem* senp = sensesp(); senp; senp=VN_CAST(senp->nextp(), NodeSenItem)) { + for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { if (senp->isSettle()) return true; } return false; } bool AstSenTree::hasInitial() const { UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it"); - for (AstNodeSenItem* senp = sensesp(); senp; senp=VN_CAST(senp->nextp(), NodeSenItem)) { + for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { if (senp->isInitial()) return true; } return false; } bool AstSenTree::hasCombo() const { UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it"); - for (AstNodeSenItem* senp = sensesp(); senp; senp=VN_CAST(senp->nextp(), NodeSenItem)) { + for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { if (senp->isCombo()) return true; } return false; @@ -787,22 +816,20 @@ bool AstSenTree::hasCombo() const { void AstTypeTable::clearCache() { // When we mass-change widthMin in V3WidthCommit, we need to correct the table. // Just clear out the maps; the search functions will be used to rebuild the map - for (int i=0; i < static_cast(AstBasicDTypeKwd::_ENUM_MAX); ++i) { + for (int i = 0; i < static_cast(AstBasicDTypeKwd::_ENUM_MAX); ++i) { m_basicps[i] = NULL; } m_detailedMap.clear(); // Clear generic()'s so dead detection will work - for (AstNode* nodep = typesp(); nodep; nodep=nodep->nextp()) { - if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) { - bdtypep->generic(false); - } + for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) { + if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) bdtypep->generic(false); } } void AstTypeTable::repairCache() { // After we mass-change widthMin in V3WidthCommit, we need to correct the table. clearCache(); - for (AstNode* nodep = typesp(); nodep; nodep=nodep->nextp()) { + for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) { if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) { (void)findInsertSameDType(bdtypep); } @@ -826,34 +853,43 @@ AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) // check the detailed map for this same node // Also adds this new node to the detailed map AstBasicDType* newp = findInsertSameDType(new1p); - if (newp != new1p) VL_DO_DANGLING(new1p->deleteTree(), new1p); - else addTypesp(newp); + if (newp != new1p) { + VL_DO_DANGLING(new1p->deleteTree(), new1p); + } else { + addTypesp(newp); + } // m_basicps[kwd] = newp; return newp; } -AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, - int width, int widthMin, AstNumeric numeric) { +AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width, + int widthMin, AstNumeric numeric) { AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin); AstBasicDType* newp = findInsertSameDType(new1p); - if (newp != new1p) VL_DO_DANGLING(new1p->deleteTree(), new1p); - else addTypesp(newp); + if (newp != new1p) { + VL_DO_DANGLING(new1p->deleteTree(), new1p); + } else { + addTypesp(newp); + } return newp; } -AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, - VNumRange range, int widthMin, AstNumeric numeric) { +AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, VNumRange range, + int widthMin, AstNumeric numeric) { AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin); AstBasicDType* newp = findInsertSameDType(new1p); - if (newp != new1p) VL_DO_DANGLING(new1p->deleteTree(), new1p); - else addTypesp(newp); + if (newp != new1p) { + VL_DO_DANGLING(new1p->deleteTree(), new1p); + } else { + addTypesp(newp); + } return newp; } AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) { - VBasicTypeKey key (nodep->width(), nodep->widthMin(), nodep->numeric(), - nodep->keyword(), nodep->nrange()); + VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(), + nodep->nrange()); DetailedMap& mapr = m_detailedMap; DetailedMap::const_iterator it = mapr.find(key); if (it != mapr.end()) return it->second; @@ -931,45 +967,49 @@ void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) { // Per-type Debugging void AstNode::dump(std::ostream& str) const { - str<m_backp - <<" =editCountLast())?"#>":">") - <<" {"<filenameLetters()<lastLineno()<<"}"; - if (user1p()) str<<" u1="<= editCountLast()) ? "#>" : ">") + << " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno() << "}"; + if (user1p()) str << " u1=" << cvtToHex(user1p()); + if (user2p()) str << " u2=" << cvtToHex(user2p()); + if (user3p()) str << " u3=" << cvtToHex(user3p()); + if (user4p()) str << " u4=" << cvtToHex(user4p()); + if (user5p()) str << " u5=" << cvtToHex(user5p()); if (hasDType()) { // Final @ so less likely to by accident read it as a nodep - if (dtypep()==this) str<<" @dt="<<"this@"; - else str<<" @dt="<dumpSmall(str); + if (dtypep() == this) { + str << " @dt=this@"; + } else { + str << " @dt=" << cvtToHex(dtypep()) << "@"; } + if (AstNodeDType* dtp = dtypep()) { dtp->dumpSmall(str); } } else { // V3Broken will throw an error - if (dtypep()) str<<" %Error-dtype-exp=null,got="<AstNode::dump(str); - if (keyword() != VAlwaysKwd::ALWAYS) str<<" ["<AstNode::dump(str); - str<<" ["<AstNodeDType::dump(str); - str<<" kwd="<AstNode::dump(str); - str<<" sz"<AstNode::dump(str); - if (recursive()) str<<" [RECURSIVE]"; - if (modp()) { str<<" -> "; modp()->dump(str); } - else { str<<" ->UNLINKED:"< "; + modp()->dump(str); + } else { + str << " ->UNLINKED:" << modName(); + } } void AstCellInline::dump(std::ostream& str) const { this->AstNode::dump(str); - str<<" -> "< " << origModName(); } const char* AstClassPackage::broken() const { BROKEN_BASE_RTN(AstNodeModule::broken()); @@ -1009,13 +1053,9 @@ void AstClass::insertCache(AstNode* nodep) { } void AstClass::repairCache() { clearCache(); - for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { - insertCache(itemp); - } -} -void AstClass::dump(std::ostream& str) const { - this->AstNode::dump(str); + for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { insertCache(itemp); } } +void AstClass::dump(std::ostream& str) const { this->AstNode::dump(str); } AstClass* AstClassExtends::classp() const { AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType); UASSERT_OBJ(refp, this, "class extends non-ref"); @@ -1023,60 +1063,82 @@ AstClass* AstClassExtends::classp() const { } void AstClassRefDType::dump(std::ostream& str) const { this->AstNode::dump(str); - if (classp()) { str<<" -> "; classp()->dump(str); } - else { str<<" -> UNLINKED"; } + if (classp()) { + str << " -> "; + classp()->dump(str); + } else { + str << " -> UNLINKED"; + } } void AstClassRefDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); - str<<"class:"<AstNode::dump(str); - if (immediate()) str<<" [IMMEDIATE]"; + if (immediate()) str << " [IMMEDIATE]"; } void AstDisplay::dump(std::ostream& str) const { this->AstNode::dump(str); - //str<<" "<AstNode::dump(str); - str<<" -> "; - if (itemp()) { itemp()->dump(str); } - else { str<<"UNLINKED"; } + str << " -> "; + if (itemp()) { + itemp()->dump(str); + } else { + str << "UNLINKED"; + } } void AstIfaceRefDType::dump(std::ostream& str) const { this->AstNode::dump(str); - if (cellName()!="") { str<<" cell="< "; cellp()->dump(str); } - else if (ifacep()) { str<<" -> "; ifacep()->dump(str); } - else { str<<" -> UNLINKED"; } + if (cellName() != "") { str << " cell=" << cellName(); } + if (ifaceName() != "") { str << " if=" << ifaceName(); } + if (modportName() != "") { str << " mp=" << modportName(); } + if (cellp()) { + str << " -> "; + cellp()->dump(str); + } else if (ifacep()) { + str << " -> "; + ifacep()->dump(str); + } else { + str << " -> UNLINKED"; + } } void AstIfaceRefDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); - str<<"iface"; + str << "iface"; } void AstInitArray::dump(std::ostream& str) const { this->AstNode::dump(str); int n = 0; const AstInitArray::KeyItemMap& mapr = map(); for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) { - if (n++ > 5) { str<<" ..."; break; } - str<<" ["<first<<"]="<<(void*)it->second; + if (n++ > 5) { + str << " ..."; + break; + } + str << " [" << it->first << "]=" << (void*)it->second; } } void AstJumpGo::dump(std::ostream& str) const { this->AstNode::dump(str); - str<<" -> "; - if (labelp()) { labelp()->dump(str); } - else { str<<"%Error:UNLINKED"; } + str << " -> "; + if (labelp()) { + labelp()->dump(str); + } else { + str << "%Error:UNLINKED"; + } } void AstMemberSel::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> "; - if (varp()) { varp()->dump(str); } - else { str << "%Error:UNLINKED"; } + if (varp()) { + varp()->dump(str); + } else { + str << "%Error:UNLINKED"; + } } void AstMethodCall::dump(std::ostream& str) const { this->AstNode::dump(str); @@ -1090,30 +1152,42 @@ void AstMethodCall::dump(std::ostream& str) const { } void AstModportFTaskRef::dump(std::ostream& str) const { this->AstNode::dump(str); - if (isExport()) str<<" EXPORT"; - if (isImport()) str<<" IMPORT"; - if (ftaskp()) { str<<" -> "; ftaskp()->dump(str); } - else { str<<" -> UNLINKED"; } + if (isExport()) str << " EXPORT"; + if (isImport()) str << " IMPORT"; + if (ftaskp()) { + str << " -> "; + ftaskp()->dump(str); + } else { + str << " -> UNLINKED"; + } } void AstModportVarRef::dump(std::ostream& str) const { this->AstNode::dump(str); - if (direction().isAny()) str<<" "< "; varp()->dump(str); } - else { str<<" -> UNLINKED"; } + if (direction().isAny()) str << " " << direction(); + if (varp()) { + str << " -> "; + varp()->dump(str); + } else { + str << " -> UNLINKED"; + } } void AstPin::dump(std::ostream& str) const { this->AstNode::dump(str); - if (modVarp()) { str<<" -> "; modVarp()->dump(str); } - else { str<<" ->UNLINKED"; } - if (svImplicit()) str<<" [.SV]"; + if (modVarp()) { + str << " -> "; + modVarp()->dump(str); + } else { + str << " ->UNLINKED"; + } + if (svImplicit()) str << " [.SV]"; } void AstTypedef::dump(std::ostream& str) const { this->AstNode::dump(str); - if (attrPublic()) str<<" [PUBLIC]"; + if (attrPublic()) str << " [PUBLIC]"; } void AstRange::dump(std::ostream& str) const { this->AstNode::dump(str); - if (littleEndian()) str<<" [LITTLE]"; + if (littleEndian()) str << " [LITTLE]"; } void AstRefDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); @@ -1121,46 +1195,46 @@ void AstRefDType::dump(std::ostream& str) const { static bool s_recursing = false; if (!s_recursing) { // Prevent infinite dump if circular typedefs s_recursing = true; - str<<" -> "; defp()->dump(str); + str << " -> "; + defp()->dump(str); s_recursing = false; } + } else { + str << " -> UNLINKED"; } - else { str<<" -> UNLINKED"; } } void AstNodeUOrStructDType::dump(std::ostream& str) const { this->AstNode::dump(str); - if (packed()) str<<" [PACKED]"; - if (isFourstate()) str<<" [4STATE]"; + if (packed()) str << " [PACKED]"; + if (isFourstate()) str << " [4STATE]"; } void AstNodeDType::dump(std::ostream& str) const { this->AstNode::dump(str); - if (generic()) str<<" [GENERIC]"; + if (generic()) str << " [GENERIC]"; if (AstNodeDType* dtp = virtRefDTypep()) { - str<<" refdt="<AstNodeDType::dumpSmall(str); - if (VN_IS(this, PackArrayDType)) str<<"p"; else str<<"u"; - str<AstNodeDType::dump(str); - str<<" "<AstNode::dump(str); - str<<" L"<AstNode::dump(str); - str<<" -> "< " << packagep(); } void AstPackageImport::dump(std::ostream& str) const { this->AstNode::dump(str); - str<<" -> "< " << packagep(); } void AstSel::dump(std::ostream& str) const { this->AstNode::dump(str); if (declRange().ranged()) { - str<<" decl"<AstNode::dump(str); - if (declRange().ranged()) { - str<<" decl"<AstNode::dump(str); - str<<" "; + str << " "; m_execMTaskp->dump(str); } void AstTypeTable::dump(std::ostream& str) const { this->AstNode::dump(str); - for (int i=0; i < static_cast(AstBasicDTypeKwd::_ENUM_MAX); ++i) { + for (int i = 0; i < static_cast(AstBasicDTypeKwd::_ENUM_MAX); ++i) { if (AstBasicDType* subnodep = m_basicps[i]) { - str< "; + str << endl; // Newline from caller, so newline first + str << "\t\t" << std::setw(8) << AstBasicDTypeKwd(i).ascii(); + str << " -> "; subnodep->dump(str); } } @@ -1229,8 +1304,8 @@ void AstTypeTable::dump(std::ostream& str) const { const DetailedMap& mapr = m_detailedMap; for (DetailedMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) { AstBasicDType* dtypep = it->second; - str< "; + str << endl; // Newline from caller, so newline first + str << "\t\tdetailed -> "; dtypep->dump(str); } } @@ -1238,21 +1313,19 @@ void AstTypeTable::dump(std::ostream& str) const { } void AstAssocArrayDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); - str<<"[assoc-"<<(void*)keyDTypep()<<"]"; + str << "[assoc-" << (void*)keyDTypep() << "]"; } string AstAssocArrayDType::prettyDTypeName() const { return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]"; } void AstDynArrayDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); - str<<"[]"; -} -string AstDynArrayDType::prettyDTypeName() const { - return subDTypep()->prettyDTypeName() + "[]"; + str << "[]"; } +string AstDynArrayDType::prettyDTypeName() const { return subDTypep()->prettyDTypeName() + "[]"; } void AstQueueDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); - str<<"[queue]"; + str << "[queue]"; } string AstQueueDType::prettyDTypeName() const { string str = subDTypep()->prettyDTypeName() + "[$"; @@ -1261,165 +1334,200 @@ string AstQueueDType::prettyDTypeName() const { } void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); - str<<"[]"; + str << "[]"; } void AstVoidDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); - str<<"void"; + str << "void"; } void AstVarScope::dump(std::ostream& str) const { this->AstNode::dump(str); - if (isCircular()) str<<" [CIRC]"; - if (varp()) { str<<" -> "; varp()->dump(str); } - else { str<<" ->UNLINKED"; } + if (isCircular()) str << " [CIRC]"; + if (varp()) { + str << " -> "; + varp()->dump(str); + } else { + str << " ->UNLINKED"; + } } void AstVarXRef::dump(std::ostream& str) const { this->AstNode::dump(str); - if (packagep()) { str<<" pkg="< "; - else str<<" [RV] <- "; - str<<".="<dump(str); } - else if (varp()) { varp()->dump(str); } - else { str<<"UNLINKED"; } + if (packagep()) { str << " pkg=" << cvtToHex(packagep()); } + if (lvalue()) { + str << " [LV] => "; + } else { + str << " [RV] <- "; + } + str << ".=" << dotted() << " "; + if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - "; + if (varScopep()) { + varScopep()->dump(str); + } else if (varp()) { + varp()->dump(str); + } else { + str << "UNLINKED"; + } } void AstVarRef::dump(std::ostream& str) const { this->AstNode::dump(str); - if (packagep()) { str<<" pkg="< "; - else str<<" [RV] <- "; - if (varScopep()) { varScopep()->dump(str); } - else if (varp()) { varp()->dump(str); } - else { str<<"UNLINKED"; } + if (packagep()) { str << " pkg=" << cvtToHex(packagep()); } + if (lvalue()) { + str << " [LV] => "; + } else { + str << " [RV] <- "; + } + if (varScopep()) { + varScopep()->dump(str); + } else if (varp()) { + varp()->dump(str); + } else { + str << "UNLINKED"; + } } void AstVar::dump(std::ostream& str) const { this->AstNode::dump(str); - if (isSc()) str<<" [SC]"; - if (isPrimaryIO()) str<<(isInoutish()?" [PIO]":(isWritable()?" [PO]":" [PI]")); - if (isIO()) str<<" "<AstNode::dump(str); - if (isMulti()) str<<" [MULTI]"; + if (isMulti()) str << " [MULTI]"; } void AstSenItem::dump(std::ostream& str) const { this->AstNode::dump(str); - str<<" ["<AstNode::dump(str); - str<<" ["<AstNode::dump(str); - if (packagep()) { str<<" pkg="< "; - if (packagep()) { packagep()->dump(str); } - else { str<<"UNLINKED"; } -} -void AstDot::dump(std::ostream& str) const { - this->AstNode::dump(str); + if (packagep()) { str << " pkg=" << cvtToHex(packagep()); } + str << " -> "; + if (packagep()) { + packagep()->dump(str); + } else { + str << "UNLINKED"; + } } +void AstDot::dump(std::ostream& str) const { this->AstNode::dump(str); } void AstActive::dump(std::ostream& str) const { this->AstNode::dump(str); - str<<" => "; - if (sensesp()) { sensesp()->dump(str); } - else { str<<"UNLINKED"; } + str << " => "; + if (sensesp()) { + sensesp()->dump(str); + } else { + str << "UNLINKED"; + } } void AstNodeFTaskRef::dump(std::ostream& str) const { this->AstNode::dump(str); - if (packagep()) { str<<" pkg="< "; - if (dotted()!="") { str<<".="<dump(str); } - else { str<<"UNLINKED"; } + if (packagep()) { str << " pkg=" << cvtToHex(packagep()); } + str << " -> "; + if (dotted() != "") { str << ".=" << dotted() << " "; } + if (taskp()) { + taskp()->dump(str); + } else { + str << "UNLINKED"; + } } void AstNodeFTask::dump(std::ostream& str) const { this->AstNode::dump(str); - if (classMethod()) str<<" [METHOD]"; - if (taskPublic()) str<<" [PUBLIC]"; - if (prototype()) str<<" [PROTOTYPE]"; - if (dpiImport()) str<<" [DPII]"; - if (dpiExport()) str<<" [DPIX]"; - if (dpiOpenChild()) str<<" [DPIOPENCHILD]"; - if (dpiOpenParent()) str<<" [DPIOPENPARENT]"; - if ((dpiImport() || dpiExport()) && cname()!=name()) str<<" [c="<AstNode::dump(str); - if (unnamed()) str<<" [UNNAMED]"; - if (generate()) str<<" [GEN]"; - if (genforp()) str<<" [GENFOR]"; - if (implied()) str<<" [IMPLIED]"; + if (unnamed()) str << " [UNNAMED]"; + if (generate()) str << " [GEN]"; + if (genforp()) str << " [GENFOR]"; + if (implied()) str << " [IMPLIED]"; } void AstCoverDecl::dump(std::ostream& str) const { this->AstNode::dump(str); if (this->dataDeclNullp()) { - str<<" -> "; + str << " -> "; this->dataDeclNullp()->dump(str); } else { - if (binNum()) { str<<" bin"<AstNode::dump(str); - str<<" -> "; - if (declp()) { declp()->dump(str); } - else { str<<"%Error:UNLINKED"; } + str << " -> "; + if (declp()) { + declp()->dump(str); + } else { + str << "%Error:UNLINKED"; + } } void AstTraceInc::dump(std::ostream& str) const { this->AstNode::dump(str); - str<<" -> "; - if (declp()) { declp()->dump(str); } - else { str<<"%Error:UNLINKED"; } + str << " -> "; + if (declp()) { + declp()->dump(str); + } else { + str << "%Error:UNLINKED"; + } } void AstNodeText::dump(std::ostream& str) const { this->AstNode::dump(str); string out = text(); string::size_type pos; if ((pos = out.find('\n')) != string::npos) { - out.erase(pos, out.length()-pos); + out.erase(pos, out.length() - pos); out += "..."; } - str<<" \""<AstNode::dump(str); -} +void AstVFile::dump(std::ostream& str) const { this->AstNode::dump(str); } void AstCFile::dump(std::ostream& str) const { this->AstNode::dump(str); - if (source()) str<<" [SRC]"; - if (slow()) str<<" [SLOW]"; + if (source()) str << " [SRC]"; + if (slow()) str << " [SLOW]"; } void AstCFunc::dump(std::ostream& str) const { this->AstNode::dump(str); - if (slow()) str<<" [SLOW]"; - if (pure()) str<<" [PURE]"; - if (isStatic().unknown()) str<<" [STATICU]"; - else if (isStatic().trueUnknown()) str<<" [STATIC]"; - if (dpiImport()) str<<" [DPII]"; - if (dpiExport()) str<<" [DPIX]"; - if (dpiExportWrapper()) str<<" [DPIXWR]"; - if (isConstructor()) str<<" [CTOR]"; - if (isDestructor()) str<<" [DTOR]"; - if (isVirtual()) str<<" [VIRT]"; + if (slow()) str << " [SLOW]"; + if (pure()) str << " [PURE]"; + if (isStatic().unknown()) { + str << " [STATICU]"; + } else if (isStatic().trueUnknown()) { + str << " [STATIC]"; + } + if (dpiImport()) str << " [DPII]"; + if (dpiExport()) str << " [DPIX]"; + if (dpiExportWrapper()) str << " [DPIXWR]"; + if (isConstructor()) str << " [CTOR]"; + if (isDestructor()) str << " [DTOR]"; + if (isVirtual()) str << " [VIRT]"; } void AstCUse::dump(std::ostream& str) const { this->AstNode::dump(str); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 4eb5676f7..aa05bd09c 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -26,20 +26,23 @@ #define ASTNODE_NODE_FUNCS_NO_DTOR(name) \ virtual void accept(AstNVisitor& v) { v.visit(this); } \ - virtual AstNode* clone() { return new Ast ##name (*this); } \ - static Ast ##name * cloneTreeNull(Ast ##name * nodep, bool cloneNextLink) { \ - return nodep ? nodep->cloneTree(cloneNextLink) : NULL; } \ - Ast ##name * cloneTree(bool cloneNext) { return static_cast(AstNode::cloneTree(cloneNext)); } \ - Ast ##name * clonep() const { return static_cast(AstNode::clonep()); } + virtual AstNode* clone() { return new Ast##name(*this); } \ + static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \ + return nodep ? nodep->cloneTree(cloneNextLink) : NULL; \ + } \ + Ast##name* cloneTree(bool cloneNext) { \ + return static_cast(AstNode::cloneTree(cloneNext)); \ + } \ + Ast##name* clonep() const { return static_cast(AstNode::clonep()); } #define ASTNODE_NODE_FUNCS(name) \ - virtual ~Ast ##name() {} \ + virtual ~Ast##name() {} \ ASTNODE_NODE_FUNCS_NO_DTOR(name) //###################################################################### // Macros replaced by 'astgen' -#define ASTGEN_SUPER(...) // Roughly: (AstType::at, ...) +#define ASTGEN_SUPER(...) // Roughly: (AstType::at, ...) //###################################################################### //=== Ast* : Specific types @@ -60,6 +63,7 @@ private: } m_num.nodep(this); } + public: AstConst(FileLine* fl, const V3Number& num) : ASTGEN_SUPER(fl) @@ -72,7 +76,7 @@ public: , m_num(this, width, value) { initWithNumber(); } - class DtypedValue{}; // for creator type-overload selection + class DtypedValue {}; // for creator type-overload selection AstConst(FileLine* fl, DtypedValue, AstNodeDType* nodedtypep, uint32_t value) : ASTGEN_SUPER(fl) , m_num(this, nodedtypep->width(), value, nodedtypep->widthSized()) { @@ -119,19 +123,28 @@ public: class RealDouble {}; // for creator type-overload selection AstConst(FileLine* fl, RealDouble, double num) : ASTGEN_SUPER(fl) - , m_num(this, 64) { m_num.setDouble(num); dtypeSetDouble(); } + , m_num(this, 64) { + m_num.setDouble(num); + dtypeSetDouble(); + } class String {}; // for creator type-overload selection AstConst(FileLine* fl, String, const string& num) : ASTGEN_SUPER(fl) - , m_num(V3Number::String(), this, num) { dtypeSetString(); } + , m_num(V3Number::String(), this, num) { + dtypeSetString(); + } class LogicFalse {}; AstConst(FileLine* fl, LogicFalse) // Shorthand const 0, dtype should be a logic of size 1 : ASTGEN_SUPER(fl) - , m_num(this, 1, 0) { dtypeSetLogicBool(); } + , m_num(this, 1, 0) { + dtypeSetLogicBool(); + } class LogicTrue {}; AstConst(FileLine* fl, LogicTrue) // Shorthand const 1, dtype should be a logic of size 1 : ASTGEN_SUPER(fl) - , m_num(this, 1, 1) { dtypeSetLogicBool(); } + , m_num(this, 1, 1) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(Const) virtual string name() const { return num().ascii(); } // * = Value const V3Number& num() const { return m_num; } // * = Value @@ -145,7 +158,8 @@ public: virtual V3Hash sameHash() const { return V3Hash(num().toHash()); } virtual bool same(const AstNode* samep) const { const AstConst* sp = static_cast(samep); - return num().isCaseEq(sp->num()); } + return num().isCaseEq(sp->num()); + } virtual int instrCount() const { return widthInstrs(); } bool isEqAllOnes() const { return num().isEqAllOnes(width()); } bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); } @@ -154,12 +168,14 @@ public: class AstRange : public AstNodeRange { // Range specification, for use under variables and cells private: - bool m_littleEndian:1; // Bit vector is little endian + bool m_littleEndian : 1; // Bit vector is little endian public: AstRange(FileLine* fl, AstNode* msbp, AstNode* lsbp) : ASTGEN_SUPER(fl) { m_littleEndian = false; - setOp2p(msbp); setOp3p(lsbp); } + setOp2p(msbp); + setOp3p(lsbp); + } AstRange(FileLine* fl, int msb, int lsb) : ASTGEN_SUPER(fl) { m_littleEndian = false; @@ -175,14 +191,31 @@ public: ASTNODE_NODE_FUNCS(Range) AstNode* msbp() const { return op2p(); } // op2 = Msb expression AstNode* lsbp() const { return op3p(); } // op3 = Lsb expression - AstNode* leftp() const { return littleEndian()?lsbp():msbp(); } // How to show a declaration - AstNode* rightp() const { return littleEndian()?msbp():lsbp(); } - int msbConst() const { AstConst* constp = VN_CAST(msbp(), Const); return (constp?constp->toSInt():0); } - int lsbConst() const { AstConst* constp = VN_CAST(lsbp(), Const); return (constp?constp->toSInt():0); } - int elementsConst() const { return (msbConst()>lsbConst()) ? msbConst()-lsbConst()+1 : lsbConst()-msbConst()+1; } - int leftConst() const { AstConst* constp = VN_CAST(leftp(), Const); return (constp?constp->toSInt():0); } - int rightConst() const { AstConst* constp = VN_CAST(rightp(), Const); return (constp?constp->toSInt():0); } - int leftToRightInc() const { return littleEndian()?1:-1; } + AstNode* leftp() const { + return littleEndian() ? lsbp() : msbp(); + } // How to show a declaration + AstNode* rightp() const { return littleEndian() ? msbp() : lsbp(); } + int msbConst() const { + AstConst* constp = VN_CAST(msbp(), Const); + return (constp ? constp->toSInt() : 0); + } + int lsbConst() const { + AstConst* constp = VN_CAST(lsbp(), Const); + return (constp ? constp->toSInt() : 0); + } + int elementsConst() const { + return (msbConst() > lsbConst()) ? msbConst() - lsbConst() + 1 + : lsbConst() - msbConst() + 1; + } + int leftConst() const { + AstConst* constp = VN_CAST(leftp(), Const); + return (constp ? constp->toSInt() : 0); + } + int rightConst() const { + AstConst* constp = VN_CAST(rightp(), Const); + return (constp ? constp->toSInt() : 0); + } + int leftToRightInc() const { return littleEndian() ? 1 : -1; } bool littleEndian() const { return m_littleEndian; } void littleEndian(bool flag) { m_littleEndian = flag; } virtual void dump(std::ostream& str) const; @@ -237,7 +270,8 @@ class AstGatePin : public AstNodeMath { public: AstGatePin(FileLine* fl, AstNode* lhsp, AstRange* rangep) : ASTGEN_SUPER(fl) { - setOp1p(lhsp); setOp2p(rangep); + setOp1p(lhsp); + setOp2p(rangep); } ASTNODE_NODE_FUNCS(GatePin) virtual string emitVerilog() { return "%l"; } @@ -271,6 +305,7 @@ class AstClass : public AstNodeModule { MemberNameMap m_members; // Members or method children AstClassPackage* m_packagep; // Class package this is under void insertCache(AstNode* nodep); + public: AstClass(FileLine* fl, const string& name) : ASTGEN_SUPER(fl, name) @@ -326,20 +361,24 @@ class AstParamTypeDType : public AstNodeDType { // Parents: MODULE // A parameter type statement; much like a var or typedef private: - AstVarType m_varType; // Type of variable (for localparam vs. param) - string m_name; // Name of variable + AstVarType m_varType; // Type of variable (for localparam vs. param) + string m_name; // Name of variable public: - AstParamTypeDType(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl), m_varType(type), m_name(name) { + AstParamTypeDType(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, + AstNodeDType* dtp) + : ASTGEN_SUPER(fl) + , m_varType(type) + , m_name(name) { childDTypep(dtp); // Only for parser dtypep(NULL); // V3Width will resolve } ASTNODE_NODE_FUNCS(ParamTypeDType) AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Type assigning to + // op1 = Type assigning to + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } - virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type + virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); } virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); } virtual AstNodeDType* skipRefToEnump() const { return subDTypep()->skipRefToEnump(); } @@ -356,17 +395,19 @@ public: void name(const string& flag) { m_name = flag; } AstVarType varType() const { return m_varType; } // * = Type of variable bool isParam() const { return true; } - bool isGParam() const { return (varType()==AstVarType::GPARAM); } + bool isGParam() const { return (varType() == AstVarType::GPARAM); } }; class AstTypedef : public AstNode { private: - string m_name; - bool m_attrPublic; - string m_tag; // Holds the string of the verilator tag -- used in XML output. + string m_name; + bool m_attrPublic; + string m_tag; // Holds the string of the verilator tag -- used in XML output. public: - AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl), m_name(name) { + AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, + AstNodeDType* dtp) + : ASTGEN_SUPER(fl) + , m_name(name) { childDTypep(dtp); // Only for parser addAttrsp(attrsp); dtypep(NULL); // V3Width will resolve @@ -375,7 +416,8 @@ public: ASTNODE_NODE_FUNCS(Typedef) virtual void dump(std::ostream& str) const; AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Type assigning to + // op1 = Type assigning to + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } void addAttrsp(AstNode* nodep) { addNOp4p(nodep); } @@ -387,17 +429,19 @@ public: void name(const string& flag) { m_name = flag; } bool attrPublic() const { return m_attrPublic; } void attrPublic(bool flag) { m_attrPublic = flag; } - virtual void tag(const string& text) { m_tag = text;} + virtual void tag(const string& text) { m_tag = text; } virtual string tag() const { return m_tag; } }; class AstTypedefFwd : public AstNode { // Forward declaration of a type; stripped after netlist parsing is complete private: - string m_name; + string m_name; + public: AstTypedefFwd(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl), m_name(name) {} + : ASTGEN_SUPER(fl) + , m_name(name) {} ASTNODE_NODE_FUNCS(TypedefFwd) // METHODS virtual string name() const { return m_name; } @@ -408,13 +452,17 @@ class AstDefImplicitDType : public AstNodeDType { // This allows "var enum {...} a,b" to share the enum definition for both variables // After link, these become typedefs private: - string m_name; - void* m_containerp; // In what scope is the name unique, so we can know what are duplicate definitions (arbitrary value) - int m_uniqueNum; + string m_name; + void* m_containerp; // In what scope is the name unique, so we can know what are duplicate + // definitions (arbitrary value) + int m_uniqueNum; + public: - AstDefImplicitDType(FileLine* fl, const string& name, void* containerp, - VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl), m_name(name), m_containerp(containerp) { + AstDefImplicitDType(FileLine* fl, const string& name, void* containerp, VFlagChildDType, + AstNodeDType* dtp) + : ASTGEN_SUPER(fl) + , m_name(name) + , m_containerp(containerp) { childDTypep(dtp); // Only for parser dtypep(NULL); // V3Width will resolve m_uniqueNum = uniqueNumInc(); @@ -422,18 +470,22 @@ public: ASTNODE_NODE_FUNCS(DefImplicitDType) virtual bool same(const AstNode* samep) const { const AstDefImplicitDType* sp = static_cast(samep); - return m_uniqueNum == sp->m_uniqueNum; } + return m_uniqueNum == sp->m_uniqueNum; + } virtual bool similarDType(AstNodeDType* samep) const { - return type()==samep->type() && same(samep); } + return type() == samep->type() && same(samep); + } virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); } AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } void* containerp() const { return m_containerp; } // METHODS - AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable - virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type + // op1 = Range of variable + AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } + virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } @@ -465,14 +517,16 @@ public: || (!m_refDTypep && childDTypep()))); BROKEN_RTN(!((m_keyDTypep && !childDTypep() && m_keyDTypep->brokeExists()) || (!m_keyDTypep && childDTypep()))); - return NULL; } + return NULL; + } virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } - if (m_keyDTypep && m_keyDTypep->clonep()) { m_keyDTypep = m_keyDTypep->clonep(); } } + if (m_keyDTypep && m_keyDTypep->clonep()) { m_keyDTypep = m_keyDTypep->clonep(); } + } virtual bool same(const AstNode* samep) const { const AstAssocArrayDType* asamep = static_cast(samep); - return (subDTypep() == asamep->subDTypep() - && keyDTypep() == asamep->keyDTypep()); } + return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep()); + } virtual bool similarDType(AstNodeDType* samep) const { const AstAssocArrayDType* asamep = static_cast(samep); return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); @@ -481,7 +535,8 @@ public: virtual void dumpSmall(std::ostream& str) const; virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } @@ -492,10 +547,11 @@ public: // AstNodeDType* keyDTypep() const { return m_keyDTypep ? m_keyDTypep : keyChildDTypep(); } void keyDTypep(AstNodeDType* nodep) { m_keyDTypep = nodep; } - AstNodeDType* keyChildDTypep() const { return VN_CAST(op2p(), NodeDType); } // op1 = Range of variable + // op1 = Range of variable + AstNodeDType* keyChildDTypep() const { return VN_CAST(op2p(), NodeDType); } void keyChildDTypep(AstNodeDType* nodep) { setOp2p(nodep); } // METHODS - virtual AstBasicDType* basicp() const { return NULL; } // (Slow) recurse down to find basic data type + virtual AstBasicDType* basicp() const { return NULL; } virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } @@ -524,12 +580,15 @@ public: virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) || (!m_refDTypep && childDTypep()))); - return NULL; } + return NULL; + } virtual void cloneRelink() { - if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } } + if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + } virtual bool same(const AstNode* samep) const { const AstAssocArrayDType* asamep = static_cast(samep); - return subDTypep() == asamep->subDTypep(); } + return subDTypep() == asamep->subDTypep(); + } virtual bool similarDType(AstNodeDType* samep) const { const AstAssocArrayDType* asamep = static_cast(samep); return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); @@ -538,14 +597,15 @@ public: virtual void dumpSmall(std::ostream& str) const; virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } // METHODS - virtual AstBasicDType* basicp() const { return NULL; } // (Slow) recurse down to find basic data type + virtual AstBasicDType* basicp() const { return NULL; } virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } @@ -620,14 +680,18 @@ public: dtypep(NULL); // V3Width will resolve } ASTNODE_NODE_FUNCS(UnsizedArrayDType) - virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); return NULL; } - virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { - m_refDTypep = m_refDTypep->clonep(); - }} + virtual const char* broken() const { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return NULL; + } + virtual void cloneRelink() { + if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + } virtual bool same(const AstNode* samep) const { const AstNodeArrayDType* asamep = static_cast(samep); - return (subDTypep()==asamep->subDTypep()); } + return (subDTypep() == asamep->subDTypep()); + } virtual bool similarDType(AstNodeDType* samep) const { const AstNodeArrayDType* asamep = static_cast(samep); return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); @@ -635,14 +699,15 @@ public: virtual void dumpSmall(std::ostream& str) const; virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } // METHODS - virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type + virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } @@ -658,12 +723,12 @@ private: AstBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type VNumRange m_nrange; // (also in VBasicTypeKey) Numeric msb/lsb (if non-opaque keyword) bool operator==(const Members& rhs) const { - return rhs.m_keyword == m_keyword - && rhs.m_nrange == m_nrange; } + return rhs.m_keyword == m_keyword && rhs.m_nrange == m_nrange; + } } m; // See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned) public: - AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, VSignedState signst=signedst_NOSIGN) + AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, VSignedState signst = signedst_NOSIGN) : ASTGEN_SUPER(fl) { init(kwd, AstNumeric(signst), 0, -1, NULL); } @@ -675,77 +740,98 @@ public: : ASTGEN_SUPER(fl) { init(AstBasicDTypeKwd::BIT, AstNumeric::NOSIGN, wantwidth, -1, NULL); } - AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstNumeric numer, int wantwidth, int widthmin) + AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstNumeric numer, int wantwidth, + int widthmin) : ASTGEN_SUPER(fl) { init(kwd, numer, wantwidth, widthmin, NULL); } - AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstNumeric numer, VNumRange range, int widthmin) + AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstNumeric numer, VNumRange range, + int widthmin) : ASTGEN_SUPER(fl) { init(kwd, numer, range.elements(), widthmin, NULL); m.m_nrange = range; // as init() presumes lsb==0, but range.lsb() might not be } // See also addRange in verilog.y private: - void init(AstBasicDTypeKwd kwd, AstNumeric numer, - int wantwidth, int wantwidthmin, AstRange* rangep) { + void init(AstBasicDTypeKwd kwd, AstNumeric numer, int wantwidth, int wantwidthmin, + AstRange* rangep) { // wantwidth=0 means figure it out, but if a widthmin is >=0 // we allow width 0 so that {{0{x}},y} works properly // wantwidthmin=-1: default, use wantwidth if it is non zero m.m_keyword = kwd; // Implicitness: // "parameter X" is implicit and sized from initial // value, "parameter reg x" not - if (keyword()==AstBasicDTypeKwd::LOGIC_IMPLICIT) { + if (keyword() == AstBasicDTypeKwd::LOGIC_IMPLICIT) { if (rangep || wantwidth) m.m_keyword = AstBasicDTypeKwd::LOGIC; } if (numer == AstNumeric::NOSIGN) { - if (keyword().isSigned()) numer = AstNumeric::SIGNED; - else if (keyword().isUnsigned()) numer = AstNumeric::UNSIGNED; + if (keyword().isSigned()) { + numer = AstNumeric::SIGNED; + } else if (keyword().isUnsigned()) { + numer = AstNumeric::UNSIGNED; + } } numeric(numer); - if (!rangep && (wantwidth || wantwidthmin>=0)) { // Constant width - if (wantwidth>1) m.m_nrange.init(wantwidth-1, 0, false); - int wmin = wantwidthmin>=0 ? wantwidthmin : wantwidth; + if (!rangep && (wantwidth || wantwidthmin >= 0)) { // Constant width + if (wantwidth > 1) m.m_nrange.init(wantwidth - 1, 0, false); + int wmin = wantwidthmin >= 0 ? wantwidthmin : wantwidth; widthForce(wantwidth, wmin); } else if (!rangep) { // Set based on keyword properties // V3Width will pull from this width if (keyword().width() > 1 && !isOpaque()) { - m.m_nrange.init(keyword().width()-1, 0, false); + m.m_nrange.init(keyword().width() - 1, 0, false); } widthForce(keyword().width(), keyword().width()); } else { - widthForce(rangep->elementsConst(), rangep->elementsConst()); // Maybe unknown if parameters underneath it + widthForce(rangep->elementsConst(), + rangep->elementsConst()); // Maybe unknown if parameters underneath it } setNOp1p(rangep); dtypep(this); } + public: ASTNODE_NODE_FUNCS(BasicDType) virtual void dump(std::ostream& str) const; - virtual V3Hash sameHash() const { return V3Hash(V3Hash(m.m_keyword), V3Hash(m.m_nrange.hi())); } + virtual V3Hash sameHash() const { + return V3Hash(V3Hash(m.m_keyword), V3Hash(m.m_nrange.hi())); + } virtual bool same(const AstNode* samep) const { // width/widthMin/numeric compared elsewhere const AstBasicDType* sp = static_cast(samep); - return m == sp->m; } + return m == sp->m; + } virtual bool similarDType(AstNodeDType* samep) const { - return type()==samep->type() && same(samep); } + return type() == samep->type() && same(samep); + } virtual string name() const { return m.m_keyword.ascii(); } virtual string prettyDTypeName() const; - virtual const char* broken() const { BROKEN_RTN(dtypep()!=this); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(dtypep() != this); + return NULL; + } AstRange* rangep() const { return VN_CAST(op1p(), Range); } // op1 = Range of variable void rangep(AstRange* nodep) { setNOp1p(nodep); } void setSignedState(VSignedState signst) { // Note NOSIGN does NOT change the state; this is required by the parser - if (signst==signedst_UNSIGNED) numeric(signst); - else if (signst==signedst_SIGNED) numeric(signst); + if (signst == signedst_UNSIGNED) { + numeric(signst); + } else if (signst == signedst_SIGNED) { + numeric(signst); + } } // METHODS - virtual AstBasicDType* basicp() const { return (AstBasicDType*)this; } // (Slow) recurse down to find basic data type + virtual AstBasicDType* basicp() const { return (AstBasicDType*)this; } virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + virtual int widthAlignBytes() const; + virtual int + widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... virtual bool isFourstate() const { return keyword().isFourstate(); } - AstBasicDTypeKwd keyword() const { return m.m_keyword; } // Avoid using - use isSomething accessors instead + AstBasicDTypeKwd keyword() const { // Avoid using - use isSomething accessors instead + return m.m_keyword; + } bool isBitLogic() const { return keyword().isBitLogic(); } bool isDouble() const { return keyword().isDouble(); } bool isOpaque() const { return keyword().isOpaque(); } @@ -762,18 +848,23 @@ public: bool isDpiPrimitive() const { // DPI uses a primitive type return !isDpiBitVec() && !isDpiLogicVec(); } - const VNumRange& nrange() const { return m.m_nrange; } // Generally the msb/lsb/etc funcs should be used instead + const VNumRange& nrange() const { + return m.m_nrange; + } // Generally the msb/lsb/etc funcs should be used instead int msb() const { return (rangep() ? rangep()->msbConst() : m.m_nrange.hi()); } int lsb() const { return (rangep() ? rangep()->lsbConst() : m.m_nrange.lo()); } - int left() const { return littleEndian()?lsb():msb(); } // How to show a declaration - int right() const { return littleEndian()?msb():lsb(); } - bool littleEndian() const { return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian()); } + int left() const { return littleEndian() ? lsb() : msb(); } // How to show a declaration + int right() const { return littleEndian() ? msb() : lsb(); } + bool littleEndian() const { + return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian()); + } bool implicit() const { return keyword() == AstBasicDTypeKwd::LOGIC_IMPLICIT; } - VNumRange declRange() const { return isRanged() ? VNumRange(msb(), lsb(), littleEndian()) : VNumRange(); } + VNumRange declRange() const { + return isRanged() ? VNumRange(msb(), lsb(), littleEndian()) : VNumRange(); + } void cvtRangeConst() { // Convert to smaller representation if (rangep() && VN_IS(rangep()->msbp(), Const) && VN_IS(rangep()->lsbp(), Const)) { - m.m_nrange.init(rangep()->msbConst(), rangep()->lsbConst(), - rangep()->littleEndian()); + m.m_nrange.init(rangep()->msbConst(), rangep()->lsbConst(), rangep()->littleEndian()); rangep()->unlinkFrBackWithNext()->deleteTree(); rangep(NULL); } @@ -785,7 +876,7 @@ class AstConstDType : public AstNodeDType { // ConstDType are removed in V3LinkLValue and become AstVar::isConst. // When more generic types are supported AstConstDType will be propagated further. private: - AstNodeDType* m_refDTypep; // Inherit from this base data type + AstNodeDType* m_refDTypep; // Inherit from this base data type public: AstConstDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) : ASTGEN_SUPER(fl) { @@ -795,26 +886,34 @@ public: widthFromSub(subDTypep()); } ASTNODE_NODE_FUNCS(ConstDType) - virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); return NULL; } - virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { - m_refDTypep = m_refDTypep->clonep(); - }} + virtual const char* broken() const { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return NULL; + } + virtual void cloneRelink() { + if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + } virtual bool same(const AstNode* samep) const { const AstConstDType* sp = static_cast(samep); - return (m_refDTypep == sp->m_refDTypep); } + return (m_refDTypep == sp->m_refDTypep); + } virtual bool similarDType(AstNodeDType* samep) const { - return skipRefp()->similarDType(samep->skipRefp()); } - virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } // node's type() included elsewhere + return skipRefp()->similarDType(samep->skipRefp()); + } + virtual V3Hash sameHash() const { + return V3Hash(m_refDTypep); + } // node's type() included elsewhere AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } // op1 = Range of variable + virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } // METHODS - virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type + virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return subDTypep()->skipRefToEnump(); } @@ -829,24 +928,27 @@ private: AstNodeModule* m_packagep; // Package hierarchy public: AstClassRefDType(FileLine* fl, AstClass* classp) - : ASTGEN_SUPER(fl), m_classp(classp), m_packagep(NULL) { + : ASTGEN_SUPER(fl) + , m_classp(classp) + , m_packagep(NULL) { dtypep(this); } ASTNODE_NODE_FUNCS(ClassRefDType) // METHODS virtual const char* broken() const { - BROKEN_RTN(m_classp && !m_classp->brokeExists()); return NULL; } + BROKEN_RTN(m_classp && !m_classp->brokeExists()); + return NULL; + } virtual void cloneRelink() { if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep(); } virtual bool same(const AstNode* samep) const { const AstClassRefDType* asamep = static_cast(samep); - return (m_classp == asamep->m_classp - && m_packagep == asamep->m_packagep); } - virtual bool similarDType(AstNodeDType* samep) const { - return this == samep || same(samep); } + return (m_classp == asamep->m_classp && m_packagep == asamep->m_packagep); + } + virtual bool similarDType(AstNodeDType* samep) const { return this == samep || same(samep); } virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_classp), V3Hash(m_packagep)); } - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; virtual void dumpSmall(std::ostream& str) const; virtual string name() const { return classp() ? classp()->name() : ""; } virtual AstBasicDType* basicp() const { return NULL; } @@ -867,35 +969,44 @@ public: class AstIfaceRefDType : public AstNodeDType { // Reference to an interface, either for a port, or inside parent cell private: - FileLine* m_modportFileline; // Where modport token was - string m_cellName; // "" = no cell, such as when connects to 'input' iface - string m_ifaceName; // Interface name - string m_modportName; // "" = no modport - AstIface* m_ifacep; // Pointer to interface; note cellp() should override - AstCell* m_cellp; // When exact parent cell known; not a guess - AstModport* m_modportp; // NULL = unlinked or no modport + FileLine* m_modportFileline; // Where modport token was + string m_cellName; // "" = no cell, such as when connects to 'input' iface + string m_ifaceName; // Interface name + string m_modportName; // "" = no modport + AstIface* m_ifacep; // Pointer to interface; note cellp() should override + AstCell* m_cellp; // When exact parent cell known; not a guess + AstModport* m_modportp; // NULL = unlinked or no modport public: - AstIfaceRefDType(FileLine* fl, - const string& cellName, const string& ifaceName) - : ASTGEN_SUPER(fl), m_modportFileline(NULL) - , m_cellName(cellName), m_ifaceName(ifaceName), m_modportName("") - , m_ifacep(NULL), m_cellp(NULL), m_modportp(NULL) { } - AstIfaceRefDType(FileLine* fl, FileLine* modportFl, - const string& cellName, const string& ifaceName, const string& modport) - : ASTGEN_SUPER(fl), m_modportFileline(modportFl) - , m_cellName(cellName), m_ifaceName(ifaceName), m_modportName(modport) - , m_ifacep(NULL), m_cellp(NULL), m_modportp(NULL) { } + AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName) + : ASTGEN_SUPER(fl) + , m_modportFileline(NULL) + , m_cellName(cellName) + , m_ifaceName(ifaceName) + , m_modportName("") + , m_ifacep(NULL) + , m_cellp(NULL) + , m_modportp(NULL) {} + AstIfaceRefDType(FileLine* fl, FileLine* modportFl, const string& cellName, + const string& ifaceName, const string& modport) + : ASTGEN_SUPER(fl) + , m_modportFileline(modportFl) + , m_cellName(cellName) + , m_ifaceName(ifaceName) + , m_modportName(modport) + , m_ifacep(NULL) + , m_cellp(NULL) + , m_modportp(NULL) {} ASTNODE_NODE_FUNCS(IfaceRefDType) // METHODS virtual const char* broken() const; - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; virtual void dumpSmall(std::ostream& str) const; virtual void cloneRelink(); virtual AstBasicDType* basicp() const { return NULL; } virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } - virtual bool similarDType(AstNodeDType* samep) const { return this==samep; } + virtual bool similarDType(AstNodeDType* samep) const { return this == samep; } virtual V3Hash sameHash() const { return V3Hash(m_cellp); } virtual int widthAlignBytes() const { return 1; } virtual int widthTotalBytes() const { return 1; } @@ -933,12 +1044,15 @@ public: virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) || (!m_refDTypep && childDTypep()))); - return NULL; } + return NULL; + } virtual void cloneRelink() { - if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } } + if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + } virtual bool same(const AstNode* samep) const { const AstQueueDType* asamep = static_cast(samep); - return (subDTypep() == asamep->subDTypep()); } + return (subDTypep() == asamep->subDTypep()); + } virtual bool similarDType(AstNodeDType* samep) const { const AstQueueDType* asamep = static_cast(samep); return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); @@ -947,13 +1061,17 @@ public: virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } virtual string prettyDTypeName() const; AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNode* boundp() const { return op2p(); } // op2 = Bound, NULL = none void boundp(AstNode* nodep) { setNOp2p(nodep); } - int boundConst() const { AstConst* constp = VN_CAST(boundp(), Const); return (constp?constp->toSInt() : 0); } + int boundConst() const { + AstConst* constp = VN_CAST(boundp(), Const); + return (constp ? constp->toSInt() : 0); + } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } // METHODS @@ -971,58 +1089,85 @@ public: class AstRefDType : public AstNodeDType { private: AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef - string m_name; // Name of an AstTypedef + string m_name; // Name of an AstTypedef AstNodeModule* m_packagep; // Package hierarchy public: AstRefDType(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl), m_refDTypep(NULL), m_name(name), m_packagep(NULL) {} + : ASTGEN_SUPER(fl) + , m_refDTypep(NULL) + , m_name(name) + , m_packagep(NULL) {} AstRefDType(FileLine* fl, AstNodeDType* defp) - : ASTGEN_SUPER(fl), m_refDTypep(defp), m_packagep(NULL) { + : ASTGEN_SUPER(fl) + , m_refDTypep(defp) + , m_packagep(NULL) { dtypeFrom(defp->dtypep()); widthFromSub(subDTypep()); } class FlagTypeOfExpr {}; // type(expr) for parser only AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) - : ASTGEN_SUPER(fl), m_refDTypep(NULL), m_packagep(NULL) { + : ASTGEN_SUPER(fl) + , m_refDTypep(NULL) + , m_packagep(NULL) { setOp2p(typeofp); } ASTNODE_NODE_FUNCS(RefDType) // METHODS - virtual const char* broken() const { BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); return NULL; } - virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { - m_refDTypep = m_refDTypep->clonep(); - }} + virtual const char* broken() const { + BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); + return NULL; + } + virtual void cloneRelink() { + if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + } virtual bool same(const AstNode* samep) const { const AstRefDType* asamep = static_cast(samep); - return (m_refDTypep == asamep->m_refDTypep - && m_name == asamep->m_name - && m_packagep == asamep->m_packagep); } + return (m_refDTypep == asamep->m_refDTypep && m_name == asamep->m_name + && m_packagep == asamep->m_packagep); + } virtual bool similarDType(AstNodeDType* samep) const { - return skipRefp()->similarDType(samep->skipRefp()); } + return skipRefp()->similarDType(samep->skipRefp()); + } virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep), V3Hash(m_packagep)); } - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; virtual string name() const { return m_name; } virtual string prettyDTypeName() const { - return subDTypep() ? subDTypep()->name() : prettyName(); } + return subDTypep() ? subDTypep()->name() : prettyName(); + } virtual AstBasicDType* basicp() const { return subDTypep() ? subDTypep()->basicp() : NULL; } virtual AstNodeDType* skipRefp() const { // Skip past both the Ref and the Typedef - if (defp()) return defp()->skipRefp(); - else { v3fatalSrc("Typedef not linked"); return NULL; } + if (defp()) { + return defp()->skipRefp(); + } else { + v3fatalSrc("Typedef not linked"); + return NULL; + } } virtual AstNodeDType* skipRefToConstp() const { - if (defp()) return defp()->skipRefToConstp(); - else { v3fatalSrc("Typedef not linked"); return NULL; } + if (defp()) { + return defp()->skipRefToConstp(); + } else { + v3fatalSrc("Typedef not linked"); + return NULL; + } } virtual AstNodeDType* skipRefToEnump() const { - if (defp()) return defp()->skipRefToEnump(); - else { v3fatalSrc("Typedef not linked"); return NULL; } + if (defp()) { + return defp()->skipRefToEnump(); + } else { + v3fatalSrc("Typedef not linked"); + return NULL; + } } virtual int widthAlignBytes() const { return dtypeSkipRefp()->widthAlignBytes(); } virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); } void name(const string& flag) { m_name = flag; } - AstNodeDType* dtypeSkipRefp() const { return defp()->skipRefp(); } // op1 = Range of variable - AstNodeDType* defp() const { return m_refDTypep; } // Code backward compatibility name for refDTypep + // op1 = Range of variable + AstNodeDType* dtypeSkipRefp() const { return defp()->skipRefp(); } + AstNodeDType* defp() const { + return m_refDTypep; + } // Code backward compatibility name for refDTypep AstNodeDType* refDTypep() const { return m_refDTypep; } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const { return refDTypep(); } @@ -1044,7 +1189,7 @@ public: class AstUnionDType : public AstNodeUOrStructDType { public: - //UNSUP: bool isTagged; + // UNSUP: bool isTagged; // AstNumeric below is mispurposed to indicate if packed or not AstUnionDType(FileLine* fl, AstNumeric numericUnpack) : ASTGEN_SUPER(fl, numericUnpack) {} @@ -1057,21 +1202,23 @@ class AstMemberDType : public AstNodeDType { // PARENT: AstNodeUOrStructDType private: AstNodeDType* m_refDTypep; // Elements of this type (after widthing) - string m_name; // Name of variable - string m_tag; // Holds the string of the verilator tag -- used in XML output. - int m_lsb; // Within this level's packed struct, the LSB of the first bit of the member - //UNSUP: int m_randType; // Randomization type (IEEE) + string m_name; // Name of variable + string m_tag; // Holds the string of the verilator tag -- used in XML output. + int m_lsb; // Within this level's packed struct, the LSB of the first bit of the member + // UNSUP: int m_randType; // Randomization type (IEEE) public: AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp) : ASTGEN_SUPER(fl) - , m_name(name), m_lsb(-1) { + , m_name(name) + , m_lsb(-1) { childDTypep(dtp); // Only for parser dtypep(NULL); // V3Width will resolve refDTypep(NULL); } AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp) : ASTGEN_SUPER(fl) - , m_name(name), m_lsb(-1) { + , m_name(name) + , m_lsb(-1) { UASSERT(dtp, "AstMember created with no dtype"); refDTypep(dtp); dtypep(this); @@ -1082,13 +1229,14 @@ public: virtual bool hasDType() const { return true; } virtual bool maybePointedTo() const { return true; } AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } - virtual bool similarDType(AstNodeDType* samep) const { return this==samep; } + virtual bool similarDType(AstNodeDType* samep) const { return this == samep; } // // (Slow) recurse down to find basic data type (Note don't need virtual - // AstVar isn't a NodeDType) @@ -1104,7 +1252,7 @@ public: virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } // METHODS virtual void name(const string& name) { m_name = name; } - virtual void tag(const string& text) { m_tag = text;} + virtual void tag(const string& text) { m_tag = text; } virtual string tag() const { return m_tag; } int lsb() const { return m_lsb; } void lsb(int lsb) { m_lsb = lsb; } @@ -1114,15 +1262,17 @@ class AstVoidDType : public AstNodeDType { // For e.g. a function returning void public: explicit AstVoidDType(FileLine* fl) - : ASTGEN_SUPER(fl) { dtypep(this); } + : ASTGEN_SUPER(fl) { + dtypep(this); + } ASTNODE_NODE_FUNCS(VoidDType) virtual void dumpSmall(std::ostream& str) const; virtual bool hasDType() const { return true; } virtual bool maybePointedTo() const { return true; } virtual AstNodeDType* subDTypep() const { return NULL; } virtual AstNodeDType* virtRefDTypep() const { return NULL; } - virtual void virtRefDTypep(AstNodeDType* nodep) { } - virtual bool similarDType(AstNodeDType* samep) const { return this==samep; } + virtual void virtRefDTypep(AstNodeDType* nodep) {} + virtual bool similarDType(AstNodeDType* samep) const { return this == samep; } virtual AstBasicDType* basicp() const { return NULL; } // cppcheck-suppress csyleCast virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } @@ -1137,12 +1287,16 @@ public: class AstEnumItem : public AstNode { private: - string m_name; + string m_name; + public: // Parents: ENUM AstEnumItem(FileLine* fl, const string& name, AstNode* rangep, AstNode* initp) - : ASTGEN_SUPER(fl), m_name(name) - { addNOp1p(rangep); addNOp2p(initp); } + : ASTGEN_SUPER(fl) + , m_name(name) { + addNOp1p(rangep); + addNOp2p(initp); + } ASTNODE_NODE_FUNCS(EnumItem) virtual string name() const { return m_name; } virtual bool maybePointedTo() const { return true; } @@ -1160,18 +1314,26 @@ private: AstNodeModule* m_packagep; // Package hierarchy public: AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* packagep) - : ASTGEN_SUPER(fl), m_itemp(itemp), m_packagep(packagep) { + : ASTGEN_SUPER(fl) + , m_itemp(itemp) + , m_packagep(packagep) { dtypeFrom(m_itemp); } ASTNODE_NODE_FUNCS(EnumItemRef) virtual void dump(std::ostream& str) const; virtual string name() const { return itemp()->name(); } - virtual const char* broken() const { BROKEN_RTN(!VN_IS(itemp(), EnumItem)); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(!VN_IS(itemp(), EnumItem)); + return NULL; + } virtual int instrCount() const { return 0; } - virtual void cloneRelink() { if (m_itemp->clonep()) m_itemp = VN_CAST(m_itemp->clonep(), EnumItem); } + virtual void cloneRelink() { + if (m_itemp->clonep()) m_itemp = VN_CAST(m_itemp->clonep(), EnumItem); + } virtual bool same(const AstNode* samep) const { const AstEnumItemRef* sp = static_cast(samep); - return itemp() == sp->itemp(); } + return itemp() == sp->itemp(); + } AstEnumItem* itemp() const { return m_itemp; } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); } @@ -1187,6 +1349,7 @@ private: string m_name; // Name from upper typedef, if any AstNodeDType* m_refDTypep; // Elements are of this type after V3Width int m_uniqueNum; + public: AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* itemsp) : ASTGEN_SUPER(fl) { @@ -1198,20 +1361,25 @@ public: m_uniqueNum = uniqueNumInc(); } ASTNODE_NODE_FUNCS(EnumDType) - virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); return NULL; } - virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { - m_refDTypep = m_refDTypep->clonep(); - }} + virtual const char* broken() const { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return NULL; + } + virtual void cloneRelink() { + if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + } virtual bool same(const AstNode* samep) const { const AstEnumDType* sp = static_cast(samep); - return m_uniqueNum == sp->m_uniqueNum; } - virtual bool similarDType(AstNodeDType* samep) const { return this==samep; } + return m_uniqueNum == sp->m_uniqueNum; + } + virtual bool similarDType(AstNodeDType* samep) const { return this == samep; } virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); } AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Data type void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } // op1 = Range of variable + // op1 = Range of variable + virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } @@ -1220,7 +1388,7 @@ public: AstEnumItem* itemsp() const { return VN_CAST(op2p(), EnumItem); } // op2 = AstEnumItem's void addValuesp(AstNode* nodep) { addOp2p(nodep); } // METHODS - virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type + virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); } virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); } // cppcheck-suppress csyleCast @@ -1239,7 +1407,7 @@ public: ASTNODE_NODE_FUNCS(ParseTypeDType) AstNodeDType* dtypep() const { return NULL; } // METHODS - virtual bool similarDType(AstNodeDType* samep) const { return this==samep; } + virtual bool similarDType(AstNodeDType* samep) const { return this == samep; } virtual AstBasicDType* basicp() const { return NULL; } virtual AstNodeDType* skipRefp() const { return NULL; } // cppcheck-suppress csyleCast @@ -1262,6 +1430,7 @@ private: dtypeFrom(VN_CAST(fromp->dtypep()->skipRefp(), NodeArrayDType)->subDTypep()); } } + public: AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp) : ASTGEN_SUPER(fl, fromp, bitp) { @@ -1272,9 +1441,12 @@ public: init(fromp); } ASTNODE_NODE_FUNCS(ArraySel) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstArraySel(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstArraySel(this->fileline(), lhsp, rhsp); + } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { - V3ERROR_NA; /* How can from be a const? */ } + V3ERROR_NA; /* How can from be a const? */ + } virtual string emitVerilog() { return "%k(%l%f[%r])"; } virtual string emitC() { return "%li%k[%ri]"; } virtual bool cleanOut() const { return true; } @@ -1288,7 +1460,8 @@ public: virtual bool same(const AstNode* samep) const { return true; } virtual int instrCount() const { return widthInstrs(); } // Special operators - static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences? + static AstNode* + baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences? }; class AstAssocSel : public AstNodeSel { @@ -1301,6 +1474,7 @@ private: dtypeFrom(VN_CAST(fromp->dtypep()->skipRefp(), AssocArrayDType)->subDTypep()); } } + public: AstAssocSel(FileLine* fl, AstNode* fromp, AstNode* bitp) : ASTGEN_SUPER(fl, fromp, bitp) { @@ -1308,9 +1482,11 @@ public: } ASTNODE_NODE_FUNCS(AssocSel) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { - return new AstAssocSel(this->fileline(), lhsp, rhsp); } + return new AstAssocSel(this->fileline(), lhsp, rhsp); + } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { - V3ERROR_NA; } + V3ERROR_NA; + } virtual string emitVerilog() { return "%k(%l%f[%r])"; } virtual string emitC() { return "%li%k[%ri]"; } virtual bool cleanOut() const { return true; } @@ -1333,8 +1509,12 @@ public: dtypeSetUInt32(); // Always used on WData arrays so returns edata size } ASTNODE_NODE_FUNCS(WordSel) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstWordSel(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit) { V3ERROR_NA; } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstWordSel(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit) { + V3ERROR_NA; + } virtual string emitVerilog() { return "%k(%l%f[%r])"; } virtual string emitC() { return "%li[%ri]"; } // Not %k, as usually it's a small constant rhsp virtual bool cleanOut() const { return true; } @@ -1363,7 +1543,8 @@ public: AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp) : ASTGEN_SUPER(fl, fromp, bitp, NULL) { UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, - "not coded to create after dtypes resolved"); } + "not coded to create after dtypes resolved"); + } ASTNODE_NODE_FUNCS(SelBit) AstNode* bitp() const { return rhsp(); } }; @@ -1397,32 +1578,32 @@ class AstSel : public AstNodeTriop { // Tempting to have an lvalue() style method here as LHS selects are quite // different, but that doesn't play well with V3Inst and bidirects which don't know direction private: - VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid - int m_declElWidth; // If a packed array, the number of bits per element + VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid + int m_declElWidth; // If a packed array, the number of bits per element public: AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp) : ASTGEN_SUPER(fl, fromp, lsbp, widthp) { m_declElWidth = 1; if (VN_IS(widthp, Const)) { - dtypeSetLogicSized(VN_CAST(widthp, Const)->toUInt(), - AstNumeric::UNSIGNED); + dtypeSetLogicSized(VN_CAST(widthp, Const)->toUInt(), AstNumeric::UNSIGNED); } } AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth) - : ASTGEN_SUPER(fl, fromp, - new AstConst(fl, lsb), new AstConst(fl, bitwidth)) { + : ASTGEN_SUPER(fl, fromp, new AstConst(fl, lsb), new AstConst(fl, bitwidth)) { m_declElWidth = 1; dtypeSetLogicSized(bitwidth, AstNumeric::UNSIGNED); } ASTNODE_NODE_FUNCS(Sel) virtual void dump(std::ostream& str) const; - virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, const V3Number& width) { - out.opSel(from, bit.toUInt()+width.toUInt()-1, bit.toUInt()); } + virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, + const V3Number& width) { + out.opSel(from, bit.toUInt() + width.toUInt() - 1, bit.toUInt()); + } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual string emitC() { - return this->widthp()->isOne() - ? "VL_BITSEL_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri)" - : "VL_SEL_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri, %ti)"; } + return this->widthp()->isOne() ? "VL_BITSEL_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri)" + : "VL_SEL_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri, %ti)"; + } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } virtual bool cleanRhs() const { return true; } @@ -1432,13 +1613,13 @@ public: virtual bool sizeMattersThs() const { return false; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode*) const { return true; } - virtual int instrCount() const { return widthInstrs()*(VN_CAST(lsbp(), Const)?3:10); } + virtual int instrCount() const { return widthInstrs() * (VN_CAST(lsbp(), Const) ? 3 : 10); } AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing) AstNode* lsbp() const { return op2p(); } // op2 = Msb selection expression AstNode* widthp() const { return op3p(); } // op3 = Width int widthConst() const { return VN_CAST(widthp(), Const)->toSInt(); } int lsbConst() const { return VN_CAST(lsbp(), Const)->toSInt(); } - int msbConst() const { return lsbConst()+widthConst()-1; } + int msbConst() const { return lsbConst() + widthConst() - 1; } VNumRange& declRange() { return m_declRange; } const VNumRange& declRange() const { return m_declRange; } void declRange(const VNumRange& flag) { m_declRange = flag; } @@ -1454,14 +1635,15 @@ private: VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid public: AstSliceSel(FileLine* fl, AstNode* fromp, const VNumRange& declRange) - : ASTGEN_SUPER(fl, fromp, - new AstConst(fl, declRange.lo()), + : ASTGEN_SUPER(fl, fromp, new AstConst(fl, declRange.lo()), new AstConst(fl, declRange.elements())) - , m_declRange(declRange) { } + , m_declRange(declRange) {} ASTNODE_NODE_FUNCS(SliceSel) virtual void dump(std::ostream& str) const; - virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo, const V3Number& width) { - V3ERROR_NA; } + virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo, + const V3Number& width) { + V3ERROR_NA; + } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); } // Removed before EmitC virtual bool cleanOut() const { return false; } @@ -1505,7 +1687,10 @@ public: } virtual void dump(std::ostream& str) const; virtual bool hasDType() const { return true; } - void makeStatement() { statement(true); dtypeSetVoid(); } + void makeStatement() { + statement(true); + dtypeSetVoid(); + } AstNode* fromp() const { return op2p(); } // op2 = Extracting what (NULL=TBD during parsing) void fromp(AstNode* nodep) { setOp2p(nodep); } }; @@ -1541,10 +1726,14 @@ public: virtual V3Hash sameHash() const { return V3Hash(m_name); } virtual bool same(const AstNode* samep) const { const AstCMethodHard* asamep = static_cast(samep); - return (m_name == asamep->m_name); } + return (m_name == asamep->m_name); + } virtual bool isPure() const { return m_pure; } void pure(bool flag) { m_pure = flag; } - void makeStatement() { statement(true); dtypeSetVoid(); } + void makeStatement() { + statement(true); + dtypeSetVoid(); + } AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing) void fromp(AstNode* nodep) { setOp1p(nodep); } AstNode* pinsp() const { return op2p(); } // op2 = Pin interconnection list @@ -1554,87 +1743,115 @@ public: class AstVar : public AstNode { // A variable (in/out/wire/reg/param) inside a module private: - string m_name; // Name of variable - string m_origName; // Original name before dot addition - string m_tag; // Holds the string of the verilator tag -- used in XML output. - AstVarType m_varType; // Type of variable - VDirection m_direction; // Direction input/output etc - VDirection m_declDirection; // Declared direction input/output etc + string m_name; // Name of variable + string m_origName; // Original name before dot addition + string m_tag; // Holds the string of the verilator tag -- used in XML output. + AstVarType m_varType; // Type of variable + VDirection m_direction; // Direction input/output etc + VDirection m_declDirection; // Declared direction input/output etc AstBasicDTypeKwd m_declKwd; // Keyword at declaration time - bool m_ansi:1; // ANSI port list variable (for dedup check) - bool m_declTyped:1; // Declared as type (for dedup check) - bool m_tristate:1; // Inout or triwire or trireg - bool m_primaryIO:1; // In/out to top level (or directly assigned from same) - bool m_sc:1; // SystemC variable - bool m_scClocked:1; // SystemC sc_clk<> needed - bool m_scSensitive:1;// SystemC sensitive() needed - bool m_sigPublic:1; // User C code accesses this signal or is top signal - bool m_sigModPublic:1;// User C code accesses this signal and module - bool m_sigUserRdPublic:1; // User C code accesses this signal, read only - bool m_sigUserRWPublic:1; // User C code accesses this signal, read-write - bool m_usedClock:1; // Signal used as a clock - bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup) - bool m_usedLoopIdx:1; // Variable subject of for unrolling - bool m_funcLocal:1; // Local variable for a function - bool m_funcReturn:1; // Return variable for a function - bool m_attrClockEn:1;// User clock enable attribute - bool m_attrScBv:1; // User force bit vector attribute - bool m_attrIsolateAssign:1;// User isolate_assignments attribute - bool m_attrSFormat:1;// User sformat attribute - bool m_attrSplitVar:1; // declared with split_var metacomment - bool m_fileDescr:1; // File descriptor - bool m_isConst:1; // Table contains constant data - bool m_isStatic:1; // Static variable - bool m_isPulldown:1; // Tri0 - bool m_isPullup:1; // Tri1 - bool m_isIfaceParent:1; // dtype is reference to interface present in this module - bool m_isDpiOpenArray:1; // DPI import open array - bool m_noReset:1; // Do not do automated reset/randomization - bool m_noSubst:1; // Do not substitute out references - bool m_trace:1; // Trace this variable + bool m_ansi : 1; // ANSI port list variable (for dedup check) + bool m_declTyped : 1; // Declared as type (for dedup check) + bool m_tristate : 1; // Inout or triwire or trireg + bool m_primaryIO : 1; // In/out to top level (or directly assigned from same) + bool m_sc : 1; // SystemC variable + bool m_scClocked : 1; // SystemC sc_clk<> needed + bool m_scSensitive : 1; // SystemC sensitive() needed + bool m_sigPublic : 1; // User C code accesses this signal or is top signal + bool m_sigModPublic : 1; // User C code accesses this signal and module + bool m_sigUserRdPublic : 1; // User C code accesses this signal, read only + bool m_sigUserRWPublic : 1; // User C code accesses this signal, read-write + bool m_usedClock : 1; // Signal used as a clock + bool m_usedParam : 1; // Parameter is referenced (on link; later signals not setup) + bool m_usedLoopIdx : 1; // Variable subject of for unrolling + bool m_funcLocal : 1; // Local variable for a function + bool m_funcReturn : 1; // Return variable for a function + bool m_attrClockEn : 1; // User clock enable attribute + bool m_attrScBv : 1; // User force bit vector attribute + bool m_attrIsolateAssign : 1; // User isolate_assignments attribute + bool m_attrSFormat : 1; // User sformat attribute + bool m_attrSplitVar : 1; // declared with split_var metacomment + bool m_fileDescr : 1; // File descriptor + bool m_isConst : 1; // Table contains constant data + bool m_isStatic : 1; // Static variable + bool m_isPulldown : 1; // Tri0 + bool m_isPullup : 1; // Tri1 + bool m_isIfaceParent : 1; // dtype is reference to interface present in this module + bool m_isDpiOpenArray : 1; // DPI import open array + bool m_noReset : 1; // Do not do automated reset/randomization + bool m_noSubst : 1; // Do not substitute out references + bool m_trace : 1; // Trace this variable VVarAttrClocker m_attrClocker; - MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var + MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var void init() { - m_ansi = false; m_declTyped = false; - m_tristate = false; m_primaryIO = false; - m_sc = false; m_scClocked = false; m_scSensitive = false; - m_usedClock = false; m_usedParam = false; m_usedLoopIdx = false; - m_sigPublic = false; m_sigModPublic = false; - m_sigUserRdPublic = false; m_sigUserRWPublic = false; - m_funcLocal = false; m_funcReturn = false; - m_attrClockEn = false; m_attrScBv = false; - m_attrIsolateAssign = false; m_attrSFormat = false; m_attrSplitVar = false; - m_fileDescr = false; m_isConst = false; - m_isStatic = false; m_isPulldown = false; m_isPullup = false; - m_isIfaceParent = false; m_isDpiOpenArray = false; - m_noReset = false; m_noSubst = false; m_trace = false; + m_ansi = false; + m_declTyped = false; + m_tristate = false; + m_primaryIO = false; + m_sc = false; + m_scClocked = false; + m_scSensitive = false; + m_usedClock = false; + m_usedParam = false; + m_usedLoopIdx = false; + m_sigPublic = false; + m_sigModPublic = false; + m_sigUserRdPublic = false; + m_sigUserRWPublic = false; + m_funcLocal = false; + m_funcReturn = false; + m_attrClockEn = false; + m_attrScBv = false; + m_attrIsolateAssign = false; + m_attrSFormat = false; + m_attrSplitVar = false; + m_fileDescr = false; + m_isConst = false; + m_isStatic = false; + m_isPulldown = false; + m_isPullup = false; + m_isIfaceParent = false; + m_isDpiOpenArray = false; + m_noReset = false; + m_noSubst = false; + m_trace = false; m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN; } + public: AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) : ASTGEN_SUPER(fl) - , m_name(name), m_origName(name) { + , m_name(name) + , m_origName(name) { init(); combineType(type); childDTypep(dtp); // Only for parser dtypep(NULL); // V3Width will resolve - if (dtp->basicp()) m_declKwd = dtp->basicp()->keyword(); - else m_declKwd = AstBasicDTypeKwd::LOGIC; + if (dtp->basicp()) { + m_declKwd = dtp->basicp()->keyword(); + } else { + m_declKwd = AstBasicDTypeKwd::LOGIC; + } } AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtp) : ASTGEN_SUPER(fl) - , m_name(name), m_origName(name) { + , m_name(name) + , m_origName(name) { init(); combineType(type); UASSERT(dtp, "AstVar created with no dtype"); dtypep(dtp); - if (dtp->basicp()) m_declKwd = dtp->basicp()->keyword(); - else m_declKwd = AstBasicDTypeKwd::LOGIC; + if (dtp->basicp()) { + m_declKwd = dtp->basicp()->keyword(); + } else { + m_declKwd = AstBasicDTypeKwd::LOGIC; + } } AstVar(FileLine* fl, AstVarType type, const string& name, VFlagLogicPacked, int wantwidth) : ASTGEN_SUPER(fl) - , m_name(name), m_origName(name) { + , m_name(name) + , m_origName(name) { init(); combineType(type); dtypeSetLogicSized(wantwidth, AstNumeric::UNSIGNED); @@ -1642,7 +1859,8 @@ public: } AstVar(FileLine* fl, AstVarType type, const string& name, VFlagBitPacked, int wantwidth) : ASTGEN_SUPER(fl) - , m_name(name), m_origName(name) { + , m_name(name) + , m_origName(name) { init(); combineType(type); dtypeSetBitSized(wantwidth, AstNumeric::UNSIGNED); @@ -1650,12 +1868,11 @@ public: } AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep) : ASTGEN_SUPER(fl) - , m_name(name), m_origName(name) { + , m_name(name) + , m_origName(name) { init(); combineType(type); - if (examplep->childDTypep()) { - childDTypep(examplep->childDTypep()->cloneTree(true)); - } + if (examplep->childDTypep()) { childDTypep(examplep->childDTypep()->cloneTree(true)); } dtypeFrom(examplep); m_declKwd = examplep->declKwd(); } @@ -1669,32 +1886,43 @@ public: AstVarType varType() const { return m_varType; } // * = Type of variable void direction(const VDirection& flag) { m_direction = flag; - if (m_direction == VDirection::INOUT) m_tristate = true; } + if (m_direction == VDirection::INOUT) m_tristate = true; + } VDirection direction() const { return m_direction; } bool isIO() const { return m_direction != VDirection::NONE; } void declDirection(const VDirection& flag) { m_declDirection = flag; } VDirection declDirection() const { return m_declDirection; } void varType(AstVarType type) { m_varType = type; } - void varType2Out() { m_tristate = 0; m_direction = VDirection::OUTPUT; } - void varType2In() { m_tristate = 0; m_direction = VDirection::INPUT; } + void varType2Out() { + m_tristate = 0; + m_direction = VDirection::OUTPUT; + } + void varType2In() { + m_tristate = 0; + m_direction = VDirection::INPUT; + } AstBasicDTypeKwd declKwd() const { return m_declKwd; } string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv - string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc. + // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc. + string cPubArgType(bool named, bool forReturn) const; string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument // Return Verilator internal type for argument: CData, SData, IData, WData - string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc="") const; + string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "") const; string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc string vlPropInit() const; // Return VerilatorVarProps initializer void combineType(AstVarType type); AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - // AstVar isn't a NodeDType) AstBasicDType* basicp() const { return subDTypep()->basicp(); } - AstNode* valuep() const { return op3p(); } // op3 = Initial value that never changes (static const) - void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than an AstConst + // op3 = Initial value that never changes (static const) + AstNode* valuep() const { return op3p(); } + // It's valuep(), not constp(), as may be more complicated than an AstConst + void valuep(AstNode* nodep) { setOp3p(nodep); } void addAttrsp(AstNode* nodep) { addNOp4p(nodep); } AstNode* attrsp() const { return op4p(); } // op4 = Attributes during early parse void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } @@ -1714,8 +1942,14 @@ public: void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; } void sigPublic(bool flag) { m_sigPublic = flag; } void sigModPublic(bool flag) { m_sigModPublic = flag; } - void sigUserRdPublic(bool flag) { m_sigUserRdPublic = flag; if (flag) sigPublic(true); } - void sigUserRWPublic(bool flag) { m_sigUserRWPublic = flag; if (flag) sigUserRdPublic(true); } + void sigUserRdPublic(bool flag) { + m_sigUserRdPublic = flag; + if (flag) sigPublic(true); + } + void sigUserRWPublic(bool flag) { + m_sigUserRWPublic = flag; + if (flag) sigUserRdPublic(true); + } void sc(bool flag) { m_sc = flag; } void scSensitive(bool flag) { m_scSensitive = flag; } void primaryIO(bool flag) { m_primaryIO = flag; } @@ -1733,7 +1967,7 @@ public: void trace(bool flag) { m_trace = flag; } // METHODS virtual void name(const string& name) { m_name = name; } - virtual void tag(const string& text) { m_tag = text;} + virtual void tag(const string& text) { m_tag = text; } virtual string tag() const { return m_tag; } bool isAnsi() const { return m_ansi; } bool isDeclTyped() const { return m_declTyped; } @@ -1744,7 +1978,7 @@ public: bool isTristate() const { return m_tristate; } bool isPrimaryIO() const { return m_primaryIO; } bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); } - bool isIfaceRef() const { return (varType()==AstVarType::IFACEREF); } + bool isIfaceRef() const { return (varType() == AstVarType::IFACEREF); } bool isIfaceParent() const { return m_isIfaceParent; } bool isSignal() const { return varType().isSignal(); } bool isTemp() const { return varType().isTemp(); } @@ -1752,15 +1986,21 @@ public: return ((isIO() || isSignal()) && (isIO() || isBitLogic()) // Wrapper would otherwise duplicate wrapped module's coverage - && !isSc() && !isPrimaryIO() && !isConst()); } + && !isSc() && !isPrimaryIO() && !isConst()); + } bool isClassMember() const { return varType() == AstVarType::MEMBER; } - bool isStatementTemp() const { return (varType()==AstVarType::STMTTEMP); } - bool isMovableToBlock() const { return (varType()==AstVarType::BLOCKTEMP || isFuncLocal()); } - bool isXTemp() const { return (varType()==AstVarType::XTEMP); } - bool isParam() const { return (varType()==AstVarType::LPARAM || varType()==AstVarType::GPARAM); } - bool isGParam() const { return (varType()==AstVarType::GPARAM); } - bool isGenVar() const { return (varType()==AstVarType::GENVAR); } - bool isBitLogic() const { AstBasicDType* bdtypep = basicp(); return bdtypep && bdtypep->isBitLogic(); } + bool isStatementTemp() const { return (varType() == AstVarType::STMTTEMP); } + bool isMovableToBlock() const { return (varType() == AstVarType::BLOCKTEMP || isFuncLocal()); } + bool isXTemp() const { return (varType() == AstVarType::XTEMP); } + bool isParam() const { + return (varType() == AstVarType::LPARAM || varType() == AstVarType::GPARAM); + } + bool isGParam() const { return (varType() == AstVarType::GPARAM); } + bool isGenVar() const { return (varType() == AstVarType::GENVAR); } + bool isBitLogic() const { + AstBasicDType* bdtypep = basicp(); + return bdtypep && bdtypep->isBitLogic(); + } bool isUsedClock() const { return m_usedClock; } bool isUsedParam() const { return m_usedParam; } bool isUsedLoopIdx() const { return m_usedLoopIdx; } @@ -1813,7 +2053,7 @@ public: if (typevarp->attrScClocked()) attrScClocked(true); } void inlineAttrReset(const string& name) { - if (direction()==VDirection::INOUT && varType()==AstVarType::WIRE) { + if (direction() == VDirection::INOUT && varType() == AstVarType::WIRE) { m_varType = AstVarType::TRIWIRE; } m_direction = VDirection::NONE; @@ -1824,6 +2064,7 @@ public: void addConsumingMTaskId(int id) { m_mtaskIds.insert(id); } const MTaskIdSet& mtaskIds() const { return m_mtaskIds; } string mtasksString() const; + private: class VlArgTypeRecursed; VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep, @@ -1835,8 +2076,8 @@ class AstDefParam : public AstNode { // Parents: MODULE // Children: math private: - string m_name; // Name of variable getting set - string m_path; // Dotted cellname to set parameter of + string m_name; // Name of variable getting set + string m_path; // Dotted cellname to set parameter of public: AstDefParam(FileLine* fl, const string& path, const string& name, AstNode* rhsp) : ASTGEN_SUPER(fl) { @@ -1871,15 +2112,18 @@ class AstScope : public AstNode { // Children: NODEBLOCK private: // An AstScope->name() is special: . indicates an uninlined scope, __DOT__ an inlined scope - string m_name; // Name - AstScope* m_aboveScopep; // Scope above this one in the hierarchy (NULL if top) - AstCell* m_aboveCellp; // Cell above this in the hierarchy (NULL if top) - AstNodeModule* m_modp; // Module scope corresponds to + string m_name; // Name + AstScope* m_aboveScopep; // Scope above this one in the hierarchy (NULL if top) + AstCell* m_aboveCellp; // Cell above this in the hierarchy (NULL if top) + AstNodeModule* m_modp; // Module scope corresponds to public: - AstScope(FileLine* fl, AstNodeModule* modp, const string& name, - AstScope* aboveScopep, AstCell* aboveCellp) + AstScope(FileLine* fl, AstNodeModule* modp, const string& name, AstScope* aboveScopep, + AstCell* aboveCellp) : ASTGEN_SUPER(fl) - , m_name(name), m_aboveScopep(aboveScopep), m_aboveCellp(aboveCellp), m_modp(modp) {} + , m_name(name) + , m_aboveScopep(aboveScopep) + , m_aboveCellp(aboveCellp) + , m_modp(modp) {} ASTNODE_NODE_FUNCS(Scope) virtual void cloneRelink(); virtual const char* broken() const; @@ -1897,7 +2141,7 @@ public: AstNode* finalClksp() const { return op3p(); } // op3 = Final assigns for clock correction AstScope* aboveScopep() const { return m_aboveScopep; } AstCell* aboveCellp() const { return m_aboveCellp; } - bool isTop() const { return aboveScopep()==NULL; } // At top of hierarchy + bool isTop() const { return aboveScopep() == NULL; } // At top of hierarchy }; class AstTopScope : public AstNode { @@ -1907,8 +2151,9 @@ class AstTopScope : public AstNode { // Children: SCOPEs public: AstTopScope(FileLine* fl, AstScope* ascopep) - : ASTGEN_SUPER(fl) - {addNOp2p(ascopep);} + : ASTGEN_SUPER(fl) { + addNOp2p(ascopep); + } ASTNODE_NODE_FUNCS(TopScope) AstNode* stmtsp() const { return op1p(); } void addStmtsp(AstNode* nodep) { addOp1p(nodep); } @@ -1922,33 +2167,40 @@ class AstVarScope : public AstNode { // Parents: MODULE // Children: none private: - AstScope* m_scopep; // Scope variable is underneath - AstVar* m_varp; // [AfterLink] Pointer to variable itself - bool m_circular:1; // Used in circular ordering dependency, need change detect - bool m_trace:1; // Tracing is turned on for this scope + AstScope* m_scopep; // Scope variable is underneath + AstVar* m_varp; // [AfterLink] Pointer to variable itself + bool m_circular : 1; // Used in circular ordering dependency, need change detect + bool m_trace : 1; // Tracing is turned on for this scope public: AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp) : ASTGEN_SUPER(fl) - , m_scopep(scopep), m_varp(varp) { + , m_scopep(scopep) + , m_varp(varp) { m_circular = false; m_trace = true; dtypeFrom(varp); } ASTNODE_NODE_FUNCS(VarScope) - virtual void cloneRelink() { if (m_varp && m_varp->clonep()) { - m_varp = m_varp->clonep(); - UASSERT(m_scopep->clonep(), "No clone cross link: "<clonep(); - }} - virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); - BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); return NULL; } + virtual void cloneRelink() { + if (m_varp && m_varp->clonep()) { + m_varp = m_varp->clonep(); + UASSERT(m_scopep->clonep(), "No clone cross link: " << this); + m_scopep = m_scopep->clonep(); + } + } + virtual const char* broken() const { + BROKEN_RTN(m_varp && !m_varp->brokeExists()); + BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); + return NULL; + } virtual bool maybePointedTo() const { return true; } - virtual string name() const {return scopep()->name()+"->"+varp()->name();} // * = Var name + virtual string name() const { return scopep()->name() + "->" + varp()->name(); } virtual void dump(std::ostream& str) const; virtual bool hasDType() const { return true; } AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under - AstNode* valuep() const { return op1p(); } // op1 = Calculation of value of variable, NULL=complicated + // op1 = Calculation of value of variable, NULL=complicated + AstNode* valuep() const { return op1p(); } void valuep(AstNode* valuep) { addOp1p(valuep); } bool isCircular() const { return m_circular; } void circular(bool flag) { m_circular = flag; } @@ -1974,18 +2226,24 @@ public: virtual void dump(std::ostream& str) const; virtual V3Hash sameHash() const { return V3Hash(V3Hash(varp()->name()), V3Hash(hiername())); } virtual bool same(const AstNode* samep) const { - return same(static_cast(samep)); } + return same(static_cast(samep)); + } inline bool same(const AstVarRef* samep) const { - if (varScopep()) return (varScopep()==samep->varScopep() - && lvalue()==samep->lvalue()); - else return (hiername()==samep->hiername() - && varp()->name()==samep->varp()->name() - && lvalue()==samep->lvalue()); } + if (varScopep()) { + return (varScopep() == samep->varScopep() && lvalue() == samep->lvalue()); + } else { + return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name() + && lvalue() == samep->lvalue()); + } + } inline bool sameNoLvalue(AstVarRef* samep) const { - if (varScopep()) return (varScopep()==samep->varScopep()); - else return (hiername()==samep->hiername() - && varp()->name()==samep->varp()->name()); } - virtual int instrCount() const { return widthInstrs()*(lvalue()?1:instrCountLd()); } + if (varScopep()) { + return (varScopep() == samep->varScopep()); + } else { + return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name()); + } + } + virtual int instrCount() const { return widthInstrs() * (lvalue() ? 1 : instrCountLd()); } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } @@ -1995,12 +2253,12 @@ class AstVarXRef : public AstNodeVarRef { // A VarRef to something in another module before AstScope. // Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope private: - string m_dotted; // Dotted part of scope the name()'ed reference is under or "" - string m_inlinedDots; // Dotted hierarchy flattened out + string m_dotted; // Dotted part of scope the name()'ed reference is under or "" + string m_inlinedDots; // Dotted hierarchy flattened out public: AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue) : ASTGEN_SUPER(fl, name, NULL, lvalue) - , m_dotted(dotted) { } + , m_dotted(dotted) {} AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, bool lvalue) : ASTGEN_SUPER(fl, varp->name(), varp, lvalue) , m_dotted(dotted) { @@ -2020,32 +2278,35 @@ public: virtual V3Hash sameHash() const { return V3Hash(V3Hash(varp()), V3Hash(dotted())); } virtual bool same(const AstNode* samep) const { const AstVarXRef* asamep = static_cast(samep); - return (hiername() == asamep->hiername() - && varp() == asamep->varp() - && name() == asamep->name() - && dotted() == asamep->dotted()); } + return (hiername() == asamep->hiername() && varp() == asamep->varp() + && name() == asamep->name() && dotted() == asamep->dotted()); + } }; class AstPin : public AstNode { // A pin on a cell private: - int m_pinNum; // Pin number - string m_name; // Pin name, or "" for number based interconnect - AstVar* m_modVarp; // Input/output this pin connects to on submodule. - AstParamTypeDType* m_modPTypep; // Param type this pin connects to on submodule. - bool m_param; // Pin connects to parameter - bool m_svImplicit; // Pin is SystemVerilog .name'ed + int m_pinNum; // Pin number + string m_name; // Pin name, or "" for number based interconnect + AstVar* m_modVarp; // Input/output this pin connects to on submodule. + AstParamTypeDType* m_modPTypep; // Param type this pin connects to on submodule. + bool m_param; // Pin connects to parameter + bool m_svImplicit; // Pin is SystemVerilog .name'ed public: AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp) : ASTGEN_SUPER(fl) - , m_name(name), m_param(false), m_svImplicit(false) { + , m_name(name) + , m_param(false) + , m_svImplicit(false) { m_pinNum = pinNum; m_modVarp = NULL; m_modPTypep = NULL; setNOp1p(exprp); } AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp) - : ASTGEN_SUPER(fl), m_param(false), m_svImplicit(false) { + : ASTGEN_SUPER(fl) + , m_param(false) + , m_svImplicit(false) { m_name = varname->name(); m_pinNum = pinNum; m_modVarp = NULL; @@ -2057,22 +2318,26 @@ public: virtual const char* broken() const { BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); BROKEN_RTN(m_modPTypep && !m_modPTypep->brokeExists()); - return NULL; } + return NULL; + } virtual string name() const { return m_name; } // * = Pin name, ""=go by number virtual void name(const string& name) { m_name = name; } virtual string prettyOperatorName() const { - return modVarp() ? ((modVarp()->direction().isAny() - ? modVarp()->direction().prettyName()+" " - : "") - +"port connection "+modVarp()->prettyNameQ()) - : "port connection"; } + return modVarp() + ? ((modVarp()->direction().isAny() ? modVarp()->direction().prettyName() + " " + : "") + + "port connection " + modVarp()->prettyNameQ()) + : "port connection"; + } bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked int pinNum() const { return m_pinNum; } void exprp(AstNode* nodep) { addOp1p(nodep); } - AstNode* exprp() const { return op1p(); } // op1 = Expression connected to pin, NULL if unconnected + // op1 = Expression connected to pin, NULL if unconnected + AstNode* exprp() const { return op1p(); } AstVar* modVarp() const { return m_modVarp; } // [After Link] Pointer to variable void modVarp(AstVar* nodep) { m_modVarp = nodep; } - AstParamTypeDType* modPTypep() const { return m_modPTypep; } // [After Link] Pointer to variable + // [After Link] Pointer to variable + AstParamTypeDType* modPTypep() const { return m_modPTypep; } void modPTypep(AstParamTypeDType* nodep) { m_modPTypep = nodep; } bool param() const { return m_param; } void param(bool flag) { m_param = flag; } @@ -2083,7 +2348,7 @@ public: class AstArg : public AstNode { // An argument to a function/task private: - string m_name; // Pin name, or "" for number based interconnect + string m_name; // Pin name, or "" for number based interconnect public: AstArg(FileLine* fl, const string& name, AstNode* exprp) : ASTGEN_SUPER(fl) @@ -2095,8 +2360,9 @@ public: virtual void name(const string& name) { m_name = name; } virtual V3Hash sameHash() const { return V3Hash(); } void exprp(AstNode* nodep) { addOp1p(nodep); } - AstNode* exprp() const { return op1p(); } // op1 = Expression connected to pin, NULL if unconnected - bool emptyConnectNoNext() const { return !exprp() && name()=="" && !nextp(); } + // op1 = Expression connected to pin, NULL if unconnected + AstNode* exprp() const { return op1p(); } + bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); } }; class AstModule : public AstNodeModule { @@ -2149,14 +2415,21 @@ public: class AstPackageExport : public AstNode { private: // A package export declaration - string m_name; - AstPackage* m_packagep; // Package hierarchy + string m_name; + AstPackage* m_packagep; // Package hierarchy public: AstPackageExport(FileLine* fl, AstPackage* packagep, const string& name) - : ASTGEN_SUPER(fl), m_name(name), m_packagep(packagep) {} + : ASTGEN_SUPER(fl) + , m_name(name) + , m_packagep(packagep) {} ASTNODE_NODE_FUNCS(PackageExport) - virtual const char* broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return NULL; } - virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); } + virtual const char* broken() const { + BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); + return NULL; + } + virtual void cloneRelink() { + if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); + } virtual void dump(std::ostream& str) const; virtual string name() const { return m_name; } AstPackage* packagep() const { return m_packagep; } @@ -2166,14 +2439,21 @@ public: class AstPackageImport : public AstNode { private: // A package import declaration - string m_name; - AstPackage* m_packagep; // Package hierarchy + string m_name; + AstPackage* m_packagep; // Package hierarchy public: AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name) - : ASTGEN_SUPER(fl), m_name(name), m_packagep(packagep) {} + : ASTGEN_SUPER(fl) + , m_name(name) + , m_packagep(packagep) {} ASTNODE_NODE_FUNCS(PackageImport) - virtual const char* broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return NULL; } - virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); } + virtual const char* broken() const { + BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); + return NULL; + } + virtual void cloneRelink() { + if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); + } virtual void dump(std::ostream& str) const; virtual string name() const { return m_name; } AstPackage* packagep() const { return m_packagep; } @@ -2184,7 +2464,7 @@ class AstIface : public AstNodeModule { // A module declaration public: AstIface(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) { } + : ASTGEN_SUPER(fl, name) {} ASTNODE_NODE_FUNCS(Iface) }; @@ -2211,14 +2491,19 @@ public: dtypep(dtp); } ASTNODE_NODE_FUNCS(MemberSel) - virtual void cloneRelink() { if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep(); } } + virtual void cloneRelink() { + if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep(); } + } virtual const char* broken() const { - BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; } + BROKEN_RTN(m_varp && !m_varp->brokeExists()); + return NULL; + } virtual void dump(std::ostream& str) const; virtual string name() const { return m_name; } virtual V3Hash sameHash() const { return V3Hash(m_name); } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { - V3ERROR_NA; /* How can from be a const? */ } + V3ERROR_NA; /* How can from be a const? */ + } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return false; } @@ -2236,17 +2521,25 @@ class AstModportFTaskRef : public AstNode { // interface/instantiator, thus this is a reference // PARENT: AstModport private: - string m_name; // Name of the variable referenced - bool m_export; // Type of the function (import/export) - AstNodeFTask* m_ftaskp; // Link to the function + string m_name; // Name of the variable referenced + bool m_export; // Type of the function (import/export) + AstNodeFTask* m_ftaskp; // Link to the function public: AstModportFTaskRef(FileLine* fl, const string& name, bool isExport) - : ASTGEN_SUPER(fl), m_name(name), m_export(isExport), m_ftaskp(NULL) { } + : ASTGEN_SUPER(fl) + , m_name(name) + , m_export(isExport) + , m_ftaskp(NULL) {} ASTNODE_NODE_FUNCS(ModportFTaskRef) - virtual const char* broken() const { BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists()); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists()); + return NULL; + } virtual void dump(std::ostream& str) const; virtual string name() const { return m_name; } - virtual void cloneRelink() { if (m_ftaskp && m_ftaskp->clonep()) m_ftaskp = m_ftaskp->clonep(); } + virtual void cloneRelink() { + if (m_ftaskp && m_ftaskp->clonep()) m_ftaskp = m_ftaskp->clonep(); + } bool isImport() const { return !m_export; } bool isExport() const { return m_export; } AstNodeFTask* ftaskp() const { return m_ftaskp; } // [After Link] Pointer to variable @@ -2258,16 +2551,24 @@ class AstModportVarRef : public AstNode { // The storage for the variable itself is inside the interface, thus this is a reference // PARENT: AstModport private: - string m_name; // Name of the variable referenced - VDirection m_direction; // Direction of the variable (in/out) - AstVar* m_varp; // Link to the actual Var + string m_name; // Name of the variable referenced + VDirection m_direction; // Direction of the variable (in/out) + AstVar* m_varp; // Link to the actual Var public: AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction) - : ASTGEN_SUPER(fl), m_name(name), m_direction(direction), m_varp(NULL) { } + : ASTGEN_SUPER(fl) + , m_name(name) + , m_direction(direction) + , m_varp(NULL) {} ASTNODE_NODE_FUNCS(ModportVarRef) - virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(m_varp && !m_varp->brokeExists()); + return NULL; + } virtual void dump(std::ostream& str) const; - virtual void cloneRelink() { if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); } + virtual void cloneRelink() { + if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); + } virtual string name() const { return m_name; } void direction(const VDirection& flag) { m_direction = flag; } VDirection direction() const { return m_direction; } @@ -2278,11 +2579,13 @@ public: class AstModport : public AstNode { // A modport in an interface private: - string m_name; // Name of the modport + string m_name; // Name of the modport public: AstModport(FileLine* fl, const string& name, AstNode* varsp) - : ASTGEN_SUPER(fl), m_name(name) { - addNOp1p(varsp); } + : ASTGEN_SUPER(fl) + , m_name(name) { + addNOp1p(varsp); + } virtual string name() const { return m_name; } virtual bool maybePointedTo() const { return true; } ASTNODE_NODE_FUNCS(Modport) @@ -2295,7 +2598,8 @@ private: string m_name; // Name of the reference public: AstIntfRef(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl), m_name(name) { } + : ASTGEN_SUPER(fl) + , m_name(name) {} virtual string name() const { return m_name; } ASTNODE_NODE_FUNCS(IntfRef) }; @@ -2303,27 +2607,37 @@ public: class AstCell : public AstNode { // A instantiation cell or interface call (don't know which until link) private: - FileLine* m_modNameFileline; // Where module the cell instances token was - string m_name; // Cell name - string m_origName; // Original name before dot addition - string m_modName; // Module the cell instances - AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced - bool m_hasIfaceVar:1; // True if a Var has been created for this cell - bool m_recursive:1; // Self-recursive module - bool m_trace:1; // Trace this cell + FileLine* m_modNameFileline; // Where module the cell instances token was + string m_name; // Cell name + string m_origName; // Original name before dot addition + string m_modName; // Module the cell instances + AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced + bool m_hasIfaceVar : 1; // True if a Var has been created for this cell + bool m_recursive : 1; // Self-recursive module + bool m_trace : 1; // Trace this cell public: - AstCell(FileLine* fl, FileLine* mfl, - const string& instName, const string& modName, + AstCell(FileLine* fl, FileLine* mfl, const string& instName, const string& modName, AstPin* pinsp, AstPin* paramsp, AstRange* rangep) : ASTGEN_SUPER(fl) , m_modNameFileline(mfl) - , m_name(instName), m_origName(instName), m_modName(modName) - , m_modp(NULL), m_hasIfaceVar(false), m_recursive(false), m_trace(true) { - addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); } + , m_name(instName) + , m_origName(instName) + , m_modName(modName) + , m_modp(NULL) + , m_hasIfaceVar(false) + , m_recursive(false) + , m_trace(true) { + addNOp1p(pinsp); + addNOp2p(paramsp); + setNOp3p(rangep); + } ASTNODE_NODE_FUNCS(Cell) // No cloneRelink, we presume cloneee's want the same module linkages virtual void dump(std::ostream& str) const; - virtual const char* broken() const { BROKEN_RTN(m_modp && !m_modp->brokeExists()); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(m_modp && !m_modp->brokeExists()); + return NULL; + } virtual bool maybePointedTo() const { return true; } // ACCESSORS virtual string name() const { return m_name; } // * = Cell name @@ -2334,9 +2648,12 @@ public: void modName(const string& name) { m_modName = name; } FileLine* modNameFileline() const { return m_modNameFileline; } AstPin* pinsp() const { return VN_CAST(op1p(), Pin); } // op1 = List of cell ports - AstPin* paramsp() const { return VN_CAST(op2p(), Pin); } // op2 = List of parameter #(##) values - AstRange* rangep() const { return VN_CAST(op3p(), Range); } // op3 = Range of arrayed instants (NULL=not ranged) - AstIntfRef* intfRefp() const { return VN_CAST(op4p(), IntfRef); } // op4 = List of interface references + // op2 = List of parameter #(##) values + AstPin* paramsp() const { return VN_CAST(op2p(), Pin); } + // op3 = Range of arrayed instants (NULL=not ranged) + AstRange* rangep() const { return VN_CAST(op3p(), Range); } + // op4 = List of interface references + AstIntfRef* intfRefp() const { return VN_CAST(op4p(), IntfRef); } AstNodeModule* modp() const { return m_modp; } // [AfterLink] = Pointer to module instantiated void addPinsp(AstPin* nodep) { addOp1p(nodep); } void addParamsp(AstPin* nodep) { addOp2p(nodep); } @@ -2357,16 +2674,21 @@ class AstCellInline : public AstNode { // It is augmented with the scope in V3Scope for VPI. // Children: When 2 levels inlined, other CellInline under this private: - string m_name; // Cell name, possibly {a}__DOT__{b}... - string m_origModName; // Original name of the module, ignoring name() changes, for dot lookup - AstScope* m_scopep; // The scope that the cell is inlined into + string m_name; // Cell name, possibly {a}__DOT__{b}... + string m_origModName; // Original name of the module, ignoring name() changes, for dot lookup + AstScope* m_scopep; // The scope that the cell is inlined into public: AstCellInline(FileLine* fl, const string& name, const string& origModName) : ASTGEN_SUPER(fl) - , m_name(name), m_origModName(origModName), m_scopep(NULL) {} + , m_name(name) + , m_origModName(origModName) + , m_scopep(NULL) {} ASTNODE_NODE_FUNCS(CellInline) virtual void dump(std::ostream& str) const; - virtual const char* broken() const { BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); + return NULL; + } // ACCESSORS virtual string name() const { return m_name; } // * = Cell name string origModName() const { return m_origModName; } // * = modp()->origName() before inlining @@ -2378,13 +2700,14 @@ public: class AstCellRef : public AstNode { // As-of-yet unlinkable reference into a cell private: - string m_name; // Cell name + string m_name; // Cell name public: - AstCellRef(FileLine* fl, - const string& name, AstNode* cellp, AstNode* exprp) + AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNode* exprp) : ASTGEN_SUPER(fl) , m_name(name) { - addNOp1p(cellp); addNOp2p(exprp); } + addNOp1p(cellp); + addNOp2p(exprp); + } ASTNODE_NODE_FUNCS(CellRef) // ACCESSORS virtual string name() const { return m_name; } // * = Array name @@ -2395,13 +2718,13 @@ public: class AstCellArrayRef : public AstNode { // As-of-yet unlinkable reference into an array of cells private: - string m_name; // Array name + string m_name; // Array name public: - AstCellArrayRef(FileLine* fl, - const string& name, AstNode* selectExprp) + AstCellArrayRef(FileLine* fl, const string& name, AstNode* selectExprp) : ASTGEN_SUPER(fl) , m_name(name) { - addNOp1p(selectExprp); } + addNOp1p(selectExprp); + } ASTNODE_NODE_FUNCS(CellArrayRef) // ACCESSORS virtual string name() const { return m_name; } // * = Array name @@ -2411,13 +2734,14 @@ public: class AstUnlinkedRef : public AstNode { // As-of-yet unlinkable Ref private: - string m_name; // Var name + string m_name; // Var name public: - AstUnlinkedRef(FileLine* fl, - AstNode* refp, const string& name, AstNode* crp) + AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* crp) : ASTGEN_SUPER(fl) , m_name(name) { - addNOp1p(refp); addNOp2p(crp); } + addNOp1p(refp); + addNOp2p(crp); + } ASTNODE_NODE_FUNCS(UnlinkedRef) // ACCESSORS virtual string name() const { return m_name; } // * = Var name @@ -2429,7 +2753,7 @@ class AstBind : public AstNode { // Parents: MODULE // Children: CELL private: - string m_name; // Binding to name + string m_name; // Binding to name public: AstBind(FileLine* fl, const string& name, AstNode* cellsp) : ASTGEN_SUPER(fl) @@ -2447,12 +2771,13 @@ public: class AstPort : public AstNode { // A port (in/out/inout) on a module private: - int m_pinNum; // Pin number - string m_name; // Name of pin + int m_pinNum; // Pin number + string m_name; // Name of pin public: AstPort(FileLine* fl, int pinnum, const string& name) : ASTGEN_SUPER(fl) - , m_pinNum(pinnum), m_name(name) {} + , m_pinNum(pinnum) + , m_name(name) {} ASTNODE_NODE_FUNCS(Port) virtual string name() const { return m_name; } // * = Port name int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation @@ -2470,18 +2795,24 @@ class AstParseRef : public AstNode { private: VParseRefExp m_expect; // Type we think it should resolve to string m_name; + public: - AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, - AstNode* lhsp, AstNodeFTaskRef* ftaskrefp) - : ASTGEN_SUPER(fl), m_expect(expect), m_name(name) { setNOp1p(lhsp); setNOp2p(ftaskrefp); } + AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp, + AstNodeFTaskRef* ftaskrefp) + : ASTGEN_SUPER(fl) + , m_expect(expect) + , m_name(name) { + setNOp1p(lhsp); + setNOp2p(ftaskrefp); + } ASTNODE_NODE_FUNCS(ParseRef) virtual void dump(std::ostream& str) const; virtual string name() const { return m_name; } // * = Var name virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_expect), V3Hash(m_name)); } virtual bool same(const AstNode* samep) const { const AstParseRef* asamep = static_cast(samep); - return (expect() == asamep->expect() - && m_name == asamep->m_name); } + return (expect() == asamep->expect() && m_name == asamep->m_name); + } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual void name(const string& name) { m_name = name; } @@ -2495,20 +2826,25 @@ public: class AstPackageRef : public AstNode { private: - AstPackage* m_packagep; // Package hierarchy + AstPackage* m_packagep; // Package hierarchy public: AstPackageRef(FileLine* fl, AstPackage* packagep) - : ASTGEN_SUPER(fl), m_packagep(packagep) {} + : ASTGEN_SUPER(fl) + , m_packagep(packagep) {} ASTNODE_NODE_FUNCS(PackageRef) // METHODS - virtual const char* broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return NULL; } - virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) { - m_packagep = m_packagep->clonep(); - }} + virtual const char* broken() const { + BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); + return NULL; + } + virtual void cloneRelink() { + if (m_packagep && m_packagep->clonep()) { m_packagep = m_packagep->clonep(); } + } virtual bool same(const AstNode* samep) const { - return (m_packagep==static_cast(samep)->m_packagep); } + return (m_packagep == static_cast(samep)->m_packagep); + } virtual V3Hash sameHash() const { return V3Hash(m_packagep); } - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep = nodep; } }; @@ -2518,7 +2854,10 @@ class AstDot : public AstNode { // These are eliminated in the link stage public: AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl) { setOp1p(lhsp); setOp2p(rhsp); } + : ASTGEN_SUPER(fl) { + setOp1p(lhsp); + setOp2p(rhsp); + } ASTNODE_NODE_FUNCS(Dot) // For parser, make only if non-null package static AstNode* newIfPkg(FileLine* fl, AstPackage* packagep, AstNode* rhsp) { @@ -2591,11 +2930,13 @@ class AstDpiExport : public AstNode { // however we're not *calling* it, so that seems somehow wrong. // (Probably AstNodeFTaskRef should be renamed AstNodeFTaskCall and have-a AstNodeFTaskRef) private: - string m_name; // Name of function - string m_cname; // Name of function on c side + string m_name; // Name of function + string m_cname; // Name of function on c side public: AstDpiExport(FileLine* fl, const string& vname, const string& cname) - : ASTGEN_SUPER(fl), m_name(vname), m_cname(cname) { } + : ASTGEN_SUPER(fl) + , m_name(vname) + , m_cname(cname) {} ASTNODE_NODE_FUNCS(DpiExport) virtual string name() const { return m_name; } virtual void name(const string& name) { m_name = name; } @@ -2611,13 +2952,14 @@ class AstSenItem : public AstNodeSenItem { private: VEdgeType m_edgeType; // Edge type public: - class Combo {}; // for creator type-overload selection + class Combo {}; // for creator type-overload selection class Illegal {}; // for creator type-overload selection class Initial {}; // for creator type-overload selection - class Settle {}; // for creator type-overload selection - class Never {}; // for creator type-overload selection + class Settle {}; // for creator type-overload selection + class Never {}; // for creator type-overload selection AstSenItem(FileLine* fl, VEdgeType edgeType, AstNode* varrefp) - : ASTGEN_SUPER(fl), m_edgeType(edgeType) { + : ASTGEN_SUPER(fl) + , m_edgeType(edgeType) { setOp1p(varrefp); } AstSenItem(FileLine* fl, Combo) @@ -2644,19 +2986,25 @@ public: virtual void dump(std::ostream& str) const; virtual V3Hash sameHash() const { return V3Hash(edgeType()); } virtual bool same(const AstNode* samep) const { - return edgeType()==static_cast(samep)->edgeType(); } + return edgeType() == static_cast(samep)->edgeType(); + } VEdgeType edgeType() const { return m_edgeType; } // * = Posedge/negedge - void edgeType(VEdgeType type) { m_edgeType = type; editCountInc(); } // * = Posedge/negedge + void edgeType(VEdgeType type) { + m_edgeType = type; + editCountInc(); + } // * = Posedge/negedge AstNode* sensp() const { return op1p(); } // op1 = Signal sensitized - AstNodeVarRef* varrefp() const { return VN_CAST(op1p(), NodeVarRef); } // op1 = Signal sensitized + AstNodeVarRef* varrefp() const { + return VN_CAST(op1p(), NodeVarRef); + } // op1 = Signal sensitized // virtual bool isClocked() const { return edgeType().clockedStmt(); } - virtual bool isCombo() const { return edgeType()==VEdgeType::ET_COMBO; } - virtual bool isInitial() const { return edgeType()==VEdgeType::ET_INITIAL; } - virtual bool isIllegal() const { return edgeType()==VEdgeType::ET_ILLEGAL; } - virtual bool isSettle() const { return edgeType()==VEdgeType::ET_SETTLE; } - virtual bool isNever() const { return edgeType()==VEdgeType::ET_NEVER; } - bool hasVar() const { return !(isCombo()||isInitial()||isSettle()||isNever()); } + virtual bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; } + virtual bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; } + virtual bool isIllegal() const { return edgeType() == VEdgeType::ET_ILLEGAL; } + virtual bool isSettle() const { return edgeType() == VEdgeType::ET_SETTLE; } + virtual bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; } + bool hasVar() const { return !(isCombo() || isInitial() || isSettle() || isNever()); } }; class AstSenGate : public AstNodeSenItem { @@ -2667,7 +3015,9 @@ class AstSenGate : public AstNodeSenItem { public: AstSenGate(FileLine* fl, AstSenItem* sensesp, AstNode* rhsp) : ASTGEN_SUPER(fl) { - dtypeSetLogicBool(); addOp1p(sensesp); setOp2p(rhsp); + dtypeSetLogicBool(); + addOp1p(sensesp); + setOp2p(rhsp); } ASTNODE_NODE_FUNCS(SenGate) virtual string emitVerilog() { return "(%l) %f&& (%r)"; } @@ -2691,7 +3041,8 @@ private: bool m_multi; // Created from combo logic by ORing multiple clock domains public: AstSenTree(FileLine* fl, AstNodeSenItem* sensesp) - : ASTGEN_SUPER(fl), m_multi(false) { + : ASTGEN_SUPER(fl) + , m_multi(false) { addNOp1p(sensesp); } ASTNODE_NODE_FUNCS(SenTree) @@ -2699,22 +3050,26 @@ public: virtual bool maybePointedTo() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } bool isMulti() const { return m_multi; } - AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); } // op1 = Sensitivity list + // op1 = Sensitivity list + AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); } void addSensesp(AstNodeSenItem* nodep) { addOp1p(nodep); } void multi(bool flag) { m_multi = true; } // METHODS bool hasClocked() const; // Includes a clocked statement - bool hasSettle() const; // Includes a SETTLE SenItem + bool hasSettle() const; // Includes a SETTLE SenItem bool hasInitial() const; // Includes a INITIAL SenItem - bool hasCombo() const; // Includes a COMBO SenItem + bool hasCombo() const; // Includes a COMBO SenItem }; class AstAlways : public AstNode { VAlwaysKwd m_keyword; + public: AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER(fl), m_keyword(keyword) { - addNOp1p(sensesp); addNOp2p(bodysp); + : ASTGEN_SUPER(fl) + , m_keyword(keyword) { + addNOp1p(sensesp); + addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(Always) // @@ -2733,7 +3088,8 @@ class AstAlwaysPublic : public AstNodeStmt { public: AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) : ASTGEN_SUPER(fl) { - addNOp1p(sensesp); addNOp2p(bodysp); + addNOp1p(sensesp); + addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(AlwaysPublic) virtual V3Hash sameHash() const { return V3Hash(); } @@ -2751,7 +3107,8 @@ class AstAlwaysPost : public AstNode { public: AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) : ASTGEN_SUPER(fl) { - addNOp1p(sensesp); addNOp2p(bodysp); + addNOp1p(sensesp); + addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(AlwaysPost) // @@ -2766,7 +3123,9 @@ public: dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Assign) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssign(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstAssign(this->fileline(), lhsp, rhsp); + } virtual bool brokeLhsMustBeLvalue() const { return true; } }; @@ -2786,7 +3145,9 @@ public: AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignDly) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignDly(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstAssignDly(this->fileline(), lhsp, rhsp); + } virtual bool isGateOptimizable() const { return false; } virtual string verilogKwd() const { return "<="; } virtual bool brokeLhsMustBeLvalue() const { return true; } @@ -2796,9 +3157,11 @@ class AstAssignW : public AstNodeAssign { // Like assign, but wire/assign's in verilog, the only setting of the specified variable public: AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { } + : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignW) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignW(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstAssignW(this->fileline(), lhsp, rhsp); + } virtual bool brokeLhsMustBeLvalue() const { return true; } AstAlways* convertToAlways() { AstNode* lhs1p = lhsp()->unlinkFrBack(); @@ -2818,13 +3181,16 @@ public: dtypeFrom(rhsp); } ASTNODE_NODE_FUNCS(AssignVarScope) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignVarScope(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstAssignVarScope(this->fileline(), lhsp, rhsp); + } virtual bool brokeLhsMustBeLvalue() const { return false; } }; class AstPull : public AstNode { private: bool m_direction; + public: AstPull(FileLine* fl, AstNode* lhsp, bool direction) : ASTGEN_SUPER(fl) { @@ -2833,10 +3199,11 @@ public: } ASTNODE_NODE_FUNCS(Pull) virtual bool same(const AstNode* samep) const { - return direction()==static_cast(samep)->direction(); } + return direction() == static_cast(samep)->direction(); + } void lhsp(AstNode* np) { setOp1p(np); } AstNode* lhsp() const { return op1p(); } // op1 = Assign to - uint32_t direction() const { return (uint32_t) m_direction; } + uint32_t direction() const { return (uint32_t)m_direction; } }; class AstAssignPre : public AstNodeAssign { @@ -2845,7 +3212,9 @@ public: AstAssignPre(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignPre) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignPre(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstAssignPre(this->fileline(), lhsp, rhsp); + } virtual bool brokeLhsMustBeLvalue() const { return true; } }; @@ -2855,7 +3224,9 @@ public: AstAssignPost(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignPost) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignPost(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstAssignPost(this->fileline(), lhsp, rhsp); + } virtual bool brokeLhsMustBeLvalue() const { return true; } }; @@ -2867,9 +3238,10 @@ private: bool m_showAt; // Show "at " string m_name; // Text of comment public: - AstComment(FileLine* fl, const string& name, bool showAt=false) + AstComment(FileLine* fl, const string& name, bool showAt = false) : ASTGEN_SUPER(fl) - , m_showAt(showAt), m_name(name) {} + , m_showAt(showAt) + , m_name(name) {} ASTNODE_NODE_FUNCS(Comment) virtual string name() const { return m_name; } // * = Text virtual V3Hash sameHash() const { return V3Hash(); } // Ignore name in comments @@ -2886,7 +3258,8 @@ public: : ASTGEN_SUPER(fl, condp, expr1p, expr2p) {} ASTNODE_NODE_FUNCS(Cond) virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) { - return new AstCond(this->fileline(), condp, expr1p, expr2p); } + return new AstCond(this->fileline(), condp, expr1p, expr2p); + } }; class AstCondBound : public AstNodeCond { @@ -2898,7 +3271,8 @@ public: : ASTGEN_SUPER(fl, condp, expr1p, expr2p) {} ASTNODE_NODE_FUNCS(CondBound) virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) { - return new AstCondBound(this->fileline(), condp, expr1p, expr2p); } + return new AstCondBound(this->fileline(), condp, expr1p, expr2p); + } }; class AstCoverDecl : public AstNodeStmt { @@ -2906,16 +3280,19 @@ class AstCoverDecl : public AstNodeStmt { // Parents: {statement list} // Children: none private: - AstCoverDecl* m_dataDeclp; // [After V3CoverageJoin] Pointer to duplicate declaration to get data from instead - string m_page; - string m_text; - string m_hier; - int m_column; - int m_binNum; // Set by V3EmitCSyms to tell final V3Emit what to increment + AstCoverDecl* m_dataDeclp; // [After V3CoverageJoin] Pointer to duplicate declaration to get + // data from instead + string m_page; + string m_text; + string m_hier; + int m_column; + int m_binNum; // Set by V3EmitCSyms to tell final V3Emit what to increment public: AstCoverDecl(FileLine* fl, int column, const string& page, const string& comment) : ASTGEN_SUPER(fl) { - m_text = comment; m_page = page; m_column = column; + m_text = comment; + m_page = page; + m_column = column; m_binNum = 0; m_dataDeclp = NULL; } @@ -2925,10 +3302,13 @@ public: if (m_dataDeclp && m_dataDeclp->m_dataDeclp) { // Avoid O(n^2) accessing v3fatalSrc("dataDeclp should point to real data, not be a list"); } - return NULL; } - virtual void cloneRelink() { if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep(); } + return NULL; + } + virtual void cloneRelink() { + if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep(); + } virtual void dump(std::ostream& str) const; - virtual int instrCount() const { return 1+2*instrCountLd(); } + virtual int instrCount() const { return 1 + 2 * instrCountLd(); } virtual bool maybePointedTo() const { return true; } int column() const { return m_column; } void binNum(int flag) { m_binNum = flag; } @@ -2941,16 +3321,15 @@ public: virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { const AstCoverDecl* asamep = static_cast(samep); - return (fileline() == asamep->fileline() - && hier() == asamep->hier() - && comment() == asamep->comment() - && column() == asamep->column()); } + return (fileline() == asamep->fileline() && hier() == asamep->hier() + && comment() == asamep->comment() && column() == asamep->column()); + } virtual bool isPredictOptimizable() const { return false; } void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; } // dataDecl NULL means "use this one", but often you want "this" to // indicate to get data from here AstCoverDecl* dataDeclNullp() const { return m_dataDeclp; } - AstCoverDecl* dataDeclThisp() { return dataDeclNullp()?dataDeclNullp():this; } + AstCoverDecl* dataDeclThisp() { return dataDeclNullp() ? dataDeclNullp() : this; } }; class AstCoverInc : public AstNodeStmt { @@ -2965,13 +3344,19 @@ public: m_declp = declp; } ASTNODE_NODE_FUNCS(CoverInc) - virtual const char* broken() const { BROKEN_RTN(!declp()->brokeExists()); return NULL; } - virtual void cloneRelink() { if (m_declp->clonep()) m_declp = m_declp->clonep(); } + virtual const char* broken() const { + BROKEN_RTN(!declp()->brokeExists()); + return NULL; + } + virtual void cloneRelink() { + if (m_declp->clonep()) m_declp = m_declp->clonep(); + } virtual void dump(std::ostream& str) const; - virtual int instrCount() const { return 1+2*instrCountLd(); } + virtual int instrCount() const { return 1 + 2 * instrCountLd(); } virtual V3Hash sameHash() const { return V3Hash(declp()); } virtual bool same(const AstNode* samep) const { - return declp() == static_cast(samep)->declp(); } + return declp() == static_cast(samep)->declp(); + } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isOutputter() const { return true; } @@ -2991,12 +3376,14 @@ public: setOp3p(changep); } ASTNODE_NODE_FUNCS(CoverToggle) - virtual int instrCount() const { return 3+instrCountBranch()+instrCountLd(); } + virtual int instrCount() const { return 3 + instrCountBranch() + instrCountLd(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { return true; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return true; } - virtual bool isOutputter() const { return false; } // Though the AstCoverInc under this is an outputter + virtual bool isOutputter() const { + return false; // Though the AstCoverInc under this is an outputter + } // but isPure() true AstCoverInc* incp() const { return VN_CAST(op1p(), CoverInc); } void incp(AstCoverInc* nodep) { setOp1p(nodep); } @@ -3011,8 +3398,7 @@ class AstGenCase : public AstNodeCase { // casesp Children: CASEITEMs public: AstGenCase(FileLine* fl, AstNode* exprp, AstNode* casesp) - : ASTGEN_SUPER(fl, exprp, casesp) { - } + : ASTGEN_SUPER(fl, exprp, casesp) {} ASTNODE_NODE_FUNCS(GenCase) }; @@ -3022,27 +3408,31 @@ class AstCase : public AstNodeCase { // exprp Children: MATHs // casesp Children: CASEITEMs private: - VCaseType m_casex; // 0=case, 1=casex, 2=casez - bool m_fullPragma; // Synthesis full_case - bool m_parallelPragma; // Synthesis parallel_case - bool m_uniquePragma; // unique case - bool m_unique0Pragma; // unique0 case - bool m_priorityPragma; // priority case + VCaseType m_casex; // 0=case, 1=casex, 2=casez + bool m_fullPragma; // Synthesis full_case + bool m_parallelPragma; // Synthesis parallel_case + bool m_uniquePragma; // unique case + bool m_unique0Pragma; // unique0 case + bool m_priorityPragma; // priority case public: AstCase(FileLine* fl, VCaseType casex, AstNode* exprp, AstNode* casesp) : ASTGEN_SUPER(fl, exprp, casesp) { m_casex = casex; - m_fullPragma = false; m_parallelPragma = false; - m_uniquePragma = false; m_unique0Pragma = false; m_priorityPragma = false; + m_fullPragma = false; + m_parallelPragma = false; + m_uniquePragma = false; + m_unique0Pragma = false; + m_priorityPragma = false; } ASTNODE_NODE_FUNCS(Case) - virtual string verilogKwd() const { return casez()?"casez":casex()?"casex":"case"; } + virtual string verilogKwd() const { return casez() ? "casez" : casex() ? "casex" : "case"; } virtual bool same(const AstNode* samep) const { - return m_casex==static_cast(samep)->m_casex; } - bool casex() const { return m_casex==VCaseType::CT_CASEX; } - bool casez() const { return m_casex==VCaseType::CT_CASEZ; } - bool caseInside() const { return m_casex==VCaseType::CT_CASEINSIDE; } - bool caseSimple() const { return m_casex==VCaseType::CT_CASE; } + return m_casex == static_cast(samep)->m_casex; + } + bool casex() const { return m_casex == VCaseType::CT_CASEX; } + bool casez() const { return m_casex == VCaseType::CT_CASEZ; } + bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; } + bool caseSimple() const { return m_casex == VCaseType::CT_CASE; } void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; } bool fullPragma() const { return m_fullPragma; } void fullPragma(bool flag) { m_fullPragma = flag; } @@ -3066,16 +3456,17 @@ private: public: AstCaseItem(FileLine* fl, AstNode* condsp, AstNode* bodysp) : ASTGEN_SUPER(fl) { - addNOp1p(condsp); addNOp2p(bodysp); + addNOp1p(condsp); + addNOp2p(bodysp); m_ignoreOverlap = false; } ASTNODE_NODE_FUNCS(CaseItem) - virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } + virtual int instrCount() const { return widthInstrs() + instrCountBranch(); } AstNode* condsp() const { return op1p(); } // op1 = list of possible matching expressions AstNode* bodysp() const { return op2p(); } // op2 = what to do void condsp(AstNode* nodep) { setOp1p(nodep); } void addBodysp(AstNode* newp) { addOp2p(newp); } - bool isDefault() const { return condsp()==NULL; } + bool isDefault() const { return condsp() == NULL; } bool ignoreOverlap() const { return m_ignoreOverlap; } void ignoreOverlap(bool flag) { m_ignoreOverlap = flag; } }; @@ -3092,21 +3483,32 @@ public: AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, char missingArgChar = 'd') : ASTGEN_SUPER(fl) - , m_text(text), m_hidden(hidden), m_hasFormat(true), m_missingArgChar(missingArgChar) { + , m_text(text) + , m_hidden(hidden) + , m_hasFormat(true) + , m_missingArgChar(missingArgChar) { dtypeSetString(); - addNOp1p(exprsp); addNOp2p(NULL); } + addNOp1p(exprsp); + addNOp2p(NULL); + } AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd') : ASTGEN_SUPER(fl) - , m_text(""), m_hidden(true), m_hasFormat(false), m_missingArgChar(missingArgChar) { + , m_text("") + , m_hidden(true) + , m_hasFormat(false) + , m_missingArgChar(missingArgChar) { dtypeSetString(); - addNOp1p(exprsp); addNOp2p(NULL); } + addNOp1p(exprsp); + addNOp2p(NULL); + } ASTNODE_NODE_FUNCS(SFormatF) virtual string name() const { return m_text; } virtual int instrCount() const { return instrCountPli(); } virtual V3Hash sameHash() const { return V3Hash(text()); } virtual bool hasDType() const { return true; } virtual bool same(const AstNode* samep) const { - return text()==static_cast(samep)->text(); } + return text() == static_cast(samep)->text(); + } virtual string verilogKwd() const { return "$sformatf"; } void addExprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output @@ -3115,7 +3517,8 @@ public: AstScopeName* scopeNamep() const { return VN_CAST(op2p(), ScopeName); } void scopeNamep(AstNode* nodep) { setNOp2p(nodep); } bool formatScopeTracking() const { // Track scopeNamep(); Ok if false positive - return (name().find("%m") != string::npos || name().find("%M") != string::npos); } + return (name().find("%m") != string::npos || name().find("%M") != string::npos); + } bool hidden() const { return m_hidden; } void hasFormat(bool flag) { m_hasFormat = flag; } bool hasFormat() const { return m_hasFormat; } @@ -3128,6 +3531,7 @@ class AstDisplay : public AstNodeStmt { // Children: SFORMATF to generate print string private: AstDisplayType m_displayType; + public: AstDisplay(FileLine* fl, AstDisplayType dispType, const string& text, AstNode* filep, AstNode* exprsp, char missingArgChar = 'd') @@ -3145,9 +3549,14 @@ public: } ASTNODE_NODE_FUNCS(Display) virtual void dump(std::ostream& str) const; - virtual const char* broken() const { BROKEN_RTN(!fmtp()); return NULL; } - virtual string verilogKwd() const { return (filep() ? string("$f")+string(displayType().ascii()) - : string("$")+string(displayType().ascii())); } + virtual const char* broken() const { + BROKEN_RTN(!fmtp()); + return NULL; + } + virtual string verilogKwd() const { + return (filep() ? string("$f") + string(displayType().ascii()) + : string("$") + string(displayType().ascii())); + } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering @@ -3155,11 +3564,13 @@ public: virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(displayType()); } virtual bool same(const AstNode* samep) const { - return displayType()==static_cast(samep)->displayType(); } + return displayType() == static_cast(samep)->displayType(); + } virtual int instrCount() const { return instrCountPli(); } AstDisplayType displayType() const { return m_displayType; } void displayType(AstDisplayType type) { m_displayType = type; } - bool addNewline() const { return displayType().addNewline(); } // * = Add a newline for $display + // * = Add a newline for $display + bool addNewline() const { return displayType().addNewline(); } void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter AstSFormatF* fmtp() const { return VN_CAST(op1p(), SFormatF); } AstNode* filep() const { return op3p(); } @@ -3173,7 +3584,8 @@ class AstDumpCtl : public AstNodeStmt { VDumpCtlType m_ctlType; // Type of operation public: AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNode* exprp = NULL) - : ASTGEN_SUPER(fl), m_ctlType(ctlType) { + : ASTGEN_SUPER(fl) + , m_ctlType(ctlType) { setNOp1p(exprp); } ASTNODE_NODE_FUNCS(DumpCtl) @@ -3196,6 +3608,7 @@ class AstElabDisplay : public AstNode { // Children: SFORMATF to generate print string private: AstDisplayType m_displayType; + public: AstElabDisplay(FileLine* fl, AstDisplayType dispType, AstNode* exprsp) : ASTGEN_SUPER(fl) { @@ -3203,8 +3616,11 @@ public: m_displayType = dispType; } ASTNODE_NODE_FUNCS(ElabDisplay) - virtual const char* broken() const { BROKEN_RTN(!fmtp()); return NULL; } - virtual string verilogKwd() const { return (string("$")+string(displayType().ascii())); } + virtual const char* broken() const { + BROKEN_RTN(!fmtp()); + return NULL; + } + virtual string verilogKwd() const { return (string("$") + string(displayType().ascii())); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering @@ -3212,7 +3628,8 @@ public: virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(displayType()); } virtual bool same(const AstNode* samep) const { - return displayType()==static_cast(samep)->displayType(); } + return displayType() == static_cast(samep)->displayType(); + } virtual int instrCount() const { return instrCountPli(); } AstDisplayType displayType() const { return m_displayType; } void displayType(AstDisplayType type) { m_displayType = type; } @@ -3232,7 +3649,10 @@ public: setOp3p(lhsp); } ASTNODE_NODE_FUNCS(SFormat) - virtual const char* broken() const { BROKEN_RTN(!fmtp()); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(!fmtp()); + return NULL; + } virtual string verilogKwd() const { return "$sformat"; } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); } @@ -3256,7 +3676,9 @@ class AstSysFuncAsTask : public AstNodeStmt { // Children: a system function public: AstSysFuncAsTask(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { addNOp1p(exprsp); } + : ASTGEN_SUPER(fl) { + addNOp1p(exprsp); + } ASTNODE_NODE_FUNCS(SysFuncAsTask) virtual string verilogKwd() const { return ""; } virtual bool isGateOptimizable() const { return true; } @@ -3275,7 +3697,9 @@ class AstSysIgnore : public AstNodeStmt { // Children: varrefs or exprs public: AstSysIgnore(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { addNOp1p(exprsp); } + : ASTGEN_SUPER(fl) { + addNOp1p(exprsp); + } ASTNODE_NODE_FUNCS(SysIgnore) virtual string verilogKwd() const { return "$ignored"; } virtual bool isGateOptimizable() const { return false; } // Though deleted before opt @@ -3359,8 +3783,7 @@ class AstFRead : public AstNodeMath { // Children: low index // Children: count public: - AstFRead(FileLine* fl, AstNode* memp, AstNode* filep, - AstNode* startp, AstNode* countp) + AstFRead(FileLine* fl, AstNode* memp, AstNode* filep, AstNode* startp, AstNode* countp) : ASTGEN_SUPER(fl) { setOp1p(memp); setOp2p(filep); @@ -3442,8 +3865,7 @@ class AstFSeek : public AstNodeMath { // Children: offset // Children: operation public: - AstFSeek(FileLine* fl, AstNode* filep, - AstNode* offset, AstNode* operation) + AstFSeek(FileLine* fl, AstNode* filep, AstNode* offset, AstNode* operation) : ASTGEN_SUPER(fl) { setOp2p(filep); setNOp3p(offset); @@ -3473,10 +3895,12 @@ class AstFScanF : public AstNodeMath { // Children: file which must be a varref // Children: varrefs to load private: - string m_text; + string m_text; + public: AstFScanF(FileLine* fl, const string& text, AstNode* filep, AstNode* exprsp) - : ASTGEN_SUPER(fl), m_text(text) { + : ASTGEN_SUPER(fl) + , m_text(text) { addNOp1p(exprsp); setNOp2p(filep); } @@ -3492,7 +3916,8 @@ public: virtual bool cleanOut() const { return false; } virtual V3Hash sameHash() const { return V3Hash(text()); } virtual bool same(const AstNode* samep) const { - return text()==static_cast(samep)->text(); } + return text() == static_cast(samep)->text(); + } AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output string text() const { return m_text; } // * = Text to display @@ -3506,10 +3931,12 @@ class AstSScanF : public AstNodeMath { // Children: file which must be a varref // Children: varrefs to load private: - string m_text; + string m_text; + public: AstSScanF(FileLine* fl, const string& text, AstNode* fromp, AstNode* exprsp) - : ASTGEN_SUPER(fl), m_text(text) { + : ASTGEN_SUPER(fl) + , m_text(text) { addNOp1p(exprsp); setOp2p(fromp); } @@ -3525,7 +3952,8 @@ public: virtual bool cleanOut() const { return false; } virtual V3Hash sameHash() const { return V3Hash(text()); } virtual bool same(const AstNode* samep) const { - return text()==static_cast(samep)->text(); } + return text() == static_cast(samep)->text(); + } AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output string text() const { return m_text; } // * = Text to display @@ -3538,11 +3966,14 @@ class AstNodeReadWriteMem : public AstNodeStmt { private: bool m_isHex; // readmemh, not readmemb public: - AstNodeReadWriteMem(AstType t, FileLine* fl, bool hex, - AstNode* filenamep, AstNode* memp, + AstNodeReadWriteMem(AstType t, FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) - : AstNodeStmt(t, fl), m_isHex(hex) { - setOp1p(filenamep); setOp2p(memp); setNOp3p(lsbp); setNOp4p(msbp); + : AstNodeStmt(t, fl) + , m_isHex(hex) { + setOp1p(filenamep); + setOp2p(memp); + setNOp3p(lsbp); + setNOp4p(msbp); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } @@ -3551,7 +3982,7 @@ public: virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { - return isHex()==static_cast(samep)->isHex(); + return isHex() == static_cast(samep)->isHex(); } bool isHex() const { return m_isHex; } AstNode* filenamep() const { return op1p(); } @@ -3573,11 +4004,10 @@ public: class AstWriteMem : public AstNodeReadWriteMem { public: - AstWriteMem(FileLine* fl, - AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) - : ASTGEN_SUPER(fl, true, filenamep, memp, lsbp, msbp) { } + AstWriteMem(FileLine* fl, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) + : ASTGEN_SUPER(fl, true, filenamep, memp, lsbp, msbp) {} ASTNODE_NODE_FUNCS(WriteMem) - virtual string verilogKwd() const { return (isHex()?"$writememh":"$writememb"); } + virtual string verilogKwd() const { return (isHex() ? "$writememh" : "$writememb"); } virtual const char* cFuncPrefixp() const { return "VL_WRITEMEM_"; } }; @@ -3628,7 +4058,8 @@ class AstValuePlusArgs : public AstNodeMath { public: AstValuePlusArgs(FileLine* fl, AstNode* searchp, AstNode* outp) : ASTGEN_SUPER(fl) { - setOp1p(searchp); setOp2p(outp); + setOp1p(searchp); + setOp2p(outp); } ASTNODE_NODE_FUNCS(ValuePlusArgs) virtual string verilogKwd() const { return "$value$plusargs"; } @@ -3649,7 +4080,8 @@ class AstTestPlusArgs : public AstNodeMath { // Parents: expr // Child: variable to set. If NULL then this is a $test$plusargs instead of $value$plusargs private: - string m_text; + string m_text; + public: AstTestPlusArgs(FileLine* fl, const string& text) : ASTGEN_SUPER(fl) @@ -3664,7 +4096,8 @@ public: virtual bool cleanOut() const { return true; } virtual V3Hash sameHash() const { return V3Hash(text()); } virtual bool same(const AstNode* samep) const { - return text() == static_cast(samep)->text(); } + return text() == static_cast(samep)->text(); + } string text() const { return m_text; } // * = Text to display void text(const string& text) { m_text = text; } }; @@ -3680,7 +4113,9 @@ class AstForeach : public AstNodeStmt { public: AstForeach(FileLine* fl, AstNode* arrayp, AstNode* varsp, AstNode* bodysp) : ASTGEN_SUPER(fl) { - setOp1p(arrayp); addNOp2p(varsp); addNOp4p(bodysp); + setOp1p(arrayp); + addNOp2p(varsp); + addNOp4p(bodysp); } ASTNODE_NODE_FUNCS(Foreach) AstNode* arrayp() const { return op1p(); } // op1 = array @@ -3696,7 +4131,8 @@ class AstRepeat : public AstNodeStmt { public: AstRepeat(FileLine* fl, AstNode* countp, AstNode* bodysp) : ASTGEN_SUPER(fl) { - setOp2p(countp); addNOp3p(bodysp); + setOp2p(countp); + addNOp3p(bodysp); } ASTNODE_NODE_FUNCS(Repeat) AstNode* countp() const { return op2p(); } // op2 = condition to continue @@ -3709,12 +4145,15 @@ public: class AstWhile : public AstNodeStmt { public: - AstWhile(FileLine* fl, AstNode* condp, AstNode* bodysp, AstNode* incsp=NULL) + AstWhile(FileLine* fl, AstNode* condp, AstNode* bodysp, AstNode* incsp = NULL) : ASTGEN_SUPER(fl) { - setOp2p(condp); addNOp3p(bodysp); addNOp4p(incsp); + setOp2p(condp); + addNOp3p(bodysp); + addNOp4p(incsp); } ASTNODE_NODE_FUNCS(While) - AstNode* precondsp() const { return op1p(); } // op1 = prepare statements for condition (exec every loop) + // op1 = prepare statements for condition (exec every loop) + AstNode* precondsp() const { return op1p(); } AstNode* condp() const { return op2p(); } // op2 = condition to continue AstNode* bodysp() const { return op3p(); } // op3 = body of loop AstNode* incsp() const { return op4p(); } // op4 = increment (if from a FOR loop) @@ -3736,7 +4175,9 @@ public: ASTNODE_NODE_FUNCS(Break) virtual string verilogKwd() const { return "break"; } virtual V3Hash sameHash() const { return V3Hash(); } - virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks + virtual bool isBrancher() const { + return true; // SPECIAL: We don't process code after breaks + } }; class AstContinue : public AstNodeStmt { @@ -3746,7 +4187,9 @@ public: ASTNODE_NODE_FUNCS(Continue) virtual string verilogKwd() const { return "continue"; } virtual V3Hash sameHash() const { return V3Hash(); } - virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks + virtual bool isBrancher() const { + return true; // SPECIAL: We don't process code after breaks + } }; class AstDisable : public AstNodeStmt { @@ -3754,11 +4197,14 @@ private: string m_name; // Name of block public: AstDisable(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl), m_name(name) {} + : ASTGEN_SUPER(fl) + , m_name(name) {} ASTNODE_NODE_FUNCS(Disable) virtual string name() const { return m_name; } // * = Block name void name(const string& flag) { m_name = flag; } - virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks + virtual bool isBrancher() const { + return true; // SPECIAL: We don't process code after breaks + } }; class AstReturn : public AstNodeStmt { @@ -3771,7 +4217,9 @@ public: virtual string verilogKwd() const { return "return"; } virtual V3Hash sameHash() const { return V3Hash(); } AstNode* lhsp() const { return op1p(); } - virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks + virtual bool isBrancher() const { + return true; // SPECIAL: We don't process code after breaks + } }; class AstGenIf : public AstNodeIf { @@ -3783,13 +4231,15 @@ public: class AstIf : public AstNodeIf { private: - bool m_uniquePragma; // unique case - bool m_unique0Pragma; // unique0 case - bool m_priorityPragma; // priority case + bool m_uniquePragma; // unique case + bool m_unique0Pragma; // unique0 case + bool m_priorityPragma; // priority case public: - AstIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp=NULL) + AstIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp = NULL) : ASTGEN_SUPER(fl, condp, ifsp, elsesp) { - m_uniquePragma = false; m_unique0Pragma = false; m_priorityPragma = false; + m_uniquePragma = false; + m_unique0Pragma = false; + m_priorityPragma = false; } ASTNODE_NODE_FUNCS(If) bool uniquePragma() const { return m_uniquePragma; } @@ -3809,7 +4259,8 @@ private: int m_labelNum; // Set by V3EmitCSyms to tell final V3Emit what to increment public: AstJumpLabel(FileLine* fl, AstNode* stmtsp) - : ASTGEN_SUPER(fl), m_labelNum(0) { + : ASTGEN_SUPER(fl) + , m_labelNum(0) { addNOp1p(stmtsp); } virtual int instrCount() const { return 0; } @@ -3835,15 +4286,24 @@ public: m_labelp = labelp; } ASTNODE_NODE_FUNCS(JumpGo) - virtual const char* broken() const { BROKEN_RTN(!labelp()->brokeExistsAbove()); return NULL; } - virtual void cloneRelink() { if (m_labelp->clonep()) m_labelp = m_labelp->clonep(); } + virtual const char* broken() const { + BROKEN_RTN(!labelp()->brokeExistsAbove()); + return NULL; + } + virtual void cloneRelink() { + if (m_labelp->clonep()) m_labelp = m_labelp->clonep(); + } virtual void dump(std::ostream& str) const; virtual int instrCount() const { return instrCountBranch(); } virtual V3Hash sameHash() const { return V3Hash(labelp()); } - virtual bool same(const AstNode* samep) const { // Also same if identical tree structure all the way down, but hard to detect - return labelp() == static_cast(samep)->labelp(); } + virtual bool same(const AstNode* samep) const { + // Also same if identical tree structure all the way down, but hard to detect + return labelp() == static_cast(samep)->labelp(); + } virtual bool isGateOptimizable() const { return false; } - virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks + virtual bool isBrancher() const { + return true; // SPECIAL: We don't process code after breaks + } AstJumpLabel* labelp() const { return m_labelp; } }; @@ -3858,8 +4318,12 @@ public: dtypeSetUInt32(); // Always used on, and returns word entities } ASTNODE_NODE_FUNCS(ChangeXor) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstChangeXor(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opChangeXor(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstChangeXor(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opChangeXor(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f^ %r)"; } virtual string emitC() { return "VL_CHANGEXOR_%li(%lw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "^"; } @@ -3879,7 +4343,9 @@ public: // Null lhs+rhs used to indicate change needed with no spec vars AstChangeDet(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool clockReq) : ASTGEN_SUPER(fl) { - setNOp1p(lhsp); setNOp2p(rhsp); m_clockReq = clockReq; + setNOp1p(lhsp); + setNOp2p(rhsp); + m_clockReq = clockReq; } ASTNODE_NODE_FUNCS(ChangeDet) AstNode* lhsp() const { return op1p(); } @@ -3897,10 +4363,10 @@ class AstBegin : public AstNode { // Parents: statement // Children: statements private: - string m_name; // Name of block - bool m_unnamed; // Originally unnamed (name change does not affect this) - bool m_generate; // Underneath a generate - bool m_implied; // Not inserted by user + string m_name; // Name of block + bool m_unnamed; // Originally unnamed (name change does not affect this) + bool m_generate; // Underneath a generate + bool m_implied; // Not inserted by user public: // Node that simply puts name into the output stream AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false, @@ -3954,12 +4420,14 @@ class AstInside : public AstNodeMath { public: AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp) : ASTGEN_SUPER(fl) { - addOp1p(exprp); addOp2p(itemsp); + addOp1p(exprp); + addOp2p(itemsp); dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(Inside) AstNode* exprp() const { return op1p(); } // op1 = LHS expression to compare with - AstNode* itemsp() const { return op2p(); } // op2 = RHS, possibly a list of expr or AstInsideRange + // op2 = RHS, possibly a list of expr or AstInsideRange + AstNode* itemsp() const { return op2p(); } virtual string emitVerilog() { return "%l inside { %r }"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return false; } // NA @@ -3969,7 +4437,8 @@ class AstInsideRange : public AstNodeMath { public: AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl) { - addOp1p(lhsp); addOp2p(rhsp); + addOp1p(lhsp); + addOp2p(rhsp); } ASTNODE_NODE_FUNCS(InsideRange) AstNode* lhsp() const { return op1p(); } // op1 = LHS @@ -3988,7 +4457,9 @@ class AstInitItem : public AstNode { public: // Parents: INITARRAY AstInitItem(FileLine* fl, AstNode* valuep) - : ASTGEN_SUPER(fl) { addOp1p(valuep); } + : ASTGEN_SUPER(fl) { + addOp1p(valuep); + } ASTNODE_NODE_FUNCS(InitItem) virtual bool maybePointedTo() const { return true; } virtual bool hasDType() const { return false; } // See valuep()'s dtype instead @@ -4006,6 +4477,7 @@ class AstInitArray : public AstNode { // Children: AstInitItem public: typedef std::map KeyItemMap; + private: KeyItemMap m_map; // Node value for each array index public: @@ -4056,8 +4528,11 @@ public: } AstNode* getIndexValuep(uint32_t index) const { KeyItemMap::const_iterator it = m_map.find(index); - if (it == m_map.end()) return NULL; - else return it->second->valuep(); + if (it == m_map.end()) { + return NULL; + } else { + return it->second->valuep(); + } } AstNode* getIndexDefaultedValuep(uint32_t index) const { AstNode* valuep = getIndexValuep(index); @@ -4141,7 +4616,8 @@ public: virtual V3Hash sameHash() const { return V3Hash(pragType()); } virtual bool isPredictOptimizable() const { return false; } virtual bool same(const AstNode* samep) const { - return pragType() == static_cast(samep)->pragType(); } + return pragType() == static_cast(samep)->pragType(); + } }; class AstStop : public AstNodeStmt { @@ -4156,8 +4632,7 @@ public: virtual bool isUnlikely() const { return true; } virtual int instrCount() const { return 0; } // Rarely executes virtual V3Hash sameHash() const { return V3Hash(fileline()->lineno()); } - virtual bool same(const AstNode* samep) const { - return fileline() == samep->fileline(); } + virtual bool same(const AstNode* samep) const { return fileline() == samep->fileline(); } }; class AstFinish : public AstNodeStmt { @@ -4172,8 +4647,7 @@ public: virtual bool isUnlikely() const { return true; } virtual int instrCount() const { return 0; } // Rarely executes virtual V3Hash sameHash() const { return V3Hash(fileline()->lineno()); } - virtual bool same(const AstNode* samep) const { - return fileline() == samep->fileline(); } + virtual bool same(const AstNode* samep) const { return fileline() == samep->fileline(); } }; class AstNullCheck : public AstNodeUniop { @@ -4203,29 +4677,30 @@ class AstTraceDecl : public AstNodeStmt { // Parents: {statement list} // Children: none private: - string m_showname; // Name of variable - uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines - VNumRange m_bitRange; // Property of var the trace details - VNumRange m_arrayRange; // Property of var the trace details - uint32_t m_codeInc; // Code increment - AstVarType m_varType; // Type of variable (for localparam vs. param) + string m_showname; // Name of variable + uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines + VNumRange m_bitRange; // Property of var the trace details + VNumRange m_arrayRange; // Property of var the trace details + uint32_t m_codeInc; // Code increment + AstVarType m_varType; // Type of variable (for localparam vs. param) AstBasicDTypeKwd m_declKwd; // Keyword at declaration time - VDirection m_declDirection; // Declared direction input/output etc - bool m_isScoped; // Uses run-time scope (for interfaces) + VDirection m_declDirection; // Declared direction input/output etc + bool m_isScoped; // Uses run-time scope (for interfaces) public: AstTraceDecl(FileLine* fl, const string& showname, AstVar* varp, // For input/output state etc - AstNode* valuep, - const VNumRange& bitRange, const VNumRange& arrayRange, + AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange, bool isScoped) : ASTGEN_SUPER(fl) - , m_showname(showname), m_bitRange(bitRange), m_arrayRange(arrayRange) + , m_showname(showname) + , m_bitRange(bitRange) + , m_arrayRange(arrayRange) , m_isScoped(isScoped) { dtypeFrom(valuep); m_code = 0; - m_codeInc = ((arrayRange.ranged() ? arrayRange.elements() : 1) - * valuep->dtypep()->widthWords() - * (VL_EDATASIZE / (8*sizeof(uint32_t)))); // A code is always 32-bits + m_codeInc + = ((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords() + * (VL_EDATASIZE / (8 * sizeof(uint32_t)))); // A code is always 32-bits m_varType = varp->varType(); m_declKwd = varp->declKwd(); m_declDirection = varp->declDirection(); @@ -4254,7 +4729,7 @@ class AstTraceInc : public AstNodeStmt { // Parents: {statement list} // Children: incremental value private: - AstTraceDecl* m_declp; // [After V3Trace] Pointer to declaration + AstTraceDecl* m_declp; // [After V3Trace] Pointer to declaration public: AstTraceInc(FileLine* fl, AstTraceDecl* declp, AstNode* valuep) : ASTGEN_SUPER(fl) { @@ -4263,20 +4738,28 @@ public: addNOp2p(valuep); } ASTNODE_NODE_FUNCS(TraceInc) - virtual const char* broken() const { BROKEN_RTN(!declp()->brokeExists()); return NULL; } - virtual void cloneRelink() { if (m_declp->clonep()) m_declp = m_declp->clonep(); } + virtual const char* broken() const { + BROKEN_RTN(!declp()->brokeExists()); + return NULL; + } + virtual void cloneRelink() { + if (m_declp->clonep()) m_declp = m_declp->clonep(); + } virtual void dump(std::ostream& str) const; - virtual int instrCount() const { return 10+2*instrCountLd(); } + virtual int instrCount() const { return 10 + 2 * instrCountLd(); } virtual bool hasDType() const { return true; } virtual V3Hash sameHash() const { return V3Hash(declp()); } virtual bool same(const AstNode* samep) const { - return declp() == static_cast(samep)->declp(); } + return declp() == static_cast(samep)->declp(); + } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isOutputter() const { return true; } // but isPure() true // op1 = Statements before the value - AstNode* precondsp() const { return op1p(); } // op1 = prepare statements for condition (exec every loop) + AstNode* precondsp() const { + return op1p(); + } // op1 = prepare statements for condition (exec every loop) void addPrecondsp(AstNode* newp) { addOp1p(newp); } // op2 = Value to trace AstTraceDecl* declp() const { return m_declp; } // Where defined @@ -4288,8 +4771,9 @@ class AstActive : public AstNode { // Parents: MODULE | CFUNC // Children: SENTREE, statements private: - string m_name; + string m_name; AstSenTree* m_sensesp; + public: AstActive(FileLine* fl, const string& name, AstSenTree* sensesp) : ASTGEN_SUPER(fl) { @@ -4298,13 +4782,16 @@ public: m_sensesp = sensesp; } ASTNODE_NODE_FUNCS(Active) - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; virtual string name() const { return m_name; } - virtual const char* broken() const { BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); + return NULL; + } virtual void cloneRelink() { if (m_sensesp->clonep()) { m_sensesp = m_sensesp->clonep(); - UASSERT(m_sensesp, "Bad clone cross link: "<(samep)->m_dpiExport; } + return m_dpiExport == static_cast(samep)->m_dpiExport; + } virtual string emitVerilog() { return ""; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } @@ -4366,13 +4856,17 @@ public: AstText* scopeEntrp() const { return VN_CAST(op2p(), Text); } void scopeEntrp(AstNode* nodep) { addOp2p(nodep); } string scopeSymName() const { // Name for __Vscope variable including children - return scopeNameFormatter(scopeAttrp()); } + return scopeNameFormatter(scopeAttrp()); + } string scopeDpiName() const { // Name for DPI import scope - return scopeNameFormatter(scopeEntrp()); } + return scopeNameFormatter(scopeEntrp()); + } string scopePrettySymName() const { // Name for __Vscope variable including children - return scopePrettyNameFormatter(scopeAttrp()); } + return scopePrettyNameFormatter(scopeAttrp()); + } string scopePrettyDpiName() const { // Name for __Vscope variable including children - return scopePrettyNameFormatter(scopeEntrp()); } + return scopePrettyNameFormatter(scopeEntrp()); + } bool dpiExport() const { return m_dpiExport; } void dpiExport(bool flag) { m_dpiExport = flag; } }; @@ -4384,11 +4878,13 @@ public: addNOp1p(bodysp); } ASTNODE_NODE_FUNCS(UdpTable) - AstUdpTableLine* bodysp() const { return VN_CAST(op1p(), UdpTableLine); } // op1 = List of UdpTableLines + // op1 = List of UdpTableLines + AstUdpTableLine* bodysp() const { return VN_CAST(op1p(), UdpTableLine); } }; class AstUdpTableLine : public AstNode { - string m_text; + string m_text; + public: AstUdpTableLine(FileLine* fl, const string& text) : ASTGEN_SUPER(fl) @@ -4407,16 +4903,18 @@ private: bool m_reset; // Random reset, versus always random public: AstRand(FileLine* fl, AstNodeDType* dtp, bool reset) - : ASTGEN_SUPER(fl) { dtypep(dtp); m_reset = reset; } + : ASTGEN_SUPER(fl) { + dtypep(dtp); + m_reset = reset; + } explicit AstRand(FileLine* fl) : ASTGEN_SUPER(fl) , m_reset(false) {} ASTNODE_NODE_FUNCS(Rand) virtual string emitVerilog() { return "%f$random"; } virtual string emitC() { - return (m_reset ? - "VL_RAND_RESET_%nq(%nw, %P)" - :"VL_RANDOM_%nq(%nw, %P)"); } + return (m_reset ? "VL_RAND_RESET_%nq(%nw, %P)" : "VL_RANDOM_%nq(%nw, %P)"); + } virtual bool cleanOut() const { return true; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } @@ -4428,7 +4926,9 @@ public: class AstTime : public AstNodeTermop { public: explicit AstTime(FileLine* fl) - : ASTGEN_SUPER(fl) { dtypeSetUInt64(); } + : ASTGEN_SUPER(fl) { + dtypeSetUInt64(); + } ASTNODE_NODE_FUNCS(Time) virtual string emitVerilog() { return "%f$time"; } virtual string emitC() { return "VL_TIME_%nq()"; } @@ -4443,7 +4943,9 @@ public: class AstTimeD : public AstNodeTermop { public: explicit AstTimeD(FileLine* fl) - : ASTGEN_SUPER(fl) { dtypeSetDouble(); } + : ASTGEN_SUPER(fl) { + dtypeSetDouble(); + } ASTNODE_NODE_FUNCS(TimeD) virtual string emitVerilog() { return "%f$realtime"; } virtual string emitC() { return "VL_TIME_D()"; } @@ -4484,7 +4986,9 @@ public: class AstNegate : public AstNodeUniop { public: AstNegate(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(Negate) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegate(lhs); } virtual string emitVerilog() { return "%f(- %l)"; } @@ -4496,7 +5000,9 @@ public: class AstNegateD : public AstNodeUniop { public: AstNegateD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetDouble(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetDouble(); + } ASTNODE_NODE_FUNCS(NegateD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegateD(lhs); } virtual string emitVerilog() { return "%f(- %l)"; } @@ -4511,7 +5017,9 @@ public: class AstRedAnd : public AstNodeUniop { public: AstRedAnd(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(RedAnd) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedAnd(lhs); } virtual string emitVerilog() { return "%f(& %l)"; } @@ -4523,7 +5031,9 @@ public: class AstRedOr : public AstNodeUniop { public: AstRedOr(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(RedOr) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedOr(lhs); } virtual string emitVerilog() { return "%f(| %l)"; } @@ -4535,37 +5045,48 @@ public: class AstRedXor : public AstNodeUniop { public: AstRedXor(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(RedXor) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedXor(lhs); } virtual string emitVerilog() { return "%f(^ %l)"; } virtual string emitC() { return "VL_REDXOR_%lq(%lW, %P, %li)"; } virtual bool cleanOut() const { return false; } - virtual bool cleanLhs() const {int w = lhsp()->width(); - return (w!=1 && w!=2 && w!=4 && w!=8 && w!=16); } + virtual bool cleanLhs() const { + int w = lhsp()->width(); + return (w != 1 && w != 2 && w != 4 && w != 8 && w != 16); + } virtual bool sizeMattersLhs() const { return false; } - virtual int instrCount() const { return 1+V3Number::log2b(width()); } + virtual int instrCount() const { return 1 + V3Number::log2b(width()); } }; class AstRedXnor : public AstNodeUniop { // AstRedXnors are replaced with AstRedXors in V3Const. public: AstRedXnor(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(RedXnor) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedXnor(lhs); } virtual string emitVerilog() { return "%f(~^ %l)"; } - virtual string emitC() { v3fatalSrc("REDXNOR should have became REDXOR"); return ""; } + virtual string emitC() { + v3fatalSrc("REDXNOR should have became REDXOR"); + return ""; + } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } - virtual int instrCount() const { return 1+V3Number::log2b(width()); } + virtual int instrCount() const { return 1 + V3Number::log2b(width()); } }; class AstLenN : public AstNodeUniop { // Length of a string public: AstLenN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetSigned32(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetSigned32(); + } ASTNODE_NODE_FUNCS(LenN) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opLenN(lhs); } virtual string emitVerilog() { return "%f(%l)"; } @@ -4577,7 +5098,9 @@ public: class AstLogNot : public AstNodeUniop { public: AstLogNot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LogNot) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opLogNot(lhs); } virtual string emitVerilog() { return "%f(! %l)"; } @@ -4590,7 +5113,9 @@ public: class AstNot : public AstNodeUniop { public: AstNot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(Not) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNot(lhs); } virtual string emitVerilog() { return "%f(~ %l)"; } @@ -4606,14 +5131,18 @@ public: AstExtend(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} AstExtend(FileLine* fl, AstNode* lhsp, int width) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetLogicSized(width, AstNumeric::UNSIGNED); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicSized(width, AstNumeric::UNSIGNED); + } ASTNODE_NODE_FUNCS(Extend) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); } virtual string emitVerilog() { return "%l"; } virtual string emitC() { return "VL_EXTEND_%nq%lq(%nw,%lw, %P, %li)"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } // Because the EXTEND operator self-casts + virtual bool sizeMattersLhs() const { + return false; // Because the EXTEND operator self-casts + } virtual int instrCount() const { return 0; } }; class AstExtendS : public AstNodeUniop { @@ -4623,7 +5152,9 @@ public: : ASTGEN_SUPER(fl, lhsp) {} AstExtendS(FileLine* fl, AstNode* lhsp, int width) // Important that widthMin be correct, as opExtend requires it after V3Expand - : ASTGEN_SUPER(fl, lhsp) { dtypeSetLogicSized(width, AstNumeric::UNSIGNED); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicSized(width, AstNumeric::UNSIGNED); + } ASTNODE_NODE_FUNCS(ExtendS) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opExtendS(lhs, lhsp()->widthMinV()); @@ -4632,7 +5163,9 @@ public: virtual string emitC() { return "VL_EXTENDS_%nq%lq(%nw,%lw, %P, %li)"; } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } // Because the EXTEND operator self-casts + virtual bool sizeMattersLhs() const { + return false; // Because the EXTEND operator self-casts + } virtual int instrCount() const { return 0; } virtual bool signedFlavor() const { return true; } }; @@ -4642,9 +5175,13 @@ public: AstSigned(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, - "not coded to create after dtypes resolved"); } + "not coded to create after dtypes resolved"); + } ASTNODE_NODE_FUNCS(Signed) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); out.isSigned(false); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.opAssign(lhs); + out.isSigned(false); + } virtual string emitVerilog() { return "%f$signed(%l)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return false; } @@ -4658,9 +5195,13 @@ public: AstUnsigned(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, - "not coded to create after dtypes resolved"); } + "not coded to create after dtypes resolved"); + } ASTNODE_NODE_FUNCS(Unsigned) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); out.isSigned(false); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.opAssign(lhs); + out.isSigned(false); + } virtual string emitVerilog() { return "%f$unsigned(%l)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return false; } @@ -4672,7 +5213,9 @@ class AstRToIS : public AstNodeUniop { // $rtoi(lhs) public: AstRToIS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetSigned32(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetSigned32(); + } ASTNODE_NODE_FUNCS(RToIS) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRToIS(lhs); } virtual string emitVerilog() { return "%f$rtoi(%l)"; } @@ -4701,7 +5244,9 @@ public: class AstIToRD : public AstNodeUniop { public: AstIToRD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetDouble(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetDouble(); + } ASTNODE_NODE_FUNCS(IToRD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIToRD(lhs); } virtual string emitVerilog() { return "%f$itor(%l)"; } @@ -4714,7 +5259,9 @@ public: class AstRealToBits : public AstNodeUniop { public: AstRealToBits(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetUInt64(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetUInt64(); + } ASTNODE_NODE_FUNCS(RealToBits) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRealToBits(lhs); } virtual string emitVerilog() { return "%f$realtobits(%l)"; } @@ -4727,7 +5274,9 @@ public: class AstBitsToRealD : public AstNodeUniop { public: AstBitsToRealD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetDouble(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetDouble(); + } ASTNODE_NODE_FUNCS(BitsToRealD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opBitsToRealD(lhs); } virtual string emitVerilog() { return "%f$bitstoreal(%l)"; } @@ -4749,7 +5298,7 @@ public: virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*16; } + virtual int instrCount() const { return widthInstrs() * 16; } }; class AstCountOnes : public AstNodeUniop { // Number of bits set in vector @@ -4763,13 +5312,15 @@ public: virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*16; } + virtual int instrCount() const { return widthInstrs() * 16; } }; class AstIsUnknown : public AstNodeUniop { // True if any unknown bits public: AstIsUnknown(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(IsUnknown) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIsUnknown(lhs); } virtual string emitVerilog() { return "%f$isunknown(%l)"; } @@ -4782,7 +5333,9 @@ class AstOneHot : public AstNodeUniop { // True if only single bit set in vector public: AstOneHot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(OneHot) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opOneHot(lhs); } virtual string emitVerilog() { return "%f$onehot(%l)"; } @@ -4790,13 +5343,15 @@ public: virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*4; } + virtual int instrCount() const { return widthInstrs() * 4; } }; class AstOneHot0 : public AstNodeUniop { // True if only single bit, or no bits set in vector public: AstOneHot0(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(OneHot0) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opOneHot0(lhs); } virtual string emitVerilog() { return "%f$onehot0(%l)"; } @@ -4804,7 +5359,7 @@ public: virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*3; } + virtual int instrCount() const { return widthInstrs() * 3; } }; class AstCast : public AstNode { @@ -4812,7 +5367,8 @@ class AstCast : public AstNode { public: AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtp) : ASTGEN_SUPER(fl) { - setOp1p(lhsp); setOp2p(dtp); + setOp1p(lhsp); + setOp2p(dtp); dtypeFrom(dtp); } ASTNODE_NODE_FUNCS(Cast) @@ -4832,7 +5388,8 @@ class AstCastParse : public AstNode { public: AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp) : ASTGEN_SUPER(fl) { - setOp1p(lhsp); setOp2p(dtp); + setOp1p(lhsp); + setOp2p(dtp); } ASTNODE_NODE_FUNCS(CastParse) virtual string emitVerilog() { return "((%d)'(%l))"; } @@ -4849,7 +5406,8 @@ class AstCastSize : public AstNode { public: AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) : ASTGEN_SUPER(fl) { - setOp1p(lhsp); setOp2p(rhsp); + setOp1p(lhsp); + setOp2p(rhsp); } ASTNODE_NODE_FUNCS(CastSize) // No hasDType because widthing removes this node before the hasDType check @@ -4865,13 +5423,14 @@ public: class AstCCast : public AstNodeUniop { // Cast to C-based data type private: - int m_size; + int m_size; + public: - AstCCast(FileLine* fl, AstNode* lhsp, int setwidth, int minwidth=-1) + AstCCast(FileLine* fl, AstNode* lhsp, int setwidth, int minwidth = -1) : ASTGEN_SUPER(fl, lhsp) { m_size = setwidth; if (setwidth) { - if (minwidth==-1) minwidth = setwidth; + if (minwidth == -1) minwidth = setwidth; dtypeSetLogicUnsized(setwidth, minwidth, AstNumeric::UNSIGNED); } } @@ -4889,8 +5448,9 @@ public: virtual bool sizeMattersLhs() const { return false; } // Special cased in V3Cast virtual V3Hash sameHash() const { return V3Hash(size()); } virtual bool same(const AstNode* samep) const { - return size() == static_cast(samep)->size(); } - virtual void dump(std::ostream& str=std::cout) const; + return size() == static_cast(samep)->size(); + } + virtual void dump(std::ostream& str = std::cout) const; // int size() const { return m_size; } }; @@ -4899,7 +5459,9 @@ class AstCvtPackString : public AstNodeUniop { // Convert to Verilator Packed String (aka verilog "string") public: AstCvtPackString(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetString(); } // Really, width should be dtypep -> STRING + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetString(); + } ASTNODE_NODE_FUNCS(CvtPackString) virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } virtual string emitVerilog() { return "%f$_CAST(%l)"; } @@ -4922,7 +5484,7 @@ public: virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*16; } + virtual int instrCount() const { return widthInstrs() * 16; } virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering AstNode* filep() const { return lhsp(); } }; @@ -4963,7 +5525,7 @@ public: virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*64; } + virtual int instrCount() const { return widthInstrs() * 64; } virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering AstNode* filep() const { return lhsp(); } }; @@ -4973,9 +5535,12 @@ public: AstFUngetC(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(FUngetC) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + V3ERROR_NA; + } virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { - return new AstFUngetC(this->fileline(), lhsp, rhsp); } + return new AstFUngetC(this->fileline(), lhsp, rhsp); + } virtual string emitVerilog() { return "%f$ungetc(%r, %l)"; } // Non-existent filehandle returns EOF virtual string emitC() { return "(%li ? (ungetc(%ri, VL_CVT_I_FP(%li)) >= 0 ? 0 : -1) : -1)"; } @@ -4993,7 +5558,9 @@ public: class AstNodeSystemUniop : public AstNodeUniop { public: AstNodeSystemUniop(AstType t, FileLine* fl, AstNode* lhsp) - : AstNodeUniop(t, fl, lhsp) { dtypeSetDouble(); } + : AstNodeUniop(t, fl, lhsp) { + dtypeSetDouble(); + } ASTNODE_BASE_FUNCS(NodeSystemUniop) virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return false; } @@ -5007,7 +5574,9 @@ public: AstLogD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(LogD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(log(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(log(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$ln(%l)"; } virtual string emitC() { return "log(%li)"; } }; @@ -5016,7 +5585,9 @@ public: AstLog10D(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(Log10D) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(log10(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(log10(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$log10(%l)"; } virtual string emitC() { return "log10(%li)"; } }; @@ -5026,7 +5597,9 @@ public: AstExpD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(ExpD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(exp(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(exp(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$exp(%l)"; } virtual string emitC() { return "exp(%li)"; } }; @@ -5036,7 +5609,9 @@ public: AstSqrtD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(SqrtD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(sqrt(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(sqrt(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$sqrt(%l)"; } virtual string emitC() { return "sqrt(%li)"; } }; @@ -5046,7 +5621,9 @@ public: AstFloorD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(FloorD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(floor(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(floor(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$floor(%l)"; } virtual string emitC() { return "floor(%li)"; } }; @@ -5056,7 +5633,9 @@ public: AstCeilD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(CeilD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(ceil(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(ceil(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$ceil(%l)"; } virtual string emitC() { return "ceil(%li)"; } }; @@ -5066,7 +5645,9 @@ public: AstSinD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(SinD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(sin(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(sin(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$sin(%l)"; } virtual string emitC() { return "sin(%li)"; } }; @@ -5076,7 +5657,9 @@ public: AstCosD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(CosD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(cos(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(cos(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$cos(%l)"; } virtual string emitC() { return "cos(%li)"; } }; @@ -5086,7 +5669,9 @@ public: AstTanD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(TanD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(tan(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(tan(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$tan(%l)"; } virtual string emitC() { return "tan(%li)"; } }; @@ -5096,7 +5681,9 @@ public: AstAsinD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(AsinD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(asin(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(asin(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$asin(%l)"; } virtual string emitC() { return "asin(%li)"; } }; @@ -5106,7 +5693,9 @@ public: AstAcosD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(AcosD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(acos(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(acos(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$acos(%l)"; } virtual string emitC() { return "acos(%li)"; } }; @@ -5116,7 +5705,9 @@ public: AstAtanD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(AtanD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(atan(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(atan(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$atan(%l)"; } virtual string emitC() { return "atan(%li)"; } }; @@ -5126,7 +5717,9 @@ public: AstSinhD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(SinhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(sinh(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(sinh(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$sinh(%l)"; } virtual string emitC() { return "sinh(%li)"; } }; @@ -5136,7 +5729,9 @@ public: AstCoshD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(CoshD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(cosh(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(cosh(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$cosh(%l)"; } virtual string emitC() { return "cosh(%li)"; } }; @@ -5146,7 +5741,9 @@ public: AstTanhD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(TanhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(tanh(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(tanh(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$tanh(%l)"; } virtual string emitC() { return "tanh(%li)"; } }; @@ -5156,7 +5753,9 @@ public: AstAsinhD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(AsinhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(asinh(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(asinh(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$asinh(%l)"; } virtual string emitC() { return "asinh(%li)"; } }; @@ -5166,7 +5765,9 @@ public: AstAcoshD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(AcoshD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(acosh(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(acosh(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$acosh(%l)"; } virtual string emitC() { return "acosh(%li)"; } }; @@ -5176,7 +5777,9 @@ public: AstAtanhD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} ASTNODE_NODE_FUNCS(AtanhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(atanh(lhs.toDouble())); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.setDouble(atanh(lhs.toDouble())); + } virtual string emitVerilog() { return "%f$atanh(%l)"; } virtual string emitC() { return "atanh(%li)"; } }; @@ -5184,7 +5787,9 @@ class AstToLowerN : public AstNodeUniop { // string.tolower() public: AstToLowerN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetString(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetString(); + } ASTNODE_NODE_FUNCS(ToLowerN) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opToLowerN(lhs); } virtual string emitVerilog() { return "%l.tolower()"; } @@ -5197,7 +5802,9 @@ class AstToUpperN : public AstNodeUniop { // string.toupper() public: AstToUpperN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { dtypeSetString(); } + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetString(); + } ASTNODE_NODE_FUNCS(ToUpperN) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opToUpperN(lhs); } virtual string emitVerilog() { return "%l.toupper()"; } @@ -5210,7 +5817,8 @@ public: class AstAtoN : public AstNodeUniop { // string.atoi(), atobin(), atohex(), atooct(), atoireal() public: - enum FmtType {ATOI = 10, ATOHEX = 16, ATOOCT = 8, ATOBIN = 2, ATOREAL = -1}; + enum FmtType { ATOI = 10, ATOHEX = 16, ATOOCT = 8, ATOBIN = 2, ATOREAL = -1 }; + private: FmtType m_fmt; // Operation type public: @@ -5254,10 +5862,16 @@ public: class AstLogOr : public AstNodeBiop { public: AstLogOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LogOr) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLogOr(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLogOr(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLogOr(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLogOr(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f|| %r)"; } virtual string emitC() { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "||"; } @@ -5266,15 +5880,21 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } + virtual int instrCount() const { return widthInstrs() + instrCountBranch(); } }; class AstLogAnd : public AstNodeBiop { public: AstLogAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LogAnd) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLogAnd(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLogAnd(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLogAnd(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLogAnd(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f&& %r)"; } virtual string emitC() { return "VL_LOGAND_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "&&"; } @@ -5283,17 +5903,21 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } + virtual int instrCount() const { return widthInstrs() + instrCountBranch(); } }; class AstLogEq : public AstNodeBiCom { public: AstLogEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LogEq) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { - return new AstLogEq(this->fileline(), lhsp, rhsp); } + return new AstLogEq(this->fileline(), lhsp, rhsp); + } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { - out.opLogEq(lhs, rhs); } + out.opLogEq(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f<-> %r)"; } virtual string emitC() { return "VL_LOGEQ_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "<->"; } @@ -5302,17 +5926,21 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } + virtual int instrCount() const { return widthInstrs() + instrCountBranch(); } }; class AstLogIf : public AstNodeBiop { public: AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LogIf) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { - return new AstLogIf(this->fileline(), lhsp, rhsp); } + return new AstLogIf(this->fileline(), lhsp, rhsp); + } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { - out.opLogIf(lhs, rhs); } + out.opLogIf(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f-> %r)"; } virtual string emitC() { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "->"; } @@ -5321,15 +5949,21 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } + virtual int instrCount() const { return widthInstrs() + instrCountBranch(); } }; class AstOr : public AstNodeBiComAsv { public: AstOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(Or) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstOr(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opOr(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstOr(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opOr(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f| %r)"; } virtual string emitC() { return "VL_OR_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "|"; } @@ -5342,10 +5976,16 @@ public: class AstAnd : public AstNodeBiComAsv { public: AstAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(And) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAnd(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAnd(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstAnd(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opAnd(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f& %r)"; } virtual string emitC() { return "VL_AND_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "&"; } @@ -5358,10 +5998,16 @@ public: class AstXor : public AstNodeBiComAsv { public: AstXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(Xor) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstXor(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opXor(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstXor(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opXor(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f^ %r)"; } virtual string emitC() { return "VL_XOR_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "^"; } @@ -5374,10 +6020,16 @@ public: class AstXnor : public AstNodeBiComAsv { public: AstXnor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(Xnor) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstXnor(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opXnor(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstXnor(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opXnor(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f^ ~ %r)"; } virtual string emitC() { return "VL_XNOR_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "^ ~"; } @@ -5390,11 +6042,18 @@ public: class AstEq : public AstNodeBiCom { public: AstEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(Eq) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEq(this->fileline(), lhsp, rhsp); } - static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp); // Return AstEq/AstEqD - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEq(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstEq(this->fileline(), lhsp, rhsp); + } + static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, + AstNode* rhsp); // Return AstEq/AstEqD + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opEq(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f== %r)"; } virtual string emitC() { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "=="; } @@ -5407,10 +6066,16 @@ public: class AstEqD : public AstNodeBiCom { public: AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(EqD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEqD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEqD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstEqD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opEqD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f== %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "=="; } @@ -5425,10 +6090,16 @@ public: class AstEqN : public AstNodeBiCom { public: AstEqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(EqN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEqN(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEqN(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstEqN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opEqN(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f== %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "=="; } @@ -5443,10 +6114,16 @@ public: class AstNeq : public AstNodeBiCom { public: AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(Neq) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstNeq(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeq(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstNeq(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opNeq(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f!= %r)"; } virtual string emitC() { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "!="; } @@ -5459,10 +6136,16 @@ public: class AstNeqD : public AstNodeBiCom { public: AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(NeqD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstNeqD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeqD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstNeqD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opNeqD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f!= %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "!="; } @@ -5477,10 +6160,16 @@ public: class AstNeqN : public AstNodeBiCom { public: AstNeqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(NeqN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstNeqN(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeqN(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstNeqN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opNeqN(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f!= %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "!="; } @@ -5495,10 +6184,16 @@ public: class AstLt : public AstNodeBiop { public: AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(Lt) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLt(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLt(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLt(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLt(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f< %r)"; } virtual string emitC() { return "VL_LT_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "<"; } @@ -5511,10 +6206,16 @@ public: class AstLtD : public AstNodeBiop { public: AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LtD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLtD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLtD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLtD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f< %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "<"; } @@ -5529,10 +6230,16 @@ public: class AstLtS : public AstNodeBiop { public: AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LtS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLtS(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtS(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLtS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLtS(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f< %r)"; } virtual string emitC() { return "VL_LTS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } @@ -5546,10 +6253,16 @@ public: class AstLtN : public AstNodeBiop { public: AstLtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LtN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLtN(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtN(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLtN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLtN(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f< %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "<"; } @@ -5564,10 +6277,16 @@ public: class AstGt : public AstNodeBiop { public: AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(Gt) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGt(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGt(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstGt(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opGt(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f> %r)"; } virtual string emitC() { return "VL_GT_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ">"; } @@ -5580,10 +6299,16 @@ public: class AstGtD : public AstNodeBiop { public: AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(GtD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGtD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstGtD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opGtD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f> %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return ">"; } @@ -5598,10 +6323,16 @@ public: class AstGtS : public AstNodeBiop { public: AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(GtS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGtS(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtS(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstGtS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opGtS(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f> %r)"; } virtual string emitC() { return "VL_GTS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } @@ -5615,10 +6346,16 @@ public: class AstGtN : public AstNodeBiop { public: AstGtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(GtN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGtN(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtN(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstGtN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opGtN(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f> %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return ">"; } @@ -5633,11 +6370,18 @@ public: class AstGte : public AstNodeBiop { public: AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(Gte) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGte(this->fileline(), lhsp, rhsp); } - static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp); // Return AstGte/AstGteS/AstGteD - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGte(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstGte(this->fileline(), lhsp, rhsp); + } + static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, + AstNode* rhsp); // Return AstGte/AstGteS/AstGteD + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opGte(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f>= %r)"; } virtual string emitC() { return "VL_GTE_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ">="; } @@ -5650,10 +6394,16 @@ public: class AstGteD : public AstNodeBiop { public: AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(GteD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGteD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstGteD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opGteD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f>= %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return ">="; } @@ -5668,10 +6418,16 @@ public: class AstGteS : public AstNodeBiop { public: AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(GteS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGteS(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteS(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstGteS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opGteS(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f>= %r)"; } virtual string emitC() { return "VL_GTES_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } @@ -5685,10 +6441,16 @@ public: class AstGteN : public AstNodeBiop { public: AstGteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(GteN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGteN(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteN(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstGteN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opGteN(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f>= %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return ">="; } @@ -5703,11 +6465,18 @@ public: class AstLte : public AstNodeBiop { public: AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(Lte) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLte(this->fileline(), lhsp, rhsp); } - static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp); // Return AstLte/AstLteS/AstLteD - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLte(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLte(this->fileline(), lhsp, rhsp); + } + static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, + AstNode* rhsp); // Return AstLte/AstLteS/AstLteD + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLte(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f<= %r)"; } virtual string emitC() { return "VL_LTE_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "<="; } @@ -5720,10 +6489,16 @@ public: class AstLteD : public AstNodeBiop { public: AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LteD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLteD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLteD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLteD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f<= %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "<="; } @@ -5738,10 +6513,16 @@ public: class AstLteS : public AstNodeBiop { public: AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LteS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLteS(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteS(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLteS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLteS(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f<= %r)"; } virtual string emitC() { return "VL_LTES_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } @@ -5755,10 +6536,16 @@ public: class AstLteN : public AstNodeBiop { public: AstLteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(LteN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstLteN(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteN(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstLteN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opLteN(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f<= %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "<="; } @@ -5772,13 +6559,17 @@ public: }; class AstShiftL : public AstNodeBiop { public: - AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth=0) + AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { if (setwidth) { dtypeSetLogicSized(setwidth, AstNumeric::UNSIGNED); } } ASTNODE_NODE_FUNCS(ShiftL) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstShiftL(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opShiftL(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstShiftL(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opShiftL(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f<< %r)"; } virtual string emitC() { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "<<"; } @@ -5790,13 +6581,17 @@ public: }; class AstShiftR : public AstNodeBiop { public: - AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth=0) + AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { if (setwidth) { dtypeSetLogicSized(setwidth, AstNumeric::UNSIGNED); } } ASTNODE_NODE_FUNCS(ShiftR) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstShiftR(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opShiftR(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstShiftR(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opShiftR(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f>> %r)"; } virtual string emitC() { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ">>"; } @@ -5811,15 +6606,18 @@ class AstShiftRS : public AstNodeBiop { // Shift right with sign extension, >>> operator // Output data type's width determines which bit is used for sign extension public: - AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth=0) + AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { // Important that widthMin be correct, as opExtend requires it after V3Expand if (setwidth) { dtypeSetLogicSized(setwidth, AstNumeric::SIGNED); } } ASTNODE_NODE_FUNCS(ShiftRS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstShiftRS(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstShiftRS(this->fileline(), lhsp, rhsp); + } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { - out.opShiftRS(lhs, rhs, lhsp()->widthMinV()); } + out.opShiftRS(lhs, rhs, lhsp()->widthMinV()); + } virtual string emitVerilog() { return "%k(%l %f>>> %r)"; } virtual string emitC() { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } @@ -5833,10 +6631,16 @@ public: class AstAdd : public AstNodeBiComAsv { public: AstAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(Add) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAdd(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAdd(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstAdd(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opAdd(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f+ %r)"; } virtual string emitC() { return "VL_ADD_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "+"; } @@ -5849,10 +6653,16 @@ public: class AstAddD : public AstNodeBiComAsv { public: AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetDouble(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetDouble(); + } ASTNODE_NODE_FUNCS(AddD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAddD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAddD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstAddD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opAddD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f+ %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "+"; } @@ -5867,10 +6677,16 @@ public: class AstSub : public AstNodeBiop { public: AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(Sub) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstSub(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opSub(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstSub(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opSub(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f- %r)"; } virtual string emitC() { return "VL_SUB_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "-"; } @@ -5883,10 +6699,16 @@ public: class AstSubD : public AstNodeBiop { public: AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetDouble(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetDouble(); + } ASTNODE_NODE_FUNCS(SubD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstSubD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opSubD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstSubD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opSubD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f- %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "-"; } @@ -5901,10 +6723,16 @@ public: class AstMul : public AstNodeBiComAsv { public: AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(Mul) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstMul(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opMul(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstMul(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opMul(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f* %r)"; } virtual string emitC() { return "VL_MUL_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "*"; } @@ -5913,15 +6741,21 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return true; } - virtual int instrCount() const { return widthInstrs()*instrCountMul(); } + virtual int instrCount() const { return widthInstrs() * instrCountMul(); } }; class AstMulD : public AstNodeBiComAsv { public: AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetDouble(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetDouble(); + } ASTNODE_NODE_FUNCS(MulD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstMulD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opMulD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstMulD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opMulD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f* %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "*"; } @@ -5936,10 +6770,16 @@ public: class AstMulS : public AstNodeBiComAsv { public: AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(MulS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstMulS(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opMulS(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstMulS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opMulS(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f* %r)"; } virtual string emitC() { return "VL_MULS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } @@ -5948,16 +6788,22 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return true; } - virtual int instrCount() const { return widthInstrs()*instrCountMul(); } + virtual int instrCount() const { return widthInstrs() * instrCountMul(); } virtual bool signedFlavor() const { return true; } }; class AstDiv : public AstNodeBiop { public: AstDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(Div) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstDiv(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDiv(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstDiv(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opDiv(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f/ %r)"; } virtual string emitC() { return "VL_DIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } virtual bool cleanOut() const { return false; } @@ -5965,15 +6811,21 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return true; } - virtual int instrCount() const { return widthInstrs()*instrCountDiv(); } + virtual int instrCount() const { return widthInstrs() * instrCountDiv(); } }; class AstDivD : public AstNodeBiop { public: AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetDouble(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetDouble(); + } ASTNODE_NODE_FUNCS(DivD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstDivD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDivD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstDivD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opDivD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f/ %r)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { return "/"; } @@ -5988,10 +6840,16 @@ public: class AstDivS : public AstNodeBiop { public: AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(DivS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstDivS(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDivS(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstDivS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opDivS(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f/ %r)"; } virtual string emitC() { return "VL_DIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } virtual bool cleanOut() const { return false; } @@ -5999,16 +6857,22 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return true; } - virtual int instrCount() const { return widthInstrs()*instrCountDiv(); } + virtual int instrCount() const { return widthInstrs() * instrCountDiv(); } virtual bool signedFlavor() const { return true; } }; class AstModDiv : public AstNodeBiop { public: AstModDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(ModDiv) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstModDiv(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opModDiv(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstModDiv(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opModDiv(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f%% %r)"; } virtual string emitC() { return "VL_MODDIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } virtual bool cleanOut() const { return false; } @@ -6016,15 +6880,21 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return true; } - virtual int instrCount() const { return widthInstrs()*instrCountDiv(); } + virtual int instrCount() const { return widthInstrs() * instrCountDiv(); } }; class AstModDivS : public AstNodeBiop { public: AstModDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(ModDivS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstModDivS(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opModDivS(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstModDivS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opModDivS(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f%% %r)"; } virtual string emitC() { return "VL_MODDIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } virtual bool cleanOut() const { return false; } @@ -6032,16 +6902,22 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return true; } - virtual int instrCount() const { return widthInstrs()*instrCountDiv(); } + virtual int instrCount() const { return widthInstrs() * instrCountDiv(); } virtual bool signedFlavor() const { return true; } }; class AstPow : public AstNodeBiop { public: AstPow(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(Pow) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstPow(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPow(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstPow(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opPow(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "VL_POW_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual bool cleanOut() const { return false; } @@ -6049,15 +6925,21 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*instrCountMul()*10; } + virtual int instrCount() const { return widthInstrs() * instrCountMul() * 10; } }; class AstPowD : public AstNodeBiop { public: AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetDouble(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetDouble(); + } ASTNODE_NODE_FUNCS(PowD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstPowD(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowD(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstPowD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opPowD(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "pow(%li,%ri)"; } virtual bool cleanOut() const { return false; } @@ -6065,16 +6947,22 @@ public: virtual bool cleanRhs() const { return false; } virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return instrCountDoubleDiv()*5; } + virtual int instrCount() const { return instrCountDoubleDiv() * 5; } virtual bool doubleFlavor() const { return true; } }; class AstPowSU : public AstNodeBiop { public: AstPowSU(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(PowSU) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstPowSU(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowSU(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstPowSU(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opPowSU(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,0)"; } virtual bool cleanOut() const { return false; } @@ -6082,16 +6970,22 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*instrCountMul()*10; } + virtual int instrCount() const { return widthInstrs() * instrCountMul() * 10; } virtual bool signedFlavor() const { return true; } }; class AstPowSS : public AstNodeBiop { public: AstPowSS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(PowSS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstPowSS(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowSS(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstPowSS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opPowSS(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,1)"; } virtual bool cleanOut() const { return false; } @@ -6099,16 +6993,22 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*instrCountMul()*10; } + virtual int instrCount() const { return widthInstrs() * instrCountMul() * 10; } virtual bool signedFlavor() const { return true; } }; class AstPowUS : public AstNodeBiop { public: AstPowUS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(PowUS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstPowUS(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowUS(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstPowUS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opPowUS(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 0,1)"; } virtual bool cleanOut() const { return false; } @@ -6116,16 +7016,22 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*instrCountMul()*10; } + virtual int instrCount() const { return widthInstrs() * instrCountMul() * 10; } virtual bool signedFlavor() const { return true; } }; class AstEqCase : public AstNodeBiCom { public: AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(EqCase) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEqCase(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opCaseEq(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstEqCase(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opCaseEq(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f=== %r)"; } virtual string emitC() { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "=="; } @@ -6138,10 +7044,16 @@ public: class AstNeqCase : public AstNodeBiCom { public: AstNeqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(NeqCase) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstNeqCase(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opCaseNeq(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstNeqCase(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opCaseNeq(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f!== %r)"; } virtual string emitC() { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "!="; } @@ -6155,11 +7067,18 @@ class AstEqWild : public AstNodeBiop { // Note wildcard operator rhs differs from lhs public: AstEqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(EqWild) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEqWild(this->fileline(), lhsp, rhsp); } - static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp); // Return AstEqWild/AstEqD - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opWildEq(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstEqWild(this->fileline(), lhsp, rhsp); + } + static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, + AstNode* rhsp); // Return AstEqWild/AstEqD + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opWildEq(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f==? %r)"; } virtual string emitC() { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "=="; } @@ -6172,10 +7091,16 @@ public: class AstNeqWild : public AstNodeBiop { public: AstNeqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetLogicBool(); + } ASTNODE_NODE_FUNCS(NeqWild) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstNeqWild(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opWildNeq(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstNeqWild(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opWildNeq(lhs, rhs); + } virtual string emitVerilog() { return "%k(%l %f!=? %r)"; } virtual string emitC() { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "!="; } @@ -6191,31 +7116,41 @@ public: AstConcat(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { if (lhsp->dtypep() && rhsp->dtypep()) { - dtypeSetLogicSized(lhsp->dtypep()->width()+rhsp->dtypep()->width(), + dtypeSetLogicSized(lhsp->dtypep()->width() + rhsp->dtypep()->width(), AstNumeric::UNSIGNED); } } ASTNODE_NODE_FUNCS(Concat) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstConcat(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstConcat(this->fileline(), lhsp, rhsp); + } virtual string emitVerilog() { return "%f{%l, %k%r}"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opConcat(lhs, rhs); } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opConcat(lhs, rhs); + } virtual string emitC() { return "VL_CONCAT_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return true; } virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*2; } + virtual int instrCount() const { return widthInstrs() * 2; } }; class AstConcatN : public AstNodeBiop { // String concatenate public: AstConcatN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetString(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetString(); + } ASTNODE_NODE_FUNCS(ConcatN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstConcatN(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstConcatN(this->fileline(), lhsp, rhsp); + } virtual string emitVerilog() { return "%f{%l, %k%r}"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opConcatN(lhs, rhs); } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opConcatN(lhs, rhs); + } virtual string emitC() { return "VL_CONCATN_NNN(%li, %ri)"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return true; } @@ -6232,19 +7167,27 @@ private: void init() { if (lhsp()) { if (const AstConst* constp = VN_CAST(rhsp(), Const)) { - dtypeSetLogicSized(lhsp()->width()*constp->toUInt(), - AstNumeric::UNSIGNED); + dtypeSetLogicSized(lhsp()->width() * constp->toUInt(), AstNumeric::UNSIGNED); } } } + public: AstReplicate(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { init(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + init(); + } AstReplicate(FileLine* fl, AstNode* lhsp, uint32_t repCount) - : ASTGEN_SUPER(fl, lhsp, new AstConst(fl, repCount)) { init(); } + : ASTGEN_SUPER(fl, lhsp, new AstConst(fl, repCount)) { + init(); + } ASTNODE_NODE_FUNCS(Replicate) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstReplicate(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opRepl(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstReplicate(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opRepl(lhs, rhs); + } virtual string emitVerilog() { return "%f{%r{%k%l}}"; } virtual string emitC() { return "VL_REPLICATE_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual bool cleanOut() const { return false; } @@ -6252,20 +7195,29 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*2; } + virtual int instrCount() const { return widthInstrs() * 2; } }; class AstReplicateN : public AstNodeBiop { // String replicate private: void init() { dtypeSetString(); } + public: AstReplicateN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { init(); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + init(); + } AstReplicateN(FileLine* fl, AstNode* lhsp, uint32_t repCount) - : ASTGEN_SUPER(fl, lhsp, new AstConst(fl, repCount)) { init(); } + : ASTGEN_SUPER(fl, lhsp, new AstConst(fl, repCount)) { + init(); + } ASTNODE_NODE_FUNCS(ReplicateN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstReplicateN(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opReplN(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstReplicateN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opReplN(lhs, rhs); + } virtual string emitVerilog() { return "%f{%r{%k%l}}"; } virtual string emitC() { return "VL_REPLICATEN_NN%rq(0,0,%rw, %li, %ri)"; } virtual bool cleanOut() const { return false; } @@ -6273,7 +7225,7 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*2; } + virtual int instrCount() const { return widthInstrs() * 2; } virtual bool stringFlavor() const { return true; } }; class AstStreamL : public AstNodeStream { @@ -6282,16 +7234,20 @@ public: AstStreamL(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(StreamL) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstStreamL(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstStreamL(this->fileline(), lhsp, rhsp); + } virtual string emitVerilog() { return "%f{ << %r %k{%l} }"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opStreamL(lhs, rhs); } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opStreamL(lhs, rhs); + } virtual string emitC() { return "VL_STREAML_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual bool cleanOut() const { return true; } virtual bool cleanLhs() const { return true; } virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*2; } + virtual int instrCount() const { return widthInstrs() * 2; } }; class AstStreamR : public AstNodeStream { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() @@ -6299,16 +7255,20 @@ public: AstStreamR(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(StreamR) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstStreamR(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstStreamR(this->fileline(), lhsp, rhsp); + } virtual string emitVerilog() { return "%f{ >> %r %k{%l} }"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAssign(lhs); } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opAssign(lhs); + } virtual string emitC() { return isWide() ? "VL_ASSIGN_W(%nw, %P, %li)" : "%li"; } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return false; } virtual bool cleanRhs() const { return false; } virtual bool sizeMattersLhs() const { return true; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*2; } + virtual int instrCount() const { return widthInstrs() * 2; } }; class AstBufIf1 : public AstNodeBiop { // lhs is enable, rhs is data to drive @@ -6316,10 +7276,16 @@ class AstBufIf1 : public AstNodeBiop { // bit enables respective rhsp bit public: AstBufIf1(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeFrom(lhsp); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } ASTNODE_NODE_FUNCS(BufIf1) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstBufIf1(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opBufIf1(lhs, rhs); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstBufIf1(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opBufIf1(lhs, rhs); + } virtual string emitVerilog() { return "bufif(%r,%l)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } // Lclean || Rclean virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } // Lclean || Rclean @@ -6334,8 +7300,12 @@ public: AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(FGetS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstFGetS(this->fileline(), lhsp, rhsp); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstFGetS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + V3ERROR_NA; + } virtual string emitVerilog() { return "%f$fgets(%l,%r)"; } virtual string emitC() { return "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)"; } virtual bool cleanOut() const { return false; } @@ -6343,7 +7313,7 @@ public: virtual bool cleanRhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersRhs() const { return false; } - virtual int instrCount() const { return widthInstrs()*64; } + virtual int instrCount() const { return widthInstrs() * 64; } AstNode* strgp() const { return lhsp(); } AstNode* filep() const { return rhsp(); } }; @@ -6351,7 +7321,9 @@ public: class AstNodeSystemBiop : public AstNodeBiop { public: AstNodeSystemBiop(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : AstNodeBiop(t, fl, lhsp, rhsp) { dtypeSetDouble(); } + : AstNodeBiop(t, fl, lhsp, rhsp) { + dtypeSetDouble(); + } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return false; } virtual bool cleanRhs() const { return false; } @@ -6366,9 +7338,12 @@ public: AstAtan2D(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(Atan2D) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAtan2D(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstAtan2D(this->fileline(), lhsp, rhsp); + } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { - out.setDouble(atan2(lhs.toDouble(), rhs.toDouble())); } + out.setDouble(atan2(lhs.toDouble(), rhs.toDouble())); + } virtual string emitVerilog() { return "%f$atan2(%l,%r)"; } virtual string emitC() { return "atan2(%li,%ri)"; } }; @@ -6378,9 +7353,12 @@ public: AstHypotD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(HypotD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstHypotD(this->fileline(), lhsp, rhsp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstHypotD(this->fileline(), lhsp, rhsp); + } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { - out.setDouble(hypot(lhs.toDouble(), rhs.toDouble())); } + out.setDouble(hypot(lhs.toDouble(), rhs.toDouble())); + } virtual string emitVerilog() { return "%f$hypot(%l,%r)"; } virtual string emitC() { return "hypot(%li,%ri)"; } }; @@ -6389,10 +7367,12 @@ class AstPutcN : public AstNodeTriop { // Verilog string.putc() public: AstPutcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) - : ASTGEN_SUPER(fl, lhsp, rhsp, ths) { dtypeSetString(); } + : ASTGEN_SUPER(fl, lhsp, rhsp, ths) { + dtypeSetString(); + } ASTNODE_NODE_FUNCS(PutcN) - virtual void numberOperate(V3Number& out, const V3Number& lhs, - const V3Number& rhs, const V3Number& ths) { + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) { out.opPutcN(lhs, rhs, ths); } virtual string name() const { return "putc"; } @@ -6412,7 +7392,9 @@ class AstGetcN : public AstNodeBiop { // Verilog string.getc() public: AstGetcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetBitSized(8, AstNumeric::UNSIGNED); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetBitSized(8, AstNumeric::UNSIGNED); + } ASTNODE_NODE_FUNCS(GetcN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGetcN(this->fileline(), lhsp, rhsp); @@ -6436,7 +7418,9 @@ class AstGetcRefN : public AstNodeBiop { // Spec says is of type byte (not string of single character) public: AstGetcRefN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetBitSized(8, AstNumeric::UNSIGNED); } + : ASTGEN_SUPER(fl, lhsp, rhsp) { + dtypeSetBitSized(8, AstNumeric::UNSIGNED); + } ASTNODE_NODE_FUNCS(GetcRefN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstGetcRefN(this->fileline(), lhsp, rhsp); @@ -6458,10 +7442,12 @@ class AstSubstrN : public AstNodeTriop { // Verilog string.substr() public: AstSubstrN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) - : ASTGEN_SUPER(fl, lhsp, rhsp, ths) { dtypeSetString(); } + : ASTGEN_SUPER(fl, lhsp, rhsp, ths) { + dtypeSetString(); + } ASTNODE_NODE_FUNCS(SubstrN) - virtual void numberOperate(V3Number& out, const V3Number& lhs, - const V3Number& rhs, const V3Number& ths) { + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) { out.opSubstrN(lhs, rhs, ths); } virtual string name() const { return "substr"; } @@ -6515,10 +7501,15 @@ class AstPast : public AstNodeMath { // Children: expression public: AstPast(FileLine* fl, AstNode* exprp, AstNode* ticksp) - : ASTGEN_SUPER(fl) { addOp1p(exprp); addNOp2p(ticksp); } + : ASTGEN_SUPER(fl) { + addOp1p(exprp); + addNOp2p(ticksp); + } ASTNODE_NODE_FUNCS(Past) virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + V3ERROR_NA; + } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } @@ -6537,7 +7528,9 @@ class AstSampled : public AstNodeMath { // Children: expression public: AstSampled(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER(fl) { addOp1p(exprp); } + : ASTGEN_SUPER(fl) { + addOp1p(exprp); + } ASTNODE_NODE_FUNCS(Sampled) virtual string emitVerilog() { return "$sampled(%l)"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } @@ -6555,16 +7548,22 @@ class AstPattern : public AstNodeMath { // Children: expression, AstPattern, AstPatReplicate public: AstPattern(FileLine* fl, AstNode* itemsp) - : ASTGEN_SUPER(fl) { addNOp2p(itemsp); } + : ASTGEN_SUPER(fl) { + addNOp2p(itemsp); + } ASTNODE_NODE_FUNCS(Pattern) virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + V3ERROR_NA; + } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } virtual int instrCount() const { return widthInstrs(); } AstNodeDType* getChildDTypep() const { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Type assigning to + AstNodeDType* childDTypep() const { + return VN_CAST(op1p(), NodeDType); + } // op1 = Type assigning to void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc @@ -6574,18 +7573,25 @@ class AstPatMember : public AstNodeMath { // Parents: AstPattern // Children: expression, AstPattern, replication count private: - bool m_default; + bool m_default; + public: AstPatMember(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* repp) - : ASTGEN_SUPER(fl) { addOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); m_default = false; } + : ASTGEN_SUPER(fl) { + addOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); + m_default = false; + } ASTNODE_NODE_FUNCS(PatMember) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + V3ERROR_NA; + } virtual string emitVerilog() { return lhssp() ? "%f{%r{%k%l}}" : "%l"; } virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } virtual int instrCount() const { return widthInstrs() * 2; } - AstNode* lhssp() const { return op1p(); } // op1 = expression to assign or another AstPattern (list if replicated) + // op1 = expression to assign or another AstPattern (list if replicated) + AstNode* lhssp() const { return op1p(); } AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text) AstNode* repp() const { return op3p(); } // op3 = replication count, or NULL for count 1 bool isDefault() const { return m_default; } @@ -6606,7 +7612,8 @@ public: addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(Clocking) - AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); } // op1 = Sensitivity list + // op1 = Sensitivity list + AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); } AstNode* bodysp() const { return op2p(); } // op2 = Body }; @@ -6626,7 +7633,9 @@ public: } ASTNODE_NODE_FUNCS(PropClocked) virtual bool hasDType() const { return true; } // Used under Cover, which expects a bool child - AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); } // op1 = Sensitivity list + AstNodeSenItem* sensesp() const { + return VN_CAST(op1p(), NodeSenItem); + } // op1 = Sensitivity list AstNode* disablep() const { return op2p(); } // op2 = disable AstNode* propp() const { return op3p(); } // op3 = property }; @@ -6639,8 +7648,8 @@ private: bool m_immediate; // Immediate assertion/cover string m_name; // Name to report public: - AstNodeCoverOrAssert(AstType t, FileLine* fl, AstNode* propp, AstNode* passsp, - bool immediate, const string& name="") + AstNodeCoverOrAssert(AstType t, FileLine* fl, AstNode* propp, AstNode* passsp, bool immediate, + const string& name = "") : AstNodeStmt(t, fl) , m_immediate(immediate) , m_name(name) { @@ -6652,7 +7661,7 @@ public: virtual V3Hash sameHash() const { return V3Hash(name()); } virtual bool same(const AstNode* samep) const { return samep->name() == name(); } virtual void name(const string& name) { m_name = name; } - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; AstNode* propp() const { return op1p(); } // op1 = property AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain @@ -6663,8 +7672,8 @@ public: class AstAssert : public AstNodeCoverOrAssert { public: ASTNODE_NODE_FUNCS(Assert) - AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, - bool immediate, const string& name = "") + AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, bool immediate, + const string& name = "") : ASTGEN_SUPER(fl, propp, passsp, immediate, name) { addNOp3p(failsp); } @@ -6674,8 +7683,8 @@ public: class AstCover : public AstNodeCoverOrAssert { public: ASTNODE_NODE_FUNCS(Cover) - AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, - bool immediate, const string& name = "") + AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, bool immediate, + const string& name = "") : ASTGEN_SUPER(fl, propp, stmtsp, immediate, name) {} AstNode* coverincp() const { return op3p(); } // op3 = coverage node void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node @@ -6696,8 +7705,9 @@ class AstNodeSimpleText : public AstNodeText { private: bool m_tracking; // When emit, it's ok to parse the string to do indentation public: - AstNodeSimpleText(AstType t, FileLine* fl, const string& textp, bool tracking=false) - : AstNodeText(t, fl, textp), m_tracking(tracking) {} + AstNodeSimpleText(AstType t, FileLine* fl, const string& textp, bool tracking = false) + : AstNodeText(t, fl, textp) + , m_tracking(tracking) {} ASTNODE_BASE_FUNCS(NodeSimpleText) void tracking(bool flag) { m_tracking = flag; } bool tracking() const { return m_tracking; } @@ -6705,7 +7715,7 @@ public: class AstText : public AstNodeSimpleText { public: - AstText(FileLine* fl, const string& textp, bool tracking=false) + AstText(FileLine* fl, const string& textp, bool tracking = false) : ASTGEN_SUPER(fl, textp, tracking) {} ASTNODE_NODE_FUNCS(Text) }; @@ -6723,7 +7733,7 @@ public: bool commas() const { return m_commas; } AstNode* nodesp() const { return op1p(); } void addNodep(AstNode* nodep) { addOp1p(nodep); } - void addText(FileLine* fl, const string& textp, bool tracking=false) { + void addText(FileLine* fl, const string& textp, bool tracking = false) { addNodep(new AstText(fl, textp, tracking)); } }; @@ -6807,7 +7817,7 @@ class AstNodeFile : public AstNode { // Parents: NETLIST // Children: AstTextBlock private: - string m_name; ///< Filename + string m_name; ///< Filename public: AstNodeFile(AstType t, FileLine* fl, const string& name) : AstNode(t, fl) { @@ -6831,7 +7841,7 @@ public: AstVFile(FileLine* fl, const string& name) : ASTGEN_SUPER(fl, name) {} ASTNODE_NODE_FUNCS(VFile) - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; }; //====================================================================== @@ -6841,9 +7851,9 @@ class AstCFile : public AstNodeFile { // C++ output file // Parents: NETLIST private: - bool m_slow:1; ///< Compile w/o optimization - bool m_source:1; ///< Source file (vs header file) - bool m_support:1; ///< Support file (non systemc) + bool m_slow : 1; ///< Compile w/o optimization + bool m_source : 1; ///< Source file (vs header file) + bool m_support : 1; ///< Support file (non systemc) public: AstCFile(FileLine* fl, const string& name) : ASTGEN_SUPER(fl, name) { @@ -6852,7 +7862,7 @@ public: m_support = false; } ASTNODE_NODE_FUNCS(CFile) - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; bool slow() const { return m_slow; } void slow(bool flag) { m_slow = flag; } bool source() const { return m_source; } @@ -6867,34 +7877,34 @@ class AstCFunc : public AstNode { // Children: VAR/statements private: AstCFuncType m_funcType; - AstScope* m_scopep; - string m_name; - string m_cname; // C name, for dpiExports - string m_rtnType; // void, bool, or other return type - string m_argTypes; - string m_ifdef; // #ifdef symbol around this function - VBoolOrUnknown m_isConst; // Function is declared const (*this not changed) - VBoolOrUnknown m_isStatic; // Function is declared static (no this) - bool m_dontCombine:1; // V3Combine shouldn't compare this func tree, it's special - bool m_skipDecl:1; // Don't declare it - bool m_declPrivate:1; // Declare it private - bool m_formCallTree:1; // Make a global function to call entire tree of functions - bool m_slow:1; // Slow routine, called once or just at init time - bool m_funcPublic:1; // From user public task/function - bool m_isConstructor:1; // Is C class constructor - bool m_isDestructor:1; // Is C class destructor - bool m_isMethod:1; // Is inside a class definition - bool m_isInline:1; // Inline function - bool m_isVirtual:1; // Virtual function - bool m_symProlog:1; // Setup symbol table for later instructions - bool m_entryPoint:1; // User may call into this top level function - bool m_pure:1; // Pure function - bool m_dpiExport:1; // From dpi export - bool m_dpiExportWrapper:1; // From dpi export; static function with dispatch table - bool m_dpiImport:1; // From dpi import - bool m_dpiImportWrapper:1; // Wrapper from dpi import + AstScope* m_scopep; + string m_name; + string m_cname; // C name, for dpiExports + string m_rtnType; // void, bool, or other return type + string m_argTypes; + string m_ifdef; // #ifdef symbol around this function + VBoolOrUnknown m_isConst; // Function is declared const (*this not changed) + VBoolOrUnknown m_isStatic; // Function is declared static (no this) + bool m_dontCombine : 1; // V3Combine shouldn't compare this func tree, it's special + bool m_skipDecl : 1; // Don't declare it + bool m_declPrivate : 1; // Declare it private + bool m_formCallTree : 1; // Make a global function to call entire tree of functions + bool m_slow : 1; // Slow routine, called once or just at init time + bool m_funcPublic : 1; // From user public task/function + bool m_isConstructor : 1; // Is C class constructor + bool m_isDestructor : 1; // Is C class destructor + bool m_isMethod : 1; // Is inside a class definition + bool m_isInline : 1; // Inline function + bool m_isVirtual : 1; // Virtual function + bool m_symProlog : 1; // Setup symbol table for later instructions + bool m_entryPoint : 1; // User may call into this top level function + bool m_pure : 1; // Pure function + bool m_dpiExport : 1; // From dpi export + bool m_dpiExportWrapper : 1; // From dpi export; static function with dispatch table + bool m_dpiImport : 1; // From dpi import + bool m_dpiImportWrapper : 1; // Wrapper from dpi import public: - AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType="") + AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "") : ASTGEN_SUPER(fl) { m_funcType = AstCFuncType::FT_NORMAL; m_isConst = VBoolOrUnknown::BU_UNKNOWN; // Unknown until analyzed @@ -6923,17 +7933,19 @@ public: } ASTNODE_NODE_FUNCS(CFunc) virtual string name() const { return m_name; } - virtual const char* broken() const { BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); return NULL; } + virtual const char* broken() const { + BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); + return NULL; + } virtual bool maybePointedTo() const { return true; } - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { const AstCFunc* asamep = static_cast(samep); - return ((funcType() == asamep->funcType()) - && (rtnTypeVoid() == asamep->rtnTypeVoid()) + return ((funcType() == asamep->funcType()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) && (argTypes() == asamep->argTypes()) - && (!(dpiImport() || dpiExport()) - || name() == asamep->name())); } + && (!(dpiImport() || dpiExport()) || name() == asamep->name())); + } // virtual void name(const string& name) { m_name = name; } virtual int instrCount() const { return dpiImport() ? instrCountDpi() : 0; } @@ -6947,8 +7959,8 @@ public: string cname() const { return m_cname; } AstScope* scopep() const { return m_scopep; } void scopep(AstScope* nodep) { m_scopep = nodep; } - string rtnTypeVoid() const { return ((m_rtnType=="") ? "void" : m_rtnType); } - bool dontCombine() const { return m_dontCombine || funcType()!=AstCFuncType::FT_NORMAL; } + string rtnTypeVoid() const { return ((m_rtnType == "") ? "void" : m_rtnType); } + bool dontCombine() const { return m_dontCombine || funcType() != AstCFuncType::FT_NORMAL; } void dontCombine(bool flag) { m_dontCombine = flag; } bool dontInline() const { return dontCombine() || slow() || skipDecl() || funcPublic(); } bool skipDecl() const { return m_skipDecl; } @@ -7002,7 +8014,9 @@ public: AstNode* finalsp() const { return op4p(); } void addFinalsp(AstNode* nodep) { addOp4p(nodep); } // Special methods - bool emptyBody() const { return argsp()==NULL && initsp()==NULL && stmtsp()==NULL && finalsp()==NULL; } + bool emptyBody() const { + return argsp() == NULL && initsp() == NULL && stmtsp() == NULL && finalsp() == NULL; + } }; class AstCCall : public AstNodeCCall { @@ -7079,12 +8093,16 @@ private: public: // Emit C textual math function (like AstUCFunc) AstCMath(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl), m_cleanOut(true), m_pure(false) { + : ASTGEN_SUPER(fl) + , m_cleanOut(true) + , m_pure(false) { addOp1p(exprsp); dtypeFrom(exprsp); } - AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut=true) - : ASTGEN_SUPER(fl), m_cleanOut(cleanOut), m_pure(true) { + AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut = true) + : ASTGEN_SUPER(fl) + , m_cleanOut(cleanOut) + , m_pure(true) { addNOp1p(new AstText(fl, textStmt, true)); if (setwidth) { dtypeSetLogicSized(setwidth, AstNumeric::UNSIGNED); } } @@ -7143,6 +8161,7 @@ class AstCUse : public AstNode { private: VUseType m_useType; // What sort of use this is string m_name; + public: AstCUse(FileLine* fl, VUseType useType, const string& name) : ASTGEN_SUPER(fl) @@ -7159,17 +8178,21 @@ class AstMTaskBody : public AstNode { // Hold statements for each MTask private: ExecMTask* m_execMTaskp; + public: explicit AstMTaskBody(FileLine* fl) : ASTGEN_SUPER(fl) , m_execMTaskp(NULL) {} ASTNODE_NODE_FUNCS(MTaskBody); - virtual const char* broken() const { BROKEN_RTN(!m_execMTaskp); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(!m_execMTaskp); + return NULL; + } AstNode* stmtsp() const { return op1p(); } void addStmtsp(AstNode* nodep) { addOp1p(nodep); } ExecMTask* execMTaskp() const { return m_execMTaskp; } void execMTaskp(ExecMTask* execMTaskp) { m_execMTaskp = execMTaskp; } - virtual void dump(std::ostream& str=std::cout) const; + virtual void dump(std::ostream& str = std::cout) const; }; class AstExecGraph : public AstNode { @@ -7182,12 +8205,15 @@ class AstExecGraph : public AstNode { // them without traversing the graph (it's not always needed to // traverse the graph.) private: - V3Graph *m_depGraphp; // contains ExecMTask's + V3Graph* m_depGraphp; // contains ExecMTask's public: explicit AstExecGraph(FileLine* fl); ASTNODE_NODE_FUNCS_NO_DTOR(ExecGraph) virtual ~AstExecGraph(); - virtual const char* broken() const { BROKEN_RTN(!m_depGraphp); return NULL; } + virtual const char* broken() const { + BROKEN_RTN(!m_depGraphp); + return NULL; + } const V3Graph* depGraphp() const { return m_depGraphp; } V3Graph* mutableDepGraphp() { return m_depGraphp; } void addMTaskBody(AstMTaskBody* bodyp) { addOp1p(bodyp); } @@ -7210,26 +8236,28 @@ class AstTypeTable : public AstNode { AstVoidDType* m_voidp; AstBasicDType* m_basicps[AstBasicDTypeKwd::_ENUM_MAX]; // - typedef std::map DetailedMap; + typedef std::map DetailedMap; DetailedMap m_detailedMap; + public: explicit AstTypeTable(FileLine* fl) - : ASTGEN_SUPER(fl), m_voidp(NULL) { - for (int i=0; i1 mode public: AstNetlist() @@ -7258,26 +8286,33 @@ public: return NULL; } AstNodeModule* modulesp() const { // op1 = List of modules - return VN_CAST(op1p(), NodeModule); } + return VN_CAST(op1p(), NodeModule); + } AstNodeModule* topModulep() const { // * = Top module in hierarchy (first one added, for now) - return VN_CAST(op1p(), NodeModule); } + return VN_CAST(op1p(), NodeModule); + } void addModulep(AstNodeModule* modulep) { addOp1p(modulep); } AstNodeFile* filesp() const { return VN_CAST(op2p(), NodeFile); } // op2 = List of files void addFilesp(AstNodeFile* filep) { addOp2p(filep); } AstNode* miscsp() const { return op3p(); } // op3 = List of dtypes etc void addMiscsp(AstNode* nodep) { addOp3p(nodep); } AstTypeTable* typeTablep() { return m_typeTablep; } - void addTypeTablep(AstTypeTable* nodep) { m_typeTablep = nodep; addMiscsp(nodep); } + void addTypeTablep(AstTypeTable* nodep) { + m_typeTablep = nodep; + addMiscsp(nodep); + } AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; } AstPackage* dollarUnitPkgAddp() { if (!m_dollarUnitPkgp) { m_dollarUnitPkgp = new AstPackage(fileline(), AstPackage::dollarUnitName()); - m_dollarUnitPkgp->inLibrary(true); // packages are always libraries; don't want to make them a "top" + // packages are always libraries; don't want to make them a "top" + m_dollarUnitPkgp->inLibrary(true); m_dollarUnitPkgp->modTrace(false); // may reconsider later m_dollarUnitPkgp->internal(true); addModulep(m_dollarUnitPkgp); } - return m_dollarUnitPkgp; } + return m_dollarUnitPkgp; + } AstCFunc* evalp() const { return m_evalp; } void evalp(AstCFunc* evalp) { m_evalp = evalp; } AstExecGraph* execGraphp() const { return m_execGraphp; } diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 80cd56fe8..e1fc1cbf9 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -42,14 +42,14 @@ class BeginState { private: // NODE STATE - //Entire netlist: + // Entire netlist: // AstNodeFTask::user1 -> bool, 1=processed - AstUser1InUse m_inuser1; - bool m_anyFuncInBegin; + AstUser1InUse m_inuser1; + bool m_anyFuncInBegin; + public: - BeginState() { - m_anyFuncInBegin = false; - } + BeginState() + : m_anyFuncInBegin(false) {} ~BeginState() {} void userMarkChanged(AstNode* nodep) { nodep->user1(true); @@ -63,12 +63,12 @@ public: class BeginVisitor : public AstNVisitor { private: // STATE - BeginState* m_statep; // Current global state - AstNodeModule* m_modp; // Current module - AstNodeFTask* m_ftaskp; // Current function/task - string m_namedScope; // Name of begin blocks above us - string m_unnamedScope; // Name of begin blocks, including unnamed blocks - int m_ifDepth; // Current if depth + BeginState* m_statep; // Current global state + AstNodeModule* m_modp; // Current module + AstNodeFTask* m_ftaskp; // Current function/task + string m_namedScope; // Name of begin blocks above us + string m_unnamedScope; // Name of begin blocks, including unnamed blocks + int m_ifDepth; // Current if depth // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -83,11 +83,11 @@ private: m_modp = origModp; } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { - UINFO(8," "<name(m_unnamedScope+"__DOT__"+nodep->name()); - UINFO(8," rename to "<name()<name(m_unnamedScope + "__DOT__" + nodep->name()); + UINFO(8, " rename to " << nodep->name() << endl); m_statep->userMarkChanged(nodep); } // BEGIN wrapping a function rename that function, but don't affect @@ -109,28 +109,34 @@ private: } virtual void visit(AstBegin* nodep) VL_OVERRIDE { // Begin blocks were only useful in variable creation, change names and delete - UINFO(8," "<name() != "") { // Else unneeded unnamed block // Create data for dotted variable resolution string dottedname = nodep->name() + "__DOT__"; // So always found string::size_type pos; - while ((pos=dottedname.find("__DOT__")) != string::npos) { + while ((pos = dottedname.find("__DOT__")) != string::npos) { string ident = dottedname.substr(0, pos); - dottedname = dottedname.substr(pos+strlen("__DOT__")); + dottedname = dottedname.substr(pos + strlen("__DOT__")); if (nodep->name() != "") { - if (m_namedScope=="") m_namedScope = ident; - else m_namedScope = m_namedScope + "__DOT__"+ident; + if (m_namedScope == "") { + m_namedScope = ident; + } else { + m_namedScope = m_namedScope + "__DOT__" + ident; + } + } + if (m_unnamedScope == "") { + m_unnamedScope = ident; + } else { + m_unnamedScope = m_unnamedScope + "__DOT__" + ident; } - if (m_unnamedScope=="") m_unnamedScope = ident; - else m_unnamedScope = m_unnamedScope + "__DOT__"+ident; // Create CellInline for dotted var resolution if (!m_ftaskp) { - AstCellInline* inlinep = new AstCellInline(nodep->fileline(), - m_unnamedScope, "__BEGIN__"); + AstCellInline* inlinep + = new AstCellInline(nodep->fileline(), m_unnamedScope, "__BEGIN__"); m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells } } @@ -147,7 +153,11 @@ private: AstNode* addsp = NULL; if (AstNode* stmtsp = nodep->stmtsp()) { stmtsp->unlinkFrBackWithNext(); - if (addsp) { addsp = addsp->addNextNull(stmtsp); } else { addsp = stmtsp; } + if (addsp) { + addsp = addsp->addNextNull(stmtsp); + } else { + addsp = stmtsp; + } } if (addsp) { nodep->replaceWith(addsp); @@ -159,12 +169,15 @@ private: virtual void visit(AstVar* nodep) VL_OVERRIDE { if (m_unnamedScope != "") { // Rename it - nodep->name(m_unnamedScope+"__DOT__"+nodep->name()); + nodep->name(m_unnamedScope + "__DOT__" + nodep->name()); m_statep->userMarkChanged(nodep); // Move to module nodep->unlinkFrBack(); - if (m_ftaskp) m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func - else m_modp->addStmtp(nodep); + if (m_ftaskp) { + m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func + } else { + m_modp->addStmtp(nodep); + } } } virtual void visit(AstTypedef* nodep) VL_OVERRIDE { @@ -175,17 +188,20 @@ private: // Move to module nodep->unlinkFrBack(); // Begins under funcs just move into the func - if (m_ftaskp) m_ftaskp->addStmtsp(nodep); - else m_modp->addStmtp(nodep); + if (m_ftaskp) { + m_ftaskp->addStmtsp(nodep); + } else { + m_modp->addStmtp(nodep); + } } } virtual void visit(AstCell* nodep) VL_OVERRIDE { - UINFO(8," CELL "<userMarkChanged(nodep); // Rename it - nodep->name(m_namedScope+"__DOT__"+nodep->name()); - UINFO(8," rename to "<name()<name(m_namedScope + "__DOT__" + nodep->name()); + UINFO(8, " rename to " << nodep->name() << endl); // Move to module nodep->unlinkFrBack(); m_modp->addStmtp(nodep); @@ -193,10 +209,10 @@ private: iterateChildren(nodep); } virtual void visit(AstVarXRef* nodep) VL_OVERRIDE { - UINFO(9, " VARXREF "<inlinedDots() == "") { nodep->inlinedDots(m_namedScope); - UINFO(9, " rescope to "<scopeAttrp(); if (afterp) afterp->unlinkFrBackWithNext(); - nodep->scopeAttrp(new AstText(nodep->fileline(), string("__DOT__")+m_namedScope)); + nodep->scopeAttrp(new AstText(nodep->fileline(), string("__DOT__") + m_namedScope)); if (afterp) nodep->scopeAttrp(afterp); } iterateChildren(nodep); @@ -218,14 +234,15 @@ private: iterateChildren(nodep); } // VISITORS - LINT CHECK - virtual void visit(AstIf* nodep) VL_OVERRIDE { // Note not AstNodeIf; other types don't get covered + virtual void visit(AstIf* nodep) VL_OVERRIDE { // not AstNodeIf; other types not covered // Check IFDEPTH warning - could be in other transform files if desire int prevIfDepth = m_ifDepth; - if (m_ifDepth == -1 || v3Global.opt.ifDepth()<1) { // Turned off + if (m_ifDepth == -1 || v3Global.opt.ifDepth() < 1) { // Turned off } else if (nodep->uniquePragma() || nodep->unique0Pragma() || nodep->priorityPragma()) { m_ifDepth = -1; } else if (++m_ifDepth > v3Global.opt.ifDepth()) { - nodep->v3warn(IFDEPTH,"Deep 'if' statement; suggest unique/priority to avoid slow logic"); + nodep->v3warn(IFDEPTH, + "Deep 'if' statement; suggest unique/priority to avoid slow logic"); nodep->fileline()->modifyWarnOff(V3ErrorCode::IFDEPTH, true); // Warn only once m_ifDepth = -1; } @@ -258,14 +275,14 @@ private: // VISITORS virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { if (nodep->taskp()->user1()) { // It was converted - UINFO(9, " relinkFTask "<name(nodep->taskp()->name()); } iterateChildren(nodep); } virtual void visit(AstVarRef* nodep) VL_OVERRIDE { if (nodep->varp()->user1()) { // It was converted - UINFO(9, " relinVarRef "<name(nodep->varp()->name()); } iterateChildren(nodep); @@ -273,9 +290,9 @@ private: virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE { // May have changed cell names // TypeTable is always after all modules, so names are stable - UINFO(8," IFACEREFDTYPE "<cellp()) nodep->cellName(nodep->cellp()->name()); - UINFO(8," rename to "<= 3); } diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index b27dc4b04..21db1485f 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -42,35 +42,35 @@ class BrokenTable : public AstNVisitor { private: // MEMBERS // For each node, we keep if it exists or not. - typedef vl_unordered_map NodeMap; // Performance matters (when --debug) + typedef vl_unordered_map NodeMap; // Performance matters (when --debug) static NodeMap s_nodes; // Set of all nodes that exist // BITMASK - enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed - enum { FLAG_IN_TREE = 0x02 }; // Is in netlist tree - enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to - enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked - enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node + enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed + enum { FLAG_IN_TREE = 0x02 }; // Is in netlist tree + enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to + enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked + enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node public: // METHODS static void deleted(const AstNode* nodep) { // Called by operator delete on any node - only if VL_LEAK_CHECKS - if (debug()>=9) cout<<"-nodeDel: "<= 9) cout << "-nodeDel: " << cvtToHex(nodep) << endl; NodeMap::iterator iter = s_nodes.find(nodep); - UASSERT_OBJ(!(iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)), + UASSERT_OBJ(!(iter == s_nodes.end() || !(iter->second & FLAG_ALLOCATED)), reinterpret_cast(nodep), "Deleting AstNode object that was never tracked or already deleted"); - if (iter!=s_nodes.end()) s_nodes.erase(iter); + if (iter != s_nodes.end()) s_nodes.erase(iter); } #if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 4 // GCC 4.4.* compiler warning bug, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39390 -# pragma GCC diagnostic ignored "-Wstrict-aliasing" +#pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif static void addNewed(const AstNode* nodep) { // Called by operator new on any node - only if VL_LEAK_CHECKS - if (debug()>=9) cout<<"-nodeNew: "<= 9) cout << "-nodeNew: " << cvtToHex(nodep) << endl; NodeMap::iterator iter = s_nodes.find(nodep); - UASSERT_OBJ(!(iter !=s_nodes.end() && (iter->second & FLAG_ALLOCATED)), - nodep, "Newing AstNode object that is already allocated"); + UASSERT_OBJ(!(iter != s_nodes.end() && (iter->second & FLAG_ALLOCATED)), nodep, + "Newing AstNode object that is already allocated"); if (iter == s_nodes.end()) { int flags = FLAG_ALLOCATED; // This int needed to appease GCC 4.1.2 s_nodes.insert(make_pair(nodep, flags)); @@ -80,9 +80,9 @@ public: // Called by BrokenCheckVisitor when each node entered/exited if (!okIfLinkedTo(nodep)) return; NodeMap::iterator iter = s_nodes.find(nodep); - if (iter!=s_nodes.end()) { + if (iter != s_nodes.end()) { iter->second &= ~FLAG_UNDER_NOW; - if (flag) iter->second |= FLAG_UNDER_NOW; + if (flag) iter->second |= FLAG_UNDER_NOW; } } static void addInTree(AstNode* nodep, bool linkable) { @@ -103,7 +103,7 @@ public: UASSERT_OBJ(!(iter->second & FLAG_IN_TREE), nodep, "AstNode is already in tree at another location"); } - int or_flags = FLAG_IN_TREE | (linkable?FLAG_LINKABLE:0); + int or_flags = FLAG_IN_TREE | (linkable ? FLAG_LINKABLE : 0); if (iter == s_nodes.end()) { s_nodes.insert(make_pair(nodep, or_flags)); } else { @@ -149,12 +149,12 @@ public: } } static void doneWithTree() { - for (int backs=0; backs<2; backs++) { // Those with backp() are probably under one leaking without + for (int backs = 0; backs < 2; + backs++) { // Those with backp() are probably under one leaking without for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) { - if ((it->second & FLAG_ALLOCATED) - && !(it->second & FLAG_IN_TREE) + if ((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE) && !(it->second & FLAG_LEAKED) - && (it->first->backp() ? backs==1 : backs==0)) { + && (it->first->backp() ? backs == 1 : backs == 0)) { // Use only AstNode::dump instead of the virtual one, as there // may be varp() and other cross links that are bad. if (v3Global.opt.debugCheck()) { @@ -163,11 +163,12 @@ public: // watch AstNode::s_editCntGbl==#### // run // bt - std::cerr<<"%Error: LeakedNode"<<(it->first->backp()?"Back: ":": "); - AstNode* rawp = const_cast - (static_cast(it->first)); + std::cerr << "%Error: LeakedNode" + << (it->first->backp() ? "Back: " : ": "); + AstNode* rawp + = const_cast(static_cast(it->first)); rawp->AstNode::dump(std::cerr); - std::cerr<second |= FLAG_LEAKED; @@ -175,6 +176,7 @@ public: } } } + public: // CONSTRUCTORS BrokenTable() {} @@ -213,9 +215,7 @@ private: public: // CONSTRUCTORS - explicit BrokenMarkVisitor(AstNetlist* nodep) { - iterate(nodep); - } + explicit BrokenMarkVisitor(AstNetlist* nodep) { iterate(nodep); } virtual ~BrokenMarkVisitor() {} }; @@ -226,27 +226,27 @@ class BrokenCheckVisitor : public AstNVisitor { private: void checkWidthMin(const AstNode* nodep) { UASSERT_OBJ(nodep->width() == nodep->widthMin() - || v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH, + || v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH, nodep, "Width != WidthMin"); } void processAndIterate(AstNode* nodep) { BrokenTable::setUnder(nodep, true); const char* whyp = nodep->broken(); UASSERT_OBJ(!whyp, nodep, - "Broken link in node (or something without maybePointedTo): "<dtypep()) { UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep, - "Broken link in node->dtypep() to "<dtypep())); + "Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep())); UASSERT_OBJ(VN_IS(nodep->dtypep(), NodeDType), nodep, - "Non-dtype link in node->dtypep() to "<dtypep())); + "Non-dtype link in node->dtypep() to " << cvtToHex(nodep->dtypep())); } if (v3Global.assertDTypesResolved()) { if (nodep->hasDType()) { UASSERT_OBJ(nodep->dtypep(), nodep, - "No dtype on node with hasDType(): "<prettyTypeName()); + "No dtype on node with hasDType(): " << nodep->prettyTypeName()); } else { UASSERT_OBJ(!nodep->dtypep(), nodep, - "DType on node without hasDType(): "<prettyTypeName()); + "DType on node without hasDType(): " << nodep->prettyTypeName()); } UASSERT_OBJ(!nodep->getChildDTypep(), nodep, "childDTypep() non-null on node after should have removed"); @@ -258,8 +258,7 @@ private: } virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { processAndIterate(nodep); - UASSERT_OBJ(!(v3Global.assertDTypesResolved() - && nodep->brokeLhsMustBeLvalue() + UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue() && VN_IS(nodep->lhsp(), NodeVarRef) && !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()), nodep, "Assignment LHS is not an lvalue"); @@ -268,11 +267,10 @@ private: // Process not just iterate processAndIterate(nodep); } + public: // CONSTRUCTORS - explicit BrokenCheckVisitor(AstNetlist* nodep) { - iterate(nodep); - } + explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); } virtual ~BrokenCheckVisitor() {} }; @@ -280,27 +278,21 @@ public: // Broken class functions void V3Broken::brokenAll(AstNetlist* nodep) { - //UINFO(9,__FUNCTION__<<": "<fileline(), - m_basename+"_"+cvtToStr(++m_funcNum), NULL, "void"); + m_funcp = new AstCFunc(m_modp->fileline(), m_basename + "_" + cvtToStr(++m_funcNum), + NULL, "void"); m_funcp->isStatic(false); m_funcp->declPrivate(true); m_funcp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path @@ -75,9 +74,8 @@ public: m_numStmts += 1; } - V3CCtorsVisitor(AstNodeModule* nodep, const string& basename, - const string& argsp="", const string& callargsp="", - const string& stmt="") { + V3CCtorsVisitor(AstNodeModule* nodep, const string& basename, const string& argsp = "", + const string& callargsp = "", const string& stmt = "") { m_basename = basename; m_argsp = argsp; m_callargsp = callargsp; @@ -89,13 +87,12 @@ public: m_tlFuncp->isStatic(false); m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path m_tlFuncp->argTypes(m_argsp); - if (stmt != "") { - m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); - } + if (stmt != "") { m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); } m_funcp = m_tlFuncp; m_modp->addStmtp(m_tlFuncp); } ~V3CCtorsVisitor() {} + private: VL_UNCOPYABLE(V3CCtorsVisitor); }; @@ -122,15 +119,16 @@ void V3CCtors::evalAsserts() { if (varp->isWide()) { newp = new AstWordSel( varp->fileline(), newp, - new AstConst(varp->fileline(), varp->widthWords()-1)); + new AstConst(varp->fileline(), varp->widthWords() - 1)); } uint64_t value = VL_MASK_Q(storedWidth) & ~VL_MASK_Q(lastWordWidth); newp = new AstAnd(varp->fileline(), newp, new AstConst(varp->fileline(), AstConst::WidthedValue(), storedWidth, value)); - AstNodeIf* ifp = new AstIf(varp->fileline(), newp, - new AstCStmt(varp->fileline(), - "Verilated::overWidthError(\""+varp->prettyName()+"\");")); + AstNodeIf* ifp = new AstIf( + varp->fileline(), newp, + new AstCStmt(varp->fileline(), "Verilated::overWidthError(\"" + + varp->prettyName() + "\");")); ifp->branchPred(VBranchPred::BP_UNLIKELY); newp = ifp; funcp->addStmtsp(newp); @@ -142,10 +140,10 @@ void V3CCtors::evalAsserts() { } void V3CCtors::cctorsAll() { - UINFO(2,__FUNCTION__<<": "<modulesp(); - modp; modp = VN_CAST(modp->nextp(), NodeModule)) { + for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; + modp = VN_CAST(modp->nextp(), NodeModule)) { // Process each module in turn AstCFunc* varResetFuncp; { @@ -158,8 +156,7 @@ void V3CCtors::cctorsAll() { for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { if (AstVar* varp = VN_CAST(np, Var)) { - if (!varp->isIfaceParent() && !varp->isIfaceRef() - && !varp->noReset()) { + if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) { var_reset.add(new AstCReset(varp->fileline(), new AstVarRef(varp->fileline(), varp, true))); } @@ -168,10 +165,8 @@ void V3CCtors::cctorsAll() { } if (v3Global.opt.coverage()) { V3CCtorsVisitor configure_coverage( - modp, "_configure_coverage", - EmitCBaseVisitor::symClassVar() + ", bool first", - "vlSymsp, first", - "if (false && vlSymsp && first) {} // Prevent unused\n"); + modp, "_configure_coverage", EmitCBaseVisitor::symClassVar() + ", bool first", + "vlSymsp, first", "if (false && vlSymsp && first) {} // Prevent unused\n"); for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { if (AstCoverDecl* coverp = VN_CAST(np, CoverDecl)) { AstNode* backp = coverp->backp(); diff --git a/src/V3Case.cpp b/src/V3Case.cpp index c81caf941..e125afcd7 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -45,9 +45,9 @@ #include #include -#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in -#define CASE_BARF 999999 // Magic width when non-constant -#define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree +#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in +#define CASE_BARF 999999 // Magic width when non-constant +#define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree //###################################################################### @@ -64,8 +64,8 @@ private: } // Detect multiple defaults bool hitDefault = false; - for (AstCaseItem* itemp = nodep->itemsp(); - itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { if (itemp->isDefault()) { if (hitDefault) { itemp->v3error("Multiple default statements in case statement."); @@ -78,8 +78,8 @@ private: { m_caseExprp = nodep; iterate(nodep->exprp()); - for (AstCaseItem* itemp = nodep->itemsp(); - itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { iterateAndNextNull(itemp->condsp()); } m_caseExprp = NULL; @@ -89,16 +89,20 @@ private: // See also neverItem if (m_caseExprp && nodep->num().isFourState()) { if (VN_IS(m_caseExprp, GenCase)) { - nodep->v3error("Use of x/? constant in generate case statement, (no such thing as 'generate casez')"); + nodep->v3error("Use of x/? constant in generate case statement, " + "(no such thing as 'generate casez')"); } else if (VN_IS(m_caseExprp, Case) && VN_CAST(m_caseExprp, Case)->casex()) { // Don't sweat it, we already complained about casex in general - } else if (VN_IS(m_caseExprp, Case) && (VN_CAST(m_caseExprp, Case)->casez() - || VN_CAST(m_caseExprp, Case)->caseInside())) { + } else if (VN_IS(m_caseExprp, Case) + && (VN_CAST(m_caseExprp, Case)->casez() + || VN_CAST(m_caseExprp, Case)->caseInside())) { if (nodep->num().isUnknown()) { - nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, (perhaps intended ?/z in constant)"); + nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, " + "(perhaps intended ?/z in constant)"); } } else { - nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, (perhaps intended casex/casez)"); + nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, " + "(perhaps intended casex/casez)"); } } } @@ -121,17 +125,18 @@ private: // NODE STATE // Cleared each Case // AstIf::user3() -> bool. Set true to indicate clone not needed - AstUser3InUse m_inuser3; + AstUser3InUse m_inuser3; // STATE VDouble0 m_statCaseFast; // Statistic tracking VDouble0 m_statCaseSlow; // Statistic tracking // Per-CASE - int m_caseWidth; // Width of valueItems - int m_caseItems; // Number of caseItem unique values - bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant - AstNode* m_valueItem[1<itemsp(); - itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) { - for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { + for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) { if (icondp->width() > width) width = icondp->width(); if (icondp->isDouble()) opaque = true; if (!VN_IS(icondp, Const)) width = CASE_BARF; // Can't parse; not a constant @@ -151,38 +156,39 @@ private: } } m_caseWidth = width; - if (width==0 || width > CASE_OVERLAP_WIDTH || opaque) { + if (width == 0 || width > CASE_OVERLAP_WIDTH || opaque) { m_caseNoOverlapsAllCovered = false; return false; // Too wide for analysis } - UINFO(8,"Simple case statement: "<itemsp(); - itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) { - for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) { - //if (debug()>=9) icondp->dumpTree(cout, " caseitem: "); + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { + for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) { + // if (debug() >= 9) icondp->dumpTree(cout, " caseitem: "); AstConst* iconstp = VN_CAST(icondp, Const); UASSERT_OBJ(iconstp, nodep, "above 'can't parse' should have caught this"); if (neverItem(nodep, iconstp)) { // X in casez can't ever be executed } else { - V3Number nummask (itemp, iconstp->width()); + V3Number nummask(itemp, iconstp->width()); nummask.opBitsNonX(iconstp->num()); uint32_t mask = nummask.toUInt(); - V3Number numval (itemp, iconstp->width()); + V3Number numval(itemp, iconstp->width()); numval.opBitsOne(iconstp->num()); - uint32_t val = numval.toUInt(); - for (uint32_t i=0; i<(1UL<ignoreOverlap() && !bitched) { - icondp->v3warn(CASEOVERLAP, "Case values overlap (example pattern 0x" - <v3warn(CASEOVERLAP, + "Case values overlap (example pattern 0x" + << std::hex << i << ")"); bitched = true; m_caseNoOverlapsAllCovered = false; } @@ -192,15 +198,16 @@ private: } // Defaults were moved to last in the caseitem list by V3LinkDot if (itemp->isDefault()) { // Case statement's default... Fill the table - for (uint32_t i=0; i<(1UL<v3warn(CASEINCOMPLETE, "Case values incompletely covered (example pattern 0x" - <v3warn(CASEINCOMPLETE, "Case values incompletely covered " + "(example pattern 0x" + << std::hex << i << ")"); m_caseNoOverlapsAllCovered = false; return false; } @@ -213,24 +220,23 @@ private: // Convert valueItem from AstCaseItem* to the expression // Not done earlier, as we may now have a NULL because it's just a ";" NOP branch - for (uint32_t i=0; i<(1UL<bodysp(); } return true; // All is fine } AstNode* replaceCaseFastRecurse(AstNode* cexprp, int msb, uint32_t upperValue) { - if (msb<0) { + if (msb < 0) { // There's no space for a IF. We know upperValue is thus down to a specific // exact value, so just return the tree value // Note can't clone here, as we're going to check for equivalence above return m_valueItem[upperValue]; - } - else { + } else { // Make left and right subtrees // cexpr[msb:lsb] == 1 - AstNode* tree0p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | 0); - AstNode* tree1p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | (1UL<deleteTree(), tree1p); @@ -256,14 +263,12 @@ private: if (tree1p && !tree1p->user3()) tree1p = tree1p->cloneTree(true); // Alternate scheme if we ever do multiple bits at a time: - //V3Number nummask (cexprp, cexprp->width(), (1UL<fileline(), cexprp->cloneTree(false), + // V3Number nummask (cexprp, cexprp->width(), (1UL<fileline(), cexprp->cloneTree(false), // new AstConst(cexprp->fileline(), nummask)); - AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false), - msb, 1); - AstNode* eqp = new AstNeq(cexprp->fileline(), - new AstConst(cexprp->fileline(), 0), - and1p); + AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false), msb, 1); + AstNode* eqp + = new AstNeq(cexprp->fileline(), new AstConst(cexprp->fileline(), 0), and1p); AstIf* ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p); ifp->user3(1); // So we don't bother to clone it return ifp; @@ -276,10 +281,10 @@ private: // IF(msb-1, 01, 00)) AstNode* cexprp = nodep->exprp()->unlinkFrBack(); - if (debug()>=9) { - for (uint32_t i=0; i<(1UL<= 9) { + for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) { if (AstNode* itemp = m_valueItem[i]) { - UINFO(9,"Value "<user3()) ifrootp = ifrootp->cloneTree(true); - if (ifrootp) nodep->replaceWith(ifrootp); - else nodep->unlinkFrBack(); + if (ifrootp) { + nodep->replaceWith(ifrootp); + } else { + nodep->unlinkFrBack(); + } VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(cexprp->deleteTree(), cexprp); - if (debug()>=9) ifrootp->dumpTree(cout, " _simp: "); + if (debug() >= 9) ifrootp->dumpTree(cout, " _simp: "); } void replaceCaseComplicated(AstCase* nodep) { @@ -307,9 +315,10 @@ private: AstNode* cexprp = nodep->exprp()->unlinkFrBack(); // We'll do this in two stages. First stage, convert the conditions to // the appropriate IF AND terms. - if (debug()>=9) nodep->dumpTree(cout, " _comp_IN: "); + if (debug() >= 9) nodep->dumpTree(cout, " _comp_IN: "); bool hadDefault = false; - for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { if (!itemp->condsp()) { // Default clause. Just make true, we'll optimize it away later itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue())); @@ -318,7 +327,7 @@ private: // Expressioned clause AstNode* icondNextp = NULL; AstNode* ifexprp = NULL; // If expression to test - for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondNextp) { + for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondNextp) { icondNextp = icondp->nextp(); icondp->unlinkFrBack(); @@ -326,7 +335,8 @@ private: AstConst* iconstp = VN_CAST(icondp, Const); if (iconstp && neverItem(nodep, iconstp)) { // X in casez can't ever be executed - VL_DO_DANGLING(icondp->deleteTree(), icondp); VL_DANGLING(iconstp); + VL_DO_DANGLING(icondp->deleteTree(), icondp); + VL_DANGLING(iconstp); // For simplicity, make expression that is not equal, and let later // optimizations remove it condp = new AstConst(itemp->fileline(), AstConst::LogicFalse()); @@ -336,16 +346,17 @@ private: irangep->rhsp()->unlinkFrBack()); } else if (iconstp && iconstp->num().isFourState() && (nodep->casex() || nodep->casez() || nodep->caseInside())) { - V3Number nummask (itemp, iconstp->width()); + V3Number nummask(itemp, iconstp->width()); nummask.opBitsNonX(iconstp->num()); - V3Number numval (itemp, iconstp->width()); + V3Number numval(itemp, iconstp->width()); numval.opBitsOne(iconstp->num()); AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false), new AstConst(itemp->fileline(), nummask)); AstNode* and2p = new AstAnd(itemp->fileline(), new AstConst(itemp->fileline(), numval), new AstConst(itemp->fileline(), nummask)); - VL_DO_DANGLING(icondp->deleteTree(), icondp); VL_DANGLING(iconstp); + VL_DO_DANGLING(icondp->deleteTree(), icondp); + VL_DANGLING(iconstp); condp = AstEq::newTyped(itemp->fileline(), and1p, and2p); } else { // Not a caseX mask, we can simply build CASEEQ(cexpr icond) @@ -367,11 +378,10 @@ private: if (!hadDefault) { // If there was no default, add a empty one, this greatly simplifies below code // and constant propagation will just eliminate it for us later. - nodep->addItemsp(new AstCaseItem(nodep->fileline(), - new AstConst(nodep->fileline(), AstConst::LogicTrue()), - NULL)); + nodep->addItemsp(new AstCaseItem( + nodep->fileline(), new AstConst(nodep->fileline(), AstConst::LogicTrue()), NULL)); } - if (debug()>=9) nodep->dumpTree(cout, " _comp_COND: "); + if (debug() >= 9) nodep->dumpTree(cout, " _comp_COND: "); // Now build the IF statement tree // The tree can be quite huge. Pull ever group of 8 out, and make a OR tree. // This reduces the depth for the bottom elements, at the cost of @@ -382,46 +392,56 @@ private: AstNode* grouprootp = NULL; AstIf* groupnextp = NULL; AstIf* itemnextp = NULL; - for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action. if (istmtsp) istmtsp->unlinkFrBackWithNext(); // Expressioned clause AstNode* ifexprp = itemp->condsp()->unlinkFrBack(); - { // Prepare for next group + { // Prepare for next group if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1; if (depth == 1) { // First group or starting new group itemnextp = NULL; - AstIf* newp = new AstIf(itemp->fileline(), - ifexprp->cloneTree(true), NULL, NULL); - if (groupnextp) groupnextp->addElsesp(newp); - else grouprootp = newp; + AstIf* newp + = new AstIf(itemp->fileline(), ifexprp->cloneTree(true), NULL, NULL); + if (groupnextp) { + groupnextp->addElsesp(newp); + } else { + grouprootp = newp; + } groupnextp = newp; } else { // Continue group, modify if condition to OR in this new condition AstNode* condp = groupnextp->condp()->unlinkFrBack(); - groupnextp->condp(new AstOr(ifexprp->fileline(), - condp, - ifexprp->cloneTree(true))); + groupnextp->condp( + new AstOr(ifexprp->fileline(), condp, ifexprp->cloneTree(true))); } } - { // Make the new lower IF and attach in the tree - AstNode* itemexprp = ifexprp; VL_DANGLING(ifexprp); - if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition + { // Make the new lower IF and attach in the tree + AstNode* itemexprp = ifexprp; + VL_DANGLING(ifexprp); + if (depth == CASE_ENCODER_GROUP_DEPTH) { // End of group - can skip the condition VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp); itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue()); } AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL); - if (itemnextp) itemnextp->addElsesp(newp); - else groupnextp->addIfsp(newp); // First in a new group + if (itemnextp) { + itemnextp->addElsesp(newp); + } else { + groupnextp->addIfsp(newp); // First in a new group + } itemnextp = newp; } } - if (debug()>=9) nodep->dumpTree(cout, " _comp_TREE: "); + if (debug() >= 9) nodep->dumpTree(cout, " _comp_TREE: "); // Handle any assertions replaceCaseParallel(nodep, false); // Replace the CASE... with IF... - if (debug()>=9 && grouprootp) grouprootp->dumpTree(cout, " _new: "); - if (grouprootp) nodep->replaceWith(grouprootp); - else nodep->unlinkFrBack(); + if (debug() >= 9 && grouprootp) grouprootp->dumpTree(cout, " _new: "); + if (grouprootp) { + nodep->replaceWith(grouprootp); + } else { + nodep->unlinkFrBack(); + } VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -451,7 +471,7 @@ private: virtual void visit(AstCase* nodep) VL_OVERRIDE { V3Case::caseLint(nodep); iterateChildren(nodep); - if (debug()>=9) nodep->dumpTree(cout, " case_old: "); + if (debug() >= 9) nodep->dumpTree(cout, " case_old: "); if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) { // It's a simple priority encoder or complete statement // we can make a tree of statements to avoid extra comparisons @@ -471,9 +491,7 @@ public: m_caseWidth = 0; m_caseItems = 0; m_caseNoOverlapsAllCovered = false; - for (uint32_t i=0; i<(1UL<= 3); } void V3Case::caseLint(AstNodeCase* nodep) { - UINFO(4,__FUNCTION__<<": "<unlinkFrBack(&relinkHandle); // AstCCast* castp = new AstCCast(nodep->fileline(), nodep, needsize, nodep->widthMin()); relinkHandle.relink(castp); - //if (debug()>8) castp->dumpTree(cout, "-castins: "); + // if (debug() > 8) castp->dumpTree(cout, "-castins: "); // ensureLower32Cast(castp); nodep->user1(1); // Now must be of known size } int castSize(AstNode* nodep) { - if (nodep->isQuad()) return VL_QUADSIZE; - else if (nodep->width() <= 8) return 8; - else if (nodep->width() <= 16) return 16; - else return VL_IDATASIZE; + if (nodep->isQuad()) { + return VL_QUADSIZE; + } else if (nodep->width() <= 8) { + return 8; + } else if (nodep->width() <= 16) { + return 16; + } else { + return VL_IDATASIZE; + } } void ensureCast(AstNode* nodep) { - if (castSize(nodep->backp()) != castSize(nodep) - || !nodep->user1()) { + if (castSize(nodep->backp()) != castSize(nodep) || !nodep->user1()) { insertCast(nodep, castSize(nodep->backp())); } } @@ -91,8 +95,7 @@ private: // really needs to be CAST(uint64(CAST(uint32(x))). // Otherwise a (uint64)(a>b) would return wrong value, as // less than has nondeterministic signedness. - if (nodep->isQuad() && !nodep->lhsp()->isQuad() - && !VN_IS(nodep->lhsp(), CCast)) { + if (nodep->isQuad() && !nodep->lhsp()->isQuad() && !VN_IS(nodep->lhsp(), CCast)) { insertCast(nodep->lhsp(), VL_IDATASIZE); } } @@ -114,16 +117,13 @@ private: } virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE { iterateChildren(nodep); - nodep->user1(nodep->lhsp()->user1() - | nodep->rhsp()->user1()); + nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1()); if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp()); if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp()); } virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE { iterateChildren(nodep); - nodep->user1(nodep->lhsp()->user1() - | nodep->rhsp()->user1() - | nodep->thsp()->user1()); + nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()); if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp()); if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp()); if (nodep->sizeMattersThs()) ensureCast(nodep->thsp()); @@ -136,7 +136,7 @@ private: virtual void visit(AstNegate* nodep) VL_OVERRIDE { iterateChildren(nodep); nodep->user1(nodep->lhsp()->user1()); - if (nodep->lhsp()->widthMin()==1) { + if (nodep->lhsp()->widthMin() == 1) { // We want to avoid a GCC "converting of negative value" warning // from our expansion of // out = {32{a out = - (alvalue() - && !VN_IS(nodep->backp(), CCast) - && VN_IS(nodep->backp(), NodeMath) - && !VN_IS(nodep->backp(), ArraySel) - && nodep->backp()->width() + if (!nodep->lvalue() && !VN_IS(nodep->backp(), CCast) && VN_IS(nodep->backp(), NodeMath) + && !VN_IS(nodep->backp(), ArraySel) && nodep->backp()->width() && castSize(nodep) != castSize(nodep->varp())) { // Cast vars to IData first, else below has upper bits wrongly set // CData x=3; out = (QData)(x<<30); @@ -187,9 +184,7 @@ private: public: // CONSTRUCTORS - explicit CastVisitor(AstNetlist* nodep) { - iterate(nodep); - } + explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); } virtual ~CastVisitor() {} }; @@ -197,9 +192,7 @@ public: // Cast class functions void V3Cast::castAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 0fc002f27..358160c49 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -40,7 +40,7 @@ #include #include -#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic +#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic //###################################################################### @@ -53,18 +53,23 @@ public: // Graph support classes class CdcEitherVertex : public V3GraphVertex { - AstScope* m_scopep; - AstNode* m_nodep; + AstScope* m_scopep; + AstNode* m_nodep; AstSenTree* m_srcDomainp; AstSenTree* m_dstDomainp; - bool m_srcDomainSet:1; - bool m_dstDomainSet:1; - bool m_asyncPath:1; + bool m_srcDomainSet : 1; + bool m_dstDomainSet : 1; + bool m_asyncPath : 1; + public: CdcEitherVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep) - : V3GraphVertex(graphp), m_scopep(scopep), m_nodep(nodep) - , m_srcDomainp(NULL), m_dstDomainp(NULL) - , m_srcDomainSet(false), m_dstDomainSet(false) + : V3GraphVertex(graphp) + , m_scopep(scopep) + , m_nodep(nodep) + , m_srcDomainp(NULL) + , m_dstDomainp(NULL) + , m_srcDomainSet(false) + , m_dstDomainSet(false) , m_asyncPath(false) {} virtual ~CdcEitherVertex() {} // ACCESSORS @@ -85,18 +90,22 @@ public: class CdcVarVertex : public CdcEitherVertex { AstVarScope* m_varScp; - int m_cntAsyncRst; - bool m_fromFlop; + int m_cntAsyncRst; + bool m_fromFlop; + public: CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : CdcEitherVertex(graphp, scopep, varScp) - , m_varScp(varScp), m_cntAsyncRst(0), m_fromFlop(false) {} + , m_varScp(varScp) + , m_cntAsyncRst(0) + , m_fromFlop(false) {} virtual ~CdcVarVertex() {} // ACCESSORS AstVarScope* varScp() const { return m_varScp; } - virtual string name() const { return (cvtToHex(m_varScp)+" "+varScp()->name()); } + virtual string name() const { return (cvtToHex(m_varScp) + " " + varScp()->name()); } virtual string dotColor() const { - return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue"; } + return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue"; + } int cntAsyncRst() const { return m_cntAsyncRst; } void cntAsyncRst(int flag) { m_cntAsyncRst = flag; } bool fromFlop() const { return m_fromFlop; } @@ -104,19 +113,26 @@ public: }; class CdcLogicVertex : public CdcEitherVertex { - bool m_hazard:1; - bool m_isFlop:1; + bool m_hazard : 1; + bool m_isFlop : 1; + public: CdcLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstSenTree* sensenodep) : CdcEitherVertex(graphp, scopep, nodep) - , m_hazard(false), m_isFlop(false) - { srcDomainp(sensenodep); dstDomainp(sensenodep); } + , m_hazard(false) + , m_isFlop(false) { + srcDomainp(sensenodep); + dstDomainp(sensenodep); + } virtual ~CdcLogicVertex() {} // ACCESSORS - virtual string name() const { return (cvtToHex(nodep())+"@"+scopep()->prettyName()); } + virtual string name() const { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); } virtual string dotColor() const { return hazard() ? "black" : "yellow"; } bool hazard() const { return m_hazard; } - void setHazard(AstNode* nodep) { m_hazard = true; nodep->user3(true); } + void setHazard(AstNode* nodep) { + m_hazard = true; + nodep->user3(true); + } void clearHazard() { m_hazard = false; } bool isFlop() const { return m_isFlop; } void isFlop(bool flag) { m_isFlop = flag; } @@ -127,16 +143,19 @@ public: class CdcDumpVisitor : public CdcBaseVisitor { private: // NODE STATE - //Entire netlist: + // Entire netlist: // {statement}Node::user3 -> bool, indicating not hazard std::ofstream* m_ofp; // Output file - string m_prefix; + string m_prefix; virtual void visit(AstNode* nodep) VL_OVERRIDE { - *m_ofp<user3()) *m_ofp<<" %%"; - else *m_ofp<<" "; - *m_ofp<prettyTypeName()<<" "<user3()) { + *m_ofp << " %%"; + } else { + *m_ofp << " "; + } + *m_ofp << nodep->prettyTypeName() << " " << endl; string lastPrefix = m_prefix; m_prefix = lastPrefix + "1:"; iterateAndNextNull(nodep->op1p()); @@ -163,19 +182,20 @@ public: class CdcWidthVisitor : public CdcBaseVisitor { private: - int m_maxLineno; - size_t m_maxFilenameLen; + int m_maxLineno; + size_t m_maxFilenameLen; virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); // Keeping line+filename lengths separate is much faster than calling ascii().length() if (nodep->fileline()->lineno() >= m_maxLineno) { - m_maxLineno = nodep->fileline()->lineno()+1; + m_maxLineno = nodep->fileline()->lineno() + 1; } if (nodep->fileline()->filename().length() >= m_maxFilenameLen) { - m_maxFilenameLen = nodep->fileline()->filename().length()+1; + m_maxFilenameLen = nodep->fileline()->filename().length() + 1; } } + public: // CONSTRUCTORS explicit CdcWidthVisitor(AstNode* nodep) { @@ -201,32 +221,32 @@ public: class CdcVisitor : public CdcBaseVisitor { private: // NODE STATE - //Entire netlist: + // Entire netlist: // AstVarScope::user1p -> CdcVarVertex* for usage var, 0=not set yet // AstVarScope::user2 -> bool Used in sensitivity list // {statement}Node::user1p -> CdcLogicVertex* for this statement // AstNode::user3 -> bool True indicates to print %% (via V3EmitV) - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser3InUse m_inuser3; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; + AstUser3InUse m_inuser3; // STATE - V3Graph m_graph; // Scoreboard of var usages/dependencies - CdcLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored - AstScope* m_scopep; // Current scope being processed - AstNodeModule* m_modp; // Current module - AstSenTree* m_domainp; // Current sentree - bool m_inDly; // In delayed assign - int m_inSenItem; // Number of senitems - string m_ofFilename; // Output filename - std::ofstream* m_ofp; // Output file - uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices - int m_filelineWidth; // Characters in longest fileline + V3Graph m_graph; // Scoreboard of var usages/dependencies + CdcLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored + AstScope* m_scopep; // Current scope being processed + AstNodeModule* m_modp; // Current module + AstSenTree* m_domainp; // Current sentree + bool m_inDly; // In delayed assign + int m_inSenItem; // Number of senitems + string m_ofFilename; // Output filename + std::ofstream* m_ofp; // Output file + uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices + int m_filelineWidth; // Characters in longest fileline // METHODS void iterateNewStmt(AstNode* nodep) { if (m_scopep) { - UINFO(4," STMT "<hasClocked()) { // To/from a flop m_logicVertexp->isFlop(true); @@ -238,7 +258,7 @@ private: iterateChildren(nodep); m_logicVertexp = NULL; - if (0 && debug()>=9) { + if (0 && debug() >= 9) { UINFO(9, "Trace Logic:\n"); nodep->dumpTree(cout, "-log1: "); } @@ -248,15 +268,15 @@ private: CdcVarVertex* makeVarVertex(AstVarScope* varscp) { CdcVarVertex* vertexp = reinterpret_cast(varscp->user1p()); if (!vertexp) { - UINFO(6,"New vertex "<user1p(vertexp); if (varscp->varp()->isUsedClock()) {} if (varscp->varp()->isPrimaryIO()) { - // Create IO vertex - note it's relative to the pointed to var, not where we are now - // This allows reporting to easily print the input statement - CdcLogicVertex* ioVertexp = new CdcLogicVertex(&m_graph, varscp->scopep(), - varscp->varp(), NULL); + // Create IO vertex - note it's relative to the pointed to var, not where we are + // now This allows reporting to easily print the input statement + CdcLogicVertex* ioVertexp + = new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL); if (varscp->varp()->isWritable()) { new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1); } else { @@ -266,10 +286,10 @@ private: } if (m_inSenItem) { varscp->user2(true); // It's like a clock... - // TODO: In the future we could mark it here and do normal clock tree glitch checks also + // TODO: In the future mark it here and do normal clock tree glitch checks also } else if (varscp->user2()) { // It was detected in a sensitivity list earlier // And now it's used as logic. So must be a reset. - vertexp->cntAsyncRst(vertexp->cntAsyncRst()+1); + vertexp->cntAsyncRst(vertexp->cntAsyncRst() + 1); } return vertexp; } @@ -279,9 +299,9 @@ private: nodep->v3warnCode(code, msg); if (!told_file) { told_file = 1; - std::cerr<fileline()<<" "<fileline() << " " << msg << endl; } void setNodeHazard(AstNode* nodep) { @@ -291,28 +311,34 @@ private: // an issue until we find a hitting flop. // Furthermore, a module like a "Or" module would only get flagged // once, even though the signals feeding it are radically different. - if (!m_domainp || m_domainp->hasCombo()) { // Source flop logic in a posedge block is OK for reset (not async though) + if (!m_domainp || m_domainp->hasCombo()) { + // Source flop logic in a posedge block is OK for reset (not async though) if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) { - UINFO(8,"Set hazard "<setHazard(nodep); } } } - string spaces(int level) { string out; while (level--) out += " "; return out; } // LCOV_EXCL_LINE + string spaces(int level) { + string out; + while (level--) out += " "; + return out; + } // LCOV_EXCL_LINE string pad(unsigned column, const string& in) { string out = in; - while (out.length()6) m_graph.dump(); - if (debug()>6) m_graph.dumpDotFilePrefixed("cdc_pre"); + UINFO(3, __FUNCTION__ << ": " << endl); + // if (debug() > 6) m_graph.dump(); + if (debug() > 6) m_graph.dumpDotFilePrefixed("cdc_pre"); // - m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); // This will MAX across edge weights + m_graph.removeRedundantEdges( + &V3GraphEdge::followAlwaysTrue); // This will MAX across edge weights // m_graph.dumpDotFilePrefixed("cdc_simp"); // @@ -321,7 +347,7 @@ private: int filelineWidth() { if (!m_filelineWidth) { - CdcWidthVisitor visitor (v3Global.rootp()); + CdcWidthVisitor visitor(v3Global.rootp()); m_filelineWidth = visitor.maxWidth(); } return m_filelineWidth; @@ -334,15 +360,15 @@ private: // Find all async reset wires, and trace backwards // userClearVertices is very slow, so we use a generation count instead m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (CdcVarVertex* vvertexp = dynamic_cast(itp)) { if (vvertexp->cntAsyncRst()) { m_userGeneration++; // Effectively a userClearVertices() - UINFO(8, " Trace One async: "<user()>=m_userGeneration) return NULL; // Processed - prevent loop + if (vertexp->user() >= m_userGeneration) return NULL; // Processed - prevent loop vertexp->user(m_userGeneration); CdcEitherVertex* mark_outp = NULL; - UINFO(9," Trace: "<asyncPath(false); @@ -369,8 +395,7 @@ private: // Any logic considered bad, at the moment, anyhow if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp; // And keep tracing back so the user can understand what's up - } - else if (CdcVarVertex* vvertexp = dynamic_cast(vertexp)) { + } else if (CdcVarVertex* vvertexp = dynamic_cast(vertexp)) { if (mark) vvertexp->asyncPath(true); // If primary I/O, it's ok here back if (vvertexp->varScp()->varp()->isPrimaryInish()) { @@ -403,62 +428,60 @@ private: void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) { AstNode* nodep = vertexp->varScp(); - *m_ofp<<"\n"; - *m_ofp<<"\n"; + *m_ofp << "\n"; + *m_ofp << "\n"; CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many) for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { CdcEitherVertex* eToVertexp = static_cast(edgep->top()); if (!eToVertexp) targetp = eToVertexp; if (CdcLogicVertex* vvertexp = dynamic_cast(eToVertexp)) { if (vvertexp->isFlop() // IE the target flop that is upsetting us - && edgep->weight() >= CDC_WEIGHT_ASYNC) { // And this signal feeds an async reset line + && edgep->weight() >= CDC_WEIGHT_ASYNC) { // And var feeds an async reset line targetp = eToVertexp; - //UINFO(9," targetasync "<name()<<" "<<" from "<name()<name()<<" "<<" from + // "<name()<name()<<" "<nodep()->fileline()<name()<<" "<nodep()->fileline()<nodep(), V3ErrorCode::CDCRSTLOGIC, - "Logic in path that feeds async reset, via signal: "+nodep->prettyNameQ()); + "Logic in path that feeds async reset, via signal: " + nodep->prettyNameQ()); dumpAsyncRecurse(targetp, "", " ", 0); } - bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, - const string& sep, int level) { + bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& sep, + int level) { // level=0 is special, indicates to dump destination flop // Return true if printed anything // If mark, also mark the output even if nothing hazardous below - if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop + if (vertexp->user() >= m_userGeneration) return false; // Processed - prevent loop vertexp->user(m_userGeneration); - if (!vertexp->asyncPath() && level!=0) return false; // Not part of path + if (!vertexp->asyncPath() && level != 0) return false; // Not part of path // Other logic in the path - string cont = prefix+sep; + string cont = prefix + sep; string nextsep = " "; for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { CdcEitherVertex* eFromVertexp = static_cast(edgep->fromp()); - if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level+1)) { - nextsep = " | "; - } + if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level + 1)) nextsep = " | "; } // Dump single variable/logic block // See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp) AstNode* nodep = vertexp->nodep(); - string front = pad(filelineWidth(), nodep->fileline()->ascii()+":")+" "+prefix+" +- "; + string front + = pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- "; if (VN_IS(nodep, VarScope)) { - *m_ofp<prettyName()<prettyName() << endl; + } else { + V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix + " +- ", filelineWidth(), vertexp->srcDomainp(), true); - if (debug()) { - CdcDumpVisitor visitor (nodep, m_ofp, front+"DBG: "); - } + if (debug()) { CdcDumpVisitor visitor(nodep, m_ofp, front + "DBG: "); } } nextsep = " | "; - if (level) *m_ofp<(vertexp)) { // Now that we've printed a path with this hazard, don't bother to print any more @@ -479,27 +502,27 @@ private: // module. Disabling flattening though makes us consider each // signal in it's own unique clock domain. - UINFO(3,__FUNCTION__<<": "<verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (CdcVarVertex* vvertexp = dynamic_cast(itp)) { - UINFO(9, " Trace One edge: "< ofp (V3File::new_ofstream(filename)); - if (ofp->fail()) v3fatal("Can't write "< ofp(V3File::new_ofstream(filename)); + if (ofp->fail()) v3fatal("Can't write " << filename); + *ofp << "Edge Report for " << v3Global.opt.prefix() << endl; std::deque report; // Sort output by name - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (CdcVarVertex* vvertexp = dynamic_cast(itp)) { AstVar* varp = vvertexp->varScp()->varp(); { @@ -511,46 +534,50 @@ private: // Module name - doesn't work due to flattening having lost the original // so we assume the modulename matches the filebasename string fname = vvertexp->varScp()->fileline()->filebasename() + ":"; - os<<" "<varScp()->prettyName(); - os<<" SRC="; - if (vvertexp->srcDomainp()) V3EmitV::verilogForTree(vvertexp->srcDomainp(), os); - os<<" DST="; - if (vvertexp->dstDomainp()) V3EmitV::verilogForTree(vvertexp->dstDomainp(), os); - os<varScp()->prettyName(); + os << " SRC="; + if (vvertexp->srcDomainp()) { + V3EmitV::verilogForTree(vvertexp->srcDomainp(), os); + } + os << " DST="; + if (vvertexp->dstDomainp()) { + V3EmitV::verilogForTree(vvertexp->dstDomainp(), os); + } + os << std::setw(0); + os << endl; report.push_back(os.str()); } } } stable_sort(report.begin(), report.end()); - for (std::deque::iterator it = report.begin(); it!=report.end(); ++it) { + for (std::deque::iterator it = report.begin(); it != report.end(); ++it) { *ofp << *it; } } void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) { // Scan back to inputs/outputs, flops, and compute clock domain information - UINFO(8,spaces(level)<<" Tracein "<user()>=m_userGeneration) return; // Mid-Processed - prevent loop + UINFO(8, spaces(level) << " Tracein " << vertexp << endl); + if (vertexp->user() >= m_userGeneration) return; // Mid-Processed - prevent loop vertexp->user(m_userGeneration); // Variables from flops already are domained - if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) return; // Fully computed + if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) { + return; + } // Fully computed typedef std::set SenSet; SenSet senouts; // List of all sensitivities for new signal if (CdcLogicVertex* vvertexp = dynamic_cast(vertexp)) { if (vvertexp) {} // Unused - } - else if (CdcVarVertex* vvertexp = dynamic_cast(vertexp)) { + } else if (CdcVarVertex* vvertexp = dynamic_cast(vertexp)) { // If primary I/O, give it domain of the input AstVar* varp = vvertexp->varScp()->varp(); if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) { - senouts.insert( - new AstSenTree(varp->fileline(), - new AstSenItem(varp->fileline(), AstSenItem::Combo()))); + senouts.insert(new AstSenTree( + varp->fileline(), new AstSenItem(varp->fileline(), AstSenItem::Combo()))); } } @@ -558,23 +585,24 @@ private: if (traceDests) { for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { CdcEitherVertex* eToVertexp = static_cast(edgep->top()); - edgeDomainRecurse(eToVertexp, traceDests, level+1); + edgeDomainRecurse(eToVertexp, traceDests, level + 1); if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp()); } } else { for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { CdcEitherVertex* eFromVertexp = static_cast(edgep->fromp()); - edgeDomainRecurse(eFromVertexp, traceDests, level+1); + edgeDomainRecurse(eFromVertexp, traceDests, level + 1); if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp()); } } // Convert list of senses into one sense node AstSenTree* senoutp = NULL; - bool senedited = false; - for (SenSet::iterator it=senouts.begin(); it!=senouts.end(); ++it) { - if (!senoutp) senoutp = *it; - else { + bool senedited = false; + for (SenSet::iterator it = senouts.begin(); it != senouts.end(); ++it) { + if (!senoutp) { + senoutp = *it; + } else { if (!senedited) { senedited = true; senoutp = senoutp->cloneTree(true); @@ -583,22 +611,26 @@ private: } } // If multiple domains need to do complicated optimizations - if (senedited) { - senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree); - } + if (senedited) { senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree); } if (traceDests) { vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that vertexp->dstDomainp(senoutp); - if (debug()>=9) { - UINFO(9,spaces(level)+" Tracedst "<= 9) { + UINFO(9, spaces(level) + " Tracedst " << vertexp); + if (senoutp) { + V3EmitV::verilogForTree(senoutp, cout); + cout << endl; + } } } else { vertexp->srcDomainSet(true); // Note it's set - domainp may be null, so can't use that vertexp->srcDomainp(senoutp); - if (debug()>=9) { - UINFO(9,spaces(level)+" Tracesrc "<= 9) { + UINFO(9, spaces(level) + " Tracesrc " << vertexp); + if (senoutp) { + V3EmitV::verilogForTree(senoutp, cout); + cout << endl; + } } } } @@ -613,7 +645,7 @@ private: m_modp = origModp; } virtual void visit(AstScope* nodep) VL_OVERRIDE { - UINFO(4," SCOPE "<sensesp(); - if (!m_domainp || m_domainp->hasCombo() || m_domainp->hasClocked()) { // IE not hasSettle/hasInitial + if (!m_domainp || m_domainp->hasCombo() + || m_domainp->hasClocked()) { // IE not hasSettle/hasInitial iterateNewStmt(nodep); } m_domainp = NULL; @@ -636,7 +669,7 @@ private: AstVarScope* varscp = nodep->varScopep(); UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp"); CdcVarVertex* varvertexp = makeVarVertex(varscp); - UINFO(5," VARREF to "<cntAsyncRst()) { - //UINFO(9," edgeasync "<name()<<" to "<name()<<" to "<name()<<" to "<name()<<" to "<lsbp(), Const)) setNodeHazard(nodep); iterateChildren(nodep); @@ -738,15 +757,16 @@ public: m_filelineWidth = 0; // Make report of all signal names and what clock edges they have - string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc.txt"; + string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc.txt"; m_ofp = V3File::new_ofstream(filename); - if (m_ofp->fail()) v3fatal("Can't write "<fail()) v3fatal("Can't write " << filename); m_ofFilename = filename; - *m_ofp<<"CDC Report for "<fileline(), - "_change_request_" + cvtToStr(++m_funcNum), - m_scopetopp, "QData"); + m_chgFuncp + = new AstCFunc(m_scopetopp->fileline(), "_change_request_" + cvtToStr(++m_funcNum), + m_scopetopp, "QData"); m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar()); m_chgFuncp->symProlog(true); m_chgFuncp->declPrivate(true); @@ -89,9 +89,9 @@ public: // we want and is similar to the logic already in use inside // V3EmitC, however, it also means that verbose logging may // miss to print change detect variables. - AstNode* newp = new AstCReturn(m_scopetopp->fileline(), - new AstLogOr(m_scopetopp->fileline(), callp, - returnp->lhsp()->unlinkFrBack())); + AstNode* newp = new AstCReturn( + m_scopetopp->fileline(), + new AstLogOr(m_scopetopp->fileline(), callp, returnp->lhsp()->unlinkFrBack())); returnp->replaceWith(newp); VL_DO_DANGLING(returnp->deleteTree(), returnp); } @@ -106,57 +106,57 @@ public: class ChangedInsertVisitor : public AstNVisitor { private: // STATE - ChangedState* m_statep; // Shared state across visitors - AstVarScope* m_vscp; // Original (non-change) variable we're change-detecting - AstVarScope* m_newvscp; // New (change detect) variable we're change-detecting - AstNode* m_varEqnp; // Original var's equation to get var value - AstNode* m_newLvEqnp; // New var's equation to read value - AstNode* m_newRvEqnp; // New var's equation to set value - uint32_t m_detects; // # detects created + ChangedState* m_statep; // Shared state across visitors + AstVarScope* m_vscp; // Original (non-change) variable we're change-detecting + AstVarScope* m_newvscp; // New (change detect) variable we're change-detecting + AstNode* m_varEqnp; // Original var's equation to get var value + AstNode* m_newLvEqnp; // New var's equation to read value + AstNode* m_newRvEqnp; // New var's equation to set value + uint32_t m_detects; // # detects created // CONSTANTS enum MiscConsts { - DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error + DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error // Ok to increase this, but may result in much slower model }; void newChangeDet() { if (++m_detects > DETECTARRAY_MAX_INDEXES) { - m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than " - <prettyName()<warnMore() - <<"... Could recompile with DETECTARRAY_MAX_INDEXES increased"<v3warn(E_DETECTARRAY, + "Unsupported: Can't detect more than " + << cvtToStr(DETECTARRAY_MAX_INDEXES) + << " array indexes (probably with UNOPTFLAT warning suppressed): " + << m_vscp->prettyName() << endl + << m_vscp->warnMore() + << "... Could recompile with DETECTARRAY_MAX_INDEXES increased" + << endl); return; } m_statep->maybeCreateChgFuncp(); - AstChangeDet* changep = new AstChangeDet(m_vscp->fileline(), - m_varEqnp->cloneTree(true), + AstChangeDet* changep = new AstChangeDet(m_vscp->fileline(), m_varEqnp->cloneTree(true), m_newRvEqnp->cloneTree(true), false); m_statep->m_chgFuncp->addStmtsp(changep); - AstAssign* initp = new AstAssign(m_vscp->fileline(), - m_newLvEqnp->cloneTree(true), + AstAssign* initp = new AstAssign(m_vscp->fileline(), m_newLvEqnp->cloneTree(true), m_varEqnp->cloneTree(true)); m_statep->m_chgFuncp->addFinalsp(initp); EmitCBaseCounterVisitor visitor(initp); m_statep->m_numStmts += visitor.count(); } - virtual void visit(AstBasicDType* nodep) VL_OVERRIDE { + virtual void visit(AstBasicDType* nodep) VL_OVERRIDE { // newChangeDet(); } - virtual void visit(AstPackArrayDType* nodep) VL_OVERRIDE { + virtual void visit(AstPackArrayDType* nodep) VL_OVERRIDE { // newChangeDet(); } virtual void visit(AstUnpackArrayDType* nodep) VL_OVERRIDE { - for (int index=0; index < nodep->elementsConst(); ++index) { + for (int index = 0; index < nodep->elementsConst(); ++index) { AstNode* origVEp = m_varEqnp; AstNode* origNLEp = m_newLvEqnp; AstNode* origNREp = m_newRvEqnp; - m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index); + m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index); m_newLvEqnp = new AstArraySel(nodep->fileline(), m_newLvEqnp->cloneTree(true), index); m_newRvEqnp = new AstArraySel(nodep->fileline(), m_newRvEqnp->cloneTree(true), index); @@ -166,7 +166,7 @@ private: m_newLvEqnp->deleteTree(); m_newRvEqnp->deleteTree(); - m_varEqnp = origVEp; + m_varEqnp = origVEp; m_newLvEqnp = origNLEp; m_newRvEqnp = origNREp; } @@ -177,17 +177,18 @@ private: } else { if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-class-"); m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable" - " (probably with UNOPTFLAT warning suppressed): " - <varp()->prettyNameQ()); + " (probably with UNOPTFLAT warning suppressed): " + << m_vscp->varp()->prettyNameQ()); } } virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-"); m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable" - " (probably with UNOPTFLAT warning suppressed): " - <varp()->prettyNameQ()); + " (probably with UNOPTFLAT warning suppressed): " + << m_vscp->varp()->prettyNameQ()); } + public: // CONSTRUCTORS ChangedInsertVisitor(AstVarScope* vscp, ChangedState* statep) { @@ -196,19 +197,19 @@ public: m_detects = 0; { AstVar* varp = m_vscp->varp(); - string newvarname = ("__Vchglast__"+m_vscp->scopep()->nameDotless() - +"__"+varp->shortName()); + string newvarname + = ("__Vchglast__" + m_vscp->scopep()->nameDotless() + "__" + varp->shortName()); // Create: VARREF(_last) // ASSIGN(VARREF(_last), VARREF(var)) // ... // CHANGEDET(VARREF(_last), VARREF(var)) - AstVar* newvarp = new AstVar(varp->fileline(), AstVarType::MODULETEMP, - newvarname, varp); + AstVar* newvarp + = new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp); m_statep->m_topModp->addStmtp(newvarp); m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp); m_statep->m_scopetopp->addVarp(m_newvscp); - m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false); + m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false); m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true); m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false); } @@ -229,41 +230,38 @@ private: // NODE STATE // Entire netlist: // AstVarScope::user1() -> bool. True indicates processed - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE - ChangedState* m_statep; // Shared state across visitors + ChangedState* m_statep; // Shared state across visitors // METHODS VL_DEBUG_FUNC; // Declare debug() void genChangeDet(AstVarScope* vscp) { - vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: "<prettyNameQ()); - ChangedInsertVisitor visitor (vscp, m_statep); + vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: " << vscp->prettyNameQ()); + ChangedInsertVisitor visitor(vscp, m_statep); } // VISITORS virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { - UINFO(4," MOD "<isTop()) { - m_statep->m_topModp = nodep; - } + UINFO(4, " MOD " << nodep << endl); + if (nodep->isTop()) m_statep->m_topModp = nodep; iterateChildren(nodep); } virtual void visit(AstTopScope* nodep) VL_OVERRIDE { - UINFO(4," TS "<scopep(); - UASSERT_OBJ(scopep, nodep, - "No scope found on top level, perhaps you have no statements?"); + UASSERT_OBJ(scopep, nodep, "No scope found on top level, perhaps you have no statements?"); m_statep->m_scopetopp = scopep; // Create a wrapper change detection function that calls each change detection function - m_statep->m_tlChgFuncp = new AstCFunc(nodep->fileline(), - "_change_request", scopep, "QData"); + m_statep->m_tlChgFuncp + = new AstCFunc(nodep->fileline(), "_change_request", scopep, "QData"); m_statep->m_tlChgFuncp->argTypes(EmitCBaseVisitor::symClassVar()); m_statep->m_tlChgFuncp->symProlog(true); m_statep->m_tlChgFuncp->declPrivate(true); @@ -277,10 +275,8 @@ private: } virtual void visit(AstVarScope* nodep) VL_OVERRIDE { if (nodep->isCircular()) { - UINFO(8," CIRC "<user1SetOnce()) { - genChangeDet(nodep); - } + UINFO(8, " CIRC " << nodep << endl); + if (!nodep->user1SetOnce()) genChangeDet(nodep); } } //-------------------- @@ -300,10 +296,10 @@ public: // Changed class functions void V3Changed::changedAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 9ee147aed..164463364 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -43,9 +43,9 @@ private: // AstNode::user() -> CleanState. For this node, 0==UNKNOWN // AstNode::user2() -> bool. True indicates widthMin has been propagated // AstNodeDType::user3() -> AstNodeDType*. Alternative node with C size - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser3InUse m_inuser3; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; + AstUser3InUse m_inuser3; // TYPES enum CleanState { CS_UNKNOWN, CS_CLEAN, CS_DIRTY }; @@ -57,10 +57,14 @@ private: VL_DEBUG_FUNC; // Declare debug() // Width resetting - int cppWidth(AstNode* nodep) { - if (nodep->width() <= VL_IDATASIZE) return VL_IDATASIZE; - else if (nodep->width() <= VL_QUADSIZE) return VL_QUADSIZE; - else return nodep->widthWords() * VL_EDATASIZE; + int cppWidth(AstNode* nodep) { + if (nodep->width() <= VL_IDATASIZE) { + return VL_IDATASIZE; + } else if (nodep->width() <= VL_QUADSIZE) { + return VL_QUADSIZE; + } else { + return nodep->widthWords() * VL_EDATASIZE; + } } void setCppWidth(AstNode* nodep) { nodep->user2(true); // Don't resize it again @@ -82,7 +86,8 @@ private: } void computeCppWidth(AstNode* nodep) { if (!nodep->user2() && nodep->hasDType()) { - if (VN_IS(nodep, Var) || VN_IS(nodep, NodeDType) // Don't want to change variable widths! + if (VN_IS(nodep, Var) + || VN_IS(nodep, NodeDType) // Don't want to change variable widths! || VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays || VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType) || VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType) @@ -96,39 +101,33 @@ private: } // Store the clean state in the userp on each node - void setCleanState(AstNode* nodep, CleanState clean) { - nodep->user1(clean); - } - CleanState getCleanState(AstNode* nodep) { - return static_cast(nodep->user1()); - } + void setCleanState(AstNode* nodep, CleanState clean) { nodep->user1(clean); } + CleanState getCleanState(AstNode* nodep) { return static_cast(nodep->user1()); } bool isClean(AstNode* nodep) { CleanState clstate = getCleanState(nodep); - if (clstate==CS_CLEAN) return true; - if (clstate==CS_DIRTY) return false; - nodep->v3fatalSrc("Unknown clean state on node: "+nodep->prettyTypeName()); + if (clstate == CS_CLEAN) return true; + if (clstate == CS_DIRTY) return false; + nodep->v3fatalSrc("Unknown clean state on node: " + nodep->prettyTypeName()); return false; } void setClean(AstNode* nodep, bool isClean) { computeCppWidth(nodep); // Just to be sure it's in widthMin - bool wholeUint = (nodep->widthMin() == VL_IDATASIZE - || nodep->widthMin() == VL_QUADSIZE + bool wholeUint = (nodep->widthMin() == VL_IDATASIZE || nodep->widthMin() == VL_QUADSIZE || (nodep->widthMin() % VL_EDATASIZE) == 0); setCleanState(nodep, ((isClean || wholeUint) ? CS_CLEAN : CS_DIRTY)); } // Operate on nodes void insertClean(AstNode* nodep) { // We'll insert ABOVE passed node - UINFO(4," NeedClean "<unlinkFrBack(&relinkHandle); // computeCppWidth(nodep); - V3Number mask (nodep, cppWidth(nodep)); + V3Number mask(nodep, cppWidth(nodep)); mask.setMask(nodep->widthMin()); - AstNode* cleanp = new AstAnd(nodep->fileline(), - new AstConst(nodep->fileline(), mask), - nodep); + AstNode* cleanp + = new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), mask), nodep); cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS relinkHandle.relink(cleanp); } @@ -138,7 +137,7 @@ private: } void ensureCleanAndNext(AstNode* nodep) { // Editing list, careful looping! - for (AstNode* exprp = nodep; exprp; ) { + for (AstNode* exprp = nodep; exprp;) { AstNode* nextp = exprp->nextp(); ensureClean(exprp); exprp = nextp; @@ -149,27 +148,17 @@ private: void operandBiop(AstNodeBiop* nodep) { iterateChildren(nodep); computeCppWidth(nodep); - if (nodep->cleanLhs()) { - ensureClean(nodep->lhsp()); - } - if (nodep->cleanRhs()) { - ensureClean(nodep->rhsp()); - } - //no setClean.. must do it in each user routine. + if (nodep->cleanLhs()) ensureClean(nodep->lhsp()); + if (nodep->cleanRhs()) ensureClean(nodep->rhsp()); + // no setClean.. must do it in each user routine. } void operandTriop(AstNodeTriop* nodep) { iterateChildren(nodep); computeCppWidth(nodep); - if (nodep->cleanLhs()) { - ensureClean(nodep->lhsp()); - } - if (nodep->cleanRhs()) { - ensureClean(nodep->rhsp()); - } - if (nodep->cleanThs()) { - ensureClean(nodep->thsp()); - } - //no setClean.. must do it in each user routine. + if (nodep->cleanLhs()) ensureClean(nodep->lhsp()); + if (nodep->cleanRhs()) ensureClean(nodep->rhsp()); + if (nodep->cleanThs()) ensureClean(nodep->thsp()); + // no setClean.. must do it in each user routine. } // VISITORS @@ -184,9 +173,7 @@ private: virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE { iterateChildren(nodep); computeCppWidth(nodep); - if (nodep->cleanLhs()) { - ensureClean(nodep->lhsp()); - } + if (nodep->cleanLhs()) ensureClean(nodep->lhsp()); setClean(nodep, nodep->cleanOut()); } virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE { @@ -213,14 +200,12 @@ private: virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { iterateChildren(nodep); computeCppWidth(nodep); - if (nodep->cleanRhs()) { - ensureClean(nodep->rhsp()); - } + if (nodep->cleanRhs()) ensureClean(nodep->rhsp()); } - virtual void visit(AstText* nodep) VL_OVERRIDE { + virtual void visit(AstText* nodep) VL_OVERRIDE { // setClean(nodep, true); } - virtual void visit(AstScopeName* nodep) VL_OVERRIDE { + virtual void visit(AstScopeName* nodep) VL_OVERRIDE { // setClean(nodep, true); } virtual void visit(AstCNew* nodep) VL_OVERRIDE { @@ -236,9 +221,7 @@ private: computeCppWidth(nodep); setClean(nodep, false); // We always clean, as we don't trust those pesky users. - if (!VN_IS(nodep->backp(), And)) { - insertClean(nodep); - } + if (!VN_IS(nodep->backp(), And)) insertClean(nodep); ensureCleanAndNext(nodep->bodysp()); } virtual void visit(AstTraceDecl* nodep) VL_OVERRIDE { @@ -316,9 +299,7 @@ public: // Clean class functions void V3Clean::cleanAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index bbb184244..5e89b0e72 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -46,22 +46,22 @@ private: // NODE STATE // Cleared each Module: // AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created. - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // TYPES enum { DOUBLE_OR_RATE = 10 }; // How many | per ||, Determined experimentally as best // STATE - AstNodeModule* m_modp; // Current module - AstTopScope* m_topScopep; // Current top scope - AstScope* m_scopep; // Current scope - AstCFunc* m_evalFuncp; // Top eval function we are creating - AstCFunc* m_initFuncp; // Top initial function we are creating - AstCFunc* m_finalFuncp; // Top final function we are creating - AstCFunc* m_settleFuncp; // Top settlement function we are creating - AstSenTree* m_lastSenp; // Last sensitivity match, so we can detect duplicates. - AstIf* m_lastIfp; // Last sensitivity if active to add more under - AstMTaskBody* m_mtaskBodyp; // Current mtask body + AstNodeModule* m_modp; // Current module + AstTopScope* m_topScopep; // Current top scope + AstScope* m_scopep; // Current scope + AstCFunc* m_evalFuncp; // Top eval function we are creating + AstCFunc* m_initFuncp; // Top initial function we are creating + AstCFunc* m_finalFuncp; // Top final function we are creating + AstCFunc* m_settleFuncp; // Top settlement function we are creating + AstSenTree* m_lastSenp; // Last sensitivity match, so we can detect duplicates. + AstIf* m_lastIfp; // Last sensitivity if active to add more under + AstMTaskBody* m_mtaskBodyp; // Current mtask body // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -69,12 +69,14 @@ private: AstVarScope* getCreateLastClk(AstVarScope* vscp) { if (vscp->user1p()) return static_cast(vscp->user1p()); AstVar* varp = vscp->varp(); - if (!varp->width1()) varp->v3error("Unsupported: Clock edge on non-single bit signal: " - <prettyNameQ()); - string newvarname = (string("__Vclklast__") - +vscp->scopep()->nameDotless()+"__"+varp->name()); - AstVar* newvarp = new AstVar(vscp->fileline(), - AstVarType::MODULETEMP, newvarname, VFlagLogicPacked(), 1); + if (!varp->width1()) { + varp->v3error( + "Unsupported: Clock edge on non-single bit signal: " << varp->prettyNameQ()); + } + string newvarname + = (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name()); + AstVar* newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname, + VFlagLogicPacked(), 1); newvarp->noReset(true); // Reset by below assign m_modp->addStmtp(newvarp); AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp); @@ -83,18 +85,16 @@ private: // Add init AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false); if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp); - AstNode* newinitp = new AstAssign(vscp->fileline(), - new AstVarRef(newvarp->fileline(), newvscp, true), - fromp); + AstNode* newinitp = new AstAssign( + vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, true), fromp); addToInitial(newinitp); // At bottom, assign them AstAssign* finalp - = new AstAssign(vscp->fileline(), - new AstVarRef(vscp->fileline(), newvscp, true), + = new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true), new AstVarRef(vscp->fileline(), vscp, false)); m_evalFuncp->addFinalsp(finalp); // - UINFO(4,"New Last: "<edgeType()==VEdgeType::ET_ILLEGAL) { + if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) { if (!v3Global.opt.bboxUnsup()) { - nodep->v3error("Unsupported: Complicated event expression in sensitive activity list"); + nodep->v3error( + "Unsupported: Complicated event expression in sensitive activity list"); } return NULL; } AstVarScope* clkvscp = nodep->varrefp()->varScopep(); if (nodep->edgeType() == VEdgeType::ET_POSEDGE) { AstVarScope* lastVscp = getCreateLastClk(clkvscp); - newp = new AstAnd(nodep->fileline(), - new AstVarRef(nodep->fileline(), - nodep->varrefp()->varScopep(), false), - new AstNot(nodep->fileline(), - new AstVarRef(nodep->fileline(), - lastVscp, false))); + newp = new AstAnd( + nodep->fileline(), + new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false), + new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), lastVscp, false))); } else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) { AstVarScope* lastVscp = getCreateLastClk(clkvscp); - newp = new AstAnd(nodep->fileline(), - new AstNot(nodep->fileline(), - new AstVarRef(nodep->fileline(), - nodep->varrefp()->varScopep(), false)), - new AstVarRef(nodep->fileline(), lastVscp, false)); + newp = new AstAnd( + nodep->fileline(), + new AstNot(nodep->fileline(), + new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false)), + new AstVarRef(nodep->fileline(), lastVscp, false)); } else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) { AstVarScope* lastVscp = getCreateLastClk(clkvscp); - newp = new AstXor(nodep->fileline(), - new AstVarRef(nodep->fileline(), - nodep->varrefp()->varScopep(), false), - new AstVarRef(nodep->fileline(), lastVscp, false)); + newp = new AstXor( + nodep->fileline(), + new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false), + new AstVarRef(nodep->fileline(), lastVscp, false)); } else if (nodep->edgeType() == VEdgeType::ET_HIGHEDGE) { - newp = new AstVarRef(nodep->fileline(), - clkvscp, false); + newp = new AstVarRef(nodep->fileline(), clkvscp, false); } else if (nodep->edgeType() == VEdgeType::ET_LOWEDGE) { - newp = new AstNot(nodep->fileline(), - new AstVarRef(nodep->fileline(), - clkvscp, false)); + newp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), clkvscp, false)); } else { nodep->v3fatalSrc("Bad edge type"); } return newp; } AstNode* createSenGateEquation(AstSenGate* nodep) { - AstNode* newp = new AstAnd(nodep->fileline(), - createSenseEquation(nodep->sensesp()), + AstNode* newp = new AstAnd(nodep->fileline(), createSenseEquation(nodep->sensesp()), nodep->rhsp()->cloneTree(true)); return newp; } @@ -186,12 +181,12 @@ private: // VISITORS virtual void visit(AstTopScope* nodep) VL_OVERRIDE { - UINFO(4," TOPSCOPE "<scopep(); UASSERT_OBJ(m_scopep, nodep, "No scope found on top level, perhaps you have no statements?"); - //VV***** We reset all user1p() + // VV***** We reset all user1p() AstNode::user1ClearTree(); // Make top functions { @@ -223,11 +218,10 @@ private: funcp->isStatic(false); funcp->entryPoint(true); funcp->protect(false); - funcp->addInitsp(new AstCStmt - (nodep->fileline(), - EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n")); - funcp->addInitsp(new AstCStmt(nodep->fileline(), - EmitCBaseVisitor::symTopAssign()+"\n")); + funcp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symClassVar() + + " = this->__VlSymsp;\n")); + funcp->addInitsp( + new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign() + "\n")); m_scopep->addActivep(funcp); m_finalFuncp = funcp; } @@ -245,13 +239,13 @@ private: // Process the activates iterateChildren(nodep); // Done, clear so we can detect errors - UINFO(4," TOPSCOPEDONE "<finalClksp()) { @@ -289,24 +283,21 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); } virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { - //nodep->dumpTree(cout, "ct:"); - //COVERTOGGLE(INC, ORIG, CHANGE) -> + // nodep->dumpTree(cout, "ct:"); + // COVERTOGGLE(INC, ORIG, CHANGE) -> // IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; } AstNode* incp = nodep->incp()->unlinkFrBack(); AstNode* origp = nodep->origp()->unlinkFrBack(); AstNode* changep = nodep->changep()->unlinkFrBack(); - AstIf* newp = new AstIf(nodep->fileline(), - new AstXor(nodep->fileline(), - origp, - changep), + AstIf* newp = new AstIf(nodep->fileline(), new AstXor(nodep->fileline(), origp, changep), incp, NULL); // We could add another IF to detect posedges, and only increment if so. // It's another whole branch though versus a potential memory miss. // We'll go with the miss. - newp->addIfsp(new AstAssign(nodep->fileline(), - changep->cloneTree(false), - origp->cloneTree(false))); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + newp->addIfsp( + new AstAssign(nodep->fileline(), changep->cloneTree(false), origp->cloneTree(false))); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } virtual void visit(AstInitial* nodep) VL_OVERRIDE { AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true); @@ -321,7 +312,7 @@ private: iterateChildren(nodep); // Link to global function if (nodep->formCallTree()) { - UINFO(4, " formCallTree "<fileline(), nodep); callp->argTypes("vlSymsp"); m_finalFuncp->addStmtsp(callp); @@ -333,13 +324,13 @@ private: pushDeletep(nodep); } void addToEvalLoop(AstNode* stmtsp) { - m_evalFuncp->addStmtsp(stmtsp); // add to top level function + m_evalFuncp->addStmtsp(stmtsp); // add to top level function } void addToSettleLoop(AstNode* stmtsp) { - m_settleFuncp->addStmtsp(stmtsp); // add to top level function + m_settleFuncp->addStmtsp(stmtsp); // add to top level function } void addToInitial(AstNode* stmtsp) { - m_initFuncp->addStmtsp(stmtsp); // add to top level function + m_initFuncp->addStmtsp(stmtsp); // add to top level function } virtual void visit(AstActive* nodep) VL_OVERRIDE { // Careful if adding variables here, ACTIVES can be under other ACTIVES @@ -350,13 +341,13 @@ private: UASSERT_OBJ(!nodep->stmtsp(), nodep, "Non-empty lower active"); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } else if (m_mtaskBodyp) { - UINFO(4," TR ACTIVE "<stmtsp()->unlinkFrBackWithNext(); if (nodep->hasClocked()) { UASSERT_OBJ(!nodep->hasInitial(), nodep, "Initial block should not have clock sensitivity"); if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) { - UINFO(4," sameSenseTree\n"); + UINFO(4, " sameSenseTree\n"); } else { clearLastSen(); m_lastSenp = nodep->sensesp(); @@ -375,14 +366,14 @@ private: } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } else { - UINFO(4," ACTIVE "<stmtsp()->unlinkFrBackWithNext(); if (nodep->hasClocked()) { // Remember the latest sensitivity so we can compare it next time UASSERT_OBJ(!nodep->hasInitial(), nodep, "Initial block should not have clock sensitivity"); if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) { - UINFO(4," sameSenseTree\n"); + UINFO(4, " sameSenseTree\n"); } else { clearLastSen(); m_lastSenp = nodep->sensesp(); @@ -410,8 +401,7 @@ private: } } virtual void visit(AstExecGraph* nodep) VL_OVERRIDE { - for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody); - m_mtaskBodyp; + for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody); m_mtaskBodyp; m_mtaskBodyp = VN_CAST(m_mtaskBodyp->nextp(), MTaskBody)) { clearLastSen(); iterate(m_mtaskBodyp); @@ -453,9 +443,7 @@ public: // Clock class functions void V3Clock::clockAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index c9f2303f2..9224e0576 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -75,22 +75,24 @@ class CombCallVisitor : CombBaseVisitor { // Find all CCALLS of each CFUNC, so that we can later rename them private: // NODE STATE - typedef std::multimap CallMmap; - CallMmap m_callMmap; // Associative array of {function}{call} + typedef std::multimap CallMmap; + CallMmap m_callMmap; // Associative array of {function}{call} // METHODS public: void replaceFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) { - if (oldfuncp==newfuncp) return; + if (oldfuncp == newfuncp) return; if (newfuncp) { - UINFO(4, " Replace "< "< eqrange + UINFO(4, " Replace " << oldfuncp << " -WITH-> " << newfuncp << endl); + } else { + UINFO(4, " Remove " << oldfuncp << endl); + } + std::pair eqrange = m_callMmap.equal_range(oldfuncp); for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) { CallMmap::iterator eqit = nextit++; AstCCall* callp = eqit->second; if (!callp->user3()) { // !already done - UINFO(4, " Called "<funcp() == oldfuncp, callp, "Call list broken, points to call w/different func"); if (newfuncp) { @@ -108,27 +110,24 @@ public: } } // METHODS - void addCall(AstCCall* nodep) { - m_callMmap.insert(make_pair(nodep->funcp(), nodep)); - } + void addCall(AstCCall* nodep) { m_callMmap.insert(make_pair(nodep->funcp(), nodep)); } void deleteCall(AstCCall* nodep) { - std::pair eqrange + std::pair eqrange = m_callMmap.equal_range(nodep->funcp()); for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) { CallMmap::iterator eqit = nextit++; AstCCall* callp = eqit->second; - if (callp==nodep) { + if (callp == nodep) { m_callMmap.erase(eqit); return; } } nodep->v3fatalSrc("deleteCall node not found in table"); } + private: // VISITORS - virtual void visit(AstCCall* nodep) VL_OVERRIDE { - addCall(nodep); - } + virtual void visit(AstCCall* nodep) VL_OVERRIDE { addCall(nodep); } // Speed things up virtual void visit(AstNodeAssign*) VL_OVERRIDE {} virtual void visit(AstNodeMath*) VL_OVERRIDE {} @@ -154,11 +153,10 @@ private: nodep->user3(true); iterateChildren(nodep); } + public: // CONSTRUCTORS - explicit CombMarkVisitor(AstNode* nodep) { - iterate(nodep); - } + explicit CombMarkVisitor(AstNode* nodep) { iterate(nodep); } virtual ~CombMarkVisitor() {} }; @@ -172,29 +170,30 @@ private: // AstNodeStmt::user() -> bool. True if iterated already // AstCFunc::user3p() -> AstCFunc*, If set, replace ccalls to this func with new func // AstNodeStmt::user3() -> AstNode*. True if to ignore this cell - // AstNodeStmt::user4() -> V3Hashed::V3Hash. Hash value of this node (hash of 0 is illegal) - AstUser1InUse m_inuser1; - AstUser3InUse m_inuser3; - //AstUser4InUse part of V3Hashed + // AstNodeStmt::user4() -> V3Hashed::V3Hash. Hash value of this node (hash of 0 is + // illegal) + AstUser1InUse m_inuser1; + AstUser3InUse m_inuser3; + // AstUser4InUse part of V3Hashed // STATE - typedef enum {STATE_IDLE, STATE_HASH, STATE_DUP} CombineState; - VDouble0 m_statCombs; // Statistic tracking - CombineState m_state; // Major state - AstNodeModule* m_modp; // Current module - AstCFunc* m_funcp; // Current function - V3Hash m_lowerHash; // Hash of the statement we're building - CombCallVisitor m_call; // Tracking of function call users - int m_modNFuncs; // Number of functions made - AstNode* m_walkLast1p; // Final node that is the same in duplicate list - AstNode* m_walkLast2p; // Final node that is the same in duplicate list - V3Hashed m_hashed; // Hash for every node in module + typedef enum { STATE_IDLE, STATE_HASH, STATE_DUP } CombineState; + VDouble0 m_statCombs; // Statistic tracking + CombineState m_state; // Major state + AstNodeModule* m_modp; // Current module + AstCFunc* m_funcp; // Current function + V3Hash m_lowerHash; // Hash of the statement we're building + CombCallVisitor m_call; // Tracking of function call users + int m_modNFuncs; // Number of functions made + AstNode* m_walkLast1p; // Final node that is the same in duplicate list + AstNode* m_walkLast2p; // Final node that is the same in duplicate list + V3Hashed m_hashed; // Hash for every node in module // METHODS void hashStatement(AstNode* nodep) { // Compute hash on entire tree of this statement m_hashed.hashAndInsert(nodep); - //UINFO(9," stmthash "<user4()<<" "<user4() << " " << nodep << endl); } void hashFunctions(AstCFunc* nodep) { // Compute hash of all statement trees in the function @@ -209,11 +208,9 @@ private: for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) { AstNode* node1p = it->second; AstCFunc* oldfuncp = VN_CAST(node1p, CFunc); - if (oldfuncp - && oldfuncp->emptyBody() - && !oldfuncp->dontCombine()) { - UINFO(5," EmptyFunc "<user4p()) - <<" "<emptyBody() && !oldfuncp->dontCombine()) { + UINFO(5, " EmptyFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " " + << oldfuncp << endl); // Mark user3p on entire old tree, so we don't process it more CombMarkVisitor visitor(oldfuncp); m_call.replaceFunc(oldfuncp, NULL); @@ -231,7 +228,7 @@ private: for (V3Hashed::iterator eqit = it; eqit != m_hashed.end(); ++eqit) { AstNode* node2p = eqit->second; if (!(eqit->first == hashval)) break; - if (node1p==node2p) continue; // Identical iterator + if (node1p == node2p) continue; // Identical iterator if (node1p->user3p() || node2p->user3p()) continue; // Already merged if (node1p->sameTree(node2p)) { // walk of tree has same comparison // Replace AstCCall's that point here @@ -243,8 +240,10 @@ private: } } void replaceFuncWFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) { - UINFO(5," DupFunc "<user4p())<<" "<user4p())<<" "<user4p()) << " " << newfuncp + << endl); + UINFO(5, " and " << std::hex << V3Hash(oldfuncp->user4p()) << " " << oldfuncp + << endl); // Mark user3p on entire old tree, so we don't process it more ++m_statCombs; CombMarkVisitor visitor(oldfuncp); @@ -254,12 +253,10 @@ private: } void replaceOnlyCallFunc(AstCCall* nodep) { if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) { - //oldfuncp->dumpTree(cout, "MAYDEL: "); - if (nodep->nextp()==NULL - && oldfuncp->initsp()==NULL - && oldfuncp->stmtsp()==nodep - && oldfuncp->finalsp()==NULL) { - UINFO(9," Function only has call "<dumpTree(cout, "MAYDEL: "); + if (nodep->nextp() == NULL && oldfuncp->initsp() == NULL && oldfuncp->stmtsp() == nodep + && oldfuncp->finalsp() == NULL) { + UINFO(9, " Function only has call " << oldfuncp << endl); m_call.deleteCall(nodep); CombMarkVisitor visitor(oldfuncp); VL_DO_DANGLING(replaceFuncWFunc(oldfuncp, nodep->funcp()), nodep); @@ -269,18 +266,18 @@ private: void walkDupCodeStart(AstNode* node1p) { V3Hash hashval(node1p->user4p()); - //UINFO(4," STMT "< eqrange + std::pair eqrange = m_hashed.mmap().equal_range(hashval); for (V3Hashed::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) { AstNode* node2p = eqit->second; - if (node1p==node2p) continue; + if (node1p == node2p) continue; // // We need to mark iteration to prevent matching code inside // code (abab matching in ababab) @@ -288,8 +285,7 @@ private: m_walkLast1p = NULL; m_walkLast2p = NULL; int depth = walkDupCodeNext(node1p, node2p, 1); - if (depth>COMBINE_MIN_STATEMENTS - && depth>bestDepth) { + if (depth > COMBINE_MIN_STATEMENTS && depth > bestDepth) { bestDepth = depth; bestNode2p = node2p; bestLast1p = m_walkLast1p; @@ -298,11 +294,15 @@ private: } if (bestDepth) { // Found a replacement - UINFO(5," Duplicate of depth "<user3p() || node2p->user3p()) return 0; // Already merged if (!m_hashed.sameNodes(node1p, node2p)) return 0; // walk of tree has same comparison V3Hash hashval(node1p->user4p()); - //UINFO(9," wdup1 "<user4p())<<" "<user4p())<<" "<user4p())<<" "<user4p())<<" "<user1(true); node2p->user1(true); if (node1p->nextp() && node2p->nextp()) { - return hashval.depth()+walkDupCodeNext(node1p->nextp(), node2p->nextp(), level+1); + return hashval.depth() + walkDupCodeNext(node1p->nextp(), node2p->nextp(), level + 1); } return hashval.depth(); } - void walkReplace(AstNode* node1p, AstNode* node2p, - AstNode* last1p, AstNode* last2p) { // Final node in linked list, maybe null if all statements to be grabbed + void walkReplace(AstNode* node1p, AstNode* node2p, AstNode* last1p, + AstNode* last2p) { // Final node in linked list, maybe null if all statements + // to be grabbed // Make new function string oldname = m_funcp->name(); string::size_type pos; - if ((pos = oldname.find("_common")) != string::npos) { - oldname.erase(pos); - } - if ((pos = oldname.find("__")) != string::npos) { - oldname.erase(pos); - } + if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos); + if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos); AstCFunc* newfuncp = new AstCFunc(node1p->fileline(), - oldname+"_common"+cvtToStr(++m_modNFuncs), - NULL); + oldname + "_common" + cvtToStr(++m_modNFuncs), NULL); m_modp->addStmtp(newfuncp); // Create calls AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp); @@ -347,21 +343,29 @@ private: // Grab statement bodies AstNRelinker relink1Handle; AstNRelinker relink2Handle; - for (AstNode* nextp, *walkp = node1p; 1; walkp = nextp) { + for (AstNode *nextp, *walkp = node1p; 1; walkp = nextp) { nextp = walkp->nextp(); - if (walkp==node1p) walkp->unlinkFrBack(&relink1Handle); - else { walkp->unlinkFrBack(); node1p->addNext(walkp); } - if (walkp==last1p) break; + if (walkp == node1p) { + walkp->unlinkFrBack(&relink1Handle); + } else { + walkp->unlinkFrBack(); + node1p->addNext(walkp); + } + if (walkp == last1p) break; } - for (AstNode* nextp, *walkp = node2p; 1; walkp = nextp) { + for (AstNode *nextp, *walkp = node2p; 1; walkp = nextp) { nextp = walkp->nextp(); - if (walkp==node2p) walkp->unlinkFrBack(&relink2Handle); - else { walkp->unlinkFrBack(); node2p->addNext(walkp); } - if (walkp==last2p) break; + if (walkp == node2p) { + walkp->unlinkFrBack(&relink2Handle); + } else { + walkp->unlinkFrBack(); + node2p->addNext(walkp); + } + if (walkp == last2p) break; } // Move node1 statements to new function newfuncp->addStmtsp(node1p); - //newfuncp->dumpTree(cout, " newfunctree: "); + // newfuncp->dumpTree(cout, " newfunctree: "); // Mark node2 statements as dead CombMarkVisitor visitor(node2p); pushDeletep(node2p); // Delete later @@ -383,13 +387,13 @@ private: // Track all callers of each function m_call.main(nodep); // - //In V3Hashed AstNode::user4ClearTree(); // user4p() used on entire tree + // In V3Hashed AstNode::user4ClearTree(); // user4p() used on entire tree // Iterate modules backwards, in bottom-up order. // Required so that a module instantiating another can benefit from collapsing. iterateChildrenBackwards(nodep); } virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { - UINFO(4," MOD "<=9) { - m_hashed.dumpFilePrefixed("combine"); - } + if (debug() >= 9) m_hashed.dumpFilePrefixed("combine"); // Walk the hashes removing empty functions - if (emptyFunctionDeletion()) { - walkEmptyFuncs(); - } + if (emptyFunctionDeletion()) walkEmptyFuncs(); // Walk the hashes looking for duplicate functions - if (duplicateFunctionCombine()) { - walkDupFuncs(); - } + if (duplicateFunctionCombine()) walkDupFuncs(); // Walk the statements looking for large replicated code sections if (statementCombine()) { m_state = STATE_DUP; @@ -435,8 +433,7 @@ private: } if (m_state == STATE_HASH && m_funcp) { hashStatement(nodep); - } - else if (m_state == STATE_DUP && m_funcp) { + } else if (m_state == STATE_DUP && m_funcp) { walkDupCodeStart(nodep); } } @@ -459,7 +456,7 @@ public: m_walkLast2p = NULL; iterate(nodep); } - virtual ~CombineVisitor() { + virtual ~CombineVisitor() { // V3Stats::addStat("Optimizations, Combined CFuncs", m_statCombs); } }; @@ -468,9 +465,7 @@ public: // Combine class functions void V3Combine::combineAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Config.cpp b/src/V3Config.cpp index 46b491e90..7b89b4df7 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -327,12 +327,12 @@ public: inline void applyIgnores(FileLine* filelinep) { // HOT routine, called each parsed token line of this filename if (m_lastIgnore.lineno != filelinep->lineno()) { - // UINFO(9," ApplyIgnores for "<ascii()<ascii() << endl); // Process all on/offs for lines up to and including the current line int curlineno = filelinep->lastLineno(); for (; m_lastIgnore.it != m_ignLines.end(); ++m_lastIgnore.it) { if (m_lastIgnore.it->m_lineno > curlineno) break; - // UINFO(9," Hit "<<*m_lastIt<warnOn(m_lastIgnore.it->m_code, m_lastIgnore.it->m_on); } if (0 && debug() >= 9) { diff --git a/src/V3Const.cpp b/src/V3Const.cpp index c99d1950b..f0f173c84 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -61,6 +61,7 @@ class ConstVarFindVisitor : public AstNVisitor { // AstVar::user4p -> bool, input from ConstVarMarkVisitor // MEMBERS bool m_found; + private: // VISITORS virtual void visit(AstVarRef* nodep) VL_OVERRIDE { @@ -92,27 +93,25 @@ private: // AstEnum::user4 -> bool. Recursing. // STATE - bool m_params; // If true, propagate parameterized and true numbers only - bool m_required; // If true, must become a constant - bool m_wremove; // Inside scope, no assignw removal - bool m_warn; // Output warnings - bool m_doExpensive; // Enable computationally expensive optimizations - bool m_doNConst; // Enable non-constant-child simplifications - bool m_doShort; // Remove expressions that short circuit - bool m_doV; // Verilog, not C++ conversion - bool m_doGenerate; // Postpone width checking inside generate - bool m_hasJumpGo; // JumpGo under this while - AstNodeModule* m_modp; // Current module - AstArraySel* m_selp; // Current select - AstNode* m_scopep; // Current scope - AstAttrOf* m_attrp; // Current attribute + bool m_params; // If true, propagate parameterized and true numbers only + bool m_required; // If true, must become a constant + bool m_wremove; // Inside scope, no assignw removal + bool m_warn; // Output warnings + bool m_doExpensive; // Enable computationally expensive optimizations + bool m_doNConst; // Enable non-constant-child simplifications + bool m_doShort; // Remove expressions that short circuit + bool m_doV; // Verilog, not C++ conversion + bool m_doGenerate; // Postpone width checking inside generate + bool m_hasJumpGo; // JumpGo under this while + AstNodeModule* m_modp; // Current module + AstArraySel* m_selp; // Current select + AstNode* m_scopep; // Current scope + AstAttrOf* m_attrp; // Current attribute // METHODS VL_DEBUG_FUNC; // Declare debug() - bool operandConst(AstNode* nodep) { - return VN_IS(nodep, Const); - } + bool operandConst(AstNode* nodep) { return VN_IS(nodep, Const); } bool operandAsvConst(const AstNode* nodep) { // BIASV(CONST, BIASV(CONST,...)) -> BIASV( BIASV_CONSTED(a,b), ...) const AstNodeBiComAsv* bnodep = VN_CAST_CONST(nodep, NodeBiComAsv); @@ -169,10 +168,8 @@ private: // SUB( ADD(CONSTx,y), CONSTz) -> ADD(SUB(CONSTx,CONSTz), y) const AstNodeBiop* np = VN_CAST_CONST(nodep, NodeBiop); const AstNodeBiop* lp = VN_CAST_CONST(np->lhsp(), NodeBiop); - return (lp - && VN_IS(lp->lhsp(), Const) - && VN_IS(np->rhsp(), Const) - && lp->width()==np->width()); + return (lp && VN_IS(lp->lhsp(), Const) && VN_IS(np->rhsp(), Const) + && lp->width() == np->width()); } static bool operandAndOrSame(const AstNode* nodep) { @@ -181,11 +178,8 @@ private: const AstNodeBiop* np = VN_CAST_CONST(nodep, NodeBiop); const AstNodeBiop* lp = VN_CAST_CONST(np->lhsp(), NodeBiop); const AstNodeBiop* rp = VN_CAST_CONST(np->rhsp(), NodeBiop); - return (lp && rp - && lp->width()==rp->width() - && lp->type()==rp->type() - && (operandsSame(lp->lhsp(), rp->lhsp()) - || operandsSame(lp->rhsp(), rp->rhsp()))); + return (lp && rp && lp->width() == rp->width() && lp->type() == rp->type() + && (operandsSame(lp->lhsp(), rp->lhsp()) || operandsSame(lp->rhsp(), rp->rhsp()))); } static bool matchOrAndNot(AstNodeBiop* nodep) { // AstOr{$a, AstAnd{AstNot{$b}, $c}} if $a.width1, $a==$b => AstOr{$a,$c} @@ -194,22 +188,36 @@ private: // if (rst) ... else if (enable)... -> OR(rst,AND(!rst,enable)) AstNode* ap; AstNodeBiop* andp; - if (VN_IS(nodep->lhsp(), And)) { andp = VN_CAST(nodep->lhsp(), And); ap = nodep->rhsp(); } - else if (VN_IS(nodep->rhsp(), And)) { andp = VN_CAST(nodep->rhsp(), And); ap = nodep->lhsp(); } - else return false; + if (VN_IS(nodep->lhsp(), And)) { + andp = VN_CAST(nodep->lhsp(), And); + ap = nodep->rhsp(); + } else if (VN_IS(nodep->rhsp(), And)) { + andp = VN_CAST(nodep->rhsp(), And); + ap = nodep->lhsp(); + } else + return false; AstNodeUniop* notp; AstNode* cp; - if (VN_IS(andp->lhsp(), Not)) { notp = VN_CAST(andp->lhsp(), Not); cp=andp->rhsp(); } - else if (VN_IS(andp->rhsp(), Not)) { notp = VN_CAST(andp->rhsp(), Not); cp=andp->lhsp(); } - else return false; + if (VN_IS(andp->lhsp(), Not)) { + notp = VN_CAST(andp->lhsp(), Not); + cp = andp->rhsp(); + } else if (VN_IS(andp->rhsp(), Not)) { + notp = VN_CAST(andp->rhsp(), Not); + cp = andp->lhsp(); + } else + return false; AstNode* bp = notp->lhsp(); if (!operandsSame(ap, bp)) return false; // Do it cp->unlinkFrBack(); - VL_DO_DANGLING(andp->unlinkFrBack()->deleteTree(), andp); VL_DANGLING(notp); + VL_DO_DANGLING(andp->unlinkFrBack()->deleteTree(), andp); + VL_DANGLING(notp); // Replace whichever branch is now dangling - if (nodep->rhsp()) nodep->lhsp(cp); - else nodep->rhsp(cp); + if (nodep->rhsp()) { + nodep->lhsp(cp); + } else { + nodep->rhsp(cp); + } return true; } bool matchAndCond(AstAnd* nodep) { @@ -222,19 +230,19 @@ private: if (!VN_IS(condp->expr1p(), Const) && !VN_IS(condp->expr2p(), Const)) return false; AstConst* maskp = VN_CAST(nodep->lhsp(), Const); if (!maskp) return false; - UINFO(4, "AND(CONSTm, CONDcond(c, i, e))->CONDcond(c, AND(m,i), AND(m, e)) "<CONDcond(c, AND(m,i), AND(m, e)) " << nodep + << endl); AstNodeCond* newp = static_cast( condp->cloneType(condp->condp()->unlinkFrBack(), - new AstAnd(nodep->fileline(), - maskp->cloneTree(false), + new AstAnd(nodep->fileline(), maskp->cloneTree(false), condp->expr1p()->unlinkFrBack()), - new AstAnd(nodep->fileline(), - maskp->cloneTree(false), + new AstAnd(nodep->fileline(), maskp->cloneTree(false), condp->expr2p()->unlinkFrBack()))); newp->dtypeFrom(nodep); newp->expr1p()->dtypeFrom(nodep); // As And might have been to change widths newp->expr2p()->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); return true; } static bool operandShiftSame(const AstNode* nodep) { @@ -243,8 +251,7 @@ private: const AstShiftL* lp = VN_CAST_CONST(np->lhsp(), ShiftL); const AstShiftL* rp = VN_CAST_CONST(np->rhsp(), ShiftL); if (lp && rp) { - return (lp->width() == rp->width() - && lp->lhsp()->width() == rp->lhsp()->width() + return (lp->width() == rp->width() && lp->lhsp()->width() == rp->lhsp()->width() && operandsSame(lp->rhsp(), rp->rhsp())); } } @@ -252,8 +259,7 @@ private: const AstShiftR* lp = VN_CAST_CONST(np->lhsp(), ShiftR); const AstShiftR* rp = VN_CAST_CONST(np->rhsp(), ShiftR); if (lp && rp) { - return (lp->width() == rp->width() - && lp->lhsp()->width() == rp->lhsp()->width() + return (lp->width() == rp->width() && lp->lhsp()->width() == rp->lhsp()->width() && operandsSame(lp->rhsp(), rp->rhsp())); } } @@ -274,26 +280,23 @@ private: && isTPure(nodep->lhsp())); } bool operandIsTwo(const AstNode* nodep) { - return (VN_IS(nodep, Const) - && !VN_CAST_CONST(nodep, Const)->num().isFourState() - && nodep->width() <= VL_QUADSIZE - && VN_CAST_CONST(nodep, Const)->toUQuad()==2); + return (VN_IS(nodep, Const) && !VN_CAST_CONST(nodep, Const)->num().isFourState() + && nodep->width() <= VL_QUADSIZE && VN_CAST_CONST(nodep, Const)->toUQuad() == 2); } bool operandIsTwostate(const AstNode* nodep) { - return (VN_IS(nodep, Const) - && !VN_CAST_CONST(nodep, Const)->num().isFourState()); + return (VN_IS(nodep, Const) && !VN_CAST_CONST(nodep, Const)->num().isFourState()); } bool operandIsPowTwo(const AstNode* nodep) { if (!operandIsTwostate(nodep)) return false; - return (1==VN_CAST_CONST(nodep, Const)->num().countOnes()); + return (1 == VN_CAST_CONST(nodep, Const)->num().countOnes()); } bool operandShiftOp(const AstNodeBiop* nodep) { if (!VN_IS(nodep->rhsp(), Const)) return false; const AstNodeBiop* lhsp = VN_CAST(nodep->lhsp(), NodeBiop); if (!lhsp || !(VN_IS(lhsp, And) || VN_IS(lhsp, Or) || VN_IS(lhsp, Xor))) return false; - if (nodep->width()!=lhsp->width()) return false; - if (nodep->width()!=lhsp->lhsp()->width()) return false; - if (nodep->width()!=lhsp->rhsp()->width()) return false; + if (nodep->width() != lhsp->width()) return false; + if (nodep->width() != lhsp->lhsp()->width()) return false; + if (nodep->width() != lhsp->rhsp()->width()) return false; return true; } bool operandShiftShift(const AstNodeBiop* nodep) { @@ -304,25 +307,24 @@ private: // because bits may be masked in that process, or (b+c) may exceed the word width. if (!(VN_IS(nodep->rhsp(), Const) && VN_IS(lhsp->rhsp(), Const))) return false; if (VN_CAST_CONST(nodep->rhsp(), Const)->num().isFourState() - || VN_CAST_CONST(lhsp->rhsp(), Const)->num().isFourState()) return false; - if (nodep->width()!=lhsp->width()) return false; - if (nodep->width()!=lhsp->lhsp()->width()) return false; + || VN_CAST_CONST(lhsp->rhsp(), Const)->num().isFourState()) + return false; + if (nodep->width() != lhsp->width()) return false; + if (nodep->width() != lhsp->lhsp()->width()) return false; return true; } bool operandWordOOB(const AstWordSel* nodep) { // V3Expand may make a arraysel that exceeds the bounds of the array // It was an expression, then got constified. In reality, the WordSel // must be wrapped in a Cond, that will be false. - return (VN_IS(nodep->rhsp(), Const) - && VN_IS(nodep->fromp(), NodeVarRef) + return (VN_IS(nodep->rhsp(), Const) && VN_IS(nodep->fromp(), NodeVarRef) && !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->lvalue() && (static_cast(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt()) >= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords())); } bool operandSelFull(const AstSel* nodep) { - return (VN_IS(nodep->lsbp(), Const) - && VN_IS(nodep->widthp(), Const) - && nodep->lsbConst()==0 + return (VN_IS(nodep->lsbp(), Const) && VN_IS(nodep->widthp(), Const) + && nodep->lsbConst() == 0 && static_cast(nodep->widthConst()) == nodep->fromp()->width()); } bool operandSelExtend(AstSel* nodep) { @@ -330,13 +332,10 @@ private: // SEL(EXTEND(any,width,...),(width-1),0) -> ... // Since select's return unsigned, this is always an extend AstExtend* extendp = VN_CAST(nodep->fromp(), Extend); - if (!(m_doV - && extendp - && VN_IS(nodep->lsbp(), Const) - && VN_IS(nodep->widthp(), Const) - && nodep->lsbConst()==0 - && static_cast(nodep->widthConst()) == extendp->lhsp()->width() - )) return false; + if (!(m_doV && extendp && VN_IS(nodep->lsbp(), Const) && VN_IS(nodep->widthp(), Const) + && nodep->lsbConst() == 0 + && static_cast(nodep->widthConst()) == extendp->lhsp()->width())) + return false; VL_DO_DANGLING(replaceWChild(nodep, extendp->lhsp()), nodep); return true; } @@ -344,18 +343,15 @@ private: // SEL(ADD(a,b),(width-1),0) -> ADD(SEL(a),SEL(b)) // Add or any operation which doesn't care if we discard top bits AstNodeBiop* bip = VN_CAST(nodep->fromp(), NodeBiop); - if (!(m_doV - && bip - && VN_IS(nodep->lsbp(), Const) - && VN_IS(nodep->widthp(), Const) - && nodep->lsbConst()==0 - )) return false; - if (debug()>=9) nodep->dumpTree(cout, "SEL(BI)-in:"); + if (!(m_doV && bip && VN_IS(nodep->lsbp(), Const) && VN_IS(nodep->widthp(), Const) + && nodep->lsbConst() == 0)) + return false; + if (debug() >= 9) nodep->dumpTree(cout, "SEL(BI)-in:"); AstNode* bilhsp = bip->lhsp()->unlinkFrBack(); AstNode* birhsp = bip->rhsp()->unlinkFrBack(); bip->lhsp(new AstSel(nodep->fileline(), bilhsp, 0, nodep->widthConst())); bip->rhsp(new AstSel(nodep->fileline(), birhsp, 0, nodep->widthConst())); - if (debug()>=9) bip->dumpTree(cout, "SEL(BI)-ou:"); + if (debug() >= 9) bip->dumpTree(cout, "SEL(BI)-ou:"); VL_DO_DANGLING(replaceWChild(nodep, bip), nodep); return true; } @@ -364,26 +360,26 @@ private: // becomes thought other optimizations // SEL(SHIFTR({a},{b}),{lsb},{width}) -> SEL({a},{lsb+b},{width}) AstShiftR* shiftp = VN_CAST(nodep->fromp(), ShiftR); - if (!(m_doV - && shiftp - && VN_IS(shiftp->rhsp(), Const) - && VN_IS(nodep->lsbp(), Const) - && VN_IS(nodep->widthp(), Const) - )) return false; + if (!(m_doV && shiftp && VN_IS(shiftp->rhsp(), Const) && VN_IS(nodep->lsbp(), Const) + && VN_IS(nodep->widthp(), Const))) { + return false; + } AstNode* ap = shiftp->lhsp(); AstConst* bp = VN_CAST(shiftp->rhsp(), Const); AstConst* lp = VN_CAST(nodep->lsbp(), Const); - if (bp->isWide() || bp->num().isFourState() || bp->num().isNegative() - || lp->isWide() || lp->num().isFourState() || lp->num().isNegative()) return false; + if (bp->isWide() || bp->num().isFourState() || bp->num().isNegative() || lp->isWide() + || lp->num().isFourState() || lp->num().isNegative()) { + return false; + } int newLsb = lp->toSInt() + bp->toSInt(); if (newLsb + nodep->widthConst() > ap->width()) return false; // UINFO(9, "SEL(SHIFTR(a,b),l,w) -> SEL(a,l+b,w)\n"); - if (debug()>=9) nodep->dumpTree(cout, "SEL(SH)-in:"); - AstSel* newp = new AstSel(nodep->fileline(), ap->unlinkFrBack(), - newLsb, nodep->widthConst()); + if (debug() >= 9) nodep->dumpTree(cout, "SEL(SH)-in:"); + AstSel* newp + = new AstSel(nodep->fileline(), ap->unlinkFrBack(), newLsb, nodep->widthConst()); newp->dtypeFrom(nodep); - if (debug()>=9) newp->dumpTree(cout, "SEL(SH)-ou:"); + if (debug() >= 9) newp->dumpTree(cout, "SEL(SH)-ou:"); VL_DO_DANGLING(nodep->replaceWith(newp), nodep); return true; } @@ -399,19 +395,19 @@ private: int subsize = smallerp->width(); AstConst* constp = VN_CAST(nodep->lhsp(), Const); if (!constp) return false; - if (!constp->num().isBitsZero(constp->width()-1, subsize)) return false; + if (!constp->num().isBitsZero(constp->width() - 1, subsize)) return false; // - if (debug()>=9) nodep->dumpTree(cout, "BI(EXTEND)-in:"); + if (debug() >= 9) nodep->dumpTree(cout, "BI(EXTEND)-in:"); smallerp->unlinkFrBack(); VL_DO_DANGLING(extendp->unlinkFrBack()->deleteTree(), extendp); // aka nodep->lhsp. nodep->rhsp(smallerp); constp->unlinkFrBack(); - V3Number num (constp, subsize); + V3Number num(constp, subsize); num.opAssign(constp->num()); nodep->lhsp(new AstConst(constp->fileline(), num)); VL_DO_DANGLING(constp->deleteTree(), constp); - if (debug()>=9) nodep->dumpTree(cout, "BI(EXTEND)-ou:"); + if (debug() >= 9) nodep->dumpTree(cout, "BI(EXTEND)-ou:"); return true; } bool operandBiExtendConstOver(const AstNodeBiop* nodep) { @@ -424,7 +420,7 @@ private: int subsize = smallerp->width(); const AstConst* constp = VN_CAST_CONST(nodep->lhsp(), Const); if (!constp) return false; - if (constp->num().isBitsZero(constp->width()-1, subsize)) return false; + if (constp->num().isBitsZero(constp->width() - 1, subsize)) return false; return true; } @@ -453,33 +449,31 @@ private: // Find range of dtype we are selecting from // Similar code in V3Unknown::AstSel bool doit = true; - if (m_warn - && VN_IS(nodep->lsbp(), Const) - && VN_IS(nodep->widthp(), Const) - && doit) { - int maxDeclBit = nodep->declRange().hiMaxSelect()*nodep->declElWidth() - + (nodep->declElWidth()-1); + if (m_warn && VN_IS(nodep->lsbp(), Const) && VN_IS(nodep->widthp(), Const) && doit) { + int maxDeclBit = nodep->declRange().hiMaxSelect() * nodep->declElWidth() + + (nodep->declElWidth() - 1); if (VN_CAST(nodep->lsbp(), Const)->num().isFourState() || VN_CAST(nodep->widthp(), Const)->num().isFourState()) { nodep->v3error("Selection index is constantly unknown or tristated: " - "lsb="<lsbp()->name()<<" width="<widthp()->name()); + "lsb=" + << nodep->lsbp()->name() << " width=" << nodep->widthp()->name()); // Replacing nodep will make a mess above, so we replace the offender replaceZero(nodep->lsbp()); - } - else if (nodep->declRange().ranged() - && (nodep->msbConst() > maxDeclBit - || nodep->lsbConst() > maxDeclBit)) { + } else if (nodep->declRange().ranged() + && (nodep->msbConst() > maxDeclBit || nodep->lsbConst() > maxDeclBit)) { // See also warning in V3Width // Must adjust by element width as declRange() is in number of elements - nodep->v3warn(SELRANGE, "Selection index out of range: " - <<(nodep->msbConst()/nodep->declElWidth()) - <<":"<<(nodep->lsbConst()/nodep->declElWidth()) - <<" outside "<declRange().hiMaxSelect()<<":0" - <<(nodep->declRange().lo()>=0 ? "" - :(" (adjusted +"+cvtToStr(-nodep->declRange().lo()) - +" to account for negative lsb)"))); - UINFO(1," Related Raw index is "<msbConst() - <<":"<lsbConst()<v3warn(SELRANGE, + "Selection index out of range: " + << (nodep->msbConst() / nodep->declElWidth()) << ":" + << (nodep->lsbConst() / nodep->declElWidth()) << " outside " + << nodep->declRange().hiMaxSelect() << ":0" + << (nodep->declRange().lo() >= 0 + ? "" + : (" (adjusted +" + cvtToStr(-nodep->declRange().lo()) + + " to account for negative lsb)"))); + UINFO(1, " Related Raw index is " << nodep->msbConst() << ":" + << nodep->lsbConst() << endl); // Don't replace with zero, we'll do it later } } @@ -490,11 +484,10 @@ private: // For now we just detect constants & simple vars, though it could be more generic if (VN_IS(node1p, Const) && VN_IS(node2p, Const)) { return node1p->sameGateTree(node2p); - } - else if (VN_IS(node1p, VarRef) && VN_IS(node2p, VarRef)) { + } else if (VN_IS(node1p, VarRef) && VN_IS(node2p, VarRef)) { // Avoid comparing widthMin's, which results in lost optimization attempts // If cleanup sameGateTree to be smarter, this can be restored. - //return node1p->sameGateTree(node2p); + // return node1p->sameGateTree(node2p); return node1p->same(node2p); } else { return false; @@ -503,7 +496,7 @@ private: bool ifSameAssign(const AstNodeIf* nodep) { const AstNodeAssign* ifp = VN_CAST_CONST(nodep->ifsp(), NodeAssign); const AstNodeAssign* elsep = VN_CAST_CONST(nodep->elsesp(), NodeAssign); - if (!ifp || ifp->nextp()) return false; // Must be SINGLE statement + if (!ifp || ifp->nextp()) return false; // Must be SINGLE statement if (!elsep || elsep->nextp()) return false; if (ifp->type() != elsep->type()) return false; // Can't mix an assigndly and an assign if (!ifp->lhsp()->sameGateTree(elsep->lhsp())) return false; @@ -520,10 +513,7 @@ private: return true; } bool ifConcatMergeableBiop(const AstNode* nodep) { - return (VN_IS(nodep, And) - || VN_IS(nodep, Or) - || VN_IS(nodep, Xor) - || VN_IS(nodep, Xnor)); + return (VN_IS(nodep, And) || VN_IS(nodep, Or) || VN_IS(nodep, Xor) || VN_IS(nodep, Xnor)); } bool ifAdjacentSel(const AstSel* lhsp, const AstSel* rhsp) { if (!v3Global.opt.oAssemble()) return false; // opt disabled @@ -594,8 +584,9 @@ private: // {a[]&b[] & c[], a[]&b[] & c[]} if (rad && concatMergeable(lp->lhsp(), rp->lhsp())) return true; // {(a[]&b[])&(c[]&d[]), (a[]&b[])&(c[]&d[])} - if (concatMergeable(lp->lhsp(), rp->lhsp()) - && concatMergeable(lp->rhsp(), rp->rhsp())) return true; + if (concatMergeable(lp->lhsp(), rp->lhsp()) && concatMergeable(lp->rhsp(), rp->rhsp())) { + return true; + } return false; } @@ -606,17 +597,17 @@ private: void replaceNum(AstNode* oldp, const V3Number& num) { // Replace oldp node with a constant set to specified value UASSERT(oldp, "Null old"); - UASSERT_OBJ(!(VN_IS(oldp, Const) && !VN_CAST(oldp, Const)->num().isFourState()), - oldp, "Already constant??"); + UASSERT_OBJ(!(VN_IS(oldp, Const) && !VN_CAST(oldp, Const)->num().isFourState()), oldp, + "Already constant??"); AstNode* newp = new AstConst(oldp->fileline(), num); newp->dtypeFrom(oldp); - if (debug()>5) oldp->dumpTree(cout, " const_old: "); - if (debug()>5) newp->dumpTree(cout, " _new: "); + if (debug() > 5) oldp->dumpTree(cout, " const_old: "); + if (debug() > 5) newp->dumpTree(cout, " _new: "); oldp->replaceWith(newp); VL_DO_DANGLING(oldp->deleteTree(), oldp); } void replaceNum(AstNode* nodep, uint32_t val) { - V3Number num (nodep, nodep->width(), val); + V3Number num(nodep, nodep->width(), val); VL_DO_DANGLING(replaceNum(nodep, num), nodep); } void replaceNumSigned(AstNodeBiop* nodep, uint32_t val) { @@ -632,9 +623,7 @@ private: if (m_warn) nodep->v3warn(CMPCONST, "Comparison is constant due to limited range"); VL_DO_DANGLING(replaceNum(nodep, val), nodep); } - void replaceZero(AstNode* nodep) { - VL_DO_DANGLING(replaceNum(nodep, 0), nodep); - } + void replaceZero(AstNode* nodep) { VL_DO_DANGLING(replaceNum(nodep, 0), nodep); } void replaceZeroChkPure(AstNode* nodep, AstNode* checkp) { // For example, "0 * n" -> 0 if n has no side effects // Else strength reduce it to 0 & n. @@ -642,8 +631,7 @@ private: if (isTPure(checkp)) { VL_DO_DANGLING(replaceNum(nodep, 0), nodep); } else { - AstNode* newp = new AstAnd(nodep->fileline(), - new AstConst(nodep->fileline(), 0), + AstNode* newp = new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), 0), checkp->unlinkFrBack()); newp->dtypeFrom(nodep); nodep->replaceWith(newp); @@ -651,29 +639,29 @@ private: } } void replaceAllOnes(AstNode* nodep) { - V3Number ones (nodep, nodep->width(), 0); + V3Number ones(nodep, nodep->width(), 0); ones.setMask(nodep->width()); VL_DO_DANGLING(replaceNum(nodep, ones), nodep); } void replaceConst(AstNodeUniop* nodep) { - V3Number num (nodep, nodep->width()); + V3Number num(nodep, nodep->width()); nodep->numberOperate(num, VN_CAST(nodep->lhsp(), Const)->num()); - UINFO(4,"UNICONST -> "< " << num << endl); VL_DO_DANGLING(replaceNum(nodep, num), nodep); } void replaceConst(AstNodeBiop* nodep) { - V3Number num (nodep, nodep->width()); + V3Number num(nodep, nodep->width()); nodep->numberOperate(num, VN_CAST(nodep->lhsp(), Const)->num(), VN_CAST(nodep->rhsp(), Const)->num()); - UINFO(4,"BICONST -> "< " << num << endl); VL_DO_DANGLING(replaceNum(nodep, num), nodep); } void replaceConst(AstNodeTriop* nodep) { - V3Number num (nodep, nodep->width()); + V3Number num(nodep, nodep->width()); nodep->numberOperate(num, VN_CAST(nodep->lhsp(), Const)->num(), VN_CAST(nodep->rhsp(), Const)->num(), VN_CAST(nodep->thsp(), Const)->num()); - UINFO(4,"TRICONST -> "< " << num << endl); VL_DO_DANGLING(replaceNum(nodep, num), nodep); } @@ -681,8 +669,8 @@ private: // Replace oldp node with a constant set to specified value UASSERT(oldp, "Null old"); AstNode* newp = new AstConst(oldp->fileline(), AstConst::String(), num); - if (debug()>5) oldp->dumpTree(cout, " const_old: "); - if (debug()>5) newp->dumpTree(cout, " _new: "); + if (debug() > 5) oldp->dumpTree(cout, " const_old: "); + if (debug() > 5) newp->dumpTree(cout, " _new: "); oldp->replaceWith(newp); VL_DO_DANGLING(oldp->deleteTree(), oldp); } @@ -728,7 +716,7 @@ private: void replaceAsv(AstNodeBiop* nodep) { // BIASV(CONSTa, BIASV(CONSTb, c)) -> BIASV( BIASV_CONSTED(a,b), c) // BIASV(SAMEa, BIASV(SAMEb, c)) -> BIASV( BIASV(SAMEa,SAMEb), c) - //nodep->dumpTree(cout, " repAsvConst_old: "); + // nodep->dumpTree(cout, " repAsvConst_old: "); AstNode* ap = nodep->lhsp(); AstNodeBiop* rp = VN_CAST(nodep->rhsp(), NodeBiop); AstNode* bp = rp->lhsp(); @@ -742,23 +730,23 @@ private: rp->lhsp(ap); rp->rhsp(bp); if (VN_IS(rp->lhsp(), Const) && VN_IS(rp->rhsp(), Const)) replaceConst(rp); - //nodep->dumpTree(cout, " repAsvConst_new: "); + // nodep->dumpTree(cout, " repAsvConst_new: "); } void replaceAsvLUp(AstNodeBiop* nodep) { // BIASV(BIASV(CONSTll,lr),r) -> BIASV(CONSTll,BIASV(lr,r)) AstNodeBiop* lp = VN_CAST(nodep->lhsp()->unlinkFrBack(), NodeBiop); AstNode* llp = lp->lhsp()->unlinkFrBack(); AstNode* lrp = lp->rhsp()->unlinkFrBack(); - AstNode* rp = nodep->rhsp()->unlinkFrBack(); + AstNode* rp = nodep->rhsp()->unlinkFrBack(); nodep->lhsp(llp); nodep->rhsp(lp); lp->lhsp(lrp); lp->rhsp(rp); - //nodep->dumpTree(cout, " repAsvLUp_new: "); + // nodep->dumpTree(cout, " repAsvLUp_new: "); } void replaceAsvRUp(AstNodeBiop* nodep) { // BIASV(l,BIASV(CONSTrl,rr)) -> BIASV(CONSTrl,BIASV(l,rr)) - AstNode* lp = nodep->lhsp()->unlinkFrBack(); + AstNode* lp = nodep->lhsp()->unlinkFrBack(); AstNodeBiop* rp = VN_CAST(nodep->rhsp()->unlinkFrBack(), NodeBiop); AstNode* rlp = rp->lhsp()->unlinkFrBack(); AstNode* rrp = rp->rhsp()->unlinkFrBack(); @@ -766,7 +754,7 @@ private: nodep->rhsp(rp); rp->lhsp(lp); rp->rhsp(rrp); - //nodep->dumpTree(cout, " repAsvRUp_new: "); + // nodep->dumpTree(cout, " repAsvRUp_new: "); } void replaceAndOr(AstNodeBiop* nodep) { // OR (AND (CONSTll,lr), AND(CONSTrl==ll,rr)) -> AND (CONSTll, OR(lr,rr)) @@ -797,7 +785,7 @@ private: } else { nodep->v3fatalSrc("replaceAndOr on something operandAndOrSame shouldn't have matched"); } - //nodep->dumpTree(cout, " repAndOr_new: "); + // nodep->dumpTree(cout, " repAndOr_new: "); } void replaceShiftSame(AstNodeBiop* nodep) { // Or(Shift(ll,CONSTlr),Shift(rl,CONSTrr==lr)) -> Shift(Or(ll,rl),CONSTlr) @@ -815,7 +803,7 @@ private: nodep->rhsp(rlp); VL_DO_DANGLING(rp->deleteTree(), rp); VL_DO_DANGLING(rrp->deleteTree(), rrp); - //nodep->dumpTree(cout, " repShiftSame_new: "); + // nodep->dumpTree(cout, " repShiftSame_new: "); } void replaceConcatSel(AstConcat* nodep) { // {a[1], a[0]} -> a[1:0] @@ -828,9 +816,10 @@ private: UASSERT_OBJ((rstart + rwidth) == lstart, nodep, "tried to merge two selects which are not adjacent"); - AstSel* newselp = new AstSel(lselp->fromp()->fileline(), - rselp->fromp()->cloneTree(false), rstart, lwidth+rwidth); - UINFO(5, "merged two adjacent sel "<fromp()->fileline(), rselp->fromp()->cloneTree(false), + rstart, lwidth + rwidth); + UINFO(5, "merged two adjacent sel " << lselp << " and " << rselp << " to one " << newselp + << endl); nodep->replaceWith(newselp); VL_DO_DANGLING(lselp->deleteTree(), lselp); @@ -851,92 +840,103 @@ private: lp->lhsp()->replaceWith(newlp); lp->rhsp()->replaceWith(newrp); lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), AstNumeric::UNSIGNED); - UINFO(5, "merged "<< nodep <unlinkFrBack()->deleteTree(), rp); - nodep->replaceWith(lp->unlinkFrBack()); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(lp->unlinkFrBack()); + VL_DO_DANGLING(nodep->deleteTree(), nodep); iterate(lp->lhsp()); iterate(lp->rhsp()); - } else nodep->v3fatalSrc("tried to merge two Concat which are not adjacent"); + } else { + nodep->v3fatalSrc("tried to merge two Concat which are not adjacent"); + } } void replaceExtend(AstNode* nodep, AstNode* arg0p) { // -> EXTEND(nodep) // like a AstExtend{$rhsp}, but we need to set the width correctly from base node arg0p->unlinkFrBack(); AstNode* newp = (VN_IS(nodep, ExtendS) - ? static_cast(new AstExtendS(nodep->fileline(), arg0p)) - : static_cast(new AstExtend (nodep->fileline(), arg0p))); + ? static_cast(new AstExtendS(nodep->fileline(), arg0p)) + : static_cast(new AstExtend(nodep->fileline(), arg0p))); newp->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } void replacePowShift(AstNodeBiop* nodep) { // Pow or PowS - UINFO(5,"POW(2,b)->SHIFTL(1,b) "<SHIFTL(1,b) " << nodep << endl); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); - AstShiftL* newp = new AstShiftL(nodep->fileline(), - new AstConst(nodep->fileline(), 1), - rhsp); + AstShiftL* newp + = new AstShiftL(nodep->fileline(), new AstConst(nodep->fileline(), 1), rhsp); newp->dtypeFrom(nodep); newp->lhsp()->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } void replaceMulShift(AstMul* nodep) { // Mul, but not MulS as not simple shift - UINFO(5,"MUL(2^n,b)->SHIFTL(b,n) "<lhsp(), Const)->num().mostSetBitP1()-1; // 2^n->n+1 + UINFO(5, "MUL(2^n,b)->SHIFTL(b,n) " << nodep << endl); + int amount = VN_CAST(nodep->lhsp(), Const)->num().mostSetBitP1() - 1; // 2^n->n+1 AstNode* opp = nodep->rhsp()->unlinkFrBack(); - AstShiftL* newp = new AstShiftL(nodep->fileline(), - opp, new AstConst(nodep->fileline(), amount)); + AstShiftL* newp + = new AstShiftL(nodep->fileline(), opp, new AstConst(nodep->fileline(), amount)); newp->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } void replaceDivShift(AstDiv* nodep) { // Mul, but not MulS as not simple shift - UINFO(5,"DIV(b,2^n)->SHIFTR(b,n) "<rhsp(), Const)->num().mostSetBitP1()-1; // 2^n->n+1 + UINFO(5, "DIV(b,2^n)->SHIFTR(b,n) " << nodep << endl); + int amount = VN_CAST(nodep->rhsp(), Const)->num().mostSetBitP1() - 1; // 2^n->n+1 AstNode* opp = nodep->lhsp()->unlinkFrBack(); - AstShiftR* newp = new AstShiftR(nodep->fileline(), - opp, new AstConst(nodep->fileline(), amount)); + AstShiftR* newp + = new AstShiftR(nodep->fileline(), opp, new AstConst(nodep->fileline(), amount)); newp->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } void replaceModAnd(AstModDiv* nodep) { // Mod, but not ModS as not simple shift - UINFO(5,"MOD(b,2^n)->AND(b,2^n-1) "<rhsp(), Const)->num().mostSetBitP1()-1; // 2^n->n+1 + UINFO(5, "MOD(b,2^n)->AND(b,2^n-1) " << nodep << endl); + int amount = VN_CAST(nodep->rhsp(), Const)->num().mostSetBitP1() - 1; // 2^n->n+1 V3Number mask(nodep, nodep->width()); mask.setMask(amount); AstNode* opp = nodep->lhsp()->unlinkFrBack(); - AstAnd* newp = new AstAnd(nodep->fileline(), - opp, new AstConst(nodep->fileline(), mask)); + AstAnd* newp = new AstAnd(nodep->fileline(), opp, new AstConst(nodep->fileline(), mask)); newp->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } void replaceShiftOp(AstNodeBiop* nodep) { - UINFO(5,"SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) "<AND(SHIFT(a,CONST),SHIFT(b,CONST)) " << nodep << endl); AstNRelinker handle; nodep->unlinkFrBack(&handle); - AstNodeBiop* lhsp = VN_CAST(nodep->lhsp(), NodeBiop); lhsp->unlinkFrBack(); + AstNodeBiop* lhsp = VN_CAST(nodep->lhsp(), NodeBiop); + lhsp->unlinkFrBack(); AstNode* shiftp = nodep->rhsp()->unlinkFrBack(); AstNode* ap = lhsp->lhsp()->unlinkFrBack(); AstNode* bp = lhsp->rhsp()->unlinkFrBack(); AstNodeBiop* shift1p = nodep; AstNodeBiop* shift2p = nodep->cloneTree(true); - shift1p->lhsp(ap); shift1p->rhsp(shiftp->cloneTree(true)); - shift2p->lhsp(bp); shift2p->rhsp(shiftp); + shift1p->lhsp(ap); + shift1p->rhsp(shiftp->cloneTree(true)); + shift2p->lhsp(bp); + shift2p->rhsp(shiftp); AstNodeBiop* newp = lhsp; - newp->lhsp(shift1p); newp->rhsp(shift2p); + newp->lhsp(shift1p); + newp->rhsp(shift2p); handle.relink(newp); iterate(newp); // Further reduce, either node may have more reductions. } void replaceShiftShift(AstNodeBiop* nodep) { - UINFO(4,"SHIFT(SHIFT(a,s1),s2)->SHIFT(a,ADD(s1,s2)) "<=9) nodep->dumpTree(cout, " repShiftShift_old: "); - AstNodeBiop* lhsp = VN_CAST(nodep->lhsp(), NodeBiop); lhsp->unlinkFrBack(); + UINFO(4, "SHIFT(SHIFT(a,s1),s2)->SHIFT(a,ADD(s1,s2)) " << nodep << endl); + if (debug() >= 9) nodep->dumpTree(cout, " repShiftShift_old: "); + AstNodeBiop* lhsp = VN_CAST(nodep->lhsp(), NodeBiop); + lhsp->unlinkFrBack(); AstNode* ap = lhsp->lhsp()->unlinkFrBack(); AstNode* shift1p = lhsp->rhsp()->unlinkFrBack(); AstNode* shift2p = nodep->rhsp()->unlinkFrBack(); // Shift1p and shift2p may have different sizes, both are // self-determined so sum with infinite width - if (nodep->type()==lhsp->type()) { + if (nodep->type() == lhsp->type()) { int shift1 = VN_CAST(shift1p, Const)->toUInt(); int shift2 = VN_CAST(shift2p, Const)->toUInt(); - int newshift = shift1+shift2; + int newshift = shift1 + shift2; VL_DO_DANGLING(shift1p->deleteTree(), shift1p); VL_DO_DANGLING(shift2p->deleteTree(), shift2p); nodep->lhsp(ap); @@ -945,28 +945,28 @@ private: } else { // We know shift amounts are constant, but might be a mixed left/right shift int shift1 = VN_CAST(shift1p, Const)->toUInt(); - if (VN_IS(lhsp, ShiftR)) shift1=-shift1; + if (VN_IS(lhsp, ShiftR)) shift1 = -shift1; int shift2 = VN_CAST(shift2p, Const)->toUInt(); - if (VN_IS(nodep, ShiftR)) shift2=-shift2; - int newshift = shift1+shift2; + if (VN_IS(nodep, ShiftR)) shift2 = -shift2; + int newshift = shift1 + shift2; VL_DO_DANGLING(shift1p->deleteTree(), shift1p); VL_DO_DANGLING(shift2p->deleteTree(), shift2p); AstNode* newp; - V3Number mask1 (nodep, nodep->width()); - V3Number ones (nodep, nodep->width()); + V3Number mask1(nodep, nodep->width()); + V3Number ones(nodep, nodep->width()); ones.setMask(nodep->width()); - if (shift1<0) { + if (shift1 < 0) { mask1.opShiftR(ones, V3Number(nodep, VL_IDATASIZE, -shift1)); } else { mask1.opShiftL(ones, V3Number(nodep, VL_IDATASIZE, shift1)); } - V3Number mask (nodep, nodep->width()); - if (shift2<0) { + V3Number mask(nodep, nodep->width()); + if (shift2 < 0) { mask.opShiftR(mask1, V3Number(nodep, VL_IDATASIZE, -shift2)); } else { mask.opShiftL(mask1, V3Number(nodep, VL_IDATASIZE, shift2)); } - if (newshift<0) { + if (newshift < 0) { newp = new AstShiftR(nodep->fileline(), ap, new AstConst(nodep->fileline(), -newshift)); } else { @@ -974,12 +974,11 @@ private: new AstConst(nodep->fileline(), newshift)); } newp->dtypeFrom(nodep); - newp = new AstAnd(nodep->fileline(), - newp, - new AstConst(nodep->fileline(), mask)); + newp = new AstAnd(nodep->fileline(), newp, new AstConst(nodep->fileline(), mask)); newp->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - //newp->dumpTree(cout, " repShiftShift_new: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + // newp->dumpTree(cout, " repShiftShift_new: "); iterate(newp); // Further reduce, either node may have more reductions. } VL_DO_DANGLING(lhsp->deleteTree(), lhsp); @@ -989,28 +988,39 @@ private: // Multiple assignments to sequential bits can be concated // ASSIGN(SEL(a),aq), ASSIGN(SEL(a+1),bq) -> ASSIGN(SEL(a:b),CONCAT(aq,bq) // ie. assign var[2]=a, assign var[3]=b -> assign var[3:2]={b,a} - if (!m_modp) return false; // Skip if we're not const'ing an entire module (IE doing only one assign, etc) - AstSel* sel1p = VN_CAST(nodep->lhsp(), Sel); if (!sel1p) return false; - AstNodeAssign* nextp = VN_CAST(nodep->nextp(), NodeAssign); if (!nextp) return false; + + // Skip if we're not const'ing an entire module (IE doing only one assign, etc) + if (!m_modp) return false; + AstSel* sel1p = VN_CAST(nodep->lhsp(), Sel); + if (!sel1p) return false; + AstNodeAssign* nextp = VN_CAST(nodep->nextp(), NodeAssign); + if (!nextp) return false; if (nodep->type() != nextp->type()) return false; - AstSel* sel2p = VN_CAST(nextp->lhsp(), Sel); if (!sel2p) return false; - AstVarRef* varref1p = VN_CAST(sel1p->fromp(), VarRef); if (!varref1p) return false; - AstVarRef* varref2p = VN_CAST(sel2p->fromp(), VarRef); if (!varref2p) return false; + AstSel* sel2p = VN_CAST(nextp->lhsp(), Sel); + if (!sel2p) return false; + AstVarRef* varref1p = VN_CAST(sel1p->fromp(), VarRef); + if (!varref1p) return false; + AstVarRef* varref2p = VN_CAST(sel2p->fromp(), VarRef); + if (!varref2p) return false; if (!varref1p->sameGateTree(varref2p)) return false; - AstConst* con1p = VN_CAST(sel1p->lsbp(), Const); if (!con1p) return false; - AstConst* con2p = VN_CAST(sel2p->lsbp(), Const); if (!con2p) return false; + AstConst* con1p = VN_CAST(sel1p->lsbp(), Const); + if (!con1p) return false; + AstConst* con2p = VN_CAST(sel2p->lsbp(), Const); + if (!con2p) return false; // We need to make sure there's no self-references involved in either // assignment. For speed, we only look 3 deep, then give up. if (!varNotReferenced(nodep->rhsp(), varref1p->varp())) return false; if (!varNotReferenced(nextp->rhsp(), varref2p->varp())) return false; // Swap? - if (( con1p->toSInt() != con2p->toSInt() + sel2p->width()) - &&(con2p->toSInt() != con1p->toSInt() + sel1p->width())) return false; + if ((con1p->toSInt() != con2p->toSInt() + sel2p->width()) + && (con2p->toSInt() != con1p->toSInt() + sel1p->width())) { + return false; + } bool lsbFirstAssign = (con1p->toUInt() < con2p->toUInt()); - UINFO(4,"replaceAssignMultiSel "<dumpTree(cout, "comb1: "); - //nextp->dumpTree(cout, "comb2: "); + UINFO(4, "replaceAssignMultiSel " << nodep << endl); + UINFO(4, " && " << nextp << endl); + // nodep->dumpTree(cout, "comb1: "); + // nextp->dumpTree(cout, "comb2: "); AstNode* rhs1p = nodep->rhsp()->unlinkFrBack(); AstNode* rhs2p = nextp->rhsp()->unlinkFrBack(); AstNode* newp; @@ -1023,30 +1033,29 @@ private: sel2p->lsbConst(), sel1p->width() + sel2p->width()), new AstConcat(rhs1p->fileline(), rhs1p, rhs2p)); } - //pnewp->dumpTree(cout, "conew: "); + // pnewp->dumpTree(cout, "conew: "); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nextp->unlinkFrBack()->deleteTree(), nextp); return true; } - bool varNotReferenced(AstNode* nodep, AstVar* varp, int level=0) { + bool varNotReferenced(AstNode* nodep, AstVar* varp, int level = 0) { // Return true if varp never referenced under node. // Return false if referenced, or tree too deep to be worth it, or side effects if (!nodep) return true; - if (level>2) return false; + if (level > 2) return false; if (nodep->isPure()) return false; // For example a $fgetc can't be reordered - if (VN_IS(nodep, NodeVarRef) && VN_CAST(nodep, NodeVarRef)->varp()==varp) return false; - return (varNotReferenced(nodep->nextp(), varp, level+1) - && varNotReferenced(nodep->op1p(), varp, level+1) - && varNotReferenced(nodep->op2p(), varp, level+1) - && varNotReferenced(nodep->op3p(), varp, level+1) - && varNotReferenced(nodep->op4p(), varp, level+1)); + if (VN_IS(nodep, NodeVarRef) && VN_CAST(nodep, NodeVarRef)->varp() == varp) return false; + return (varNotReferenced(nodep->nextp(), varp, level + 1) + && varNotReferenced(nodep->op1p(), varp, level + 1) + && varNotReferenced(nodep->op2p(), varp, level + 1) + && varNotReferenced(nodep->op3p(), varp, level + 1) + && varNotReferenced(nodep->op4p(), varp, level + 1)); } bool replaceNodeAssign(AstNodeAssign* nodep) { - if (VN_IS(nodep->lhsp(), VarRef) - && VN_IS(nodep->rhsp(), VarRef) + if (VN_IS(nodep->lhsp(), VarRef) && VN_IS(nodep->rhsp(), VarRef) && VN_CAST(nodep->lhsp(), VarRef)->sameNoLvalue(VN_CAST(nodep->rhsp(), VarRef)) && !VN_IS(nodep, AssignDly)) { // X = X. Quite pointless, though X <= X may override another earlier assignment @@ -1057,13 +1066,12 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return true; } - } - else if (m_doV && VN_IS(nodep->lhsp(), Concat)) { + } else if (m_doV && VN_IS(nodep->lhsp(), Concat)) { bool need_temp = false; if (m_warn && !VN_IS(nodep, AssignDly)) { // Is same var on LHS and RHS? // Note only do this (need user4) when m_warn, which is // done as unique visitor - AstUser4InUse m_inuser4; + AstUser4InUse m_inuser4; ConstVarMarkVisitor mark(nodep->lhsp()); ConstVarFindVisitor find(nodep->rhsp()); if (find.found()) need_temp = true; @@ -1071,32 +1079,32 @@ private: if (need_temp) { // The first time we constify, there may be the same variable on the LHS // and RHS. In that case, we must use temporaries, or {a,b}={b,a} will break. - UINFO(4," ASSITEMP "< ASSIGN(temp1,SEL(rhs,{size})), // ASSIGN(temp2,SEL(newrhs,{size})) // ASSIGN(lc1,temp1), // ASSIGN(lc2,temp2) } else { - UINFO(4," ASSI "< ASSIGN(lc1,SEL(rhs,{size})), // ASSIGN(lc2,SEL(newrhs,{size})) } - if (debug()>=9) nodep->dumpTree(cout, " Ass_old: "); + if (debug() >= 9) nodep->dumpTree(cout, " Ass_old: "); // Unlink the stuff AstNode* lc1p = VN_CAST(nodep->lhsp(), Concat)->lhsp()->unlinkFrBack(); AstNode* lc2p = VN_CAST(nodep->lhsp(), Concat)->rhsp()->unlinkFrBack(); AstNode* conp = VN_CAST(nodep->lhsp(), Concat)->unlinkFrBack(); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); - AstNode* rhs2p = rhsp->cloneTree(false); + AstNode* rhs2p = rhsp->cloneTree(false); // Calc widths int lsb2 = 0; - int msb2 = lsb2+lc2p->width()-1; - int lsb1 = msb2+1; - int msb1 = lsb1+lc1p->width()-1; - UASSERT_OBJ(msb1 == (conp->width()-1), nodep, "Width calc mismatch"); + int msb2 = lsb2 + lc2p->width() - 1; + int lsb1 = msb2 + 1; + int msb1 = lsb1 + lc1p->width() - 1; + UASSERT_OBJ(msb1 == (conp->width() - 1), nodep, "Width calc mismatch"); // Form ranges - AstSel* sel1p = new AstSel(conp->fileline(), rhsp, lsb1, msb1-lsb1+1); - AstSel* sel2p = new AstSel(conp->fileline(), rhs2p, lsb2, msb2-lsb2+1); + AstSel* sel1p = new AstSel(conp->fileline(), rhsp, lsb1, msb1 - lsb1 + 1); + AstSel* sel2p = new AstSel(conp->fileline(), rhs2p, lsb2, msb2 - lsb2 + 1); // Make new assigns of same flavor as old one //*** Not cloneTree; just one node. AstNode* newp = NULL; @@ -1111,30 +1119,26 @@ private: UASSERT_OBJ(m_modp, nodep, "Not under module"); // We could create just one temp variable, but we'll get better optimization // if we make one per term. - string name1 = (string("__Vconcswap")+cvtToStr(m_modp->varNumGetInc())); - string name2 = (string("__Vconcswap")+cvtToStr(m_modp->varNumGetInc())); + string name1 = (string("__Vconcswap") + cvtToStr(m_modp->varNumGetInc())); + string name2 = (string("__Vconcswap") + cvtToStr(m_modp->varNumGetInc())); AstVar* temp1p = new AstVar(sel1p->fileline(), AstVarType::BLOCKTEMP, name1, - VFlagLogicPacked(), msb1-lsb1+1); + VFlagLogicPacked(), msb1 - lsb1 + 1); AstVar* temp2p = new AstVar(sel2p->fileline(), AstVarType::BLOCKTEMP, name2, - VFlagLogicPacked(), msb2-lsb2+1); + VFlagLogicPacked(), msb2 - lsb2 + 1); m_modp->addStmtp(temp1p); m_modp->addStmtp(temp2p); - AstNodeAssign* asn1ap - = VN_CAST(nodep->cloneType - (new AstVarRef(sel1p->fileline(), temp1p, true), - sel1p), NodeAssign); - AstNodeAssign* asn2ap - = VN_CAST(nodep->cloneType - (new AstVarRef(sel2p->fileline(), temp2p, true), - sel2p), NodeAssign); - AstNodeAssign* asn1bp - = VN_CAST(nodep->cloneType - (lc1p, new AstVarRef(sel1p->fileline(), temp1p, false)), - NodeAssign); - AstNodeAssign* asn2bp - = VN_CAST(nodep->cloneType - (lc2p, new AstVarRef(sel2p->fileline(), temp2p, false)), - NodeAssign); + AstNodeAssign* asn1ap = VN_CAST( + nodep->cloneType(new AstVarRef(sel1p->fileline(), temp1p, true), sel1p), + NodeAssign); + AstNodeAssign* asn2ap = VN_CAST( + nodep->cloneType(new AstVarRef(sel2p->fileline(), temp2p, true), sel2p), + NodeAssign); + AstNodeAssign* asn1bp = VN_CAST( + nodep->cloneType(lc1p, new AstVarRef(sel1p->fileline(), temp1p, false)), + NodeAssign); + AstNodeAssign* asn2bp = VN_CAST( + nodep->cloneType(lc2p, new AstVarRef(sel2p->fileline(), temp2p, false)), + NodeAssign); asn1ap->dtypeFrom(temp1p); asn1bp->dtypeFrom(temp1p); asn2ap->dtypeFrom(temp2p); @@ -1145,20 +1149,19 @@ private: newp = AstNode::addNext(newp, asn1bp); newp = AstNode::addNext(newp, asn2bp); } - if (debug()>=9 && newp) newp->dumpTreeAndNext(cout, " _new: "); + if (debug() >= 9 && newp) newp->dumpTreeAndNext(cout, " _new: "); nodep->addNextHere(newp); // Cleanup VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(conp->deleteTree(), conp); // Further reduce, either node may have more reductions. return true; - } - else if (m_doV && VN_IS(nodep->rhsp(), StreamR)) { + } else if (m_doV && VN_IS(nodep->rhsp(), StreamR)) { // The right-streaming operator on rhs of assignment does not // change the order of bits. Eliminate stream but keep its lhsp // Unlink the stuff - AstNode* srcp = VN_CAST(nodep->rhsp(), StreamR)->lhsp()->unlinkFrBack(); - AstNode* sizep = VN_CAST(nodep->rhsp(), StreamR)->rhsp()->unlinkFrBack(); + AstNode* srcp = VN_CAST(nodep->rhsp(), StreamR)->lhsp()->unlinkFrBack(); + AstNode* sizep = VN_CAST(nodep->rhsp(), StreamR)->rhsp()->unlinkFrBack(); AstNode* streamp = VN_CAST(nodep->rhsp(), StreamR)->unlinkFrBack(); nodep->rhsp(srcp); // Cleanup @@ -1166,41 +1169,38 @@ private: VL_DO_DANGLING(streamp->deleteTree(), streamp); // Further reduce, any of the nodes may have more reductions. return true; - } - else if (m_doV && VN_IS(nodep->lhsp(), StreamL)) { + } else if (m_doV && VN_IS(nodep->lhsp(), StreamL)) { // Push the stream operator to the rhs of the assignment statement int dWidth = VN_CAST(nodep->lhsp(), StreamL)->lhsp()->width(); int sWidth = nodep->rhsp()->width(); // Unlink the stuff - AstNode* dstp = VN_CAST(nodep->lhsp(), StreamL)->lhsp()->unlinkFrBack(); + AstNode* dstp = VN_CAST(nodep->lhsp(), StreamL)->lhsp()->unlinkFrBack(); AstNode* streamp = VN_CAST(nodep->lhsp(), StreamL)->unlinkFrBack(); - AstNode* srcp = nodep->rhsp()->unlinkFrBack(); + AstNode* srcp = nodep->rhsp()->unlinkFrBack(); // Connect the rhs to the stream operator and update its width VN_CAST(streamp, StreamL)->lhsp(srcp); - streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), - AstNumeric::UNSIGNED); + streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), AstNumeric::UNSIGNED); // Shrink the RHS if necessary if (sWidth > dWidth) { - streamp = new AstSel(streamp->fileline(), streamp, sWidth-dWidth, dWidth); + streamp = new AstSel(streamp->fileline(), streamp, sWidth - dWidth, dWidth); } // Link the nodes back in nodep->lhsp(dstp); nodep->rhsp(streamp); return true; - } - else if (m_doV && VN_IS(nodep->lhsp(), StreamR)) { + } else if (m_doV && VN_IS(nodep->lhsp(), StreamR)) { // The right stream operator on lhs of assignment statement does // not reorder bits. However, if the rhs is wider than the lhs, // then we select bits from the left-most, not the right-most. int dWidth = VN_CAST(nodep->lhsp(), StreamR)->lhsp()->width(); int sWidth = nodep->rhsp()->width(); // Unlink the stuff - AstNode* dstp = VN_CAST(nodep->lhsp(), StreamR)->lhsp()->unlinkFrBack(); - AstNode* sizep = VN_CAST(nodep->lhsp(), StreamR)->rhsp()->unlinkFrBack(); + AstNode* dstp = VN_CAST(nodep->lhsp(), StreamR)->lhsp()->unlinkFrBack(); + AstNode* sizep = VN_CAST(nodep->lhsp(), StreamR)->rhsp()->unlinkFrBack(); AstNode* streamp = VN_CAST(nodep->lhsp(), StreamR)->unlinkFrBack(); - AstNode* srcp = nodep->rhsp()->unlinkFrBack(); + AstNode* srcp = nodep->rhsp()->unlinkFrBack(); if (sWidth > dWidth) { - srcp = new AstSel(streamp->fileline(), srcp, sWidth-dWidth, dWidth); + srcp = new AstSel(streamp->fileline(), srcp, sWidth - dWidth, dWidth); } nodep->lhsp(dstp); nodep->rhsp(srcp); @@ -1209,8 +1209,7 @@ private: VL_DO_DANGLING(streamp->deleteTree(), streamp); // Further reduce, any of the nodes may have more reductions. return true; - } - else if (replaceAssignMultiSel(nodep)) { + } else if (replaceAssignMultiSel(nodep)) { return true; } return false; @@ -1225,25 +1224,25 @@ private: const AstShiftR* shiftp = VN_CAST(VN_CAST_CONST(nodep, And)->rhsp(), ShiftR); if (!VN_IS(shiftp->rhsp(), Const)) return false; if (static_cast(nodep->width()) - <= VN_CAST_CONST(shiftp->rhsp(), Const)->toUInt()) return false; + <= VN_CAST_CONST(shiftp->rhsp(), Const)->toUInt()) { + return false; + } return true; } void replaceBoolShift(AstNode* nodep) { - if (debug()>=9) nodep->dumpTree(cout, " bshft_old: "); + if (debug() >= 9) nodep->dumpTree(cout, " bshft_old: "); AstConst* andConstp = VN_CAST(VN_CAST(nodep, And)->lhsp(), Const); AstNode* fromp = VN_CAST(VN_CAST(nodep, And)->rhsp(), ShiftR)->lhsp()->unlinkFrBack(); - AstConst* shiftConstp = VN_CAST(VN_CAST(VN_CAST(nodep, And)->rhsp(), ShiftR)->rhsp(), - Const); - V3Number val (andConstp, andConstp->width()); + AstConst* shiftConstp + = VN_CAST(VN_CAST(VN_CAST(nodep, And)->rhsp(), ShiftR)->rhsp(), Const); + V3Number val(andConstp, andConstp->width()); val.opShiftL(andConstp->num(), shiftConstp->num()); - AstAnd* newp = new AstAnd(nodep->fileline(), - new AstConst(nodep->fileline(), val), - fromp); + AstAnd* newp = new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), val), fromp); // widthMin no longer applicable if different C-expanded width newp->dtypeSetLogicSized(nodep->width(), AstNumeric::UNSIGNED); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - if (debug()>=9) newp->dumpTree(cout, " _new: "); + if (debug() >= 9) newp->dumpTree(cout, " _new: "); } void replaceWithSimulation(AstNode* nodep) { @@ -1251,11 +1250,12 @@ private: // Run it - may be unoptimizable due to large for loop, etc simvis.mainParamEmulate(nodep); if (!simvis.optimizable()) { - AstNode* errorp = simvis.whyNotNodep(); if (!errorp) errorp = nodep; + AstNode* errorp = simvis.whyNotNodep(); + if (!errorp) errorp = nodep; nodep->v3error("Expecting expression to be constant, but can't determine constant for " - <prettyTypeName()<warnOther()<<"... Location of non-constant " - <prettyTypeName()<<": "<prettyTypeName() << endl + << errorp->warnOther() << "... Location of non-constant " + << errorp->prettyTypeName() << ": " << simvis.whyNotMessage()); VL_DO_DANGLING(replaceZero(nodep), nodep); } else { // Fetch the result @@ -1265,8 +1265,9 @@ private: AstNode* newp = valuep->cloneTree(false); newp->dtypeFrom(nodep); newp->fileline(nodep->fileline()); - UINFO(4, "Simulate->"<replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + UINFO(4, "Simulate->" << newp << endl); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } } @@ -1321,11 +1322,10 @@ private: AstNode* ap = nodep->lhsp(); AstNode* bp = bcConcp->lhsp(); // If a+b == 32,64,96 etc, then we want to have a+b together on LHS - if (VL_BITBIT_I(ap->width()+bp->width())==0) return 2; // Transform 2: to abConc - } - else { // abConcp + if (VL_BITBIT_I(ap->width() + bp->width()) == 0) return 2; // Transform 2: to abConc + } else { // abConcp // Unless lhs is already 32 bits due to above, reorder it - if (VL_BITBIT_I(nodep->lhsp()->width())!=0) return 1; // Transform 1: to bcConc + if (VL_BITBIT_I(nodep->lhsp()->width()) != 0) return 1; // Transform 1: to bcConc } return 0; // ok } @@ -1336,14 +1336,14 @@ private: // putting additional CONCATs on the RHS leads to fewer assembler operations. // However, we'll end up with lots of wide moves if we make huge trees // like that, so on 32 bit boundaries, we'll do the opposite form. - UINFO(4,"Move concat: "<1) { + UINFO(4, "Move concat: " << nodep << endl); + if (operandConcatMove(nodep) > 1) { AstNode* ap = nodep->lhsp()->unlinkFrBack(); - AstConcat* bcConcp = VN_CAST(nodep->rhsp(), Concat); bcConcp->unlinkFrBack(); + AstConcat* bcConcp = VN_CAST(nodep->rhsp(), Concat); + bcConcp->unlinkFrBack(); AstNode* bp = bcConcp->lhsp()->unlinkFrBack(); AstNode* cp = bcConcp->rhsp()->unlinkFrBack(); - AstConcat* abConcp = new AstConcat(bcConcp->fileline(), - ap, bp); + AstConcat* abConcp = new AstConcat(bcConcp->fileline(), ap, bp); nodep->lhsp(abConcp); nodep->rhsp(cp); // If bp was a concat, then we have this exact same form again! @@ -1351,12 +1351,12 @@ private: if (operandConcatMove(abConcp)) moveConcat(abConcp); VL_DO_DANGLING(bcConcp->deleteTree(), bcConcp); } else { - AstConcat* abConcp = VN_CAST(nodep->lhsp(), Concat); abConcp->unlinkFrBack(); + AstConcat* abConcp = VN_CAST(nodep->lhsp(), Concat); + abConcp->unlinkFrBack(); AstNode* ap = abConcp->lhsp()->unlinkFrBack(); AstNode* bp = abConcp->rhsp()->unlinkFrBack(); AstNode* cp = nodep->rhsp()->unlinkFrBack(); - AstConcat* bcConcp = new AstConcat(abConcp->fileline(), - bp, cp); + AstConcat* bcConcp = new AstConcat(abConcp->fileline(), bp, cp); nodep->lhsp(ap); nodep->rhsp(bcConcp); if (operandConcatMove(bcConcp)) moveConcat(bcConcp); @@ -1374,25 +1374,22 @@ private: iterateChildren(nodep); } } - virtual void visit(AstPin* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } + virtual void visit(AstPin* nodep) VL_OVERRIDE { iterateChildren(nodep); } void replaceLogEq(AstLogEq* nodep) { // LOGEQ(a,b) => AstLogAnd{AstLogOr{AstLogNot{a},b},AstLogOr{AstLogNot{b},a}} AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); // Do exactly as IEEE says, might result in extra terms, so in future may do differently - AstLogAnd* newp = new AstLogAnd(nodep->fileline(), - new AstLogOr(nodep->fileline(), - new AstLogNot(nodep->fileline(), lhsp), - rhsp), - new AstLogOr(nodep->fileline(), - new AstLogNot(nodep->fileline(), - rhsp->cloneTree(false)), - lhsp->cloneTree(false))); + AstLogAnd* newp = new AstLogAnd( + nodep->fileline(), + new AstLogOr(nodep->fileline(), new AstLogNot(nodep->fileline(), lhsp), rhsp), + new AstLogOr(nodep->fileline(), + new AstLogNot(nodep->fileline(), rhsp->cloneTree(false)), + lhsp->cloneTree(false))); newp->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } void replaceSelSel(AstSel* nodep) { @@ -1403,26 +1400,22 @@ private: AstNode* lsb1p = nodep->lsbp()->unlinkFrBack(); AstNode* lsb2p = belowp->lsbp()->unlinkFrBack(); // Eliminate lower range - UINFO(4,"Elim Lower range: "<fileline(), - VN_CAST(lsb1p, Const)->toUInt() - + VN_CAST(lsb2p, Const)->toUInt()); + newlsbp = new AstConst(lsb1p->fileline(), VN_CAST(lsb1p, Const)->toUInt() + + VN_CAST(lsb2p, Const)->toUInt()); VL_DO_DANGLING(lsb1p->deleteTree(), lsb1p); VL_DO_DANGLING(lsb2p->deleteTree(), lsb2p); } else { // Width is important, we need the width of the fromp's // expression, not the potentially smaller lsb1p's width - newlsbp = new AstAdd(lsb1p->fileline(), - lsb2p, new AstExtend(lsb1p->fileline(), lsb1p)); + newlsbp + = new AstAdd(lsb1p->fileline(), lsb2p, new AstExtend(lsb1p->fileline(), lsb1p)); newlsbp->dtypeFrom(lsb2p); // Unsigned VN_CAST(newlsbp, Add)->rhsp()->dtypeFrom(lsb2p); } - AstSel* newp = new AstSel(nodep->fileline(), - fromp, - newlsbp, - widthp); + AstSel* newp = new AstSel(nodep->fileline(), fromp, newlsbp, widthp); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -1434,34 +1427,24 @@ private: AstNode* conRhsp = conp->rhsp(); if (static_cast(nodep->lsbConst()) >= conRhsp->width()) { conLhsp->unlinkFrBack(); - AstSel* newp = new AstSel(nodep->fileline(), - conLhsp, - nodep->lsbConst() - conRhsp->width(), - nodep->widthConst()); + AstSel* newp = new AstSel(nodep->fileline(), conLhsp, + nodep->lsbConst() - conRhsp->width(), nodep->widthConst()); nodep->replaceWith(newp); - } - else if (static_cast(nodep->msbConst()) < conRhsp->width()) { + } else if (static_cast(nodep->msbConst()) < conRhsp->width()) { conRhsp->unlinkFrBack(); - AstSel* newp = new AstSel(nodep->fileline(), - conRhsp, - nodep->lsbConst(), - nodep->widthConst()); + AstSel* newp + = new AstSel(nodep->fileline(), conRhsp, nodep->lsbConst(), nodep->widthConst()); nodep->replaceWith(newp); - } - else { + } else { // Yuk, split between the two conRhsp->unlinkFrBack(); conLhsp->unlinkFrBack(); - AstConcat* newp = new AstConcat - (nodep->fileline(), - new AstSel(nodep->fileline(), - conLhsp, - 0, - nodep->msbConst() - conRhsp->width() + 1), - new AstSel(nodep->fileline(), - conRhsp, - nodep->lsbConst(), - conRhsp->width()-nodep->lsbConst())); + AstConcat* newp + = new AstConcat(nodep->fileline(), + new AstSel(nodep->fileline(), conLhsp, 0, + nodep->msbConst() - conRhsp->width() + 1), + new AstSel(nodep->fileline(), conRhsp, nodep->lsbConst(), + conRhsp->width() - nodep->lsbConst())); nodep->replaceWith(newp); } VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -1471,36 +1454,43 @@ private: // as SEL's width <= b's width AstReplicate* repp = VN_CAST(nodep->fromp(), Replicate); AstNode* fromp = repp->lhsp(); - AstConst* lsbp = VN_CAST(nodep->lsbp(), Const); if (!lsbp) return false; - AstNode* widthp = nodep->widthp(); if (!VN_IS(widthp, Const)) return false; + AstConst* lsbp = VN_CAST(nodep->lsbp(), Const); + if (!lsbp) return false; + AstNode* widthp = nodep->widthp(); + if (!VN_IS(widthp, Const)) return false; UASSERT_OBJ(fromp->width(), nodep, "Not widthed"); if ((lsbp->toUInt() / fromp->width()) - != ((lsbp->toUInt()+nodep->width()-1) / fromp->width())) return false; + != ((lsbp->toUInt() + nodep->width() - 1) / fromp->width())) { + return false; + } // fromp->unlinkFrBack(); widthp->unlinkFrBack(); - AstSel* newp = new AstSel(nodep->fileline(), - fromp, - new AstConst(lsbp->fileline(), lsbp->toUInt() % fromp->width()), - widthp); + AstSel* newp + = new AstSel(nodep->fileline(), fromp, + new AstConst(lsbp->fileline(), lsbp->toUInt() % fromp->width()), widthp); newp->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); return true; } bool operandRepRep(AstReplicate* nodep) { // REPLICATE(REPLICATE2(from2,cnt2),cnt1) => REPLICATE(from2,(cnt1+cnt2)) AstReplicate* rep2p = VN_CAST(nodep->lhsp(), Replicate); AstNode* from2p = rep2p->lhsp(); - AstConst* cnt1p = VN_CAST(nodep->rhsp(), Const); if (!cnt1p) return false; - AstConst* cnt2p = VN_CAST(rep2p->rhsp(), Const); if (!cnt2p) return false; + AstConst* cnt1p = VN_CAST(nodep->rhsp(), Const); + if (!cnt1p) return false; + AstConst* cnt2p = VN_CAST(rep2p->rhsp(), Const); + if (!cnt2p) return false; // from2p->unlinkFrBack(); cnt1p->unlinkFrBack(); cnt2p->unlinkFrBack(); - AstReplicate* newp = new AstReplicate(nodep->fileline(), - from2p, cnt1p->toUInt()*cnt2p->toUInt()); + AstReplicate* newp + = new AstReplicate(nodep->fileline(), from2p, cnt1p->toUInt() * cnt2p->toUInt()); newp->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); return true; } bool operandConcatSame(AstConcat* nodep) { @@ -1508,8 +1498,10 @@ private: // CONCAT(REP(fromp,cnt1),fromp) -> REPLICATE(fromp,cnt1+1) // CONCAT(fromp,REP(fromp,cnt1)) -> REPLICATE(fromp,1+cnt1) // CONCAT(REP(fromp,cnt1),REP(fromp,cnt2)) -> REPLICATE(fromp,cnt1+cnt2) - AstNode* from1p = nodep->lhsp(); uint32_t cnt1 = 1; - AstNode* from2p = nodep->rhsp(); uint32_t cnt2 = 1; + AstNode* from1p = nodep->lhsp(); + uint32_t cnt1 = 1; + AstNode* from2p = nodep->rhsp(); + uint32_t cnt2 = 1; if (VN_IS(from1p, Replicate)) { AstConst* cnt1p = VN_CAST(VN_CAST(from1p, Replicate)->rhsp(), Const); if (!cnt1p) return false; @@ -1525,9 +1517,10 @@ private: if (!operandsSame(from1p, from2p)) return false; // from1p->unlinkFrBack(); - AstReplicate* newp = new AstReplicate(nodep->fileline(), from1p, cnt1+cnt2); + AstReplicate* newp = new AstReplicate(nodep->fileline(), from1p, cnt1 + cnt2); newp->dtypeFrom(nodep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); return true; } void replaceSelIntoBiop(AstSel* nodep) { @@ -1540,12 +1533,12 @@ private: AstNode* bilhsp = fromp->lhsp()->unlinkFrBack(); AstNode* birhsp = fromp->rhsp()->unlinkFrBack(); // - fromp->lhsp(new AstSel(nodep->fileline(), - bilhsp, lsbp->cloneTree(true), widthp->cloneTree(true))); - fromp->rhsp(new AstSel(nodep->fileline(), - birhsp, lsbp, widthp)); + fromp->lhsp( + new AstSel(nodep->fileline(), bilhsp, lsbp->cloneTree(true), widthp->cloneTree(true))); + fromp->rhsp(new AstSel(nodep->fileline(), birhsp, lsbp, widthp)); fromp->dtypeFrom(nodep); - nodep->replaceWith(fromp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(fromp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } void replaceSelIntoUniop(AstSel* nodep) { // SEL(NOT(a),1,bit) => NOT(SEL(a,bit)) @@ -1556,10 +1549,10 @@ private: // AstNode* bilhsp = fromp->lhsp()->unlinkFrBack(); // - fromp->lhsp(new AstSel(nodep->fileline(), - bilhsp, lsbp, widthp)); + fromp->lhsp(new AstSel(nodep->fileline(), bilhsp, lsbp, widthp)); fromp->dtypeFrom(nodep); - nodep->replaceWith(fromp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(fromp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } virtual void visit(AstAttrOf* nodep) VL_OVERRIDE { @@ -1587,8 +1580,8 @@ private: nodep->replaceWith(fromp); if (VN_IS(fromp->dtypep()->skipRefp(), NodeArrayDType)) { // Strip off array to find what array references - fromp->dtypeFrom(VN_CAST(fromp->dtypep()->skipRefp(), - NodeArrayDType)->subDTypep()); + fromp->dtypeFrom( + VN_CAST(fromp->dtypep()->skipRefp(), NodeArrayDType)->subDTypep()); } VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -1600,7 +1593,7 @@ private: UASSERT_OBJ(nodep->varp(), nodep, "Not linked"); bool did = false; if (m_doV && nodep->varp()->valuep() && !m_attrp) { - //if (debug()) valuep->dumpTree(cout, " visitvaref: "); + // if (debug()) valuep->dumpTree(cout, " visitvaref: "); iterateAndNextNull(nodep->varp()->valuep()); // May change nodep->varp()->valuep() AstNode* valuep = nodep->varp()->valuep(); if (!nodep->lvalue() @@ -1609,42 +1602,39 @@ private: && v3Global.opt.oConst() // Default value, not a "known" constant for this usage && !nodep->varp()->isClassMember() - && !(nodep->varp()->isFuncLocal() - && nodep->varp()->isNonOutput()) - && !nodep->varp()->noSubst() - && !nodep->varp()->isSigPublic()) + && !(nodep->varp()->isFuncLocal() && nodep->varp()->isNonOutput()) + && !nodep->varp()->noSubst() && !nodep->varp()->isSigPublic()) || nodep->varp()->isParam())) { if (operandConst(valuep)) { const V3Number& num = VN_CAST(valuep, Const)->num(); - //UINFO(2,"constVisit "<bitConst(); AstNode* itemp = initarp->getIndexDefaultedValuep(bit); if (VN_IS(itemp, Const)) { const V3Number& num = VN_CAST(itemp, Const)->num(); - //UINFO(2,"constVisit "<backp(), Pin)) { + } else if (m_params && VN_IS(valuep, InitArray) && VN_IS(nodep->backp(), Pin)) { // Allow parameters to pass arrays // Earlier recursion of InitArray made sure each array value is constant // This exception is fairly fragile, i.e. doesn't // support arrays of arrays or other stuff AstNode* newp = valuep->cloneTree(false); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); did = true; } } } if (!did && m_required) { nodep->v3error("Expecting expression to be constant, but variable isn't const: " - <varp()->prettyNameQ()); + << nodep->varp()->prettyNameQ()); } } virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE { @@ -1652,9 +1642,9 @@ private: UASSERT_OBJ(nodep->itemp(), nodep, "Not linked"); bool did = false; if (nodep->itemp()->valuep()) { - //if (debug()) nodep->itemp()->valuep()->dumpTree(cout, " visitvaref: "); + // if (debug()) nodep->itemp()->valuep()->dumpTree(cout, " visitvaref: "); if (nodep->itemp()->user4()) { - nodep->v3error("Recursive enum value: "<itemp()->prettyNameQ()); + nodep->v3error("Recursive enum value: " << nodep->itemp()->prettyNameQ()); } else { nodep->itemp()->user4(true); iterateAndNextNull(nodep->itemp()->valuep()); @@ -1668,7 +1658,7 @@ private: } if (!did && m_required) { nodep->v3error("Expecting expression to be constant, but variable isn't const: " - <itemp()->prettyNameQ()); + << nodep->itemp()->prettyNameQ()); } } @@ -1683,8 +1673,7 @@ private: virtual void visit(AstSenItem* nodep) VL_OVERRIDE { iterateChildren(nodep); if (m_doNConst - && (VN_IS(nodep->sensp(), Const) - || VN_IS(nodep->sensp(), EnumItemRef) + && (VN_IS(nodep->sensp(), Const) || VN_IS(nodep->sensp(), EnumItemRef) || (nodep->varrefp() && nodep->varrefp()->varp()->isParam()))) { // Constants in sensitivity lists may be removed (we'll simplify later) if (nodep->isClocked()) { // A constant can never get a pos/negedge @@ -1707,15 +1696,14 @@ private: lastSensp = VN_CAST(lastSensp, Not)->lhsp(); invert = !invert; } - UINFO(8,"senItem(NOT...) "<edgeType( nodep->edgeType().invert() ); + UINFO(8, "senItem(NOT...) " << nodep << " " << invert << endl); + if (invert) nodep->edgeType(nodep->edgeType().invert()); AstNodeVarRef* senvarp = VN_CAST(lastSensp->unlinkFrBack(), NodeVarRef); UASSERT_OBJ(senvarp, sensp, "Non-varref sensitivity variable"); sensp->replaceWith(senvarp); VL_DO_DANGLING(sensp->deleteTree(), sensp); } else if (!m_doNConst // Deal with later when doNConst missing - && (VN_IS(nodep->sensp(), EnumItemRef) - || VN_IS(nodep->sensp(), Const))) { + && (VN_IS(nodep->sensp(), EnumItemRef) || VN_IS(nodep->sensp(), Const))) { } else if (nodep->isIllegal()) { // Deal with later } else { UASSERT_OBJ(!(nodep->hasVar() && !nodep->varrefp()), nodep, @@ -1726,7 +1714,7 @@ private: iterateChildren(nodep); if (AstConst* constp = VN_CAST(nodep->rhsp(), Const)) { if (constp->isZero()) { - UINFO(4,"SENGATE(...,0)->NEVER"<NEVER" << endl); if (onlySenItemInSenTree(nodep)) { nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Never())); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -1734,7 +1722,7 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } } else { - UINFO(4,"SENGATE(SENITEM,0)->ALWAYS SENITEM"<ALWAYS SENITEM" << endl); AstNode* senitemp = nodep->sensesp()->unlinkFrBack(); nodep->replaceWith(senitemp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -1743,23 +1731,25 @@ private: } struct SenItemCmp { - inline bool operator() (AstNodeSenItem* lhsp, AstNodeSenItem* rhsp) const { + inline bool operator()(AstNodeSenItem* lhsp, AstNodeSenItem* rhsp) const { if (lhsp->type() < rhsp->type()) return true; if (lhsp->type() > rhsp->type()) return false; const AstSenItem* litemp = VN_CAST_CONST(lhsp, SenItem); const AstSenItem* ritemp = VN_CAST_CONST(rhsp, SenItem); if (litemp && ritemp) { // Looks visually better if we keep sorted by name - if (!litemp->varrefp() && ritemp->varrefp()) return true; - if ( litemp->varrefp() && !ritemp->varrefp()) return false; + if (!litemp->varrefp() && ritemp->varrefp()) return true; + if (litemp->varrefp() && !ritemp->varrefp()) return false; if (litemp->varrefp() && ritemp->varrefp()) { if (litemp->varrefp()->name() < ritemp->varrefp()->name()) return true; if (litemp->varrefp()->name() > ritemp->varrefp()->name()) return false; // But might be same name with different scopes - if (litemp->varrefp()->varScopep() - < ritemp->varrefp()->varScopep()) return true; - if (litemp->varrefp()->varScopep() - > ritemp->varrefp()->varScopep()) return false; + if (litemp->varrefp()->varScopep() < ritemp->varrefp()->varScopep()) { + return true; + } + if (litemp->varrefp()->varScopep() > ritemp->varrefp()->varScopep()) { + return false; + } // Or rarely, different data types if (litemp->varrefp()->dtypep() < ritemp->varrefp()->dtypep()) return true; if (litemp->varrefp()->dtypep() > ritemp->varrefp()->dtypep()) return false; @@ -1777,7 +1767,7 @@ private: virtual void visit(AstSenTree* nodep) VL_OVERRIDE { iterateChildren(nodep); if (m_doExpensive) { - //cout<dumpTree(cout, "ssin: "); + // cout<dumpTree(cout, "ssin: "); // Optimize ideas for the future: // SENTREE(... SENGATE(x,a), SENGATE(SENITEM(x),b) ...) => SENGATE(x,OR(a,b)) @@ -1788,10 +1778,10 @@ private: // SENGATE(SENITEM(x)) -> SENITEM(x), then let it collapse with the // other SENITEM(x). { - AstUser4InUse m_inuse4; + AstUser4InUse m_inuse4; // Mark x in SENITEM(x) - for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); - senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { + for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp; + senp = VN_CAST(senp->nextp(), NodeSenItem)) { if (AstSenItem* itemp = VN_CAST(senp, SenItem)) { if (itemp->varrefp() && itemp->varrefp()->varScopep()) { itemp->varrefp()->varScopep()->user4(1); @@ -1799,8 +1789,8 @@ private: } } // Find x in SENTREE(SENITEM(x)) - for (AstNodeSenItem* nextp, * senp = VN_CAST(nodep->sensesp(), NodeSenItem); - senp; senp = nextp) { + for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp; + senp = nextp) { nextp = VN_CAST(senp->nextp(), NodeSenItem); if (AstSenGate* gatep = VN_CAST(senp, SenGate)) { if (AstSenItem* itemp = VN_CAST(gatep->sensesp(), SenItem)) { @@ -1821,8 +1811,8 @@ private: // Sort the sensitivity names so "posedge a or b" and "posedge b or a" end up together. // Also, remove duplicate assignments, and fold POS&NEGs into ANYEDGEs // Make things a little faster; check first if we need a sort - for (AstNodeSenItem* nextp, * senp = VN_CAST(nodep->sensesp(), NodeSenItem); - senp; senp = nextp) { + for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp; + senp = nextp) { nextp = VN_CAST(senp->nextp(), NodeSenItem); // cppcheck-suppress unassignedVariable // cppcheck bug SenItemCmp cmp; @@ -1830,17 +1820,17 @@ private: // Something's out of order, sort it senp = NULL; std::vector vec; - for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); - senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { + for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp; + senp = VN_CAST(senp->nextp(), NodeSenItem)) { vec.push_back(senp); } stable_sort(vec.begin(), vec.end(), SenItemCmp()); - for (std::vector::iterator it=vec.begin(); - it!=vec.end(); ++it) { + for (std::vector::iterator it = vec.begin(); it != vec.end(); + ++it) { (*it)->unlinkFrBack(); } - for (std::vector::iterator it=vec.begin(); - it!=vec.end(); ++it) { + for (std::vector::iterator it = vec.begin(); it != vec.end(); + ++it) { nodep->addSensesp(*it); } break; @@ -1848,8 +1838,8 @@ private: } // Pass2, remove dup edges - for (AstNodeSenItem* nextp, * senp = VN_CAST(nodep->sensesp(), NodeSenItem); - senp; senp = nextp) { + for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp; + senp = nextp) { nextp = VN_CAST(senp->nextp(), NodeSenItem); AstNodeSenItem* cmpp = nextp; AstSenItem* litemp = VN_CAST(senp, SenItem); @@ -1860,12 +1850,14 @@ private: || (!litemp->varrefp() && !ritemp->varrefp())) { // We've sorted in the order ANY, BOTH, POS, NEG, // so we don't need to try opposite orders - if (( litemp->edgeType() == VEdgeType::ET_ANYEDGE) // ANY or {BOTH|POS|NEG} -> ANY - || (litemp->edgeType() == VEdgeType::ET_BOTHEDGE) // BOTH or {POS|NEG} -> BOTH + if ((litemp->edgeType() + == VEdgeType::ET_ANYEDGE) // ANY or {BOTH|POS|NEG} -> ANY + || (litemp->edgeType() + == VEdgeType::ET_BOTHEDGE) // BOTH or {POS|NEG} -> BOTH || (litemp->edgeType() == VEdgeType::ET_POSEDGE // POS or NEG -> BOTH && ritemp->edgeType() == VEdgeType::ET_NEGEDGE) || (litemp->edgeType() == ritemp->edgeType()) // Identical edges - ) { + ) { // Fix edge of old node if (litemp->edgeType() == VEdgeType::ET_POSEDGE && ritemp->edgeType() == VEdgeType::ET_NEGEDGE) @@ -1879,7 +1871,7 @@ private: } } } - //nodep->dumpTree(cout, "ssou: "); + // nodep->dumpTree(cout, "ssou: "); } } @@ -1898,22 +1890,22 @@ private: virtual void visit(AstAssignW* nodep) VL_OVERRIDE { iterateChildren(nodep); if (m_doNConst && replaceNodeAssign(nodep)) return; - AstNodeVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef); // Not VarXRef, as different refs may set different values to each hierarchy - if (m_wremove && !m_params && m_doNConst - && m_modp && operandConst(nodep->rhsp()) + AstNodeVarRef* varrefp = VN_CAST( + nodep->lhsp(), + VarRef); // Not VarXRef, as different refs may set different values to each hierarchy + if (m_wremove && !m_params && m_doNConst && m_modp && operandConst(nodep->rhsp()) && !VN_CAST(nodep->rhsp(), Const)->num().isFourState() && varrefp // Don't do messes with BITREFs/ARRAYREFs && !varrefp->varp()->valuep() // Not already constified - && !varrefp->varScopep()) { // Not scoped (or each scope may have different initial value) + && !varrefp->varScopep()) { // Not scoped (or each scope may have different initial + // value) // ASSIGNW (VARREF, const) -> INITIAL ( ASSIGN (VARREF, const) ) - UINFO(4,"constAssignW "<rhsp()->unlinkFrBack(); varrefp->unlinkFrBack(); - AstInitial* newinitp - = new AstInitial(nodep->fileline(), - new AstAssign(nodep->fileline(), - varrefp, exprp)); + AstInitial* newinitp = new AstInitial( + nodep->fileline(), new AstAssign(nodep->fileline(), varrefp, exprp)); m_modp->addStmtp(newinitp); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); // Set the initial value right in the variable so we can constant propagate @@ -1928,10 +1920,10 @@ private: if (const AstConst* constp = VN_CAST(nodep->condp(), Const)) { AstNode* keepp = NULL; if (constp->isZero()) { - UINFO(4,"IF(0,{any},{x}) => {x}: "< {x}: " << nodep << endl); keepp = nodep->elsesp(); } else { - UINFO(4,"IF(!0,{x},{any}) => {x}: "< {x}: " << nodep << endl); keepp = nodep->ifsp(); } if (keepp) { @@ -1941,27 +1933,27 @@ private: nodep->unlinkFrBack(); } VL_DO_DANGLING(nodep->deleteTree(), nodep); - } - else if (!afterComment(nodep->ifsp()) && !afterComment(nodep->elsesp())) { + } else if (!afterComment(nodep->ifsp()) && !afterComment(nodep->elsesp())) { // Empty block, remove it // Note if we support more C++ then there might be side // effects in the condition itself VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (!afterComment(nodep->ifsp())) { - UINFO(4,"IF({x}) NULL {...} => IF(NOT{x}}: "<ifsp())) { + UINFO(4, "IF({x}) NULL {...} => IF(NOT{x}}: " << nodep << endl); AstNode* condp = nodep->condp(); AstNode* elsesp = nodep->elsesp(); condp->unlinkFrBackWithNext(); elsesp->unlinkFrBackWithNext(); - if (nodep->ifsp()) { nodep->ifsp()->unlinkFrBackWithNext()->deleteTree(); } // Must have been comment - nodep->condp(new AstLogNot(condp->fileline(), condp)); // LogNot, as C++ optimization also possible + if (nodep->ifsp()) { // Must have been comment + nodep->ifsp()->unlinkFrBackWithNext()->deleteTree(); + } + nodep->condp(new AstLogNot(condp->fileline(), + condp)); // LogNot, as C++ optimization also possible nodep->addIfsp(elsesp); - } - else if (((VN_IS(nodep->condp(), Not) && nodep->condp()->width()==1) - || VN_IS(nodep->condp(), LogNot)) - && nodep->ifsp() && nodep->elsesp()) { - UINFO(4,"IF(NOT {x}) => IF(x) swapped if/else"<condp(), Not) && nodep->condp()->width() == 1) + || VN_IS(nodep->condp(), LogNot)) + && nodep->ifsp() && nodep->elsesp()) { + UINFO(4, "IF(NOT {x}) => IF(x) swapped if/else" << nodep << endl); AstNode* condp = VN_CAST(nodep->condp(), Not)->lhsp()->unlinkFrBackWithNext(); AstNode* ifsp = nodep->ifsp()->unlinkFrBackWithNext(); AstNode* elsesp = nodep->elsesp()->unlinkFrBackWithNext(); @@ -1969,33 +1961,29 @@ private: ifp->branchPred(nodep->branchPred().invert()); nodep->replaceWith(ifp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - } - else if (ifSameAssign(nodep)) { - UINFO(4,"IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})"<ifsp(), NodeAssign); + } else if (ifSameAssign(nodep)) { + UINFO(4, "IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})" + << endl); + AstNodeAssign* ifp = VN_CAST(nodep->ifsp(), NodeAssign); AstNodeAssign* elsep = VN_CAST(nodep->elsesp(), NodeAssign); ifp->unlinkFrBack(); AstNode* condp = nodep->condp()->unlinkFrBack(); AstNode* truep = ifp->rhsp()->unlinkFrBack(); AstNode* falsep = elsep->rhsp()->unlinkFrBack(); - ifp->rhsp(new AstCond(truep->fileline(), - condp, truep, falsep)); + ifp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep)); nodep->replaceWith(ifp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - } - else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting - && operandIfIf(nodep)) { - UINFO(9,"IF({a}) IF({b}) => IF({a} && {b})"< IF({a} && {b})" << endl); AstNodeIf* lowerIfp = VN_CAST(nodep->ifsp(), NodeIf); AstNode* condp = nodep->condp()->unlinkFrBack(); AstNode* lowerIfsp = lowerIfp->ifsp()->unlinkFrBackWithNext(); AstNode* lowerCondp = lowerIfp->condp()->unlinkFrBackWithNext(); - nodep->condp(new AstLogAnd(lowerIfp->fileline(), - condp, lowerCondp)); + nodep->condp(new AstLogAnd(lowerIfp->fileline(), condp, lowerCondp)); lowerIfp->replaceWith(lowerIfsp); VL_DO_DANGLING(lowerIfp->deleteTree(), lowerIfp); - } - else if (operandBoolShift(nodep->condp())) { + } else if (operandBoolShift(nodep->condp())) { replaceBoolShift(nodep->condp()); } } @@ -2018,11 +2006,11 @@ private: || (prevp->displayType() == AstDisplayType::DT_DISPLAY && nodep->displayType() == AstDisplayType::DT_WRITE))) return false; - if ((prevp->filep() && !nodep->filep()) - || (!prevp->filep() && nodep->filep()) - || !prevp->filep()->sameTree(nodep->filep())) return false; - if (!prevp->fmtp() || prevp->fmtp()->nextp() - || !nodep->fmtp() || nodep->fmtp()->nextp()) return false; + if ((prevp->filep() && !nodep->filep()) || (!prevp->filep() && nodep->filep()) + || !prevp->filep()->sameTree(nodep->filep())) + return false; + if (!prevp->fmtp() || prevp->fmtp()->nextp() || !nodep->fmtp() || nodep->fmtp()->nextp()) + return false; // We don't merge scopeNames as might be different scopes (late in process) // We don't merge arguments as might need to later print warnings with right line numbers AstSFormatF* pformatp = prevp->fmtp(); @@ -2030,18 +2018,18 @@ private: AstSFormatF* nformatp = nodep->fmtp(); if (!nformatp || nformatp->exprsp() || nformatp->scopeNamep()) return false; // - UINFO(9,"DISPLAY(SF({a})) DISPLAY(SF({b})) -> DISPLAY(SF({a}+{b}))"< DISPLAY(SF({a}+{b}))" << endl); // Convert DT_DISPLAY to DT_WRITE as may allow later optimizations if (prevp->displayType() == AstDisplayType::DT_DISPLAY) { prevp->displayType(AstDisplayType::DT_WRITE); - pformatp->text(pformatp->text()+"\n"); + pformatp->text(pformatp->text() + "\n"); } // We can't replace prev() as the edit tracking iterators will get confused. // So instead we edit the prev note itself. - if (prevp->addNewline()) pformatp->text(pformatp->text()+"\n"); - pformatp->text(pformatp->text()+nformatp->text()); + if (prevp->addNewline()) pformatp->text(pformatp->text() + "\n"); + pformatp->text(pformatp->text() + nformatp->text()); if (!prevp->addNewline() && nodep->addNewline()) { - pformatp->text(pformatp->text()+"\n"); + pformatp->text(pformatp->text() + "\n"); } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return true; @@ -2052,22 +2040,25 @@ private: // This eliminates a pile of wide temps, and makes the C a whole lot more readable. iterateChildren(nodep); bool anyconst = false; - for (AstNode* argp = nodep->exprsp(); argp; argp=argp->nextp()) { - if (VN_IS(argp, Const)) { anyconst = true; break; } + for (AstNode* argp = nodep->exprsp(); argp; argp = argp->nextp()) { + if (VN_IS(argp, Const)) { + anyconst = true; + break; + } } if (m_doNConst && anyconst) { - //UINFO(9," Display in "<text()<text()<exprsp(); string text = nodep->text(); - for (string::const_iterator it = text.begin(); it!=text.end(); ++it) { + for (string::const_iterator it = text.begin(); it != text.end(); ++it) { char ch = *it; - if (!inPct && ch=='%') { + if (!inPct && ch == '%') { inPct = true; fmt = ch; - } else if (inPct && (isdigit(ch) || ch=='.' || ch=='-')) { + } else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) { fmt += ch; } else if (inPct) { inPct = false; @@ -2081,8 +2072,8 @@ private: AstNode* nextp = argp->nextp(); if (VN_IS(argp, Const)) { // Convert it string out = VN_CAST(argp, Const)->num().displayed(nodep, fmt); - UINFO(9," DispConst: "< "< " << out << " for " + << argp << endl); // fmt = out w/ replace % with %% as it must be literal. fmt = VString::quotePercent(out); VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); @@ -2098,12 +2089,10 @@ private: } if (newFormat != nodep->text()) { nodep->text(newFormat); - UINFO(9," Display out "<exprsp() - && nodep->name().find('%') == string::npos - && !nodep->hidden()) { + if (!nodep->exprsp() && nodep->name().find('%') == string::npos && !nodep->hidden()) { // Just a simple constant string - the formatting is pointless VL_DO_DANGLING(replaceConstString(nodep, nodep->name()), nodep); } @@ -2122,35 +2111,31 @@ private: virtual void visit(AstWhile* nodep) VL_OVERRIDE { bool oldHasJumpGo = m_hasJumpGo; m_hasJumpGo = false; - { - iterateChildren(nodep); - } + { iterateChildren(nodep); } bool thisWhileHasJumpGo = m_hasJumpGo; m_hasJumpGo = thisWhileHasJumpGo || oldHasJumpGo; if (m_doNConst) { if (nodep->condp()->isZero()) { - UINFO(4,"WHILE(0) => nop "<precondsp()) nodep->replaceWith(nodep->precondsp()); - else nodep->unlinkFrBack(); + UINFO(4, "WHILE(0) => nop " << nodep << endl); + if (nodep->precondsp()) { + nodep->replaceWith(nodep->precondsp()); + } else { + nodep->unlinkFrBack(); + } VL_DO_DANGLING(nodep->deleteTree(), nodep); - } - else if (nodep->condp()->isNeqZero()) { + } else if (nodep->condp()->isNeqZero()) { if (!thisWhileHasJumpGo) { nodep->v3warn(INFINITELOOP, "Infinite loop (condition always true)"); - nodep->fileline()->modifyWarnOff(V3ErrorCode::INFINITELOOP, true); // Complain just once + nodep->fileline()->modifyWarnOff(V3ErrorCode::INFINITELOOP, + true); // Complain just once } - } - else if (operandBoolShift(nodep->condp())) { + } else if (operandBoolShift(nodep->condp())) { replaceBoolShift(nodep->condp()); } } } - virtual void visit(AstInitArray* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } - virtual void visit(AstInitItem* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } + virtual void visit(AstInitArray* nodep) VL_OVERRIDE { iterateChildren(nodep); } + virtual void visit(AstInitItem* nodep) VL_OVERRIDE { iterateChildren(nodep); } // These are converted by V3Param. Don't constify as we don't want the // from() VARREF to disappear, if any. // If output of a presel didn't get consted, chances are V3Param didn't visit properly @@ -2159,9 +2144,7 @@ private: // Ignored, can eliminate early virtual void visit(AstSysIgnore* nodep) VL_OVERRIDE { iterateChildren(nodep); - if (m_doNConst) { - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } + if (m_doNConst) { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } } // Simplify @@ -2182,7 +2165,7 @@ private: if (!nodep->nextp()) { if (AstJumpLabel* aboveLabelp = VN_CAST(nodep->abovep(), JumpLabel)) { if (aboveLabelp == nodep->labelp()) { - UINFO(4, "JUMPGO => last remove "< last remove " << nodep << endl); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } @@ -2199,11 +2182,14 @@ private: iterateChildren(nodep); // AstJumpGo's below here that point to this node will set user4 if (m_doExpensive && !nodep->user4()) { - UINFO(4,"JUMPLABEL => unused "< unused " << nodep << endl); AstNode* underp = NULL; if (nodep->stmtsp()) underp = nodep->stmtsp()->unlinkFrBackWithNext(); - if (underp) nodep->replaceWith(underp); - else nodep->unlinkFrBack(); + if (underp) { + nodep->replaceWith(underp); + } else { + nodep->unlinkFrBack(); + } VL_DO_DANGLING(nodep->deleteTree(), nodep); } } @@ -2212,7 +2198,7 @@ private: // Below lines are magic expressions processed by astgen // TREE_SKIP_VISIT("AstNODETYPE") # Rename normal visit to visitGen and don't iterate //----- - + // clang-format off TREE_SKIP_VISIT("ArraySel"); //----- @@ -2527,7 +2513,7 @@ private: TREEOPC("AstPutcN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)"); TREEOPC("AstSubstrN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)"); TREEOPC("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, VN_CAST(nodep->lhsp(), Const)->num().toString())"); - + // clang-format on // Possible futures: // (a?(b?y:x):y) -> (a&&!b)?x:y @@ -2545,13 +2531,11 @@ private: // Ignore dtypes for parameter type pins } else { nodep->v3error("Expecting expression to be constant, but can't convert a " - <prettyTypeName()<<" to constant."); + << nodep->prettyTypeName() << " to constant."); } } else { // Calculate the width of this operation - if (m_params && !nodep->width()) { - nodep = V3Width::widthParamsEdit(nodep); - } + if (m_params && !nodep->width()) nodep = V3Width::widthParamsEdit(nodep); iterateChildren(nodep); } } @@ -2585,6 +2569,7 @@ public: m_scopep = NULL; m_attrp = NULL; // + // clang-format off switch (pmode) { case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true; m_required = true; break; @@ -2597,6 +2582,7 @@ public: case PROC_CPP: m_doV = false; m_doNConst = true; break; default: v3fatalSrc("Bad case"); break; } + // clang-format on } virtual ~ConstVisitor() {} AstNode* mainAcceptEdit(AstNode* nodep) { @@ -2611,7 +2597,7 @@ public: //! Force this cell node's parameter list to become a constant //! @return Pointer to the edited node. AstNode* V3Const::constifyParamsEdit(AstNode* nodep) { - //if (debug()>0) nodep->dumpTree(cout, " forceConPRE : "); + // if (debug() > 0) nodep->dumpTree(cout, " forceConPRE : "); // Resize even if the node already has a width, because buried in the tree // we may have a node we just created with signing, etc, that isn't sized yet. @@ -2627,7 +2613,7 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) { nodep = visitor.mainAcceptEdit(nodep); } // Because we do edits, nodep links may get trashed and core dump this. - //if (debug()>0) nodep->dumpTree(cout, " forceConDONE: "); + // if (debug() > 0) nodep->dumpTree(cout, " forceConDONE: "); return nodep; } @@ -2640,7 +2626,7 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) { //! width check. //! @return Pointer to the edited node. AstNode* V3Const::constifyGenerateParamsEdit(AstNode* nodep) { - //if (debug()>0) nodep->dumpTree(cout, " forceConPRE : "); + // if (debug() > 0) nodep->dumpTree(cout, " forceConPRE : "); // Resize even if the node already has a width, because buried in the tree // we may have a node we just created with signing, etc, that isn't sized // yet. @@ -2657,31 +2643,31 @@ AstNode* V3Const::constifyGenerateParamsEdit(AstNode* nodep) { nodep = visitor.mainAcceptEdit(nodep); } // Because we do edits, nodep links may get trashed and core dump this. - //if (debug()>0) nodep->dumpTree(cout, " forceConDONE: "); + // if (debug() > 0) nodep->dumpTree(cout, " forceConDONE: "); return nodep; } void V3Const::constifyAllLint(AstNetlist* nodep) { // Only call from Verilator.cpp, as it uses user#'s - UINFO(2,__FUNCTION__<<": "<= 3); } void V3Const::constifyCpp(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } AstNode* V3Const::constifyEdit(AstNode* nodep) { - ConstVisitor visitor (ConstVisitor::PROC_V_NOWARN); + ConstVisitor visitor(ConstVisitor::PROC_V_NOWARN); nodep = visitor.mainAcceptEdit(nodep); return nodep; } @@ -2690,9 +2676,9 @@ void V3Const::constifyAllLive(AstNetlist* nodep) { // Only call from Verilator.cpp, as it uses user#'s // This only pushes constants up, doesn't make any other edits // IE doesn't prune dead statements, as we need to do some usability checks after this - UINFO(2,__FUNCTION__<<": "<= 3); @@ -2700,16 +2686,16 @@ void V3Const::constifyAllLive(AstNetlist* nodep) { void V3Const::constifyAll(AstNetlist* nodep) { // Only call from Verilator.cpp, as it uses user#'s - UINFO(2,__FUNCTION__<<": "<= 3); } AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) { - ConstVisitor visitor (ConstVisitor::PROC_V_EXPENSIVE); + ConstVisitor visitor(ConstVisitor::PROC_V_EXPENSIVE); nodep = visitor.mainAcceptEdit(nodep); return nodep; } diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index c90249700..0cf64c20a 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -63,9 +63,7 @@ private: public: // CONSTRUCTORS - explicit DeadModVisitor(AstNodeModule* nodep) { - iterate(nodep); - } + explicit DeadModVisitor(AstNodeModule* nodep) { iterate(nodep); } virtual ~DeadModVisitor() {} }; @@ -80,52 +78,46 @@ private: // AstVar::user1() -> int. Count of number of references // AstVarScope::user1() -> int. Count of number of references // AstNodeDType::user1() -> int. Count of number of references - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // TYPES - typedef std::multimap AssignMap; + typedef std::multimap AssignMap; // STATE - AstNodeModule* m_modp; // Current module - std::vector m_varsp; // List of all encountered to avoid another loop through tree - std::vector m_dtypesp; // List of all encountered to avoid another loop through tree - std::vector m_vscsp; // List of all encountered to avoid another loop through tree - std::vector m_scopesp; // List of all encountered to avoid another loop through tree - std::vector m_cellsp; // List of all encountered to avoid another loop through tree - std::vector m_classesp; // List of all encountered to avoid another loop through tree - AssignMap m_assignMap; // List of all simple assignments for each variable - bool m_elimUserVars; // Allow removal of user's vars - bool m_elimDTypes; // Allow removal of DTypes - bool m_elimScopes; // Allow removal of Scopes - bool m_elimCells; // Allow removal of Cells - bool m_sideEffect; // Side effects discovered in assign RHS + AstNodeModule* m_modp; // Current module + // List of all encountered to avoid another loop through tree + std::vector m_varsp; + std::vector m_dtypesp; + std::vector m_vscsp; + std::vector m_scopesp; + std::vector m_cellsp; + std::vector m_classesp; + + AssignMap m_assignMap; // List of all simple assignments for each variable + bool m_elimUserVars; // Allow removal of user's vars + bool m_elimDTypes; // Allow removal of DTypes + bool m_elimScopes; // Allow removal of Scopes + bool m_elimCells; // Allow removal of Cells + bool m_sideEffect; // Side effects discovered in assign RHS // METHODS VL_DEBUG_FUNC; // Declare debug() void checkAll(AstNode* nodep) { if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves - if (AstNode* subnodep = nodep->dtypep()) { - subnodep->user1Inc(); - } - } - if (AstNode* subnodep = nodep->getChildDTypep()) { - subnodep->user1Inc(); + if (AstNode* subnodep = nodep->dtypep()) subnodep->user1Inc(); } + if (AstNode* subnodep = nodep->getChildDTypep()) subnodep->user1Inc(); } void checkDType(AstNodeDType* nodep) { if (!nodep->generic() // Don't remove generic types && m_elimDTypes // dtypes stick around until post-widthing && !VN_IS(nodep, MemberDType) // Keep member names iff upper type exists - ) { + ) { m_dtypesp.push_back(nodep); } - if (AstNode* subnodep = nodep->virtRefDTypep()) { - subnodep->user1Inc(); - } - if (AstNode* subnodep = nodep->virtRefDType2p()) { - subnodep->user1Inc(); - } + if (AstNode* subnodep = nodep->virtRefDTypep()) subnodep->user1Inc(); + if (AstNode* subnodep = nodep->virtRefDType2p()) subnodep->user1Inc(); } // VISITORS @@ -177,20 +169,24 @@ private: nodep->varScopep()->user1Inc(); nodep->varScopep()->varp()->user1Inc(); } - if (nodep->varp()) { - nodep->varp()->user1Inc(); - } + if (nodep->varp()) nodep->varp()->user1Inc(); if (nodep->packagep()) { - if (m_elimCells) nodep->packagep(NULL); - else nodep->packagep()->user1Inc(); + if (m_elimCells) { + nodep->packagep(NULL); + } else { + nodep->packagep()->user1Inc(); + } } } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { iterateChildren(nodep); checkAll(nodep); if (nodep->packagep()) { - if (m_elimCells) nodep->packagep(NULL); - else nodep->packagep()->user1Inc(); + if (m_elimCells) { + nodep->packagep(NULL); + } else { + nodep->packagep()->user1Inc(); + } } } virtual void visit(AstMethodCall* nodep) VL_OVERRIDE { @@ -202,8 +198,11 @@ private: checkDType(nodep); checkAll(nodep); if (nodep->packagep()) { - if (m_elimCells) nodep->packagep(NULL); - else nodep->packagep()->user1Inc(); + if (m_elimCells) { + nodep->packagep(NULL); + } else { + nodep->packagep()->user1Inc(); + } } } virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE { @@ -211,12 +210,13 @@ private: checkDType(nodep); checkAll(nodep); if (nodep->packagep()) { - if (m_elimCells) nodep->packagep(NULL); - else nodep->packagep()->user1Inc(); - } - if (nodep->classp()) { - nodep->classp()->user1Inc(); + if (m_elimCells) { + nodep->packagep(NULL); + } else { + nodep->packagep()->user1Inc(); + } } + if (nodep->classp()) nodep->classp()->user1Inc(); } virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { iterateChildren(nodep); @@ -227,8 +227,11 @@ private: iterateChildren(nodep); checkAll(nodep); if (nodep->packagep()) { - if (m_elimCells) nodep->packagep(NULL); - else nodep->packagep()->user1Inc(); + if (m_elimCells) { + nodep->packagep(NULL); + } else { + nodep->packagep()->user1Inc(); + } } checkAll(nodep); } @@ -263,17 +266,13 @@ private: iterateChildren(nodep); checkAll(nodep); if (nodep->scopep()) nodep->scopep()->user1Inc(); - if (mightElimVar(nodep->varp())) { - m_vscsp.push_back(nodep); - } + if (mightElimVar(nodep->varp())) m_vscsp.push_back(nodep); } virtual void visit(AstVar* nodep) VL_OVERRIDE { iterateChildren(nodep); checkAll(nodep); if (nodep->isSigPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc(); - if (mightElimVar(nodep)) { - m_varsp.push_back(nodep); - } + if (mightElimVar(nodep)) m_varsp.push_back(nodep); } virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { // See if simple assignments to variables may be eliminated because @@ -306,14 +305,15 @@ private: // Kill any unused modules // V3LinkCells has a graph that is capable of this too, but we need to do it // after we've done all the generate blocks - for (bool retry=true; retry; ) { + for (bool retry = true; retry;) { retry = false; AstNodeModule* nextmodp; - for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=nextmodp) { + for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp = nextmodp) { nextmodp = VN_CAST(modp->nextp(), NodeModule); - if (modp->dead() || (modp->level()>2 && modp->user1()==0 && !modp->internal())) { + if (modp->dead() + || (modp->level() > 2 && modp->user1() == 0 && !modp->internal())) { // > 2 because L1 is the wrapper, L2 is the top user module - UINFO(4," Dead module "<dead()) { // If was dead didn't increment user1's @@ -327,27 +327,23 @@ private: } bool mightElimVar(AstVar* nodep) { return (!nodep->isSigPublic() // Can't elim publics! - && !nodep->isIO() - && !nodep->isClassMember() + && !nodep->isIO() && !nodep->isClassMember() && ((nodep->isTemp() && !nodep->isTrace()) || (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly()) || m_elimUserVars)); // Post-Trace can kill most anything } void deadCheckScope() { - for (bool retry=true; retry; ) { + for (bool retry = true; retry;) { retry = false; - for (std::vector::iterator it = m_scopesp.begin(); - it != m_scopesp.end();++it) { + for (std::vector::iterator it = m_scopesp.begin(); it != m_scopesp.end(); + ++it) { AstScope* scp = *it; - if (!scp) - continue; + if (!scp) continue; if (scp->user1() == 0) { UINFO(4, " Dead AstScope " << scp << endl); scp->aboveScopep()->user1Inc(-1); - if (scp->dtypep()) { - scp->dtypep()->user1Inc(-1); - } + if (scp->dtypep()) scp->dtypep()->user1Inc(-1); VL_DO_DANGLING(scp->unlinkFrBack()->deleteTree(), scp); *it = NULL; retry = true; @@ -357,7 +353,7 @@ private: } void deadCheckCells() { - for (std::vector::iterator it = m_cellsp.begin(); it!=m_cellsp.end(); ++it) { + for (std::vector::iterator it = m_cellsp.begin(); it != m_cellsp.end(); ++it) { AstCell* cellp = *it; if (cellp->user1() == 0 && !cellp->modp()->stmtsp()) { cellp->modp()->user1Inc(-1); @@ -385,15 +381,15 @@ private: void deadCheckVar() { // Delete any unused varscopes - for (std::vector::iterator it = m_vscsp.begin(); it!=m_vscsp.end(); ++it) { + for (std::vector::iterator it = m_vscsp.begin(); it != m_vscsp.end(); ++it) { AstVarScope* vscp = *it; if (vscp->user1() == 0) { - UINFO(4," Dead "< eqrange + UINFO(4, " Dead " << vscp << endl); + std::pair eqrange = m_assignMap.equal_range(vscp); for (AssignMap::iterator itr = eqrange.first; itr != eqrange.second; ++itr) { AstNodeAssign* assp = itr->second; - UINFO(4," Dead assign "<dtypep()->user1Inc(-1); VL_DO_DANGLING(assp->unlinkFrBack()->deleteTree(), assp); } @@ -402,40 +398,36 @@ private: VL_DO_DANGLING(vscp->unlinkFrBack()->deleteTree(), vscp); } } - for (bool retry=true; retry; ) { + for (bool retry = true; retry;) { retry = false; - for (std::vector::iterator it = m_varsp.begin(); it != m_varsp.end();++it) { + for (std::vector::iterator it = m_varsp.begin(); it != m_varsp.end(); ++it) { AstVar* varp = *it; - if (!varp) - continue; + if (!varp) continue; if (varp->user1() == 0) { UINFO(4, " Dead " << varp << endl); - if (varp->dtypep()) { - varp->dtypep()->user1Inc(-1); - } + if (varp->dtypep()) varp->dtypep()->user1Inc(-1); VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp); *it = NULL; retry = true; } } } - for (std::vector::iterator it = m_dtypesp.begin(); it != m_dtypesp.end();++it) { + for (std::vector::iterator it = m_dtypesp.begin(); it != m_dtypesp.end(); ++it) { if ((*it)->user1() == 0) { - AstNodeUOrStructDType *classp; + AstNodeUOrStructDType* classp; // It's possible that there if a reference to each individual member, but // not to the dtype itself. Check and don't remove the parent dtype if // members are still alive. if ((classp = VN_CAST((*it), NodeUOrStructDType))) { bool cont = true; - for (AstMemberDType *memberp = classp->membersp(); - memberp; memberp = VN_CAST(memberp->nextp(), MemberDType)) { + for (AstMemberDType* memberp = classp->membersp(); memberp; + memberp = VN_CAST(memberp->nextp(), MemberDType)) { if (memberp->user1() != 0) { cont = false; break; } } - if (!cont) - continue; + if (!cont) continue; } VL_DO_DANGLING((*it)->unlinkFrBack()->deleteTree(), *it); } @@ -444,8 +436,8 @@ private: public: // CONSTRUCTORS - DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, - bool elimScopes, bool elimCells) { + DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes, + bool elimCells) { m_modp = NULL; m_elimCells = elimCells; m_elimUserVars = elimUserVars; @@ -476,41 +468,32 @@ public: // Dead class functions void V3Dead::deadifyModules(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 6); } void V3Dead::deadifyDTypes(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); + UINFO(2, __FUNCTION__ << ": " << endl); + { DeadVisitor visitor(nodep, false, true, true, false); } // Destruct before checking + V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, + v3Global.opt.dumpTreeLevel(__FILE__) >= 3); } void V3Dead::deadifyAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } void V3Dead::deadifyAllScoped(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 575ba1ab4..ecf80dccb 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -81,40 +81,41 @@ private: // Cleared each scope/active: // AstAssignDly::user3() -> AstVarScope*. __Vdlyvset__ created for this assign // AstAlwaysPost::user3() -> AstVarScope*. __Vdlyvset__ last referenced in IF - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser3InUse m_inuser3; - AstUser4InUse m_inuser4; - AstUser5InUse m_inuser5; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; + AstUser3InUse m_inuser3; + AstUser4InUse m_inuser4; + AstUser5InUse m_inuser5; - enum VarUsage { VU_NONE=0, VU_DLY=1, VU_NONDLY=2 }; + enum VarUsage { VU_NONE = 0, VU_DLY = 1, VU_NONDLY = 2 }; // STATE - AstActive* m_activep; // Current activate - AstCFunc* m_cfuncp; // Current public C Function - AstAssignDly* m_nextDlyp; // Next delayed assignment in a list of assignments - bool m_inDly; // True in delayed assignments - bool m_inLoop; // True in for loops - bool m_inInitial; // True in initial blocks - typedef std::map,AstVar*> VarMap; - VarMap m_modVarMap; // Table of new var names created under module - VDouble0 m_statSharedSet; // Statistic tracking - typedef std::map ScopeVecMap; + AstActive* m_activep; // Current activate + AstCFunc* m_cfuncp; // Current public C Function + AstAssignDly* m_nextDlyp; // Next delayed assignment in a list of assignments + bool m_inDly; // True in delayed assignments + bool m_inLoop; // True in for loops + bool m_inInitial; // True in initial blocks + typedef std::map, AstVar*> VarMap; + VarMap m_modVarMap; // Table of new var names created under module + VDouble0 m_statSharedSet; // Statistic tracking + typedef std::map ScopeVecMap; ScopeVecMap m_scopeVecMap; // Next var number for each scope // METHODS VL_DEBUG_FUNC; // Declare debug() void markVarUsage(AstVarScope* nodep, uint32_t flags) { - //UINFO(4," MVU "<user5( nodep->user5() | flags ); + // UINFO(4, " MVU " << flags << " " << nodep << endl); + nodep->user5(nodep->user5() | flags); if ((nodep->user5() & VU_DLY) && (nodep->user5() & VU_NONDLY)) { - nodep->v3warn(BLKANDNBLK, "Unsupported: Blocked and non-blocking assignments to same variable: " - <varp()->prettyNameQ()); + nodep->v3warn(BLKANDNBLK, + "Unsupported: Blocked and non-blocking assignments to same variable: " + << nodep->varp()->prettyNameQ()); } } AstVarScope* createVarSc(AstVarScope* oldvarscp, const string& name, - int width/*0==fromoldvar*/, AstNodeDType* newdtypep) { + int width /*0==fromoldvar*/, AstNodeDType* newdtypep) { // Because we've already scoped it, we may need to add both the AstVar and the AstVarScope UASSERT_OBJ(oldvarscp->scopep(), oldvarscp, "Var unscoped"); AstVar* varp; @@ -126,15 +127,14 @@ private: varp = it->second; } else { if (newdtypep) { - varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, - name, newdtypep); - } else if (width==0) { - varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, - name, oldvarscp->varp()); + varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, newdtypep); + } else if (width == 0) { + varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, + oldvarscp->varp()); varp->dtypeFrom(oldvarscp); } else { // Used for vset and dimensions, so can zero init - varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, - name, VFlagBitPacked(), width); + varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, + VFlagBitPacked(), width); } addmodp->addStmtp(varp); m_modVarMap.insert(make_pair(make_pair(addmodp, name), varp)); @@ -146,8 +146,8 @@ private: } AstActive* createActivePost(AstVarRef* varrefp) { - AstActive* newactp = new AstActive(varrefp->fileline(), "sequentdly", - m_activep->sensesp()); + AstActive* newactp + = new AstActive(varrefp->fileline(), "sequentdly", m_activep->sensesp()); // Was addNext(), but addNextHere() avoids a linear search. m_activep->addNextHere(newactp); return newactp; @@ -159,18 +159,18 @@ private: if (!varrefp->varp()->fileline()->warnIsOff(V3ErrorCode::MULTIDRIVEN) && !varrefp->varp()->user2()) { varrefp->varp()->v3warn( - MULTIDRIVEN, "Signal has multiple driving blocks with different clocking: " - <varp()->prettyNameQ()<warnOther()<<"... Location of first driving block"<warnContextPrimary()<warnOther()<<"... Location of other driving block"<warnContextSecondary() - ); + MULTIDRIVEN, + "Signal has multiple driving blocks with different clocking: " + << varrefp->varp()->prettyNameQ() << endl + << varrefp->warnOther() << "... Location of first driving block" << endl + << varrefp->warnContextPrimary() << endl + << oldactivep->warnOther() << "... Location of other driving block" << endl + << oldactivep->warnContextSecondary()); varrefp->varp()->user2(true); } - UINFO(4,"AssignDupDlyVar: "<sensesp()->sensesp()->cloneTree(true); AstNodeSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true); @@ -191,8 +191,8 @@ private: // Return the new LHS for the assignment, Null = unlink // Find selects AstNode* newlhsp = NULL; // NULL = unlink old assign - AstSel* bitselp = NULL; - AstArraySel* arrayselp = NULL; + AstSel* bitselp = NULL; + AstArraySel* arrayselp = NULL; if (VN_IS(lhsp, Sel)) { bitselp = VN_CAST(lhsp, Sel); arrayselp = VN_CAST(bitselp->fromp(), ArraySel); @@ -202,12 +202,12 @@ private: UASSERT_OBJ(arrayselp, nodep, "No arraysel under bitsel?"); UASSERT_OBJ(!VN_IS(arrayselp->dtypep()->skipRefp(), UnpackArrayDType), nodep, "ArraySel with unpacked arrays should have been removed in V3Slice"); - UINFO(4,"AssignDlyArray: "< dimvalp; // Assignment value for each dimension of assignment AstNode* dimselp = arrayselp; - for (; VN_IS(dimselp, ArraySel); dimselp=VN_CAST(dimselp, ArraySel)->fromp()) { + for (; VN_IS(dimselp, ArraySel); dimselp = VN_CAST(dimselp, ArraySel)->fromp()) { AstNode* valp = VN_CAST(dimselp, ArraySel)->bitp()->unlinkFrBack(); dimvalp.push_front(valp); } @@ -219,19 +219,17 @@ private: int modVecNum = m_scopeVecMap[varrefp->varScopep()]++; // std::deque dimreadps; // Read value for each dimension of assignment - for (unsigned dimension=0; dimensionshortName()+"__v"+cvtToStr(modVecNum)); - AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), - bitvarname, dimp->width(), NULL); - AstAssign* bitassignp - = new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), bitvscp, true), - dimp); + string bitvarname = (string("__Vdlyvdim") + cvtToStr(dimension) + "__" + + oldvarp->shortName() + "__v" + cvtToStr(modVecNum)); + AstVarScope* bitvscp + = createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), NULL); + AstAssign* bitassignp = new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), dimp); nodep->addNextHere(bitassignp); dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false)); } @@ -241,15 +239,16 @@ private: AstNode* bitreadp = NULL; // Code to read Vdlyvlsb if (bitselp) { AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack(); - if (VN_IS(bitselp->fromp(), Const)) { // vlsb = constant, can just push constant into where we use it + if (VN_IS(bitselp->fromp(), Const)) { + // vlsb = constant, can just push constant into where we use it bitreadp = lsbvaluep; } else { - string bitvarname = (string("__Vdlyvlsb__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum)); - AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), - bitvarname, lsbvaluep->width(), NULL); - AstAssign* bitassignp = new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), bitvscp, true), - lsbvaluep); + string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v" + + cvtToStr(modVecNum)); + AstVarScope* bitvscp + = createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), NULL); + AstAssign* bitassignp = new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), lsbvaluep); nodep->addNextHere(bitassignp); bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false); } @@ -257,11 +256,14 @@ private: // //=== Value: __Vdlyvval__ AstNode* valreadp; // Code to read Vdlyvval - if (VN_IS(nodep->rhsp(), Const)) { // vval = constant, can just push constant into where we use it + if (VN_IS(nodep->rhsp(), Const)) { + // vval = constant, can just push constant into where we use it valreadp = nodep->rhsp()->unlinkFrBack(); } else { - string valvarname = (string("__Vdlyvval__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum)); - AstVarScope* valvscp = createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep()); + string valvarname + = (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum)); + AstVarScope* valvscp + = createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep()); newlhsp = new AstVarRef(nodep->fileline(), valvscp, true); valreadp = new AstVarRef(nodep->fileline(), valvscp, false); } @@ -278,14 +280,14 @@ private: setvscp = VN_CAST(nodep->user3p(), VarScope); ++m_statSharedSet; } else { // Create new one - string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum)); + string setvarname + = (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum)); setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, NULL); setinitp = new AstAssignPre(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, true), new AstConst(nodep->fileline(), 0)); AstAssign* setassignp - = new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), setvscp, true), + = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, true), new AstConst(nodep->fileline(), AstConst::LogicTrue())); nodep->addNextHere(setassignp); } @@ -299,7 +301,7 @@ private: // in correctly ordered code - the last assignment must be last. // It also has the nice side effect of assisting cache locality. AstNode* selectsp = varrefp; - for (int dimension=int(dimreadps.size())-1; dimension>=0; --dimension) { + for (int dimension = int(dimreadps.size()) - 1; dimension >= 0; --dimension) { selectsp = new AstArraySel(nodep->fileline(), selectsp, dimreadps[dimension]); } if (bitselp) { @@ -307,16 +309,16 @@ private: bitselp->widthp()->cloneTree(false)); } // Build "IF (changeit) ... - UINFO(9," For "<varScopep()->user4p(), AlwaysPost); if (finalp) { AstActive* oldactivep = VN_CAST(finalp->user2p(), Active); checkActivePost(varrefp, oldactivep); if (setinitp) oldactivep->addStmtsp(setinitp); } else { // first time we've dealt with this memory - finalp = new AstAlwaysPost(nodep->fileline(), NULL/*sens*/, NULL/*body*/); - UINFO(9," Created "<fileline(), NULL /*sens*/, NULL /*body*/); + UINFO(9, " Created " << finalp << endl); AstActive* newactp = createActivePost(varrefp); newactp->addStmtsp(finalp); varrefp->varScopep()->user4p(finalp); @@ -332,9 +334,8 @@ private: "Delayed assignment misoptimized; prev var found w/o associated IF"); } else { postLogicp = new AstIf(nodep->fileline(), - new AstVarRef(nodep->fileline(), setvscp, false), - NULL, NULL); - UINFO(9," Created "<fileline(), setvscp, false), NULL, NULL); + UINFO(9, " Created " << postLogicp << endl); finalp->addBodysp(postLogicp); finalp->user3p(setvscp); // Remember IF's vset variable finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it @@ -345,12 +346,12 @@ private: // VISITORS virtual void visit(AstNetlist* nodep) VL_OVERRIDE { - //VV***** We reset all userp() on the netlist + // VV***** We reset all userp() on the netlist m_modVarMap.clear(); iterateChildren(nodep); } virtual void visit(AstScope* nodep) VL_OVERRIDE { - UINFO(4," MOD "<hasInitial(); - AstNode::user3ClearTree(); // Two sets to same variable in different actives must use different vars. + AstNode::user3ClearTree(); // Two sets to same variable in different + // actives must use different vars. iterateChildren(nodep); m_inInitial = oldinit; } virtual void visit(AstAssignDly* nodep) VL_OVERRIDE { m_inDly = true; - m_nextDlyp = VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL. - if (m_cfuncp) nodep->v3error("Unsupported: Delayed assignment inside public function/task"); + m_nextDlyp + = VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL. + if (m_cfuncp) { + nodep->v3error("Unsupported: Delayed assignment inside public function/task"); + } if (VN_IS(nodep->lhsp(), ArraySel) || (VN_IS(nodep->lhsp(), Sel) && VN_IS(VN_CAST(nodep->lhsp(), Sel)->fromp(), ArraySel))) { AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNode* newlhsp = createDlyArray(nodep, lhsp); - if (m_inLoop) nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for loops (non-delayed is ok - see docs)"); + if (m_inLoop) { + nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for " + "loops (non-delayed is ok - see docs)"); + } if (newlhsp) { nodep->lhsp(newlhsp); } else { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } VL_DO_DANGLING(lhsp->deleteTree(), lhsp); - } - else { + } else { iterateChildren(nodep); } m_inDly = false; @@ -394,11 +401,12 @@ private: virtual void visit(AstVarRef* nodep) VL_OVERRIDE { if (!nodep->user2Inc()) { // Not done yet if (m_inDly && nodep->lvalue()) { - UINFO(4,"AssignDlyVar: "<varScopep(), VU_DLY); UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block"); if (!m_activep->hasClocked()) { - nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active"); + nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should " + "have converted in V3Active"); } AstVarScope* oldvscp = nodep->varScopep(); UASSERT_OBJ(oldvscp, nodep, "Var didn't get varscoped in V3Scope.cpp"); @@ -408,16 +416,14 @@ private: checkActivePost(nodep, oldactivep); } if (!dlyvscp) { // First use of this delayed variable - string newvarname = (string("__Vdly__")+nodep->varp()->shortName()); + string newvarname = (string("__Vdly__") + nodep->varp()->shortName()); dlyvscp = createVarSc(oldvscp, newvarname, 0, NULL); - AstNodeAssign* prep - = new AstAssignPre(nodep->fileline(), - new AstVarRef(nodep->fileline(), dlyvscp, true), - new AstVarRef(nodep->fileline(), oldvscp, false)); - AstNodeAssign* postp - = new AstAssignPost(nodep->fileline(), - new AstVarRef(nodep->fileline(), oldvscp, true), - new AstVarRef(nodep->fileline(), dlyvscp, false)); + AstNodeAssign* prep = new AstAssignPre( + nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true), + new AstVarRef(nodep->fileline(), oldvscp, false)); + AstNodeAssign* postp = new AstAssignPost( + nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true), + new AstVarRef(nodep->fileline(), dlyvscp, false)); postp->lhsp()->user2(true); // Don't detect this assignment oldvscp->user1p(dlyvscp); // So we can find it later // Make new ACTIVE with identical sensitivity tree @@ -428,12 +434,12 @@ private: } AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true); newrefp->user2(true); // No reason to do it again - nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - } - else if (!m_inDly && nodep->lvalue()) { - //UINFO(9,"NBA "<replaceWith(newrefp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else if (!m_inDly && nodep->lvalue()) { + // UINFO(9, "NBA " << nodep << endl); if (!m_inInitial) { - UINFO(4,"AssignNDlyVar: "<varScopep(), VU_NONDLY); } } @@ -441,7 +447,8 @@ private: } virtual void visit(AstNodeFor* nodep) VL_OVERRIDE { - nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin"); + nodep->v3fatalSrc( + "For statements should have been converted to while statements in V3Begin"); } virtual void visit(AstWhile* nodep) VL_OVERRIDE { bool oldloop = m_inLoop; @@ -474,9 +481,7 @@ public: // Delayed class functions void V3Delayed::delayedAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index 9565a4a7a..ae23d3cd2 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -51,7 +51,7 @@ private: void createDeepTemp(AstNode* nodep) { UINFO(6, " Deep " << nodep << endl); - // if (debug()>=9) nodep->dumpTree(cout, "deep:"); + // if (debug() >= 9) nodep->dumpTree(cout, "deep:"); string newvarname = (string("__Vdeeptemp") + cvtToStr(m_modp->varNumGetInc())); AstVar* varp = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 3b0beaa15..4f4966a60 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -258,7 +258,7 @@ private: nodep->varScopep(NULL); } virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { - // UINFO(9," "< VarVec; typedef std::map VarSortMap; // Map size class to VarVec - bool m_suppressSemi; - AstVarRef* m_wideTempRefp; // Variable that _WW macros should be setting - VarVec m_ctorVarsVec; // All variables in constructor order - int m_labelNum; // Next label number - int m_splitSize; // # of cfunc nodes placed into output file - int m_splitFilenum; // File number being created, 0 = primary + bool m_suppressSemi; + AstVarRef* m_wideTempRefp; // Variable that _WW macros should be setting + VarVec m_ctorVarsVec; // All variables in constructor order + int m_labelNum; // Next label number + int m_splitSize; // # of cfunc nodes placed into output file + int m_splitFilenum; // File number being created, 0 = primary public: // METHODS @@ -57,27 +57,37 @@ public: // ACCESSORS int splitFilenum() const { return m_splitFilenum; } - int splitFilenumInc() { m_splitSize = 0; return ++m_splitFilenum; } + int splitFilenumInc() { + m_splitSize = 0; + return ++m_splitFilenum; + } int splitSize() const { return m_splitSize; } void splitSizeInc(int count) { m_splitSize += count; } void splitSizeInc(AstNode* nodep) { splitSizeInc(EmitCBaseCounterVisitor(nodep).count()); } - bool splitNeeded() { return (splitSize() && v3Global.opt.outputSplit() - && v3Global.opt.outputSplit() < splitSize()); } + bool splitNeeded() { + return (splitSize() && v3Global.opt.outputSplit() + && v3Global.opt.outputSplit() < splitSize()); + } // METHODS - void displayNode(AstNode* nodep, AstScopeName* scopenamep, - const string& vformat, AstNode* exprsp, bool isScan); + void displayNode(AstNode* nodep, AstScopeName* scopenamep, const string& vformat, + AstNode* exprsp, bool isScan); void displayEmit(AstNode* nodep, bool isScan); - void displayArg(AstNode* dispp, AstNode** elistp, bool isScan, - const string& vfmt, char fmtLetter); + void displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const string& vfmt, + char fmtLetter); void emitVarDecl(const AstVar* nodep, const string& prefixIfImp); - typedef enum {EVL_CLASS_IO, EVL_CLASS_SIG, EVL_CLASS_TEMP, EVL_CLASS_PAR, EVL_CLASS_ALL, - EVL_FUNC_ALL} EisWhich; + typedef enum { + EVL_CLASS_IO, + EVL_CLASS_SIG, + EVL_CLASS_TEMP, + EVL_CLASS_PAR, + EVL_CLASS_ALL, + EVL_FUNC_ALL + } EisWhich; void emitVarList(AstNode* firstp, EisWhich which, const string& prefixIfImp, string& sectionr); static void emitVarSort(const VarSortMap& vmap, VarVec* sortedp); - void emitSortedVarList(const VarVec& anons, - const VarVec& nonanons, const string& prefixIfImp); + void emitSortedVarList(const VarVec& anons, const VarVec& nonanons, const string& prefixIfImp); void emitVarCtors(bool* firstp); void emitCtorSep(bool* firstp); bool emitSimpleOk(AstNodeMath* nodep); @@ -87,34 +97,33 @@ public: } void emitScIQW(AstVar* nodep) { UASSERT_OBJ(nodep->isSc(), nodep, "emitting SystemC operator on non-SC variable"); + // clang-format off puts(nodep->isScBigUint() ? "SB" : nodep->isScUint() ? "SU" : nodep->isScBv() ? "SW" : (nodep->isScQuad() ? "SQ" : "SI")); + // clang-format on } - void emitOpName(AstNode* nodep, const string& format, - AstNode* lhsp, AstNode* rhsp, AstNode* thsp); + void emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, AstNode* rhsp, + AstNode* thsp); void emitDeclArrayBrackets(const AstVar* nodep) { // This isn't very robust and may need cleanup for other data types for (const AstUnpackArrayDType* arrayp - = VN_CAST_CONST(nodep->dtypeSkipRefp(), UnpackArrayDType); - arrayp; - arrayp = VN_CAST_CONST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) { - puts("["+cvtToStr(arrayp->elementsConst())+"]"); + = VN_CAST_CONST(nodep->dtypeSkipRefp(), UnpackArrayDType); + arrayp; arrayp = VN_CAST_CONST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) { + puts("[" + cvtToStr(arrayp->elementsConst()) + "]"); } } void emitVarCmtChg(const AstVar* varp, string* curVarCmtp) { string newVarCmt = varp->mtasksString(); if (*curVarCmtp != newVarCmt) { *curVarCmtp = newVarCmt; - if (v3Global.opt.threads()) { - puts("// Begin mtask footprint "+*curVarCmtp+"\n"); - } + if (v3Global.opt.threads()) puts("// Begin mtask footprint " + *curVarCmtp + "\n"); } } void emitTypedefs(AstNode* firstp) { bool first = true; - for (AstNode* loopp=firstp; loopp; loopp = loopp->nextp()) { + for (AstNode* loopp = firstp; loopp; loopp = loopp->nextp()) { if (const AstTypedef* nodep = VN_CAST(loopp, Typedef)) { if (nodep->attrPublic()) { if (first) { @@ -126,12 +135,13 @@ public: } if (const AstEnumDType* adtypep = VN_CAST(nodep->dtypep()->skipRefToEnump(), EnumDType)) { - if (adtypep->width()>64) { - putsDecoration("// enum "+nodep->nameProtect()+" // Ignored: Too wide for C++\n"); + if (adtypep->width() > 64) { + putsDecoration("// enum " + nodep->nameProtect() + + " // Ignored: Too wide for C++\n"); } else { - puts("enum "+nodep->name()+" {\n"); - for (AstEnumItem* itemp = adtypep->itemsp(); - itemp; itemp = VN_CAST(itemp->nextp(), EnumItem)) { + puts("enum " + nodep->name() + " {\n"); + for (AstEnumItem* itemp = adtypep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), EnumItem)) { puts(itemp->nameProtect()); puts(" = "); iterateAndNextNull(itemp->valuep()); @@ -157,8 +167,7 @@ public: for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstCFunc* funcp = VN_CAST(nodep, CFunc)) { - if (!funcp->skipDecl() - && funcp->isMethod() == methodFuncs + if (!funcp->skipDecl() && funcp->isMethod() == methodFuncs && !funcp->dpiImport()) { // DPI is prototyped in __Dpi.h funcsp.push_back(funcp); } @@ -208,9 +217,10 @@ public: // VISITORS virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { - bool paren = true; bool decind = false; + bool paren = true; + bool decind = false; if (AstSel* selp = VN_CAST(nodep->lhsp(), Sel)) { - if (selp->widthMin()==1) { + if (selp->widthMin() == 1) { putbs("VL_ASSIGNBIT_"); emitIQW(selp->fromp()); if (nodep->rhsp()->isAllOnesV()) { @@ -218,18 +228,22 @@ public: } else { puts("I("); } - puts(cvtToStr(nodep->widthMin())+","); - iterateAndNextNull(selp->lsbp()); puts(", "); - iterateAndNextNull(selp->fromp()); puts(", "); + puts(cvtToStr(nodep->widthMin()) + ","); + iterateAndNextNull(selp->lsbp()); + puts(", "); + iterateAndNextNull(selp->fromp()); + puts(", "); } else { putbs("VL_ASSIGNSEL_"); emitIQW(selp->fromp()); puts("II"); emitIQW(nodep->rhsp()); puts("("); - puts(cvtToStr(nodep->widthMin())+","); - iterateAndNextNull(selp->lsbp()); puts(", "); - iterateAndNextNull(selp->fromp()); puts(", "); + puts(cvtToStr(nodep->widthMin()) + ","); + iterateAndNextNull(selp->lsbp()); + puts(", "); + iterateAndNextNull(selp->fromp()); + puts(", "); } } else if (AstGetcRefN* selp = VN_CAST(nodep->lhsp(), GetcRefN)) { iterateAndNextNull(selp->lhsp()); @@ -244,34 +258,37 @@ public: emitScIQW(varp); emitIQW(nodep); puts("("); - puts(cvtToStr(nodep->widthMin())+","); - iterateAndNextNull(nodep->lhsp()); puts(", "); + puts(cvtToStr(nodep->widthMin()) + ","); + iterateAndNextNull(nodep->lhsp()); + puts(", "); } else if (AstVar* varp = AstVar::scVarRecurse(nodep->rhsp())) { putbs("VL_ASSIGN_"); // Get a systemC variable emitIQW(nodep); emitScIQW(varp); puts("("); - puts(cvtToStr(nodep->widthMin())+","); - iterateAndNextNull(nodep->lhsp()); puts(", "); - } else if (nodep->isWide() - && VN_IS(nodep->lhsp(), VarRef) - && !VN_IS(nodep->rhsp(), CMath) - && !VN_IS(nodep->rhsp(), CMethodHard) - && !VN_IS(nodep->rhsp(), VarRef) - && !VN_IS(nodep->rhsp(), AssocSel) + puts(cvtToStr(nodep->widthMin()) + ","); + iterateAndNextNull(nodep->lhsp()); + puts(", "); + } else if (nodep->isWide() && VN_IS(nodep->lhsp(), VarRef) // + && !VN_IS(nodep->rhsp(), CMath) // + && !VN_IS(nodep->rhsp(), CMethodHard) // + && !VN_IS(nodep->rhsp(), VarRef) // + && !VN_IS(nodep->rhsp(), AssocSel) // && !VN_IS(nodep->rhsp(), ArraySel)) { // Wide functions assign into the array directly, don't need separate assign statement m_wideTempRefp = VN_CAST(nodep->lhsp(), VarRef); paren = false; } else if (nodep->isWide()) { putbs("VL_ASSIGN_W("); - puts(cvtToStr(nodep->widthMin())+","); - iterateAndNextNull(nodep->lhsp()); puts(", "); + puts(cvtToStr(nodep->widthMin()) + ","); + iterateAndNextNull(nodep->lhsp()); + puts(", "); } else { paren = false; iterateAndNextNull(nodep->lhsp()); puts(" "); - ofp()->blockInc(); decind = true; + ofp()->blockInc(); + decind = true; if (!VN_IS(nodep->rhsp(), Const)) ofp()->putBreak(); puts("= "); } @@ -280,8 +297,7 @@ public: if (decind) ofp()->blockDec(); if (!m_suppressSemi) puts(";\n"); } - virtual void visit(AstAlwaysPublic*) VL_OVERRIDE { - } + virtual void visit(AstAlwaysPublic*) VL_OVERRIDE {} virtual void visit(AstAssocSel* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->fromp()); putbs(".at("); @@ -315,7 +331,7 @@ public: puts("("); puts(nodep->argTypes()); bool comma = (nodep->argTypes() != ""); - for (AstNode* subnodep=nodep->argsp(); subnodep; subnodep = subnodep->nextp()) { + for (AstNode* subnodep = nodep->argsp(); subnodep; subnodep = subnodep->nextp()) { if (comma) puts(", "); iterate(subnodep); comma = true; @@ -341,12 +357,11 @@ public: puts(")"); // Some are statements some are math. if (nodep->isStatement()) puts(";\n"); - UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), - nodep, "Statement of non-void data type"); + UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep, + "Statement of non-void data type"); } virtual void visit(AstIntfRef* nodep) VL_OVERRIDE { - putsQuoted(VIdProtect::protectWordsIf(AstNode::vcdName(nodep->name()), - nodep->protect())); + putsQuoted(VIdProtect::protectWordsIf(AstNode::vcdName(nodep->name()), nodep->protect())); } virtual void visit(AstNodeCase* nodep) VL_OVERRIDE { // In V3Case... @@ -355,32 +370,39 @@ public: virtual void visit(AstComment* nodep) VL_OVERRIDE { string at; if (nodep->showAt()) { - at = " at "+nodep->fileline()->ascii(); + at = " at " + nodep->fileline()->ascii(); // If protecting, passthru less information about the design if (!v3Global.opt.protectIds()) return; } if (!(nodep->protect() && v3Global.opt.protectIds())) { - putsDecoration(string("// ")+nodep->name()+at+"\n"); + putsDecoration(string("// ") + nodep->name() + at + "\n"); } iterateChildren(nodep); } virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE { puts("__vlCoverInsert("); // As Declared in emitCoverageDecl puts("&(vlSymsp->__Vcoverage["); - puts(cvtToStr(nodep->dataDeclThisp()->binNum())); puts("])"); + puts(cvtToStr(nodep->dataDeclThisp()->binNum())); + puts("])"); // If this isn't the first instantiation of this module under this // design, don't really count the bucket, and rely on verilator_cov to // aggregate counts. This is because Verilator combines all // hierarchies itself, and if verilator_cov also did it, you'd end up // with (number-of-instant) times too many counts in this bin. puts(", first"); // Enable, passed from __Vconfigure parameter - puts(", "); putsQuoted(protect(nodep->fileline()->filename())); - puts(", "); puts(cvtToStr(nodep->fileline()->lineno())); - puts(", "); puts(cvtToStr(nodep->column())); - puts(", "); putsQuoted((!nodep->hier().empty() ? "." : "") - +protectWordsIf(nodep->hier(), nodep->protect())); - puts(", "); putsQuoted(protectWordsIf(nodep->page(), nodep->protect())); - puts(", "); putsQuoted(protectWordsIf(nodep->comment(), nodep->protect())); + puts(", "); + putsQuoted(protect(nodep->fileline()->filename())); + puts(", "); + puts(cvtToStr(nodep->fileline()->lineno())); + puts(", "); + puts(cvtToStr(nodep->column())); + puts(", "); + putsQuoted((!nodep->hier().empty() ? "." : "") + + protectWordsIf(nodep->hier(), nodep->protect())); + puts(", "); + putsQuoted(protectWordsIf(nodep->page(), nodep->protect())); + puts(", "); + putsQuoted(protectWordsIf(nodep->comment(), nodep->protect())); puts(");\n"); } virtual void visit(AstCoverInc* nodep) VL_OVERRIDE { @@ -449,7 +471,7 @@ public: if (!nodep->dpiExport()) { // this is where the DPI import context scope is set string scope = nodep->scopeDpiName(); - putbs("(&(vlSymsp->"+protect("__Vscope_"+scope)+"))"); + putbs("(&(vlSymsp->" + protect("__Vscope_" + scope) + "))"); } } virtual void visit(AstSFormat* nodep) VL_OVERRIDE { @@ -496,8 +518,10 @@ public: void checkMaxWords(AstNode* nodep) { if (nodep->widthWords() > VL_TO_STRING_MAX_WORDS) { - nodep->v3error("String of "<width() - <<" bits exceeds hardcoded limit VL_TO_STRING_MAX_WORDS in verilatedos.h"); + nodep->v3error( + "String of " + << nodep->width() + << " bits exceeds hardcoded limit VL_TO_STRING_MAX_WORDS in verilatedos.h"); } } virtual void visit(AstFOpen* nodep) VL_OVERRIDE { @@ -505,7 +529,8 @@ public: puts(" = VL_FOPEN_"); emitIQW(nodep->filenamep()); emitIQW(nodep->modep()); - if (nodep->modep()->width()>4*8) nodep->modep()->v3error("$fopen mode should be <= 4 characters"); + if (nodep->modep()->width() > 4 * 8) + nodep->modep()->v3error("$fopen mode should be <= 4 characters"); puts("("); if (nodep->filenamep()->isWide()) { puts(cvtToStr(nodep->filenamep()->widthWords())); @@ -527,19 +552,18 @@ public: uint32_t array_lsb = 0; { const AstVarRef* varrefp = VN_CAST(nodep->memp(), VarRef); - if (!varrefp) { nodep->v3error(nodep->verilogKwd() << " loading non-variable"); } - else if (VN_IS(varrefp->varp()->dtypeSkipRefp(), AssocArrayDType)) { + if (!varrefp) { + nodep->v3error(nodep->verilogKwd() << " loading non-variable"); + } else if (VN_IS(varrefp->varp()->dtypeSkipRefp(), AssocArrayDType)) { // nodep->memp() below will when verilated code is compiled create a C++ template - } - else if (const AstUnpackArrayDType* adtypep - = VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType)) { + } else if (const AstUnpackArrayDType* adtypep + = VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType)) { putbs(", "); puts(cvtToStr(varrefp->varp()->dtypep()->arrayUnpackedElements())); array_lsb = adtypep->lsb(); putbs(", "); puts(cvtToStr(array_lsb)); - } - else { + } else { nodep->v3error(nodep->verilogKwd() << " loading other than unpacked/associative-array variable"); } @@ -549,10 +573,17 @@ public: putbs(", "); iterateAndNextNull(nodep->memp()); putbs(", "); - if (nodep->lsbp()) { iterateAndNextNull(nodep->lsbp()); } - else puts(cvtToStr(array_lsb)); + if (nodep->lsbp()) { + iterateAndNextNull(nodep->lsbp()); + } else { + puts(cvtToStr(array_lsb)); + } putbs(", "); - if (nodep->msbp()) { iterateAndNextNull(nodep->msbp()); } else puts("~VL_ULL(0)"); + if (nodep->msbp()) { + iterateAndNextNull(nodep->msbp()); + } else { + puts("~VL_ULL(0)"); + } puts(");\n"); } virtual void visit(AstFClose* nodep) VL_OVERRIDE { @@ -601,15 +632,15 @@ public: uint32_t array_size = 0; { const AstVarRef* varrefp = VN_CAST(nodep->memp(), VarRef); - if (!varrefp) { nodep->v3error(nodep->verilogKwd() << " loading non-variable"); } - else if (VN_CAST(varrefp->varp()->dtypeSkipRefp(), BasicDType)) { } - else if (const AstUnpackArrayDType* adtypep - = VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType)) { + if (!varrefp) { + nodep->v3error(nodep->verilogKwd() << " loading non-variable"); + } else if (VN_CAST(varrefp->varp()->dtypeSkipRefp(), BasicDType)) { + } else if (const AstUnpackArrayDType* adtypep + = VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType)) { memory = true; array_lsb = adtypep->lsb(); array_size = adtypep->elementsConst(); - } - else { + } else { nodep->v3error(nodep->verilogKwd() << " loading other than unpacked-array variable"); } @@ -624,11 +655,17 @@ public: putbs(", "); iterateAndNextNull(nodep->filep()); putbs(", "); - if (nodep->startp()) iterateAndNextNull(nodep->startp()); - else puts(cvtToStr(array_lsb)); + if (nodep->startp()) { + iterateAndNextNull(nodep->startp()); + } else { + puts(cvtToStr(array_lsb)); + } putbs(", "); - if (nodep->countp()) iterateAndNextNull(nodep->countp()); - else puts(cvtToStr(array_size)); + if (nodep->countp()) { + iterateAndNextNull(nodep->countp()); + } else { + puts(cvtToStr(array_size)); + } puts(");\n"); } virtual void visit(AstSysFuncAsTask* nodep) VL_OVERRIDE { @@ -661,14 +698,14 @@ public: puts(")"); } virtual void visit(AstJumpGo* nodep) VL_OVERRIDE { - puts("goto __Vlabel"+cvtToStr(nodep->labelp()->labelNum())+";\n"); + puts("goto __Vlabel" + cvtToStr(nodep->labelp()->labelNum()) + ";\n"); } virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE { nodep->labelNum(++m_labelNum); puts("{\n"); // Make it visually obvious label jumps outside these iterateAndNextNull(nodep->stmtsp()); puts("}\n"); - puts("__Vlabel"+cvtToStr(nodep->labelNum())+": ;\n"); + puts("__Vlabel" + cvtToStr(nodep->labelNum()) + ": ;\n"); } virtual void visit(AstWhile* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->precondsp()); @@ -683,7 +720,8 @@ public: virtual void visit(AstNodeIf* nodep) VL_OVERRIDE { puts("if ("); if (!nodep->branchPred().unknown()) { - puts(nodep->branchPred().ascii()); puts("("); + puts(nodep->branchPred().ascii()); + puts("("); } iterateAndNextNull(nodep->condp()); if (!nodep->branchPred().unknown()) puts(")"); @@ -733,13 +771,13 @@ public: iterateAndNextNull(nodep->bodysp()); } virtual void visit(AstUCStmt* nodep) VL_OVERRIDE { - putsDecoration(ifNoProtect("// $c statement at "+nodep->fileline()->ascii()+"\n")); + putsDecoration(ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n")); iterateAndNextNull(nodep->bodysp()); puts("\n"); } virtual void visit(AstUCFunc* nodep) VL_OVERRIDE { puts("\n"); - putsDecoration(ifNoProtect("// $c function at "+nodep->fileline()->ascii()+"\n")); + putsDecoration(ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n")); iterateAndNextNull(nodep->bodysp()); puts("\n"); } @@ -750,17 +788,24 @@ public: } virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE { if (emitSimpleOk(nodep)) { - putbs("("); puts(nodep->emitSimpleOperator()); puts(" "); - iterateAndNextNull(nodep->lhsp()); puts(")"); + putbs("("); + puts(nodep->emitSimpleOperator()); + puts(" "); + iterateAndNextNull(nodep->lhsp()); + puts(")"); } else { emitOpName(nodep, nodep->emitC(), nodep->lhsp(), NULL, NULL); } } virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE { if (emitSimpleOk(nodep)) { - putbs("("); iterateAndNextNull(nodep->lhsp()); - puts(" "); putbs(nodep->emitSimpleOperator()); puts(" "); - iterateAndNextNull(nodep->rhsp()); puts(")"); + putbs("("); + iterateAndNextNull(nodep->lhsp()); + puts(" "); + putbs(nodep->emitSimpleOperator()); + puts(" "); + iterateAndNextNull(nodep->rhsp()); + puts(")"); } else { emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), NULL); } @@ -782,36 +827,41 @@ public: } virtual void visit(AstMulS* nodep) VL_OVERRIDE { if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3error("Unsupported: Signed multiply of "<width() - <<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + nodep->v3error("Unsupported: Signed multiply of " + << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } visit(VN_CAST(nodep, NodeBiop)); } virtual void visit(AstPow* nodep) VL_OVERRIDE { if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3error("Unsupported: Power of "<width() - <<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + nodep->v3error("Unsupported: Power of " + << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } visit(VN_CAST(nodep, NodeBiop)); } virtual void visit(AstPowSS* nodep) VL_OVERRIDE { if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3error("Unsupported: Power of "<width() - <<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + nodep->v3error("Unsupported: Power of " + << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } visit(VN_CAST(nodep, NodeBiop)); } virtual void visit(AstPowSU* nodep) VL_OVERRIDE { if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3error("Unsupported: Power of "<width() - <<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + nodep->v3error("Unsupported: Power of " + << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } visit(VN_CAST(nodep, NodeBiop)); } virtual void visit(AstPowUS* nodep) VL_OVERRIDE { if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3error("Unsupported: Power of "<width() - <<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + nodep->v3error("Unsupported: Power of " + << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } visit(VN_CAST(nodep, NodeBiop)); } @@ -831,9 +881,12 @@ public: emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->expr1p(), nodep->expr2p()); } else { putbs("("); - iterateAndNextNull(nodep->condp()); putbs(" ? "); - iterateAndNextNull(nodep->expr1p()); putbs(" : "); - iterateAndNextNull(nodep->expr2p()); puts(")"); + iterateAndNextNull(nodep->condp()); + putbs(" ? "); + iterateAndNextNull(nodep->expr1p()); + putbs(" : "); + iterateAndNextNull(nodep->expr2p()); + puts(")"); } } virtual void visit(AstMemberSel* nodep) VL_OVERRIDE { @@ -870,17 +923,20 @@ public: virtual void visit(AstReplicate* nodep) VL_OVERRIDE { if (nodep->lhsp()->widthMin() == 1 && !nodep->isWide()) { UASSERT_OBJ((static_cast(VN_CAST(nodep->rhsp(), Const)->toUInt()) - * nodep->lhsp()->widthMin()) == nodep->widthMin(), + * nodep->lhsp()->widthMin()) + == nodep->widthMin(), nodep, "Replicate non-constant or width miscomputed"); puts("VL_REPLICATE_"); emitIQW(nodep); puts("OI("); puts(cvtToStr(nodep->widthMin())); - if (nodep->lhsp()) { puts(","+cvtToStr(nodep->lhsp()->widthMin())); } - if (nodep->rhsp()) { puts(","+cvtToStr(nodep->rhsp()->widthMin())); } + if (nodep->lhsp()) { puts("," + cvtToStr(nodep->lhsp()->widthMin())); } + if (nodep->rhsp()) { puts("," + cvtToStr(nodep->rhsp()->widthMin())); } puts(","); - iterateAndNextNull(nodep->lhsp()); puts(", "); - iterateAndNextNull(nodep->rhsp()); puts(")"); + iterateAndNextNull(nodep->lhsp()); + puts(", "); + iterateAndNextNull(nodep->rhsp()); + puts(")"); } else { emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), NULL); } @@ -896,17 +952,18 @@ public: emitIQW(nodep->lhsp()); puts("I("); puts(cvtToStr(nodep->widthMin())); - puts(","+cvtToStr(nodep->lhsp()->widthMin())); - puts(","+cvtToStr(nodep->rhsp()->widthMin())); + puts("," + cvtToStr(nodep->lhsp()->widthMin())); + puts("," + cvtToStr(nodep->rhsp()->widthMin())); puts(","); - iterateAndNextNull(nodep->lhsp()); puts(", "); + iterateAndNextNull(nodep->lhsp()); + puts(", "); uint32_t rd_log2 = V3Number::log2b(VN_CAST(nodep->rhsp(), Const)->toUInt()); - puts(cvtToStr(rd_log2)+")"); + puts(cvtToStr(rd_log2) + ")"); return; } } - emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)", - nodep->lhsp(), nodep->rhsp(), NULL); + emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)", nodep->lhsp(), + nodep->rhsp(), NULL); } // Terminals virtual void visit(AstVarRef* nodep) VL_OVERRIDE { @@ -923,7 +980,8 @@ public: emitIQW(nodep); puts("("); if (nodep->isWide()) { - puts(cvtToStr(nodep->widthWords())); // Note argument width, not node width (which is always 32) + // Note argument width, not node width (which is always 32) + puts(cvtToStr(nodep->widthWords())); puts(", "); } iterateAndNextNull(nodep); @@ -943,11 +1001,11 @@ public: int chunks = 0; if (upWidth > EMITC_NUM_CONSTW * VL_EDATASIZE) { // Output e.g. 8 words in groups of e.g. 8 - chunks = (upWidth-1) / (EMITC_NUM_CONSTW * VL_EDATASIZE); + chunks = (upWidth - 1) / (EMITC_NUM_CONSTW * VL_EDATASIZE); upWidth %= (EMITC_NUM_CONSTW * VL_EDATASIZE); if (upWidth == 0) upWidth = (EMITC_NUM_CONSTW * VL_EDATASIZE); } - { // Upper e.g. 8 words + { // Upper e.g. 8 words if (chunks) { putbs("VL_CONSTHI_W_"); puts(cvtToStr(VL_WORDS_I(upWidth))); @@ -970,11 +1028,11 @@ public: } else { iterateAndNextNull(assigntop); } - for (int word=VL_WORDS_I(upWidth)-1; word>=0; word--) { + for (int word = VL_WORDS_I(upWidth) - 1; word >= 0; word--) { // Only 32 bits - llx + long long here just to appease CPP format warning ofp()->printf(",0x%08" VL_PRI64 "x", - static_cast(nodep->num().edataWord - (word+chunks * EMITC_NUM_CONSTW))); + static_cast( + nodep->num().edataWord(word + chunks * EMITC_NUM_CONSTW))); } puts(")"); } @@ -993,18 +1051,17 @@ public: } else { iterateAndNextNull(assigntop); } - for (int word=EMITC_NUM_CONSTW-1; word>=0; word--) { + for (int word = EMITC_NUM_CONSTW - 1; word >= 0; word--) { // Only 32 bits - llx + long long here just to appease CPP format warning ofp()->printf(",0x%08" VL_PRI64 "x", - static_cast(nodep->num().edataWord - (word+chunks * EMITC_NUM_CONSTW))); + static_cast( + nodep->num().edataWord(word + chunks * EMITC_NUM_CONSTW))); } puts(")"); } } else if (nodep->isDouble()) { if (int(nodep->num().toDouble()) == nodep->num().toDouble() - && nodep->num().toDouble() < 1000 - && nodep->num().toDouble() > -1000) { + && nodep->num().toDouble() < 1000 && nodep->num().toDouble() > -1000) { ofp()->printf("%3.1f", nodep->num().toDouble()); // Force decimal point } else { // Not %g as will not always put in decimal point, so not obvious to compiler @@ -1013,13 +1070,19 @@ public: } } else if (nodep->isQuad()) { vluint64_t num = nodep->toUQuad(); - if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "u)", num); - else ofp()->printf("VL_ULL(0x%" VL_PRI64 "x)", num); + if (num < 10) { + ofp()->printf("VL_ULL(%" VL_PRI64 "u)", num); + } else { + ofp()->printf("VL_ULL(0x%" VL_PRI64 "x)", num); + } } else { uint32_t num = nodep->toUInt(); // Only 32 bits - llx + long long here just to appease CPP format warning - if (num<10) puts(cvtToStr(num)); - else ofp()->printf("0x%" VL_PRI64 "x", static_cast(num)); + if (num < 10) { + puts(cvtToStr(num)); + } else { + ofp()->printf("0x%" VL_PRI64 "x", static_cast(num)); + } // If signed, we'll do our own functions // But must be here, or <= comparisons etc may end up signed puts("U"); @@ -1044,15 +1107,9 @@ public: } // Just iterate - virtual void visit(AstNetlist* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } - virtual void visit(AstTopScope* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } - virtual void visit(AstScope* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } + virtual void visit(AstNetlist* nodep) VL_OVERRIDE { iterateChildren(nodep); } + virtual void visit(AstTopScope* nodep) VL_OVERRIDE { iterateChildren(nodep); } + virtual void visit(AstScope* nodep) VL_OVERRIDE { iterateChildren(nodep); } // NOPs virtual void visit(AstTypedef*) VL_OVERRIDE {} virtual void visit(AstPragma*) VL_OVERRIDE {} @@ -1062,13 +1119,13 @@ public: virtual void visit(AstTraceDecl*) VL_OVERRIDE {} // Handled outside the Visit class virtual void visit(AstTraceInc*) VL_OVERRIDE {} // Handled outside the Visit class virtual void visit(AstCFile*) VL_OVERRIDE {} // Handled outside the Visit class - virtual void visit(AstCellInline*) VL_OVERRIDE {} // Handled outside the Visit class (EmitCSyms) + virtual void visit(AstCellInline*) VL_OVERRIDE {} // Handled outside visit (in EmitCSyms) virtual void visit(AstCUse*) VL_OVERRIDE {} // Handled outside the Visit class // Default virtual void visit(AstNode* nodep) VL_OVERRIDE { - puts(string("\n???? // ")+nodep->prettyTypeName()+"\n"); + puts(string("\n???? // ") + nodep->prettyTypeName() + "\n"); iterateChildren(nodep); - nodep->v3fatalSrc("Unknown node type reached emitter: "<prettyTypeName()); + nodep->v3fatalSrc("Unknown node type reached emitter: " << nodep->prettyTypeName()); } void init() { @@ -1080,10 +1137,8 @@ public: } public: - EmitCStmts() { - init(); - } - EmitCStmts(AstNode* nodep, V3OutCFile* ofp, bool trackText=false) { + EmitCStmts() { init(); } + EmitCStmts(AstNode* nodep, V3OutCFile* ofp, bool trackText = false) { init(); m_ofp = ofp; m_trackText = trackText; @@ -1104,16 +1159,14 @@ private: public: // CONSTRUCTORS explicit EmitVarTspSorter(const MTaskIdSet& mtaskIds) - : m_mtaskIds(mtaskIds), - m_serial(++m_serialNext) {} + : m_mtaskIds(mtaskIds) + , m_serial(++m_serialNext) {} virtual ~EmitVarTspSorter() {} // METHODS bool operator<(const TspStateBase& other) const { return operator<(dynamic_cast(other)); } - bool operator<(const EmitVarTspSorter& other) const { - return m_serial < other.m_serial; - } + bool operator<(const EmitVarTspSorter& other) const { return m_serial < other.m_serial; } const MTaskIdSet& mtaskIds() const { return m_mtaskIds; } virtual int cost(const TspStateBase* otherp) const { return cost(dynamic_cast(otherp)); @@ -1126,8 +1179,7 @@ public: // Returns the number of elements in set_a that don't appear in set_b static int diffs(const MTaskIdSet& set_a, const MTaskIdSet& set_b) { int diffs = 0; - for (MTaskIdSet::iterator it = set_a.begin(); - it != set_a.end(); ++it) { + for (MTaskIdSet::iterator it = set_a.begin(); it != set_a.end(); ++it) { if (set_b.find(*it) == set_b.end()) ++diffs; } return diffs; @@ -1141,10 +1193,10 @@ unsigned EmitVarTspSorter::m_serialNext = 0; class EmitCImp : EmitCStmts { // MEMBERS - AstNodeModule* m_modp; + AstNodeModule* m_modp; std::vector m_blkChangeDetVec; // All encountered changes in block - bool m_slow; // Creating __Slow file - bool m_fast; // Creating non __Slow file (or both) + bool m_slow; // Creating __Slow file + bool m_fast; // Creating non __Slow file (or both) //--------------------------------------- // METHODS @@ -1153,18 +1205,19 @@ class EmitCImp : EmitCStmts { // cppcheck-suppress variableScope static int s_addDoubleOr = 10; // Determined experimentally as best if (!changep->rhsp()) { - if (!gotOne) gotOne = true; - else puts(" | "); + if (!gotOne) { + gotOne = true; + } else { + puts(" | "); + } iterateAndNextNull(changep->lhsp()); - } - else { + } else { AstNode* lhsp = changep->lhsp(); AstNode* rhsp = changep->rhsp(); UASSERT_OBJ(VN_IS(lhsp, VarRef) || VN_IS(lhsp, ArraySel), changep, "Not ref?"); UASSERT_OBJ(VN_IS(rhsp, VarRef) || VN_IS(rhsp, ArraySel), changep, "Not ref?"); - for (int word=0; - word < (changep->lhsp()->isWide() ? changep->lhsp()->widthWords() : 1); - ++word) { + for (int word = 0; + word < (changep->lhsp()->isWide() ? changep->lhsp()->widthWords() : 1); ++word) { if (!gotOne) { gotOne = true; s_addDoubleOr = 10; @@ -1176,17 +1229,20 @@ class EmitCImp : EmitCStmts { puts(" | ("); } iterateAndNextNull(changep->lhsp()); - if (changep->lhsp()->isWide()) puts("["+cvtToStr(word)+"]"); - if (changep->lhsp()->isDouble()) puts(" != "); - else puts(" ^ "); + if (changep->lhsp()->isWide()) puts("[" + cvtToStr(word) + "]"); + if (changep->lhsp()->isDouble()) { + puts(" != "); + } else { + puts(" ^ "); + } iterateAndNextNull(changep->rhsp()); - if (changep->lhsp()->isWide()) puts("["+cvtToStr(word)+"]"); + if (changep->lhsp()->isWide()) puts("[" + cvtToStr(word) + "]"); puts(")"); } } } - V3OutCFile* newOutCFile(AstNodeModule* modp, bool slow, bool source, int filenum=0) { + V3OutCFile* newOutCFile(AstNodeModule* modp, bool slow, bool source, int filenum = 0) { string filenameNoExt = v3Global.opt.makeDir() + "/" + prefixNameProtect(modp); if (filenum) filenameNoExt += "__" + cvtToStr(filenum); filenameNoExt += (slow ? "__Slow" : ""); @@ -1197,32 +1253,34 @@ class EmitCImp : EmitCStmts { string filename = VL_DEV_NULL; newCFile(filename, slow, source); ofp = new V3OutCFile(filename); - } - else if (optSystemC()) { - string filename = filenameNoExt+(source?".cpp":".h"); + } else if (optSystemC()) { + string filename = filenameNoExt + (source ? ".cpp" : ".h"); newCFile(filename, slow, source); ofp = new V3OutScFile(filename); - } - else { - string filename = filenameNoExt+(source?".cpp":".h"); + } else { + string filename = filenameNoExt + (source ? ".cpp" : ".h"); newCFile(filename, slow, source); ofp = new V3OutCFile(filename); } ofp->putsHeader(); if (modp->isTop() && !source) { - ofp->puts("// DESCR" "IPTION: Verilator output: Primary design header\n"); + ofp->puts("// DESCR" + "IPTION: Verilator output: Primary design header\n"); ofp->puts("//\n"); - ofp->puts("// This header should be included by all source files instantiating the design.\n"); + ofp->puts("// This header should be included by all source files instantiating the " + "design.\n"); ofp->puts("// The class here is then constructed to instantiate the design.\n"); ofp->puts("// See the Verilator manual for examples.\n"); } else { if (source) { - ofp->puts("// DESCR" "IPTION: Verilator output: Design implementation internals\n"); + ofp->puts("// DESCR" + "IPTION: Verilator output: Design implementation internals\n"); } else { - ofp->puts("// DESCR" "IPTION: Verilator output: Design internal header\n"); + ofp->puts("// DESCR" + "IPTION: Verilator output: Design internal header\n"); } - ofp->puts("// See "+v3Global.opt.prefix()+".h for the primary calling header\n"); + ofp->puts("// See " + v3Global.opt.prefix() + ".h for the primary calling header\n"); } return ofp; } @@ -1234,9 +1292,7 @@ class EmitCImp : EmitCStmts { uint32_t result = 0; for (V3GraphEdge* edgep = mtaskp->inBeginp(); edgep; edgep = edgep->inNextp()) { const ExecMTask* prevp = dynamic_cast(edgep->fromp()); - if (prevp->thread() != mtaskp->thread()) { - ++result; - } + if (prevp->thread() != mtaskp->thread()) ++result; } return result; } @@ -1254,10 +1310,10 @@ class EmitCImp : EmitCStmts { puts("VlProfileRec* " + recName + " = NULL;\n"); // Leave this if() here, as don't want to call VL_RDTSC_Q unless profiling puts("if (VL_UNLIKELY(vlTOPp->__Vm_profile_cycle_start)) {\n"); - puts( recName + " = vlTOPp->__Vm_threadPoolp->profileAppend();\n"); - puts( recName + "->startRecord(VL_RDTSC_Q() - vlTOPp->__Vm_profile_cycle_start,"); - puts( " "+cvtToStr(curExecMTaskp->id())+ ","); - puts( " "+cvtToStr(curExecMTaskp->cost())+");\n"); + puts(recName + " = vlTOPp->__Vm_threadPoolp->profileAppend();\n"); + puts(recName + "->startRecord(VL_RDTSC_Q() - vlTOPp->__Vm_profile_cycle_start,"); + puts(" " + cvtToStr(curExecMTaskp->id()) + ","); + puts(" " + cvtToStr(curExecMTaskp->cost()) + ");\n"); puts("}\n"); } puts("Verilated::mtaskId(" + cvtToStr(curExecMTaskp->id()) + ");\n"); @@ -1267,8 +1323,8 @@ class EmitCImp : EmitCStmts { if (v3Global.opt.profThreads()) { // Leave this if() here, as don't want to call VL_RDTSC_Q unless profiling - puts("if (VL_UNLIKELY("+recName+")) {\n"); - puts( recName + "->endRecord(VL_RDTSC_Q() - vlTOPp->__Vm_profile_cycle_start);\n"); + puts("if (VL_UNLIKELY(" + recName + ")) {\n"); + puts(recName + "->endRecord(VL_RDTSC_Q() - vlTOPp->__Vm_profile_cycle_start);\n"); puts("}\n"); } @@ -1277,11 +1333,10 @@ class EmitCImp : EmitCStmts { // For any downstream mtask that's on another thread, bump its // counter and maybe notify it. - for (V3GraphEdge* edgep = curExecMTaskp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = curExecMTaskp->outBeginp(); edgep; edgep = edgep->outNextp()) { const ExecMTask* nextp = dynamic_cast(edgep->top()); if (nextp->thread() != curExecMTaskp->thread()) { - puts("vlTOPp->__Vm_mt_"+cvtToStr(nextp->id()) + puts("vlTOPp->__Vm_mt_" + cvtToStr(nextp->id()) + ".signalUpstreamDone(even_cycle);\n"); } } @@ -1304,9 +1359,9 @@ class EmitCImp : EmitCStmts { puts("(bool even_cycle, void* symtab) {\n"); // Declare and set vlSymsp - puts(EmitCBaseVisitor::symClassVar() + " = (" - + EmitCBaseVisitor::symClassName() + "*)symtab;\n"); - puts(EmitCBaseVisitor::symTopAssign()+"\n"); + puts(EmitCBaseVisitor::symClassVar() + " = (" + EmitCBaseVisitor::symClassName() + + "*)symtab;\n"); + puts(EmitCBaseVisitor::symTopAssign() + "\n"); emitMTaskBody(nodep); puts("}\n"); @@ -1326,7 +1381,7 @@ class EmitCImp : EmitCStmts { splitSizeInc(nodep); puts("\n"); - if (nodep->ifdef()!="") puts("#ifdef "+nodep->ifdef()+"\n"); + if (nodep->ifdef() != "") puts("#ifdef " + nodep->ifdef() + "\n"); if (nodep->isInline()) puts("VL_INLINE_OPT "); if (!nodep->isConstructor() && !nodep->isDestructor()) { puts(nodep->rtnTypeVoid()); @@ -1341,21 +1396,21 @@ class EmitCImp : EmitCStmts { // "+" in the debug indicates a print from the model puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ "); - for (int i=0; ilevel(); ++i) { puts(" "); } + for (int i = 0; i < m_modp->level(); ++i) { puts(" "); } puts(prefixNameProtect(m_modp) + "::" + nodep->nameProtect() + "\\n\"); );\n"); // Declare and set vlTOPp - if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign()+"\n"); + if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign() + "\n"); if (nodep->initsp()) putsDecoration("// Variables\n"); - for (AstNode* subnodep=nodep->argsp(); subnodep; subnodep = subnodep->nextp()) { + for (AstNode* subnodep = nodep->argsp(); subnodep; subnodep = subnodep->nextp()) { if (AstVar* varp = VN_CAST(subnodep, Var)) { if (varp->isFuncReturn()) emitVarDecl(varp, ""); } } string section; - emitVarList(nodep->initsp(), EVL_FUNC_ALL, "", section/*ref*/); - emitVarList(nodep->stmtsp(), EVL_FUNC_ALL, "", section/*ref*/); + emitVarList(nodep->initsp(), EVL_FUNC_ALL, "", section /*ref*/); + emitVarList(nodep->stmtsp(), EVL_FUNC_ALL, "", section /*ref*/); iterateAndNextNull(nodep->initsp()); @@ -1369,14 +1424,15 @@ class EmitCImp : EmitCStmts { if (!m_blkChangeDetVec.empty()) puts("return __req;\n"); - //puts("__Vm_activity = true;\n"); + // puts("__Vm_activity = true;\n"); puts("}\n"); - if (nodep->ifdef()!="") puts("#endif // "+nodep->ifdef()+"\n"); + if (nodep->ifdef() != "") puts("#endif // " + nodep->ifdef() + "\n"); } void emitChangeDet() { putsDecoration("// Change detection\n"); - puts("QData __req = false; // Logically a bool\n"); // But not because it results in faster code + puts("QData __req = false; // Logically a bool\n"); // But not because it results in + // faster code bool gotOne = false; for (std::vector::iterator it = m_blkChangeDetVec.begin(); it != m_blkChangeDetVec.end(); ++it) { @@ -1384,14 +1440,15 @@ class EmitCImp : EmitCStmts { if (changep->lhsp()) { if (!gotOne) { // Not a clocked block puts("__req |= ("); + } else { + puts("\n"); } - else puts("\n"); doubleOrDetect(changep, gotOne); } } if (gotOne) puts(");\n"); if (gotOne && !v3Global.opt.protectIds()) { - //puts("VL_DEBUG_IF( if (__req) cout<<\"- CLOCKREQ );"); + // puts("VL_DEBUG_IF( if (__req) cout<<\"- CLOCKREQ );"); for (std::vector::iterator it = m_blkChangeDetVec.begin(); it != m_blkChangeDetVec.end(); ++it) { AstChangeDet* nodep = *it; @@ -1401,18 +1458,18 @@ class EmitCImp : EmitCStmts { doubleOrDetect(nodep, gotOneIgnore); string varname; if (VN_IS(nodep->lhsp(), VarRef)) { - varname = ": "+VN_CAST(nodep->lhsp(), VarRef)->varp()->prettyName(); + varname = ": " + VN_CAST(nodep->lhsp(), VarRef)->varp()->prettyName(); } puts(")) VL_DBG_MSGF(\" CHANGE: "); puts(protect(nodep->fileline()->filename())); - puts(":"+cvtToStr(nodep->fileline()->lineno())); - puts(varname+"\\n\"); );\n"); + puts(":" + cvtToStr(nodep->fileline()->lineno())); + puts(varname + "\\n\"); );\n"); } } } } - virtual void visit(AstChangeDet* nodep) VL_OVERRIDE { + virtual void visit(AstChangeDet* nodep) VL_OVERRIDE { // m_blkChangeDetVec.push_back(nodep); } @@ -1437,13 +1494,13 @@ class EmitCImp : EmitCStmts { std::vector execMTasks; // Start each root mtask - for (const V3GraphVertex* vxp = nodep->depGraphp()->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (const V3GraphVertex* vxp = nodep->depGraphp()->verticesBeginp(); vxp; + vxp = vxp->verticesNextp()) { const ExecMTask* etp = dynamic_cast(vxp); if (etp->threadRoot()) execMTasks.push_back(etp); } - UASSERT_OBJ(execMTasks.size() <= static_cast(v3Global.opt.threads()), - nodep, "More root mtasks than available threads"); + UASSERT_OBJ(execMTasks.size() <= static_cast(v3Global.opt.threads()), nodep, + "More root mtasks than available threads"); if (!execMTasks.empty()) { for (uint32_t i = 0; i < execMTasks.size(); ++i) { @@ -1456,8 +1513,7 @@ class EmitCImp : EmitCStmts { puts("Verilated::mtaskId(0);\n"); } else { // The other N-1 go to the thread pool. - puts("vlTOPp->__Vm_threadPoolp->workerp(" - + cvtToStr(i)+")->addTask(" + puts("vlTOPp->__Vm_threadPoolp->workerp(" + cvtToStr(i) + ")->addTask(" + protect(execMTasks[i]->cFuncName()) + ", vlTOPp->__Vm_even_cycle, vlSymsp);\n"); } @@ -1497,24 +1553,23 @@ class EmitCImp : EmitCStmts { UASSERT_OBJ(varp->valuep(), varp, "No init for a param?"); // If a simple CONST value we initialize it using an enum // If an ARRAYINIT we initialize it using an initial block similar to a signal - //puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n"); + // puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n"); } else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) { if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { if (initarp->defaultp()) { // MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block puts("{ int __Vi=0;"); - puts(" for (; __Vi<"+cvtToStr(adtypep->elementsConst())); + puts(" for (; __Vi<" + cvtToStr(adtypep->elementsConst())); puts("; ++__Vi) {\n"); - emitSetVarConstant(varp->nameProtect()+"[__Vi]", + emitSetVarConstant(varp->nameProtect() + "[__Vi]", VN_CAST(initarp->defaultp(), Const)); puts("}}\n"); } const AstInitArray::KeyItemMap& mapr = initarp->map(); - for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); - it != mapr.end(); ++it) { + for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); + ++it) { AstNode* valuep = it->second->valuep(); - emitSetVarConstant(varp->nameProtect() - +"["+cvtToStr(it->first)+"]", + emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(it->first) + "]", VN_CAST(valuep, Const)); } } else { @@ -1530,49 +1585,48 @@ class EmitCImp : EmitCStmts { AstBasicDType* basicp = dtypep->basicp(); // Returns string to do resetting, empty to do nothing (which caller should handle) if (AstAssocArrayDType* adtypep = VN_CAST(dtypep, AssocArrayDType)) { - string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); // Access std::array as C array - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, + string cvtarray + = (adtypep->subDTypep()->isWide() ? ".data()" + : ""); // Access std::array as C array + return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, ".atDefault()" + cvtarray); - } - else if (AstClassRefDType* adtypep = VN_CAST(dtypep, ClassRefDType)) { + } else if (AstClassRefDType* adtypep = VN_CAST(dtypep, ClassRefDType)) { return ""; // Constructor does it - } - else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) { - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()"); - } - else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) { - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()"); - } - else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { + } else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) { + return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, ".atDefault()"); + } else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) { + return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, ".atDefault()"); + } else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { UASSERT_OBJ(adtypep->msb() >= adtypep->lsb(), varp, "Should have swapped msb & lsb earlier."); - string ivar = string("__Vi")+cvtToStr(depth); + string ivar = string("__Vi") + cvtToStr(depth); // MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block - string pre = ("{ int "+ivar+"="+cvtToStr(0)+";" - +" for (; "+ivar+"<"+cvtToStr(adtypep->elementsConst()) - +"; ++"+ivar+") {\n"); - string below = emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, suffix+"["+ivar+"]"); + string pre = ("{ int " + ivar + "=" + cvtToStr(0) + ";" + " for (; " + ivar + "<" + + cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n"); + string below = emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, + suffix + "[" + ivar + "]"); string post = "}}\n"; return below.empty() ? "" : pre + below + post; - } - else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) { + } else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) { // String's constructor deals with it return ""; - } - else if (basicp) { - bool zeroit = (varp->attrFileDescr() // Zero so we don't core dump if never $fopen - || (basicp && basicp->isZeroInit()) - || (v3Global.opt.underlineZero() - && !varp->name().empty() && varp->name()[0] == '_') - || (v3Global.opt.xInitial() == "fast" - || v3Global.opt.xInitial() == "0")); + } else if (basicp) { + bool zeroit + = (varp->attrFileDescr() // Zero so we don't core dump if never $fopen + || (basicp && basicp->isZeroInit()) + || (v3Global.opt.underlineZero() && !varp->name().empty() + && varp->name()[0] == '_') + || (v3Global.opt.xInitial() == "fast" || v3Global.opt.xInitial() == "0")); splitSizeInc(1); if (dtypep->isWide()) { // Handle unpacked; not basicp->isWide string out; - if (zeroit) out += "VL_ZERO_RESET_W("; - else out += "VL_RAND_RESET_W("; + if (zeroit) { + out += "VL_ZERO_RESET_W("; + } else { + out += "VL_RAND_RESET_W("; + } out += cvtToStr(dtypep->widthMin()); - out += ", "+varp->nameProtect()+suffix+");\n"; + out += ", " + varp->nameProtect() + suffix + ");\n"; return out; } else { string out = varp->nameProtect() + suffix; @@ -1586,13 +1640,12 @@ class EmitCImp : EmitCStmts { } else { out += " = VL_RAND_RESET_"; out += dtypep->charIQWN(); - out += "("+ cvtToStr(dtypep->widthMin())+");\n"; + out += "(" + cvtToStr(dtypep->widthMin()) + ");\n"; } return out; } - } - else { - v3fatalSrc("Unknown node type in reset generator: "<prettyTypeName()); + } else { + v3fatalSrc("Unknown node type in reset generator: " << varp->prettyTypeName()); } return ""; } @@ -1627,9 +1680,7 @@ public: virtual ~EmitCImp() {} void mainImp(AstNodeModule* modp, bool slow, bool fast); void mainInt(AstNodeModule* modp); - void mainDoFunc(AstCFunc* nodep) { - iterate(nodep); - } + void mainDoFunc(AstCFunc* nodep) { iterate(nodep); } }; //###################################################################### @@ -1643,11 +1694,15 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) { if (nodep->attrScClocked() && nodep->isReadOnly()) { puts("sc_in_clk "); } else { - if (nodep->isInoutish()) puts("sc_inout<"); - else if (nodep->isWritable()) puts("sc_out<"); - else if (nodep->isNonOutput()) puts("sc_in<"); - else nodep->v3fatalSrc("Unknown type"); - + if (nodep->isInoutish()) { + puts("sc_inout<"); + } else if (nodep->isWritable()) { + puts("sc_out<"); + } else if (nodep->isNonOutput()) { + puts("sc_in<"); + } else { + nodep->v3fatalSrc("Unknown type"); + } puts(nodep->scType()); puts("> "); } @@ -1655,23 +1710,32 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) { emitDeclArrayBrackets(nodep); puts(";\n"); } else if (nodep->isIO() && basicp && !basicp->isOpaque()) { - if (nodep->isInoutish()) puts("VL_INOUT"); - else if (nodep->isWritable()) puts("VL_OUT"); - else if (nodep->isNonOutput()) puts("VL_IN"); - else nodep->v3fatalSrc("Unknown type"); + if (nodep->isInoutish()) { + puts("VL_INOUT"); + } else if (nodep->isWritable()) { + puts("VL_OUT"); + } else if (nodep->isNonOutput()) { + puts("VL_IN"); + } else { + nodep->v3fatalSrc("Unknown type"); + } - if (nodep->isQuad()) puts("64"); - else if (nodep->widthMin() <= 8) puts("8"); - else if (nodep->widthMin() <= 16) puts("16"); - else if (nodep->isWide()) puts("W"); + if (nodep->isQuad()) { + puts("64"); + } else if (nodep->widthMin() <= 8) { + puts("8"); + } else if (nodep->widthMin() <= 16) { + puts("16"); + } else if (nodep->isWide()) { + puts("W"); + } - puts("("+nodep->nameProtect()); + puts("(" + nodep->nameProtect()); emitDeclArrayBrackets(nodep); // If it's a packed struct/array then nodep->width is the whole // thing, msb/lsb is just lowest dimension - puts(","+cvtToStr(basicp->lsb()+nodep->width()-1) - +","+cvtToStr(basicp->lsb())); - if (nodep->isWide()) puts(","+cvtToStr(nodep->widthWords())); + puts("," + cvtToStr(basicp->lsb() + nodep->width() - 1) + "," + cvtToStr(basicp->lsb())); + if (nodep->isWide()) puts("," + cvtToStr(nodep->widthWords())); puts(");\n"); } else { // strings and other fundamental c types @@ -1682,7 +1746,8 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) { void EmitCStmts::emitCtorSep(bool* firstp) { if (*firstp) { - puts(" : "); *firstp = false; + puts(" : "); + *firstp = false; } else { puts(", "); } @@ -1704,7 +1769,9 @@ void EmitCStmts::emitVarCtors(bool* firstp) { } else { emitCtorSep(firstp); puts(varp->nameProtect()); - puts("("); putsQuoted(varp->nameProtect()); puts(")"); + puts("("); + putsQuoted(varp->nameProtect()); + puts(")"); } } puts("\n#endif\n"); @@ -1716,14 +1783,20 @@ bool EmitCStmts::emitSimpleOk(AstNodeMath* nodep) { // Can we put out a simple (A + B) instead of VL_ADD_III(A,B)? if (nodep->emitSimpleOperator() == "") return false; if (nodep->isWide()) return false; - if (nodep->op1p()) { if (nodep->op1p()->isWide()) return false; } - if (nodep->op2p()) { if (nodep->op2p()->isWide()) return false; } - if (nodep->op3p()) { if (nodep->op3p()->isWide()) return false; } + if (nodep->op1p()) { + if (nodep->op1p()->isWide()) return false; + } + if (nodep->op2p()) { + if (nodep->op2p()->isWide()) return false; + } + if (nodep->op3p()) { + if (nodep->op3p()->isWide()) return false; + } return true; } -void EmitCStmts::emitOpName(AstNode* nodep, const string& format, - AstNode* lhsp, AstNode* rhsp, AstNode* thsp) { +void EmitCStmts::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, AstNode* rhsp, + AstNode* thsp) { // Look at emitOperator() format for term/uni/dual/triops, // and write out appropriate text. // %n* node @@ -1739,30 +1812,49 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format, // , Commas suppressed if the previous field is suppressed string nextComma; bool needComma = false; -#define COMMA { if (!nextComma.empty()) { puts(nextComma); nextComma=""; } } +#define COMMA \ + { \ + if (!nextComma.empty()) { \ + puts(nextComma); \ + nextComma = ""; \ + } \ + } putbs(""); for (string::const_iterator pos = format.begin(); pos != format.end(); ++pos) { - if (pos[0]==',') { + if (pos[0] == ',') { // Remember we need to add one, but don't do yet to avoid ",)" if (needComma) { - if (pos[1]==' ') { nextComma = ", "; } - else nextComma = ","; + if (pos[1] == ' ') { + nextComma = ", "; + } else + nextComma = ","; needComma = false; } - if (pos[1]==' ') { ++pos; } // Must do even if no nextComma - } - else if (pos[0]=='%') { + if (pos[1] == ' ') { ++pos; } // Must do even if no nextComma + } else if (pos[0] == '%') { ++pos; bool detail = false; AstNode* detailp = NULL; switch (pos[0]) { - case '%': puts("%"); break; - case 'k': putbs(""); break; - case 'n': detail = true; detailp = nodep; break; - case 'l': detail = true; detailp = lhsp; break; - case 'r': detail = true; detailp = rhsp; break; - case 't': detail = true; detailp = thsp; break; + case '%': puts("%"); break; + case 'k': putbs(""); break; + case 'n': + detail = true; + detailp = nodep; + break; + case 'l': + detail = true; + detailp = lhsp; + break; + case 'r': + detail = true; + detailp = rhsp; + break; + case 't': + detail = true; + detailp = thsp; + break; case 'P': if (nodep->isWide()) { UASSERT_OBJ(m_wideTempRefp, nodep, @@ -1774,9 +1866,7 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format, needComma = true; } break; - default: - nodep->v3fatalSrc("Unknown emitOperator format code: %"<v3fatalSrc("Unknown emitOperator format code: %" << pos[0]); break; } if (detail) { // Get next letter of %[nlrt] @@ -1802,19 +1892,24 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format, needComma = true; break; default: - nodep->v3fatalSrc("Unknown emitOperator format code: %[nlrt]"<v3fatalSrc("Unknown emitOperator format code: %[nlrt]" << pos[0]); break; } } } else if (pos[0] == ')') { - nextComma = ""; puts(")"); + nextComma = ""; + puts(")"); } else if (pos[0] == '(') { - COMMA; needComma = false; puts("("); + COMMA; + needComma = false; + puts("("); } else { // Normal text if (isalnum(pos[0])) needComma = true; COMMA; - string s; s += pos[0]; puts(s); + string s; + s += pos[0]; + puts(s); } } } @@ -1825,8 +1920,8 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format, // We only do one display at once, so can just use static state struct EmitDispState { - string m_format; // "%s" and text from user - std::vector m_argsChar; // Format of each argument to be printed + string m_format; // "%s" and text from user + std::vector m_argsChar; // Format of each argument to be printed std::vector m_argsp; // Each argument to be printed std::vector m_argsFunc; // Function before each argument to be printed EmitDispState() { clear(); } @@ -1840,7 +1935,8 @@ struct EmitDispState { void pushFormat(char fmt) { m_format += fmt; } void pushArg(char fmtChar, AstNode* nodep, const string& func) { m_argsChar.push_back(fmtChar); - m_argsp.push_back(nodep); m_argsFunc.push_back(func); + m_argsp.push_back(nodep); + m_argsFunc.push_back(func); } } emitDispState; @@ -1859,7 +1955,9 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) { } else if (const AstSScanF* dispp = VN_CAST(nodep, SScanF)) { isStmt = false; checkMaxWords(dispp->fromp()); - puts("VL_SSCANF_I"); emitIQW(dispp->fromp()); puts("X("); + puts("VL_SSCANF_I"); + emitIQW(dispp->fromp()); + puts("X("); puts(cvtToStr(dispp->fromp()->widthMin())); puts(","); iterate(dispp->fromp()); @@ -1888,34 +1986,42 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) { } ofp()->putsQuoted(emitDispState.m_format); // Arguments - for (unsigned i=0; i < emitDispState.m_argsp.size(); i++) { + for (unsigned i = 0; i < emitDispState.m_argsp.size(); i++) { puts(","); - char fmt = emitDispState.m_argsChar[i]; + char fmt = emitDispState.m_argsChar[i]; AstNode* argp = emitDispState.m_argsp[i]; - string func = emitDispState.m_argsFunc[i]; + string func = emitDispState.m_argsFunc[i]; ofp()->indentInc(); ofp()->putbs(""); - if (func!="") puts(func); + if (func != "") puts(func); if (argp) { - if (isScan) puts("&("); - else if (fmt == '@') puts("&("); + if (isScan) { + puts("&("); + } else if (fmt == '@') { + puts("&("); + } iterate(argp); - if (isScan) puts(")"); - else if (fmt == '@') puts(")"); + if (isScan) { + puts(")"); + } else if (fmt == '@') { + puts(")"); + } } ofp()->indentDec(); } // End puts(")"); - if (isStmt) puts(";\n"); - else puts(" "); + if (isStmt) + puts(";\n"); + else + puts(" "); // Prep for next emitDispState.clear(); } } -void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, - const string& vfmt, char fmtLetter) { +void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const string& vfmt, + char fmtLetter) { // Print display argument, edits elistp AstNode* argp = *elistp; if (VL_UNCOVERABLE(!argp)) { @@ -1924,22 +2030,22 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, return; // LCOV_EXCL_LINE } if (argp->widthMin() > VL_VALUE_STRING_MAX_WIDTH) { - dispp->v3error("Exceeded limit of "+cvtToStr(VL_VALUE_STRING_MAX_WIDTH)+" bits for any $display-like arguments"); + dispp->v3error("Exceeded limit of " + cvtToStr(VL_VALUE_STRING_MAX_WIDTH) + + " bits for any $display-like arguments"); } if (argp->widthMin() > 8 && fmtLetter == 'c') { // Technically legal, but surely not what the user intended. - argp->v3warn(WIDTH, dispp->verilogKwd()<<"of %c format of > 8 bit value"); + argp->v3warn(WIDTH, dispp->verilogKwd() << "of %c format of > 8 bit value"); } - //string pfmt = "%"+displayFormat(argp, vfmt, fmtLetter)+fmtLetter; + // string pfmt = "%"+displayFormat(argp, vfmt, fmtLetter)+fmtLetter; string pfmt; - if ((fmtLetter=='#' || fmtLetter=='d' || fmtLetter=='t') - && !isScan + if ((fmtLetter == '#' || fmtLetter == 'd' || fmtLetter == 't') && !isScan && vfmt == "") { // Size decimal output. Spec says leading spaces, not zeros - double mantissabits = argp->widthMin() - ((fmtLetter=='d')?1:0); + double mantissabits = argp->widthMin() - ((fmtLetter == 'd') ? 1 : 0); double maxval = pow(2.0, mantissabits); - double dchars = log10(maxval)+1.0; - if (fmtLetter=='d') dchars++; // space for sign + double dchars = log10(maxval) + 1.0; + if (fmtLetter == 'd') dchars++; // space for sign int nchars = int(dchars); pfmt = string("%") + cvtToStr(nchars) + fmtLetter; } else { @@ -1953,9 +2059,8 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, *elistp = (*elistp)->nextp(); } -void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, - const string& vformat, AstNode* exprsp, - bool isScan) { +void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, const string& vformat, + AstNode* exprsp, bool isScan) { AstNode* elistp = exprsp; // Convert Verilog display to C printf formats @@ -1965,8 +2070,8 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, string::const_iterator pos = vformat.begin(); bool inPct = false; for (; pos != vformat.end(); ++pos) { - //UINFO(1,"Parse '"<<*pos<<"' IP"<scopePrettySymName(); - if (suffix=="") emitDispState.pushFormat("%S"); - else emitDispState.pushFormat("%N"); // Add a . when needed + if (suffix == "") { + emitDispState.pushFormat("%S"); + } else { + emitDispState.pushFormat("%N"); // Add a . when needed + } emitDispState.pushArg(' ', NULL, "vlSymsp->name()"); emitDispState.pushFormat(suffix); break; @@ -2017,7 +2126,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, break; } default: - nodep->v3error("Unknown $display-like format code: '%"<v3error("Unknown $display-like format code: '%" << pos[0] << "'"); break; } } @@ -2039,7 +2148,7 @@ void EmitCImp::emitCoverageDecl(AstNodeModule* modp) { puts("void __vlCoverInsert("); puts(v3Global.opt.threads() ? "std::atomic" : "uint32_t"); puts("* countp, bool enable, const char* filenamep, int lineno, int column,\n"); - puts( "const char* hierp, const char* pagep, const char* commentp);\n"); + puts("const char* hierp, const char* pagep, const char* commentp);\n"); } } @@ -2049,13 +2158,12 @@ void EmitCImp::emitMTaskVertexCtors(bool* firstp) { const V3Graph* depGraphp = execGraphp->depGraphp(); unsigned finalEdgesInCt = 0; - for (const V3GraphVertex* vxp = depGraphp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (const V3GraphVertex* vxp = depGraphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { const ExecMTask* mtp = dynamic_cast(vxp); unsigned edgesInCt = packedMTaskMayBlock(mtp); if (packedMTaskMayBlock(mtp) > 0) { emitCtorSep(firstp); - puts("__Vm_mt_"+cvtToStr(mtp->id())+"("+cvtToStr(edgesInCt)+")"); + puts("__Vm_mt_" + cvtToStr(mtp->id()) + "(" + cvtToStr(edgesInCt) + ")"); } // Each mtask with no packed successor will become a dependency // for the final node: @@ -2066,11 +2174,14 @@ void EmitCImp::emitMTaskVertexCtors(bool* firstp) { puts("__Vm_mt_final(" + cvtToStr(finalEdgesInCt) + ")"); // This will flip to 'true' before the start of the 0th cycle. - emitCtorSep(firstp); puts("__Vm_threadPoolp(NULL)"); + emitCtorSep(firstp); + puts("__Vm_threadPoolp(NULL)"); if (v3Global.opt.profThreads()) { - emitCtorSep(firstp); puts("__Vm_profile_cycle_start(0)"); + emitCtorSep(firstp); + puts("__Vm_profile_cycle_start(0)"); } - emitCtorSep(firstp); puts("__Vm_even_cycle(false)"); + emitCtorSep(firstp); + puts("__Vm_even_cycle(false)"); } void EmitCImp::emitCtorImp(AstNodeModule* modp) { @@ -2085,9 +2196,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { first = false; // VL_CTOR_IMP includes the first ':' } emitVarCtors(&first); - if (modp->isTop() && v3Global.opt.mtasks()) { - emitMTaskVertexCtors(&first); - } + if (modp->isTop() && v3Global.opt.mtasks()) emitMTaskVertexCtors(&first); puts(" {\n"); emitCellCtors(modp); emitSensitives(); @@ -2098,7 +2207,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { puts("\n"); } putsDecoration("// Reset structure values\n"); - puts(protect("_ctor_var_reset")+"();\n"); + puts(protect("_ctor_var_reset") + "();\n"); emitTextSection(AstType::atScCtor); if (modp->isTop() && v3Global.opt.mtasks()) { @@ -2123,8 +2232,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { // Note we create N-1 threads in the thread pool. The thread // that calls eval() becomes the final Nth thread for the // duration of the eval call. - + cvtToStr(v3Global.opt.threads() - 1) - + ", " + cvtToStr(v3Global.opt.profThreads()) + + cvtToStr(v3Global.opt.threads() - 1) + ", " + cvtToStr(v3Global.opt.profThreads()) + ");\n"); if (v3Global.opt.profThreads()) { @@ -2139,45 +2247,43 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { void EmitCImp::emitConfigureImp(AstNodeModule* modp) { puts("\nvoid " + prefixNameProtect(modp) + "::" + protect("__Vconfigure") + "(" + symClassName() + "* vlSymsp, bool first) {\n"); - puts( "if (false && first) {} // Prevent unused\n"); - puts( "this->__VlSymsp = vlSymsp;\n"); // First, as later stuff needs it. - puts( "if (false && this->__VlSymsp) {} // Prevent unused\n"); - if (v3Global.opt.coverage() ) { - puts(protect("_configure_coverage")+"(vlSymsp, first);\n"); - } + puts("if (false && first) {} // Prevent unused\n"); + puts("this->__VlSymsp = vlSymsp;\n"); // First, as later stuff needs it. + puts("if (false && this->__VlSymsp) {} // Prevent unused\n"); + if (v3Global.opt.coverage()) puts(protect("_configure_coverage") + "(vlSymsp, first);\n"); puts("}\n"); splitSizeInc(10); } void EmitCImp::emitCoverageImp(AstNodeModule* modp) { - if (v3Global.opt.coverage() ) { + if (v3Global.opt.coverage()) { puts("\n// Coverage\n"); // Rather than putting out VL_COVER_INSERT calls directly, we do it via this function // This gets around gcc slowness constructing all of the template arguments. puts("void " + prefixNameProtect(m_modp) + "::__vlCoverInsert("); puts(v3Global.opt.threads() ? "std::atomic" : "uint32_t"); puts("* countp, bool enable, const char* filenamep, int lineno, int column,\n"); - puts( "const char* hierp, const char* pagep, const char* commentp) {\n"); + puts("const char* hierp, const char* pagep, const char* commentp) {\n"); if (v3Global.opt.threads()) { - puts( "assert(sizeof(uint32_t) == sizeof(std::atomic));\n"); - puts( "uint32_t* count32p = reinterpret_cast(countp);\n"); + puts("assert(sizeof(uint32_t) == sizeof(std::atomic));\n"); + puts("uint32_t* count32p = reinterpret_cast(countp);\n"); } else { - puts( "uint32_t* count32p = countp;\n"); + puts("uint32_t* count32p = countp;\n"); } // static doesn't need save-restore as is constant - puts( "static uint32_t fake_zero_count = 0;\n"); + puts("static uint32_t fake_zero_count = 0;\n"); // Used for second++ instantiation of identical bin - puts( "if (!enable) count32p = &fake_zero_count;\n"); - puts( "*count32p = 0;\n"); + puts("if (!enable) count32p = &fake_zero_count;\n"); + puts("*count32p = 0;\n"); puts("VL_COVER_INSERT(count32p,"); - puts( " \"filename\",filenamep,"); - puts( " \"lineno\",lineno,"); - puts( " \"column\",column,\n"); + puts(" \"filename\",filenamep,"); + puts(" \"lineno\",lineno,"); + puts(" \"column\",column,\n"); // Need to move hier into scopes and back out if do this - //puts( "\"hier\",std::string(__VlSymsp->name())+hierp,"); - puts( "\"hier\",std::string(name())+hierp,"); - puts( " \"page\",pagep,"); - puts( " \"comment\",commentp);\n"); + // puts( "\"hier\",std::string(__VlSymsp->name())+hierp,"); + puts("\"hier\",std::string(name())+hierp,"); + puts(" \"page\",pagep,"); + puts(" \"comment\",commentp);\n"); puts("}\n"); splitSizeInc(10); } @@ -2187,9 +2293,7 @@ void EmitCImp::emitDestructorImp(AstNodeModule* modp) { puts("\n"); puts(prefixNameProtect(modp) + "::~" + prefixNameProtect(modp) + "() {\n"); if (modp->isTop()) { - if (v3Global.opt.mtasks()) { - puts("delete __Vm_threadPoolp; __Vm_threadPoolp = NULL;\n"); - } + if (v3Global.opt.mtasks()) puts("delete __Vm_threadPoolp; __Vm_threadPoolp = NULL;\n"); // Call via function in __Trace.cpp as this .cpp file does not have trace header if (v3Global.needTraceDumper()) { puts("#ifdef VM_TRACE\n"); @@ -2204,9 +2308,9 @@ void EmitCImp::emitDestructorImp(AstNodeModule* modp) { } void EmitCImp::emitSavableImp(AstNodeModule* modp) { - if (v3Global.opt.savable() ) { + if (v3Global.opt.savable()) { puts("\n// Savable\n"); - for (int de=0; de<2; ++de) { + for (int de = 0; de < 2; ++de) { string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize"; string funcname = de ? "__Vdeserialize" : "__Vserialize"; string op = de ? ">>" : "<<"; @@ -2223,8 +2327,8 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) { hash.insert(varp->dtypep()->width()); } } - ofp()->printf( "vluint64_t __Vcheckval = VL_ULL(0x%" VL_PRI64 "x);\n", - static_cast(hash.digestUInt64())); + ofp()->printf("vluint64_t __Vcheckval = VL_ULL(0x%" VL_PRI64 "x);\n", + static_cast(hash.digestUInt64())); if (de) { puts("os.readAssert(__Vcheckval);\n"); } else { @@ -2232,30 +2336,28 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) { } // Save all members - if (v3Global.opt.inhibitSim()) puts("os"+op+"__Vm_inhibitSim;\n"); + if (v3Global.opt.inhibitSim()) puts("os" + op + "__Vm_inhibitSim;\n"); for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstVar* varp = VN_CAST(nodep, Var)) { if (varp->isIO() && modp->isTop() && optSystemC()) { // System C top I/O doesn't need loading, as the // lower level subinst code does it. - } - else if (varp->isParam()) {} - else if (varp->isStatic() && varp->isConst()) {} - else { + } else if (varp->isParam()) { + } else if (varp->isStatic() && varp->isConst()) { + } else { int vects = 0; AstNodeDType* elementp = varp->dtypeSkipRefp(); for (AstUnpackArrayDType* arrayp = VN_CAST(elementp, UnpackArrayDType); - arrayp; - arrayp = VN_CAST(elementp, UnpackArrayDType)) { + arrayp; arrayp = VN_CAST(elementp, UnpackArrayDType)) { int vecnum = vects++; UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp, "Should have swapped msb & lsb earlier."); - string ivar = string("__Vi")+cvtToStr(vecnum); + string ivar = string("__Vi") + cvtToStr(vecnum); // MSVC++ pre V7 doesn't support 'for (int ...)', // so declare in sep block - puts("{ int __Vi"+cvtToStr(vecnum)+"="+cvtToStr(0)+";"); - puts(" for (; "+ivar+"<"+cvtToStr(arrayp->elementsConst())); - puts("; ++"+ivar+") {\n"); + puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0) + ";"); + puts(" for (; " + ivar + "<" + cvtToStr(arrayp->elementsConst())); + puts("; ++" + ivar + ") {\n"); elementp = arrayp->subDTypep()->skipRefp(); } // Want to detect types that are represented as arrays @@ -2264,21 +2366,21 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) { if (elementp->isWide() && !(basicp && basicp->keyword() == AstBasicDTypeKwd::STRING)) { int vecnum = vects++; - string ivar = string("__Vi")+cvtToStr(vecnum); - puts("{ int __Vi"+cvtToStr(vecnum)+"="+cvtToStr(0)+";"); - puts(" for (; "+ivar+"<"+cvtToStr(elementp->widthWords())); - puts("; ++"+ivar+") {\n"); + string ivar = string("__Vi") + cvtToStr(vecnum); + puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0) + ";"); + puts(" for (; " + ivar + "<" + cvtToStr(elementp->widthWords())); + puts("; ++" + ivar + ") {\n"); } - puts("os"+op+varp->nameProtect()); - for (int v=0; vnameProtect()); + for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]"); puts(";\n"); - for (int v=0; visTop()) { // Save the children - puts( "__VlSymsp->"+protect(funcname)+"(os);\n"); + puts("__VlSymsp->" + protect(funcname) + "(os);\n"); } puts("}\n"); } @@ -2294,8 +2396,8 @@ void EmitCImp::emitTextSection(AstType type) { if (last_line < 0) { puts("\n//*** Below code from `systemc in Verilog file\n"); } - putsDecoration(ifNoProtect("// From `systemc at " - +nodep->fileline()->ascii()+"\n")); + putsDecoration( + ifNoProtect("// From `systemc at " + nodep->fileline()->ascii() + "\n")); last_line = nodep->fileline()->lineno(); } ofp()->putsNoTracking(textp->text()); @@ -2303,16 +2405,15 @@ void EmitCImp::emitTextSection(AstType type) { } } } - if (last_line > 0) { - puts("//*** Above code from `systemc in Verilog file\n\n"); - } + if (last_line > 0) puts("//*** Above code from `systemc in Verilog file\n\n"); } void EmitCImp::emitCellCtors(AstNodeModule* modp) { if (modp->isTop()) { // Must be before other constructors, as __vlCoverInsert calls it - puts(EmitCBaseVisitor::symClassVar()+" = __VlSymsp = new "+symClassName()+"(this, name());\n"); - puts(EmitCBaseVisitor::symTopAssign()+"\n"); + puts(EmitCBaseVisitor::symClassVar() + " = __VlSymsp = new " + symClassName() + + "(this, name());\n"); + puts(EmitCBaseVisitor::symTopAssign() + "\n"); } for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (AstCell* cellp = VN_CAST(nodep, Cell)) { @@ -2330,27 +2431,27 @@ void EmitCImp::emitSensitives() { puts("SC_METHOD(eval);\n"); for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstVar* varp = VN_CAST(nodep, Var)) { - if (varp->isNonOutput() && (varp->isScSensitive() - || varp->isUsedClock())) { + if (varp->isNonOutput() && (varp->isScSensitive() || varp->isUsedClock())) { int vects = 0; // This isn't very robust and may need cleanup for other data types for (AstUnpackArrayDType* arrayp - = VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType); + = VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType); arrayp; arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) { int vecnum = vects++; UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp, "Should have swapped msb & lsb earlier."); - string ivar = string("__Vi")+cvtToStr(vecnum); + string ivar = string("__Vi") + cvtToStr(vecnum); // MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block - puts("{ int __Vi"+cvtToStr(vecnum)+"="+cvtToStr(arrayp->lsb())+";"); - puts(" for (; "+ivar+"<="+cvtToStr(arrayp->msb())); - puts("; ++"+ivar+") {\n"); + puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(arrayp->lsb()) + + ";"); + puts(" for (; " + ivar + "<=" + cvtToStr(arrayp->msb())); + puts("; ++" + ivar + ") {\n"); } - puts("sensitive << "+varp->nameProtect()); - for (int v=0; vnameProtect()); + for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]"); puts(";\n"); - for (int v=0; v "+cvtToStr(v3Global.opt.convergeLimit()) - +")) {\n"); - puts( "// About to fail, so enable debug to see what's not settling.\n"); - puts( "// Note you must run make with OPT=-DVL_DEBUG for debug prints.\n"); - puts( "int __Vsaved_debug = Verilated::debug();\n"); - puts( "Verilated::debug(1);\n"); - puts( "__Vchange = "+protect("_change_request")+"(vlSymsp);\n"); - puts( "Verilated::debug(__Vsaved_debug);\n"); - puts( "VL_FATAL_MT("); + puts(eval_call + "\n"); + puts("if (VL_UNLIKELY(++__VclockLoop > " + cvtToStr(v3Global.opt.convergeLimit()) + ")) {\n"); + puts("// About to fail, so enable debug to see what's not settling.\n"); + puts("// Note you must run make with OPT=-DVL_DEBUG for debug prints.\n"); + puts("int __Vsaved_debug = Verilated::debug();\n"); + puts("Verilated::debug(1);\n"); + puts("__Vchange = " + protect("_change_request") + "(vlSymsp);\n"); + puts("Verilated::debug(__Vsaved_debug);\n"); + puts("VL_FATAL_MT("); putsQuoted(protect(m_modp->fileline()->filename())); puts(", "); puts(cvtToStr(m_modp->fileline()->lineno())); @@ -2381,9 +2481,9 @@ void EmitCImp::emitSettleLoop(const std::string& eval_call, bool initial) { if (initial) puts("DC "); puts("converge\\n\"\n"); puts("\"- See DIDNOTCONVERGE in the Verilator manual\");\n"); - puts( "} else {\n"); - puts( "__Vchange = "+protect("_change_request")+"(vlSymsp);\n"); - puts( "}\n"); + puts("} else {\n"); + puts("__Vchange = " + protect("_change_request") + "(vlSymsp);\n"); + puts("}\n"); puts("} while (VL_UNLIKELY(__Vchange));\n"); } @@ -2391,73 +2491,69 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) { puts("\nvoid " + prefixNameProtect(modp) + "::eval_step() {\n"); puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate " + prefixNameProtect(modp) + "::eval\\n\"); );\n"); - puts(EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp; // Setup global symbol table\n"); - puts(EmitCBaseVisitor::symTopAssign()+"\n"); + puts(EmitCBaseVisitor::symClassVar() + " = this->__VlSymsp; // Setup global symbol table\n"); + puts(EmitCBaseVisitor::symTopAssign() + "\n"); puts("#ifdef VL_DEBUG\n"); putsDecoration("// Debug assertions\n"); - puts(protect("_eval_debug_assertions")+"();\n"); + puts(protect("_eval_debug_assertions") + "();\n"); puts("#endif // VL_DEBUG\n"); putsDecoration("// Initialize\n"); - puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) " - +protect("_eval_initial_loop")+"(vlSymsp);\n"); - if (v3Global.opt.inhibitSim()) { - puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n"); - } + puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) " + protect("_eval_initial_loop") + + "(vlSymsp);\n"); + if (v3Global.opt.inhibitSim()) puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n"); if (v3Global.opt.threads() == 1) { uint32_t mtaskId = 0; - putsDecoration("// MTask "+cvtToStr(mtaskId)+" start\n"); - puts("VL_DEBUG_IF(VL_DBG_MSGF(\"MTask"+cvtToStr(mtaskId)+" starting\\n\"););\n"); - puts("Verilated::mtaskId("+cvtToStr(mtaskId)+");\n"); + putsDecoration("// MTask " + cvtToStr(mtaskId) + " start\n"); + puts("VL_DEBUG_IF(VL_DBG_MSGF(\"MTask" + cvtToStr(mtaskId) + " starting\\n\"););\n"); + puts("Verilated::mtaskId(" + cvtToStr(mtaskId) + ");\n"); } - if (v3Global.opt.mtasks() - && v3Global.opt.profThreads()) { + if (v3Global.opt.mtasks() && v3Global.opt.profThreads()) { puts("if (VL_UNLIKELY((Verilated::profThreadsStart() != __Vm_profile_time_finished)\n"); - puts( " && (VL_TIME_Q() > Verilated::profThreadsStart())\n"); - puts( " && (Verilated::profThreadsWindow() >= 1))) {\n"); + puts(" && (VL_TIME_Q() > Verilated::profThreadsStart())\n"); + puts(" && (Verilated::profThreadsWindow() >= 1))) {\n"); // Within a profile (either starting, middle, or end) - puts( "if (vlTOPp->__Vm_profile_window_ct == 0) {\n"); // Opening file? + puts("if (vlTOPp->__Vm_profile_window_ct == 0) {\n"); // Opening file? // Start profile on this cycle. We'll capture a window worth, then // only analyze the next window worth. The idea is that the first window // capture will hit some cache-cold stuff (eg printf) but it'll be warm // by the time we hit the second window, we hope. - puts( "vlTOPp->__Vm_profile_cycle_start = VL_RDTSC_Q();\n"); + puts("vlTOPp->__Vm_profile_cycle_start = VL_RDTSC_Q();\n"); // "* 2" as first half is warmup, second half is collection - puts( "vlTOPp->__Vm_profile_window_ct = Verilated::profThreadsWindow() * 2 + 1;\n"); - puts( "}\n"); - puts( "--vlTOPp->__Vm_profile_window_ct;\n"); - puts( "if (vlTOPp->__Vm_profile_window_ct == (Verilated::profThreadsWindow())) {\n"); + puts("vlTOPp->__Vm_profile_window_ct = Verilated::profThreadsWindow() * 2 + 1;\n"); + puts("}\n"); + puts("--vlTOPp->__Vm_profile_window_ct;\n"); + puts("if (vlTOPp->__Vm_profile_window_ct == (Verilated::profThreadsWindow())) {\n"); // This barrier record in every threads' profile demarcates the // cache-warm-up cycles before the barrier from the actual profile // cycles afterward. - puts( "vlTOPp->__Vm_threadPoolp->profileAppendAll("); - puts( "VlProfileRec(VlProfileRec::Barrier()));\n"); - puts( "vlTOPp->__Vm_profile_cycle_start = VL_RDTSC_Q();\n"); - puts( "}\n"); - puts( "else if (vlTOPp->__Vm_profile_window_ct == 0) {\n"); + puts("vlTOPp->__Vm_threadPoolp->profileAppendAll("); + puts("VlProfileRec(VlProfileRec::Barrier()));\n"); + puts("vlTOPp->__Vm_profile_cycle_start = VL_RDTSC_Q();\n"); + puts("}\n"); + puts("else if (vlTOPp->__Vm_profile_window_ct == 0) {\n"); // Ending file. - puts( "vluint64_t elapsed = VL_RDTSC_Q() - vlTOPp->__Vm_profile_cycle_start;\n"); - puts( "vlTOPp->__Vm_threadPoolp->profileDump(Verilated::profThreadsFilenamep(), elapsed);\n"); + puts("vluint64_t elapsed = VL_RDTSC_Q() - vlTOPp->__Vm_profile_cycle_start;\n"); + puts("vlTOPp->__Vm_threadPoolp->profileDump(Verilated::profThreadsFilenamep(), " + "elapsed);\n"); // This turns off the test to enter the profiling code, but still // allows the user to collect another profile by changing // profThreadsStart - puts( "__Vm_profile_time_finished = Verilated::profThreadsStart();\n"); - puts( "vlTOPp->__Vm_profile_cycle_start = 0;\n"); - puts( "}\n"); + puts("__Vm_profile_time_finished = Verilated::profThreadsStart();\n"); + puts("vlTOPp->__Vm_profile_cycle_start = 0;\n"); + puts("}\n"); puts("}\n"); } - emitSettleLoop( - (string("VL_DEBUG_IF(VL_DBG_MSGF(\"+ Clock loop\\n\"););\n") - + (v3Global.opt.trace() ? "vlSymsp->__Vm_activity = true;\n" : "") - + protect("_eval")+"(vlSymsp);"), false); + emitSettleLoop((string("VL_DEBUG_IF(VL_DBG_MSGF(\"+ Clock loop\\n\"););\n") + + (v3Global.opt.trace() ? "vlSymsp->__Vm_activity = true;\n" : "") + + protect("_eval") + "(vlSymsp);"), + false); if (v3Global.opt.threads() == 1) { puts("Verilated::endOfThreadMTask(vlSymsp->__Vm_evalMsgQp);\n"); } - if (v3Global.opt.threads()) { - puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n"); - } + if (v3Global.opt.threads()) puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n"); puts("}\n"); splitSizeInc(10); @@ -2467,8 +2563,9 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) { puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+eval_end_step " + prefixNameProtect(modp) + "::eval_end_step\\n\"); );\n"); puts("#ifdef VM_TRACE\n"); - puts(EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp; // Setup global symbol table\n"); - puts(EmitCBaseVisitor::symTopAssign()+"\n"); + puts(EmitCBaseVisitor::symClassVar() + + " = this->__VlSymsp; // Setup global symbol table\n"); + puts(EmitCBaseVisitor::symTopAssign() + "\n"); putsDecoration("// Tracing\n"); // SystemC's eval loop deals with calling trace, not us puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) _traceDump();\n"); @@ -2480,12 +2577,11 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) { puts("\nvoid " + prefixNameProtect(modp) + "::" + protect("_eval_initial_loop") + "(" + EmitCBaseVisitor::symClassVar() + ") {\n"); puts("vlSymsp->__Vm_didInit = true;\n"); - puts(protect("_eval_initial")+"(vlSymsp);\n"); - if (v3Global.opt.trace()) { - puts("vlSymsp->__Vm_activity = true;\n"); - } - emitSettleLoop((protect("_eval_settle")+"(vlSymsp);\n" - +protect("_eval")+"(vlSymsp);"), true); + puts(protect("_eval_initial") + "(vlSymsp);\n"); + if (v3Global.opt.trace()) puts("vlSymsp->__Vm_activity = true;\n"); + emitSettleLoop((protect("_eval_settle") + "(vlSymsp);\n" // + + protect("_eval") + "(vlSymsp);"), + true); puts("}\n"); splitSizeInc(10); } @@ -2508,40 +2604,52 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref VarSortMap varAnonMap; VarSortMap varNonanonMap; - for (int isstatic=1; isstatic>=0; isstatic--) { - if (prefixIfImp!="" && !isstatic) continue; - for (AstNode* nodep=firstp; nodep; nodep = nodep->nextp()) { + for (int isstatic = 1; isstatic >= 0; isstatic--) { + if (prefixIfImp != "" && !isstatic) continue; + for (AstNode* nodep = firstp; nodep; nodep = nodep->nextp()) { if (const AstVar* varp = VN_CAST(nodep, Var)) { bool doit = true; switch (which) { - case EVL_CLASS_IO: doit = varp->isIO(); break; + case EVL_CLASS_IO: doit = varp->isIO(); break; case EVL_CLASS_SIG: - doit = ((varp->isSignal() || varp->isClassMember()) && !varp->isIO()); break; + doit = ((varp->isSignal() || varp->isClassMember()) && !varp->isIO()); + break; case EVL_CLASS_TEMP: doit = (varp->isTemp() && !varp->isIO()); break; - case EVL_CLASS_PAR: doit = (varp->isParam() && !VN_IS(varp->valuep(), Const)); break; - case EVL_CLASS_ALL: doit = true; break; - case EVL_FUNC_ALL: doit = true; break; + case EVL_CLASS_PAR: + doit = (varp->isParam() && !VN_IS(varp->valuep(), Const)); + break; + case EVL_CLASS_ALL: doit = true; break; + case EVL_FUNC_ALL: doit = true; break; default: v3fatalSrc("Bad Case"); } if (varp->isStatic() ? !isstatic : isstatic) doit = false; if (doit) { int sigbytes = varp->dtypeSkipRefp()->widthAlignBytes(); int sortbytes = 9; - if (varp->isUsedClock() && varp->widthMin()==1) sortbytes = 0; - else if (VN_IS(varp->dtypeSkipRefp(), UnpackArrayDType)) sortbytes = 8; - else if (varp->basicp() && varp->basicp()->isOpaque()) sortbytes = 7; - else if (varp->isScBv() || varp->isScBigUint()) sortbytes = 6; - else if (sigbytes==8) sortbytes = 5; - else if (sigbytes==4) sortbytes = 4; - else if (sigbytes==2) sortbytes = 2; - else if (sigbytes==1) sortbytes = 1; - + if (varp->isUsedClock() && varp->widthMin() == 1) { + sortbytes = 0; + } else if (VN_IS(varp->dtypeSkipRefp(), UnpackArrayDType)) { + sortbytes = 8; + } else if (varp->basicp() && varp->basicp()->isOpaque()) { + sortbytes = 7; + } else if (varp->isScBv() || varp->isScBigUint()) { + sortbytes = 6; + } else if (sigbytes == 8) { + sortbytes = 5; + } else if (sigbytes == 4) { + sortbytes = 4; + } else if (sigbytes == 2) { + sortbytes = 2; + } else if (sigbytes == 1) { + sortbytes = 1; + } bool anonOk = (v3Global.opt.compLimitMembers() != 0 // Enabled - && !varp->isStatic() - && !varp->isIO() // Confusing to user + && !varp->isStatic() && !varp->isIO() // Confusing to user && !varp->isSc() // Aggregates can't be anon - && (varp->basicp() && !varp->basicp()->isOpaque()) // Aggregates can't be anon - && which != EVL_FUNC_ALL); // Anon not legal in funcs, and gcc bug free there anyhow + && (varp->basicp() + && !varp->basicp()->isOpaque()) // Aggregates can't be anon + && which != EVL_FUNC_ALL); // Anon not legal in funcs, and gcc + // bug free there anyhow if (anonOk) { varAnonMap[sortbytes].push_back(varp); } else { @@ -2570,10 +2678,8 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) { if (!v3Global.opt.mtasks()) { // Plain old serial mode. Sort by size, from small to large, // to optimize for both packing and small offsets in code. - for (VarSortMap::const_iterator it = vmap.begin(); - it != vmap.end(); ++it) { - for (VarVec::const_iterator jt = it->second.begin(); - jt != it->second.end(); ++jt) { + for (VarSortMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) { + for (VarVec::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) { sortedp->push_back(*jt); } } @@ -2602,16 +2708,14 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) { V3TSP::StateVec sorted_states; V3TSP::tspSort(states, &sorted_states); - for (V3TSP::StateVec::iterator it = sorted_states.begin(); - it != sorted_states.end(); ++it) { + for (V3TSP::StateVec::iterator it = sorted_states.begin(); it != sorted_states.end(); ++it) { const EmitVarTspSorter* statep = dynamic_cast(*it); const VarSortMap& localVmap = m2v[statep->mtaskIds()]; // use rbegin/rend to sort size large->small - for (VarSortMap::const_reverse_iterator jt = localVmap.rbegin(); - jt != localVmap.rend(); ++jt) { + for (VarSortMap::const_reverse_iterator jt = localVmap.rbegin(); jt != localVmap.rend(); + ++jt) { const VarVec& vec = jt->second; - for (VarVec::const_iterator kt = vec.begin(); - kt != vec.end(); ++kt) { + for (VarVec::const_iterator kt = vec.begin(); kt != vec.end(); ++kt) { sortedp->push_back(*kt); } } @@ -2619,8 +2723,7 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) { } } -void EmitCStmts::emitSortedVarList(const VarVec& anons, - const VarVec& nonanons, +void EmitCStmts::emitSortedVarList(const VarVec& anons, const VarVec& nonanons, const string& prefixIfImp) { string curVarCmt; // Output anons @@ -2630,25 +2733,26 @@ void EmitCStmts::emitSortedVarList(const VarVec& anons, int anonL3s = 1; int anonL2s = 1; int anonL1s = 1; - if (anonMembers > (lim*lim*lim)) { - anonL3s = (anonMembers + (lim*lim*lim) - 1) / (lim*lim*lim); + if (anonMembers > (lim * lim * lim)) { + anonL3s = (anonMembers + (lim * lim * lim) - 1) / (lim * lim * lim); anonL2s = lim; anonL1s = lim; - } else if (anonMembers > (lim*lim)) { - anonL2s = (anonMembers + (lim*lim) - 1) / (lim*lim); + } else if (anonMembers > (lim * lim)) { + anonL2s = (anonMembers + (lim * lim) - 1) / (lim * lim); anonL1s = lim; } else if (anonMembers > lim) { anonL1s = (anonMembers + lim - 1) / lim; } - if (anonL1s != 1) puts("// Anonymous structures to workaround compiler member-count bugs\n"); + if (anonL1s != 1) + puts("// Anonymous structures to workaround compiler member-count bugs\n"); VarVec::const_iterator it = anons.begin(); - for (int l3=0; l3depGraphp(); - for (const V3GraphVertex* vxp = depGraphp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (const V3GraphVertex* vxp = depGraphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { const ExecMTask* mtp = dynamic_cast(vxp); if (packedMTaskMayBlock(mtp) > 0) { puts("VlMTaskVertex __Vm_mt_" + cvtToStr(mtp->id()) + ";\n"); @@ -2780,23 +2883,24 @@ void EmitCImp::emitInt(AstNodeModule* modp) { string section; section = "\n// PORTS\n"; - if (modp->isTop()) section += ("// The application code writes and reads these signals to\n" - "// propagate new values into/out from the Verilated model.\n"); - emitVarList(modp->stmtsp(), EVL_CLASS_IO, "", section/*ref*/); + if (modp->isTop()) + section += ("// The application code writes and reads these signals to\n" + "// propagate new values into/out from the Verilated model.\n"); + emitVarList(modp->stmtsp(), EVL_CLASS_IO, "", section /*ref*/); section = "\n// LOCAL SIGNALS\n"; if (modp->isTop()) section += "// Internals; generally not touched by application code\n"; - emitVarList(modp->stmtsp(), EVL_CLASS_SIG, "", section/*ref*/); + emitVarList(modp->stmtsp(), EVL_CLASS_SIG, "", section /*ref*/); section = "\n// LOCAL VARIABLES\n"; if (modp->isTop()) section += "// Internals; generally not touched by application code\n"; - emitVarList(modp->stmtsp(), EVL_CLASS_TEMP, "", section/*ref*/); + emitVarList(modp->stmtsp(), EVL_CLASS_TEMP, "", section /*ref*/); puts("\n// INTERNAL VARIABLES\n"); if (modp->isTop()) puts("// Internals; generally not touched by application code\n"); if (!VN_IS(modp, Class)) { // Avoid clang unused error (& don't want in every object) ofp()->putsPrivate(!modp->isTop()); // private: unless top - puts(symClassName()+"* __VlSymsp; // Symbol table\n"); + puts(symClassName() + "* __VlSymsp; // Symbol table\n"); } ofp()->putsPrivate(false); // public: if (modp->isTop()) { @@ -2808,27 +2912,33 @@ void EmitCImp::emitInt(AstNodeModule* modp) { emitCoverageDecl(modp); // may flip public/private section = "\n// PARAMETERS\n"; - if (modp->isTop()) section += "// Parameters marked /*verilator public*/ for use by application code\n"; + if (modp->isTop()) + section += "// Parameters marked /*verilator public*/ for use by application code\n"; ofp()->putsPrivate(false); // public: - emitVarList(modp->stmtsp(), EVL_CLASS_PAR, "", section/*ref*/); // Only those that are non-CONST + emitVarList(modp->stmtsp(), EVL_CLASS_PAR, "", + section /*ref*/); // Only those that are non-CONST for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstVar* varp = VN_CAST(nodep, Var)) { if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) { - if (section != "") { puts(section); section = ""; } + if (section != "") { + puts(section); + section = ""; + } UASSERT_OBJ(varp->valuep(), nodep, "No init for a param?"); // These should be static const values, however microsloth VC++ doesn't // support them. They also cause problems with GDB under GCC2.95. if (varp->isWide()) { // Unsupported for output - putsDecoration("// enum WData "+varp->nameProtect()+" //wide"); + putsDecoration("// enum WData " + varp->nameProtect() + " //wide"); } else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output - //putsDecoration("// enum ..... "+varp->nameProtect() + // putsDecoration("// enum ..... "+varp->nameProtect() // +"not simple value, see variable above instead"); } else if (VN_IS(varp->dtypep(), BasicDType) - && VN_CAST(varp->dtypep(), BasicDType)->isOpaque()) { // Can't put out e.g. doubles + && VN_CAST(varp->dtypep(), BasicDType) + ->isOpaque()) { // Can't put out e.g. doubles } else { puts("enum "); - puts(varp->isQuad()?"_QData":"_IData"); - puts(""+varp->nameProtect()+" { "+varp->nameProtect()+" = "); + puts(varp->isQuad() ? "_QData" : "_IData"); + puts("" + varp->nameProtect() + " { " + varp->nameProtect() + " = "); iterateAndNextNull(varp->valuep()); puts("};"); } @@ -2859,7 +2969,8 @@ void EmitCImp::emitInt(AstNodeModule* modp) { ofp()->putsPrivate(false); // public: if (modp->isTop()) { puts("/// Construct the model; called by application code\n"); - puts("/// The special name "" may be used to make a wrapper with a\n"); + puts("/// The special name " + " may be used to make a wrapper with a\n"); puts("/// single model invisible with respect to DPI scope names.\n"); } if (VN_IS(modp, Class)) { @@ -2875,10 +2986,12 @@ void EmitCImp::emitInt(AstNodeModule* modp) { } if (v3Global.opt.trace() && modp->isTop()) { puts("/// Trace signals in the model; called by application code\n"); - puts("void trace("+v3Global.opt.traceClassBase()+"C* tfp, int levels, int options = 0);\n"); + puts("void trace(" + v3Global.opt.traceClassBase() + + "C* tfp, int levels, int options = 0);\n"); if (optSystemC()) { puts("/// SC tracing; avoid overloaded virtual function lint warning\n"); - puts("virtual void trace(sc_trace_file* tfp) const { ::sc_core::sc_module::trace(tfp); }\n"); + puts("virtual void trace(sc_trace_file* tfp) const { " + "::sc_core::sc_module::trace(tfp); }\n"); } } @@ -2888,20 +3001,32 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("\n// API METHODS\n"); string callEvalEndStep = (v3Global.needTraceDumper() && !optSystemC()) ? "eval_end_step(); " : ""; - if (optSystemC()) ofp()->putsPrivate(true); ///< eval() is invoked by our sensitive() calls. - if (!optSystemC()) puts("/// Evaluate the model. Application must call when inputs change.\n"); + if (optSystemC()) { + ofp()->putsPrivate(true); ///< eval() is invoked by our sensitive() calls. + } + if (!optSystemC()) { + puts("/// Evaluate the model. Application must call when inputs change.\n"); + } puts("void eval() { eval_step(); " + callEvalEndStep + "}\n"); - if (!optSystemC()) puts("/// Evaluate when calling multiple units/models per time step.\n"); + if (!optSystemC()) { + puts("/// Evaluate when calling multiple units/models per time step.\n"); + } puts("void eval_step();\n"); if (!optSystemC()) { puts("/// Evaluate at end of a timestep for tracing, when using eval_step().\n"); puts("/// Application must call after all eval() and before time changes.\n"); puts("void eval_end_step()"); - if (callEvalEndStep == "") puts(" {}\n"); - else puts(";\n"); + if (callEvalEndStep == "") { + puts(" {}\n"); + } else { + puts(";\n"); + } } ofp()->putsPrivate(false); // public: - if (!optSystemC()) puts("/// Simulation complete, run final blocks. Application must call on completion.\n"); + if (!optSystemC()) { + puts("/// Simulation complete, run final blocks. Application " + "must call on completion.\n"); + } puts("void final();\n"); if (v3Global.opt.inhibitSim()) { puts("/// Disable evaluation of module (e.g. turn off)\n"); @@ -2931,17 +3056,17 @@ void EmitCImp::emitInt(AstNodeModule* modp) { if (v3Global.opt.trace() && !VN_IS(modp, Class)) { ofp()->putsPrivate(false); // public: - puts("static void "+protect("traceInit")+"("+v3Global.opt.traceClassBase() - +"* vcdp, void* userthis, uint32_t code);\n"); - puts("static void "+protect("traceFull")+"("+v3Global.opt.traceClassBase() - +"* vcdp, void* userthis, uint32_t code);\n"); - puts("static void "+protect("traceChg")+"("+v3Global.opt.traceClassBase() - +"* vcdp, void* userthis, uint32_t code);\n"); + puts("static void " + protect("traceInit") + "(" + v3Global.opt.traceClassBase() + + "* vcdp, void* userthis, uint32_t code);\n"); + puts("static void " + protect("traceFull") + "(" + v3Global.opt.traceClassBase() + + "* vcdp, void* userthis, uint32_t code);\n"); + puts("static void " + protect("traceChg") + "(" + v3Global.opt.traceClassBase() + + "* vcdp, void* userthis, uint32_t code);\n"); } if (v3Global.opt.savable()) { ofp()->putsPrivate(false); // public: - puts("void "+protect("__Vserialize")+"(VerilatedSerialize& os);\n"); - puts("void "+protect("__Vdeserialize")+"(VerilatedDeserialize& os);\n"); + puts("void " + protect("__Vserialize") + "(VerilatedSerialize& os);\n"); + puts("void " + protect("__Vdeserialize") + "(VerilatedDeserialize& os);\n"); } puts("}"); @@ -2955,14 +3080,11 @@ void EmitCImp::emitInt(AstNodeModule* modp) { if (v3Global.opt.savable() && modp->isTop()) { puts("\n"); puts("inline VerilatedSerialize& operator<<(VerilatedSerialize& os, " - + prefixNameProtect(modp) + "& rhs) {\n" - + "Verilated::quiesce(); rhs." - + protect("__Vserialize") + "(os); return os; }\n"); + + prefixNameProtect(modp) + "& rhs) {\n" // + + "Verilated::quiesce(); rhs." + protect("__Vserialize") + "(os); return os; }\n"); puts("inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, " - + prefixNameProtect(modp) - + "& rhs) {\n" - + "Verilated::quiesce(); rhs." - + protect("__Vdeserialize") + "(os); return os; }\n"); + + prefixNameProtect(modp) + "& rhs) {\n" // + + "Verilated::quiesce(); rhs." + protect("__Vdeserialize") + "(os); return os; }\n"); } } @@ -2988,7 +3110,7 @@ void EmitCImp::emitImp(AstNodeModule* modp) { puts("\n//==========\n"); if (m_slow) { string section; - emitVarList(modp->stmtsp(), EVL_CLASS_ALL, prefixNameProtect(modp), section/*ref*/); + emitVarList(modp->stmtsp(), EVL_CLASS_ALL, prefixNameProtect(modp), section /*ref*/); if (!VN_IS(modp, Class)) emitCtorImp(modp); if (!VN_IS(modp, Class)) emitConfigureImp(modp); if (!VN_IS(modp, Class)) emitDestructorImp(modp); @@ -3017,7 +3139,7 @@ void EmitCImp::maybeSplit(AstNodeModule* fileModp) { // Close old file VL_DO_CLEAR(delete m_ofp, m_ofp = NULL); // Open a new file - m_ofp = newOutCFile(fileModp, !m_fast, true/*source*/, splitFilenumInc()); + m_ofp = newOutCFile(fileModp, !m_fast, true /*source*/, splitFilenumInc()); emitImpTop(fileModp); } splitSizeInc(10); // Even blank functions get a file with a low csplit @@ -3031,7 +3153,7 @@ void EmitCImp::mainInt(AstNodeModule* modp) { UINFO(5, " Emitting " << prefixNameProtect(modp) << endl); - m_ofp = newOutCFile(fileModp, false/*slow*/, false/*source*/); + m_ofp = newOutCFile(fileModp, false /*slow*/, false /*source*/); emitIntTop(modp); emitInt(modp); if (AstClassPackage* packagep = VN_CAST(modp, ClassPackage)) { @@ -3053,7 +3175,7 @@ void EmitCImp::mainImp(AstNodeModule* modp, bool slow, bool fast) { UINFO(5, " Emitting " << prefixNameProtect(modp) << endl); - m_ofp = newOutCFile(fileModp, !m_fast, true/*source*/); + m_ofp = newOutCFile(fileModp, !m_fast, true /*source*/); emitImpTop(fileModp); emitImp(modp); @@ -3071,8 +3193,8 @@ void EmitCImp::mainImp(AstNodeModule* modp, bool slow, bool fast) { // in the ExecGraph AstExecGraph* execGraphp = v3Global.rootp()->execGraphp(); const V3Graph* depGraphp = execGraphp->depGraphp(); - for (const V3GraphVertex* vxp = depGraphp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (const V3GraphVertex* vxp = depGraphp->verticesBeginp(); vxp; + vxp = vxp->verticesNextp()) { const ExecMTask* mtaskp = dynamic_cast(vxp); if (mtaskp->threadRoot()) { maybeSplit(modp); @@ -3097,20 +3219,20 @@ class EmitCTrace : EmitCStmts { AstUser1InUse m_inuser1; // MEMBERS - AstCFunc* m_funcp; // Function we're in now - bool m_slow; // Making slow file - int m_enumNum; // Enumeration number (whole netlist) - int m_baseCode; // Code of first AstTraceInc in this function + AstCFunc* m_funcp; // Function we're in now + bool m_slow; // Making slow file + int m_enumNum; // Enumeration number (whole netlist) + int m_baseCode; // Code of first AstTraceInc in this function // METHODS void newOutCFile(int filenum) { - string filename = (v3Global.opt.makeDir()+"/" - +topClassName()+"_"+protect("_Trace")); - if (filenum) filename += "__"+cvtToStr(filenum); - filename += (m_slow ? "__Slow":""); + string filename + = (v3Global.opt.makeDir() + "/" + topClassName() + "_" + protect("_Trace")); + if (filenum) filename += "__" + cvtToStr(filenum); + filename += (m_slow ? "__Slow" : ""); filename += ".cpp"; - AstCFile* cfilep = newCFile(filename, m_slow, true/*source*/); + AstCFile* cfilep = newCFile(filename, m_slow, true /*source*/); cfilep->support(true); if (m_ofp) v3fatalSrc("Previous file not closed"); @@ -3120,7 +3242,8 @@ class EmitCTrace : EmitCStmts { m_ofp = new V3OutCFile(filename); } m_ofp->putsHeader(); - m_ofp->puts("// DESCR" "IPTION: Verilator output: Tracing implementation internals\n"); + m_ofp->puts("// DESCR" + "IPTION: Verilator output: Tracing implementation internals\n"); emitTraceHeader(); } @@ -3138,64 +3261,66 @@ class EmitCTrace : EmitCStmts { if (v3Global.needTraceDumper() && !optSystemC()) { puts("void " + topClassName() + "::_traceDump() {\n"); // Caller checked for __Vm_dumperp non-NULL - puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); - puts( "__VlSymsp->__Vm_dumperp->dump(VL_TIME_Q());\n"); + puts("VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); + puts("__VlSymsp->__Vm_dumperp->dump(VL_TIME_Q());\n"); puts("}\n"); splitSizeInc(10); } if (v3Global.needTraceDumper()) { puts("void " + topClassName() + "::_traceDumpOpen() {\n"); - puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); - puts( "if (VL_UNLIKELY(!__VlSymsp->__Vm_dumperp)) {\n"); - puts( "__VlSymsp->__Vm_dumperp = new " + v3Global.opt.traceClassLang() + "();\n"); - puts( "const char* cp = vl_dumpctl_filenamep();\n"); - puts( "trace(__VlSymsp->__Vm_dumperp, 0, 0);\n"); - puts( "__VlSymsp->__Vm_dumperp->open(vl_dumpctl_filenamep());\n"); - puts( "__VlSymsp->__Vm_dumperp->changeThread();\n"); - puts( "__VlSymsp->__Vm_dumping = true;\n"); - puts( "}\n"); + puts("VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); + puts("if (VL_UNLIKELY(!__VlSymsp->__Vm_dumperp)) {\n"); + puts("__VlSymsp->__Vm_dumperp = new " + v3Global.opt.traceClassLang() + "();\n"); + puts("const char* cp = vl_dumpctl_filenamep();\n"); + puts("trace(__VlSymsp->__Vm_dumperp, 0, 0);\n"); + puts("__VlSymsp->__Vm_dumperp->open(vl_dumpctl_filenamep());\n"); + puts("__VlSymsp->__Vm_dumperp->changeThread();\n"); + puts("__VlSymsp->__Vm_dumping = true;\n"); + puts("}\n"); puts("}\n"); splitSizeInc(10); puts("void " + topClassName() + "::_traceDumpClose() {\n"); - puts( "VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); - puts( "__VlSymsp->__Vm_dumping = false;\n"); - puts( "delete __VlSymsp->__Vm_dumperp; __VlSymsp->__Vm_dumperp = NULL;\n"); + puts("VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); + puts("__VlSymsp->__Vm_dumping = false;\n"); + puts("delete __VlSymsp->__Vm_dumperp; __VlSymsp->__Vm_dumperp = NULL;\n"); puts("}\n"); splitSizeInc(10); } - puts("void "+topClassName()+"::trace("); - puts(v3Global.opt.traceClassBase()+"C* tfp, int, int) {\n"); - puts( "tfp->spTrace()->addCallback(" - "&"+topClassName()+"::"+protect("traceInit") - +", &"+topClassName()+"::"+protect("traceFull") - +", &"+topClassName()+"::"+protect("traceChg")+", this);\n"); + puts("void " + topClassName() + "::trace("); + puts(v3Global.opt.traceClassBase() + "C* tfp, int, int) {\n"); + puts("tfp->spTrace()->addCallback(" + "&" + + topClassName() + "::" + protect("traceInit") + ", &" + topClassName() + + "::" + protect("traceFull") + ", &" + topClassName() + "::" + protect("traceChg") + + ", this);\n"); puts("}\n"); splitSizeInc(10); - puts("void "+topClassName()+"::"+protect("traceInit")+"(" - +v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n"); + puts("void " + topClassName() + "::" + protect("traceInit") + "(" + + v3Global.opt.traceClassBase() + "* vcdp, void* userthis, uint32_t code) {\n"); putsDecoration("// Callback from vcd->open()\n"); - puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n"); - puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); + puts(topClassName() + "* t = (" + topClassName() + "*)userthis;\n"); + puts(EmitCBaseVisitor::symClassVar() + " = t->__VlSymsp; // Setup global symbol table\n"); puts("if (!Verilated::calcUnusedSigs()) {\n"); - puts( "VL_FATAL_MT(__FILE__, __LINE__, __FILE__,\n"); - puts( " \"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n"); + puts("VL_FATAL_MT(__FILE__, __LINE__, __FILE__,\n"); + puts(" \"Turning on wave traces requires Verilated::traceEverOn(true) call " + "before time 0.\");\n"); puts("}\n"); puts("vcdp->scopeEscape(' ');\n"); - puts("t->"+protect("traceInitThis")+"(vlSymsp, vcdp, code);\n"); + puts("t->" + protect("traceInitThis") + "(vlSymsp, vcdp, code);\n"); puts("vcdp->scopeEscape('.');\n"); // Restore so later traced files won't break puts("}\n"); splitSizeInc(10); - puts("void "+topClassName()+"::"+protect("traceFull")+"(" - +v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n"); + puts("void " + topClassName() + "::" + protect("traceFull") + "(" + + v3Global.opt.traceClassBase() + "* vcdp, void* userthis, uint32_t code) {\n"); putsDecoration("// Callback from vcd->dump()\n"); - puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n"); - puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); - puts("t->"+protect("traceFullThis")+"(vlSymsp, vcdp, code);\n"); + puts(topClassName() + "* t = (" + topClassName() + "*)userthis;\n"); + puts(EmitCBaseVisitor::symClassVar() + " = t->__VlSymsp; // Setup global symbol table\n"); + puts("t->" + protect("traceFullThis") + "(vlSymsp, vcdp, code);\n"); puts("}\n"); splitSizeInc(10); @@ -3205,13 +3330,13 @@ class EmitCTrace : EmitCStmts { void emitTraceFast() { puts("\n//======================\n\n"); - puts("void "+topClassName()+"::"+protect("traceChg")+"(" - +v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n"); + puts("void " + topClassName() + "::" + protect("traceChg") + "(" + + v3Global.opt.traceClassBase() + "* vcdp, void* userthis, uint32_t code) {\n"); putsDecoration("// Callback from vcd->dump()\n"); - puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n"); - puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); + puts(topClassName() + "* t = (" + topClassName() + "*)userthis;\n"); + puts(EmitCBaseVisitor::symClassVar() + " = t->__VlSymsp; // Setup global symbol table\n"); puts("if (vlSymsp->getClearActivity()) {\n"); - puts("t->"+protect("traceChgThis")+"(vlSymsp, vcdp, code);\n"); + puts("t->" + protect("traceChgThis") + "(vlSymsp, vcdp, code);\n"); puts("}\n"); puts("}\n"); splitSizeInc(10); @@ -3253,24 +3378,25 @@ class EmitCTrace : EmitCStmts { puts("vcdp->declBit"); } - puts("(c+"+cvtToStr(nodep->code())); - if (nodep->arrayRange().ranged()) puts("+i*"+cvtToStr(nodep->widthWords())); + puts("(c+" + cvtToStr(nodep->code())); + if (nodep->arrayRange().ranged()) puts("+i*" + cvtToStr(nodep->widthWords())); puts(","); - if (nodep->isScoped()) { - puts("Verilated::catName(scopep,"); - } + if (nodep->isScoped()) puts("Verilated::catName(scopep,"); putsQuoted(VIdProtect::protectWordsIf(nodep->showname(), nodep->protect())); - if (nodep->isScoped()) { - puts(",\" \")"); - } + if (nodep->isScoped()) puts(",\" \")"); // Direction if (v3Global.opt.traceFormat().fstFlavor()) { - puts(","+cvtToStr(enumNum)); + puts("," + cvtToStr(enumNum)); // fstVarDir - if (nodep->declDirection().isInoutish()) puts(",FST_VD_INOUT"); - else if (nodep->declDirection().isWritable()) puts(",FST_VD_OUTPUT"); - else if (nodep->declDirection().isNonOutput()) puts(",FST_VD_INPUT"); - else puts(", FST_VD_IMPLICIT"); + if (nodep->declDirection().isInoutish()) { + puts(",FST_VD_INOUT"); + } else if (nodep->declDirection().isWritable()) { + puts(",FST_VD_OUTPUT"); + } else if (nodep->declDirection().isNonOutput()) { + puts(",FST_VD_INPUT"); + } else { + puts(", FST_VD_IMPLICIT"); + } // // fstVarType AstVarType vartype = nodep->varType(); @@ -3280,8 +3406,11 @@ class EmitCTrace : EmitCStmts { if (nodep->dtypep()->basicp()->isDouble()) { if (vartype == AstVarType::GPARAM || vartype == AstVarType::LPARAM) { fstvt = "FST_VT_VCD_REAL_PARAMETER"; - } else fstvt = "FST_VT_VCD_REAL"; + } else { + fstvt = "FST_VT_VCD_REAL"; + } } + // clang-format off else if (vartype == AstVarType::GPARAM) fstvt = "FST_VT_VCD_PARAMETER"; else if (vartype == AstVarType::LPARAM) fstvt = "FST_VT_VCD_PARAMETER"; else if (vartype == AstVarType::SUPPLY0) fstvt = "FST_VT_VCD_SUPPLY0"; @@ -3300,6 +3429,7 @@ class EmitCTrace : EmitCStmts { else if (kwd == AstBasicDTypeKwd::LONGINT) fstvt = "FST_VT_SV_LONGINT"; else if (kwd == AstBasicDTypeKwd::BYTE) fstvt = "FST_VT_SV_BYTE"; else fstvt = "FST_VT_SV_BIT"; + // clang-format on // // Not currently supported // FST_VT_VCD_EVENT @@ -3314,7 +3444,7 @@ class EmitCTrace : EmitCStmts { // FST_VT_VCD_WOR // FST_VT_SV_ENUM // FST_VT_GEN_STRING - puts(","+fstvt); + puts("," + fstvt); } // Range if (nodep->arrayRange().ranged()) { @@ -3341,31 +3471,28 @@ class EmitCTrace : EmitCStmts { enump->user1(enumNum); int nvals = 0; puts("{\n"); - puts("const char* "+protect("__VenumItemNames")+"[]\n"); + puts("const char* " + protect("__VenumItemNames") + "[]\n"); puts("= {"); for (AstEnumItem* itemp = enump->itemsp(); itemp; itemp = VN_CAST(itemp->nextp(), EnumItem)) { if (++nvals > 1) puts(", "); - putbs("\""+itemp->prettyName()+"\""); + putbs("\"" + itemp->prettyName() + "\""); } puts("};\n"); nvals = 0; - puts("const char* "+protect("__VenumItemValues")+"[]\n"); + puts("const char* " + protect("__VenumItemValues") + "[]\n"); puts("= {"); for (AstEnumItem* itemp = enump->itemsp(); itemp; itemp = VN_CAST(itemp->nextp(), EnumItem)) { AstConst* constp = VN_CAST(itemp->valuep(), Const); if (++nvals > 1) puts(", "); - putbs("\""+constp->num().displayed(nodep, "%0b")+"\""); + putbs("\"" + constp->num().displayed(nodep, "%0b") + "\""); } puts("};\n"); - puts("vcdp->declDTypeEnum("+cvtToStr(enumNum) - +", \""+enump->prettyName()+"\", " - +cvtToStr(nvals) - +", "+cvtToStr(enump->widthMin()) - +", "+protect("__VenumItemNames") - +", "+protect("__VenumItemValues") - +");\n"); + puts("vcdp->declDTypeEnum(" + cvtToStr(enumNum) + ", \"" + enump->prettyName() + + "\", " + cvtToStr(nvals) + ", " + cvtToStr(enump->widthMin()) + ", " + + protect("__VenumItemNames") + ", " + protect("__VenumItemValues") + + ");\n"); puts("}\n"); } return enumNum; @@ -3378,7 +3505,8 @@ class EmitCTrace : EmitCStmts { iterateAndNextNull(nodep->precondsp()); string full = ((m_funcp->funcType() == AstCFuncType::TRACE_FULL || m_funcp->funcType() == AstCFuncType::TRACE_FULL_SUB) - ? "full":"chg"); + ? "full" + : "chg"); bool emitWidth = false; if (nodep->dtypep()->basicp()->isDouble()) { puts("vcdp->" + full + "Double"); @@ -3406,19 +3534,30 @@ class EmitCTrace : EmitCStmts { AstVarRef* varrefp = VN_CAST(nodep->valuep(), VarRef); AstVar* varp = varrefp->varp(); puts("("); - if (emitTraceIsScBigUint(nodep)) puts("(vluint32_t*)"); - else if (emitTraceIsScBv(nodep)) puts("VL_SC_BV_DATAP("); + if (emitTraceIsScBigUint(nodep)) { + puts("(vluint32_t*)"); + } else if (emitTraceIsScBv(nodep)) { + puts("VL_SC_BV_DATAP("); + } iterate(varrefp); // Put var name out // Tracing only supports 1D arrays if (nodep->declp()->arrayRange().ranged()) { - if (arrayindex==-2) puts("[i]"); - else if (arrayindex==-1) puts("[0]"); - else puts("["+cvtToStr(arrayindex)+"]"); + if (arrayindex == -2) { + puts("[i]"); + } else if (arrayindex == -1) { + puts("[0]"); + } else { + puts("[" + cvtToStr(arrayindex) + "]"); + } } if (varp->isSc()) puts(".read()"); - if (emitTraceIsScUint(nodep)) puts(nodep->isQuad() ? ".to_uint64()" : ".to_uint()"); - else if (emitTraceIsScBigUint(nodep)) puts(".get_raw()"); - else if (emitTraceIsScBv(nodep)) puts(")"); + if (emitTraceIsScUint(nodep)) { + puts(nodep->isQuad() ? ".to_uint64()" : ".to_uint()"); + } else if (emitTraceIsScBigUint(nodep)) { + puts(".get_raw()"); + } else if (emitTraceIsScBv(nodep)) { + puts(")"); + } puts(")"); } else { puts("("); @@ -3433,9 +3572,7 @@ class EmitCTrace : EmitCStmts { // Top module only iterate(nodep->topModulep()); } - virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } + virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { iterateChildren(nodep); } virtual void visit(AstCFunc* nodep) VL_OVERRIDE { if (nodep->slow() != m_slow) return; if (nodep->funcType().isTrace()) { // TRACE_* @@ -3451,11 +3588,11 @@ class EmitCTrace : EmitCStmts { splitSizeInc(nodep); puts("\n"); - puts(nodep->rtnTypeVoid()); puts(" "); - puts(topClassName()+"::"+nodep->nameProtect() - +"("+cFuncArgs(nodep)+") {\n"); + puts(nodep->rtnTypeVoid()); + puts(" "); + puts(topClassName() + "::" + nodep->nameProtect() + "(" + cFuncArgs(nodep) + ") {\n"); - if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign()+"\n"); + if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign() + "\n"); m_baseCode = -1; @@ -3482,7 +3619,9 @@ class EmitCTrace : EmitCStmts { } else if (nodep->funcType() == AstCFuncType::TRACE_FULL_SUB) { } else if (nodep->funcType() == AstCFuncType::TRACE_CHANGE) { } else if (nodep->funcType() == AstCFuncType::TRACE_CHANGE_SUB) { - } else nodep->v3fatalSrc("Bad Case"); + } else { + nodep->v3fatalSrc("Bad Case"); + } if (nodep->initsp()) { string section; @@ -3508,7 +3647,7 @@ class EmitCTrace : EmitCStmts { virtual void visit(AstTraceDecl* nodep) VL_OVERRIDE { int enumNum = emitTraceDeclDType(nodep->dtypep()); if (nodep->arrayRange().ranged()) { - puts("{int i; for (i=0; i<"+cvtToStr(nodep->arrayRange().elements())+"; i++) {\n"); + puts("{int i; for (i=0; i<" + cvtToStr(nodep->arrayRange().elements()) + "; i++) {\n"); emitTraceInitOne(nodep, enumNum); puts("}}\n"); } else { @@ -3519,17 +3658,15 @@ class EmitCTrace : EmitCStmts { virtual void visit(AstTraceInc* nodep) VL_OVERRIDE { if (nodep->declp()->arrayRange().ranged()) { // It traces faster if we unroll the loop - for (int i=0; ideclp()->arrayRange().elements(); i++) { + for (int i = 0; i < nodep->declp()->arrayRange().elements(); i++) { emitTraceChangeOne(nodep, i); } } else { emitTraceChangeOne(nodep, -1); } } - virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE { - } - virtual void visit(AstCoverInc* nodep) VL_OVERRIDE { - } + virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {} + virtual void visit(AstCoverInc* nodep) VL_OVERRIDE {} public: explicit EmitCTrace(bool slow) { @@ -3542,8 +3679,11 @@ public: // Put out the file newOutCFile(0); - if (m_slow) emitTraceSlow(); - else emitTraceFast(); + if (m_slow) { + emitTraceSlow(); + } else { + emitTraceFast(); + } iterate(v3Global.rootp()); @@ -3555,11 +3695,12 @@ public: // EmitC class functions void V3EmitC::emitc() { - UINFO(2,__FUNCTION__<<": "<modulesp(); - nodep; nodep = VN_CAST(nodep->nextp(), NodeModule)) { + for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; + nodep = VN_CAST(nodep->nextp(), NodeModule)) { if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage + // clang-format off { EmitCImp cint; cint.mainInt(nodep); } if (v3Global.opt.outputSplit()) { { EmitCImp fast; fast.mainImp(nodep, false, true); } @@ -3567,25 +3708,29 @@ void V3EmitC::emitc() { } else { { EmitCImp both; both.mainImp(nodep, true, true); } } + // clang-format on } } void V3EmitC::emitcTrace() { - UINFO(2,__FUNCTION__<<": "<filesp(); filep; filep = VN_CAST(filep->nextp(), NodeFile)) { AstCFile* cfilep = VN_CAST(filep, CFile); if (cfilep && cfilep->tblockp()) { V3OutCFile of(cfilep->name()); - of.puts("// DESCR" "IPTION: Verilator generated C++\n"); + of.puts("// DESCR" + "IPTION: Verilator generated C++\n"); EmitCStmts visitor(cfilep->tblockp(), &of, true); } } diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index d0c9d76f8..8e98efafe 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -39,23 +39,32 @@ public: V3OutCFile* ofp() const { return m_ofp; } void puts(const string& str) { ofp()->puts(str); } void putbs(const string& str) { ofp()->putbs(str); } - void putsDecoration(const string& str) { if (v3Global.opt.decoration()) puts(str); } + void putsDecoration(const string& str) { + if (v3Global.opt.decoration()) puts(str); + } void putsQuoted(const string& str) { ofp()->putsQuoted(str); } bool optSystemC() { return v3Global.opt.systemC(); } static string protect(const string& name) { return VIdProtect::protectIf(name, true); } static string protectIf(const string& name, bool doIt) { - return VIdProtect::protectIf(name, doIt); } + return VIdProtect::protectIf(name, doIt); + } static string protectWordsIf(const string& name, bool doIt) { - return VIdProtect::protectWordsIf(name, doIt); } + return VIdProtect::protectWordsIf(name, doIt); + } static string ifNoProtect(const string& in) { return v3Global.opt.protectIds() ? "" : in; } - static string symClassName() { return v3Global.opt.prefix()+"_"+protect("_Syms"); } - static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; } + static string symClassName() { return v3Global.opt.prefix() + "_" + protect("_Syms"); } + static string symClassVar() { return symClassName() + "* __restrict vlSymsp"; } static string symTopAssign() { - return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; } + return v3Global.opt.prefix() + "* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; + } static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) { - if (nodep->isConstructor()) return prefixNameProtect(modp); - else if (nodep->isDestructor()) return string("~") + prefixNameProtect(modp); - else return nodep->nameProtect(); + if (nodep->isConstructor()) { + return prefixNameProtect(modp); + } else if (nodep->isDestructor()) { + return string("~") + prefixNameProtect(modp); + } else { + return nodep->nameProtect(); + } } static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix const AstNodeModule* modp = VN_CAST_CONST(nodep, NodeModule); @@ -79,15 +88,17 @@ public: // Return argument list for given C function string args = nodep->argTypes(); // Might be a user function with argument list. - for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) { + for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) { if (const AstVar* portp = VN_CAST_CONST(stmtp, Var)) { if (portp->isIO() && !portp->isFuncReturn()) { - if (args != "") args+= ", "; - if (nodep->dpiImport() || nodep->dpiExportWrapper()) + if (args != "") args += ", "; + if (nodep->dpiImport() || nodep->dpiExportWrapper()) { args += portp->dpiArgType(true, false); - else if (nodep->funcPublic()) + } else if (nodep->funcPublic()) { args += portp->cPubArgType(true, false); - else args += portp->vlArgType(true, false, true); + } else { + args += portp->vlArgType(true, false, true); + } } } } @@ -114,6 +125,7 @@ private: m_count++; iterateChildren(nodep); } + public: // CONSTRUCTORS explicit EmitCBaseCounterVisitor(AstNode* nodep) { diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 2eed8feb8..793ce9bbc 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -35,8 +35,7 @@ class CMakeEmitter { // STATIC FUNCTIONS // Concatenate all strings in 'strs' with ' ' between them. - template - static string cmake_list(const List& strs) { + template static string cmake_list(const List& strs) { string s; if (strs.begin() != strs.end()) { s.append("\""); @@ -56,16 +55,14 @@ class CMakeEmitter { // "BOOL", "FILEPATH", "PATH", "STRING" or "INTERNAL" for a CACHE variable // See https://cmake.org/cmake/help/latest/command/set.html static void cmake_set_raw(std::ofstream& of, const string& name, const string& raw_value, - const string& cache_type = "", const string& docstring = "") { + const string& cache_type = "", const string& docstring = "") { of << "set(" << name << " " << raw_value; - if (!cache_type.empty()) { - of << " CACHE " << cache_type << " \"" << docstring << "\""; - } + if (!cache_type.empty()) { of << " CACHE " << cache_type << " \"" << docstring << "\""; } of << ")\n"; } static void cmake_set(std::ofstream& of, const string& name, const string& value, - const string& cache_type = "", const string& docstring = "") { + const string& cache_type = "", const string& docstring = "") { string raw_value = "\"" + value + "\""; cmake_set_raw(of, name, raw_value, cache_type, docstring); } @@ -80,22 +77,24 @@ class CMakeEmitter { } static void emitOverallCMake() { - const vl_unique_ptr - of (V3File::new_ofstream(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".cmake")); + const vl_unique_ptr of( + V3File::new_ofstream(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".cmake")); string name = v3Global.opt.prefix(); *of << "# Verilated -*- CMake -*-\n"; - *of << "# DESCR" "IPTION: Verilator output: CMake include script with class lists\n"; + *of << "# DESCR" + "IPTION: Verilator output: CMake include script with class lists\n"; *of << "#\n"; - *of << "# This CMake script lists generated Verilated files, for including in higher level CMake scripts.\n"; + *of << "# This CMake script lists generated Verilated files, for " + "including in higher level CMake scripts.\n"; *of << "# This file is meant to be consumed by the verilate() function,\n"; *of << "# which becomes available after executing `find_package(verilator).\n"; *of << "\n### Constants...\n"; - cmake_set(*of, "PERL", deslash(V3Options::getenvPERL()), - "FILEPATH", "Perl executable (from $PERL)"); - cmake_set(*of, "VERILATOR_ROOT", deslash(V3Options::getenvVERILATOR_ROOT()), - "PATH", "Path to Verilator kit (from $VERILATOR_ROOT)"); + cmake_set(*of, "PERL", deslash(V3Options::getenvPERL()), "FILEPATH", + "Perl executable (from $PERL)"); + cmake_set(*of, "VERILATOR_ROOT", deslash(V3Options::getenvVERILATOR_ROOT()), "PATH", + "Path to Verilator kit (from $VERILATOR_ROOT)"); *of << "\n### Compiler flags...\n"; @@ -110,13 +109,19 @@ class CMakeEmitter { *of << "# SystemC output mode? 0/1 (from --sc)\n"; cmake_set_raw(*of, name + "_SC", v3Global.opt.systemC() ? "1" : "0"); *of << "# Coverage output mode? 0/1 (from --coverage)\n"; - cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage()?"1":"0"); + cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage() ? "1" : "0"); *of << "# Threaded output mode? 0/1/N threads (from --threads)\n"; cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads())); *of << "# VCD Tracing output mode? 0/1 (from --trace)\n"; - cmake_set_raw(*of, name + "_TRACE_VCD", (v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD))?"1":"0"); + cmake_set_raw(*of, name + "_TRACE_VCD", + (v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD)) + ? "1" + : "0"); *of << "# FST Tracing output mode? 0/1 (from --fst-trace)\n"; - cmake_set_raw(*of, name + "_TRACE_FST", (v3Global.opt.trace() && (v3Global.opt.traceFormat() != TraceFormat::VCD)) ? "1":"0"); + cmake_set_raw(*of, name + "_TRACE_FST", + (v3Global.opt.trace() && (v3Global.opt.traceFormat() != TraceFormat::VCD)) + ? "1" + : "0"); *of << "\n### Sources...\n"; std::vector classes_fast, classes_slow, support_fast, support_slow, global; @@ -141,7 +146,7 @@ class CMakeEmitter { } global.push_back("${VERILATOR_ROOT}/include/verilated.cpp"); - if (v3Global.dpi()) { + if (v3Global.dpi()) { // global.push_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp"); } if (v3Global.opt.vpi()) { @@ -154,21 +159,22 @@ class CMakeEmitter { global.push_back("${VERILATOR_ROOT}/include/verilated_cov.cpp"); } if (v3Global.opt.trace()) { - global.push_back("${VERILATOR_ROOT}/include/" - + v3Global.opt.traceSourceBase() + "_c.cpp"); + global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase() + + "_c.cpp"); if (v3Global.opt.systemC()) { if (v3Global.opt.traceFormat() != TraceFormat::VCD) { - v3error("Unsupported: This trace format is not supported in SystemC, use VCD format."); + v3error("Unsupported: This trace format is not supported in SystemC, " + "use VCD format."); } - global.push_back("${VERILATOR_ROOT}/include/" - + v3Global.opt.traceSourceLang() + ".cpp"); + global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang() + + ".cpp"); } } if (v3Global.opt.mtasks()) { global.push_back("${VERILATOR_ROOT}/include/verilated_threads.cpp"); } if (!v3Global.opt.protectLib().empty()) { - global.push_back(v3Global.opt.makeDir()+"/"+v3Global.opt.protectLib()+".cpp"); + global.push_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp"); } *of << "# Global classes, need linked once per executable\n"; @@ -177,7 +183,8 @@ class CMakeEmitter { cmake_set_raw(*of, name + "_CLASSES_SLOW", deslash(cmake_list(classes_slow))); *of << "# Generated module classes, fast-path, compile with highest optimization\n"; cmake_set_raw(*of, name + "_CLASSES_FAST", deslash(cmake_list(classes_fast))); - *of << "# Generated support classes, non-fast-path, compile with low/medium optimization\n"; + *of << "# Generated support classes, non-fast-path, compile with " + "low/medium optimization\n"; cmake_set_raw(*of, name + "_SUPPORT_SLOW", deslash(cmake_list(support_slow))); *of << "# Generated support classes, fast-path, compile with highest optimization\n"; cmake_set_raw(*of, name + "_SUPPORT_FAST", deslash(cmake_list(support_fast))); @@ -188,14 +195,13 @@ class CMakeEmitter { *of << "# User .cpp files (from .cpp's on Verilator command line)\n"; cmake_set_raw(*of, name + "_USER_CLASSES", deslash(cmake_list(v3Global.opt.cppFiles()))); } + public: - explicit CMakeEmitter() { - emitOverallCMake(); - } + explicit CMakeEmitter() { emitOverallCMake(); } virtual ~CMakeEmitter() {} }; void V3EmitCMake::emit() { - UINFO(2,__FUNCTION__<<": "<filesp(); - nodep; nodep = VN_CAST(nodep->nextp(), NodeFile)) { + if (v3Global.opt.mtasks()) { putMakeClassEntry(of, "verilated_threads.cpp"); } + } else if (support == 2 && slow) { + } else { + for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep; + nodep = VN_CAST(nodep->nextp(), NodeFile)) { AstCFile* cfilep = VN_CAST(nodep, CFile); - if (cfilep && cfilep->source() - && cfilep->slow()==(slow!=0) - && cfilep->support()==(support!=0)) { + if (cfilep && cfilep->source() && cfilep->slow() == (slow != 0) + && cfilep->support() == (support != 0)) { putMakeClassEntry(of, cfilep->name()); } } @@ -122,55 +126,56 @@ public: void emitOverallMake() { // Generate the makefile - V3OutMkFile of (v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".mk"); + V3OutMkFile of(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".mk"); of.putsHeader(); - of.puts("# DESCR" "IPTION: Verilator output: Makefile for building Verilated archive or executable\n"); + of.puts("# DESCR" + "IPTION: Verilator output: " + "Makefile for building Verilated archive or executable\n"); of.puts("#\n"); of.puts("# Execute this makefile from the object directory:\n"); - of.puts("# make -f "+v3Global.opt.prefix()+".mk"+"\n"); + of.puts("# make -f " + v3Global.opt.prefix() + ".mk" + "\n"); of.puts("\n"); if (v3Global.opt.exe()) { - of.puts("default: "+v3Global.opt.exeName()+"\n"); + of.puts("default: " + v3Global.opt.exeName() + "\n"); } else if (!v3Global.opt.protectLib().empty()) { - of.puts("default: lib"+v3Global.opt.protectLib()+"\n"); + of.puts("default: lib" + v3Global.opt.protectLib() + "\n"); } else { - of.puts("default: "+v3Global.opt.prefix()+"__ALL.a\n"); + of.puts("default: " + v3Global.opt.prefix() + "__ALL.a\n"); } of.puts("\n### Constants...\n"); of.puts("# Perl executable (from $PERL)\n"); - of.puts("PERL = "+V3Options::getenvPERL()+"\n"); + of.puts("PERL = " + V3Options::getenvPERL() + "\n"); of.puts("# Path to Verilator kit (from $VERILATOR_ROOT)\n"); - of.puts("VERILATOR_ROOT = "+V3Options::getenvVERILATOR_ROOT()+"\n"); + of.puts("VERILATOR_ROOT = " + V3Options::getenvVERILATOR_ROOT() + "\n"); of.puts("# SystemC include directory with systemc.h (from $SYSTEMC_INCLUDE)\n"); - of.puts(string("SYSTEMC_INCLUDE ?= ")+V3Options::getenvSYSTEMC_INCLUDE()+"\n"); + of.puts(string("SYSTEMC_INCLUDE ?= ") + V3Options::getenvSYSTEMC_INCLUDE() + "\n"); of.puts("# SystemC library directory with libsystemc.a (from $SYSTEMC_LIBDIR)\n"); - of.puts(string("SYSTEMC_LIBDIR ?= ")+V3Options::getenvSYSTEMC_LIBDIR()+"\n"); + of.puts(string("SYSTEMC_LIBDIR ?= ") + V3Options::getenvSYSTEMC_LIBDIR() + "\n"); of.puts("\n### Switches...\n"); of.puts("# SystemC output mode? 0/1 (from --sc)\n"); - of.puts(string("VM_SC = ")+((v3Global.opt.systemC())?"1":"0")+"\n"); + of.puts(string("VM_SC = ") + ((v3Global.opt.systemC()) ? "1" : "0") + "\n"); of.puts("# Legacy or SystemC output mode? 0/1 (from --sc)\n"); of.puts(string("VM_SP_OR_SC = $(VM_SC)\n")); of.puts("# Deprecated\n"); - of.puts(string("VM_PCLI = ")+(v3Global.opt.systemC()?"0":"1")+"\n"); - of.puts("# Deprecated: SystemC architecture to find link library path (from $SYSTEMC_ARCH)\n"); - of.puts(string("VM_SC_TARGET_ARCH = ")+V3Options::getenvSYSTEMC_ARCH()+"\n"); + of.puts(string("VM_PCLI = ") + (v3Global.opt.systemC() ? "0" : "1") + "\n"); + of.puts( + "# Deprecated: SystemC architecture to find link library path (from $SYSTEMC_ARCH)\n"); + of.puts(string("VM_SC_TARGET_ARCH = ") + V3Options::getenvSYSTEMC_ARCH() + "\n"); of.puts("\n### Vars...\n"); of.puts("# Design prefix (from --prefix)\n"); - of.puts(string("VM_PREFIX = ")+v3Global.opt.prefix()+"\n"); + of.puts(string("VM_PREFIX = ") + v3Global.opt.prefix() + "\n"); of.puts("# Module prefix (from --prefix)\n"); - of.puts(string("VM_MODPREFIX = ")+v3Global.opt.modPrefix()+"\n"); + of.puts(string("VM_MODPREFIX = ") + v3Global.opt.modPrefix() + "\n"); of.puts("# User CFLAGS (from -CFLAGS on Verilator command line)\n"); of.puts("VM_USER_CFLAGS = \\\n"); - if (!v3Global.opt.protectLib().empty()) { - of.puts("\t-fPIC \\\n"); - } + if (!v3Global.opt.protectLib().empty()) of.puts("\t-fPIC \\\n"); const V3StringList& cFlags = v3Global.opt.cFlags(); for (V3StringList::const_iterator it = cFlags.begin(); it != cFlags.end(); ++it) { - of.puts("\t"+*it+" \\\n"); + of.puts("\t" + *it + " \\\n"); } of.puts("\n"); @@ -178,7 +183,7 @@ public: of.puts("VM_USER_LDLIBS = \\\n"); const V3StringList& ldLibs = v3Global.opt.ldLibs(); for (V3StringList::const_iterator it = ldLibs.begin(); it != ldLibs.end(); ++it) { - of.puts("\t"+*it+" \\\n"); + of.puts("\t" + *it + " \\\n"); } of.puts("\n"); @@ -188,7 +193,7 @@ public: const V3StringSet& cppFiles = v3Global.opt.cppFiles(); for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) { string cppfile = *it; - of.puts("\t"+V3Os::filenameNonExt(cppfile)+" \\\n"); + of.puts("\t" + V3Os::filenameNonExt(cppfile) + " \\\n"); string dir = V3Os::filenameDir(cppfile); dirs.insert(dir); } @@ -196,14 +201,14 @@ public: of.puts("# User .cpp directories (from .cpp's on Verilator command line)\n"); of.puts("VM_USER_DIR = \\\n"); - for (V3StringSet::iterator it = dirs.begin(); it!=dirs.end(); ++it) { - of.puts("\t"+*it+" \\\n"); + for (V3StringSet::iterator it = dirs.begin(); it != dirs.end(); ++it) { + of.puts("\t" + *it + " \\\n"); } of.puts("\n"); of.puts("\n### Default rules...\n"); of.puts("# Include list of all generated classes\n"); - of.puts("include "+v3Global.opt.prefix()+"_classes.mk\n"); + of.puts("include " + v3Global.opt.prefix() + "_classes.mk\n"); of.puts("# Include global rules\n"); of.puts("include $(VERILATOR_ROOT)/include/verilated.mk\n"); @@ -215,12 +220,13 @@ public: string cppfile = *it; string basename = V3Os::filenameNonExt(cppfile); // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - of.puts(basename+".o: "+cppfile+"\n"); + of.puts(basename + ".o: " + cppfile + "\n"); of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<\n"); } of.puts("\n### Link rules... (from --exe)\n"); - of.puts(v3Global.opt.exeName()+": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a\n"); + of.puts(v3Global.opt.exeName() + + ": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a\n"); of.puts("\t$(LINK) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ $(LIBS) $(SC_LIBS)\n"); of.puts("\n"); } @@ -229,18 +235,20 @@ public: of.puts("\n### Library rules... (from --protect-lib)\n"); of.puts("# Using -fPIC objects for both static and dynamic libraries " "(which appears to work)\n"); - of.puts(v3Global.opt.protectLibName(false)+": $(VK_OBJS) $(VK_GLOBAL_OBJS)\n"); - of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o "+ - v3Global.opt.protectLib()+".o "+v3Global.opt.protectLib()+".cpp\n"); - of.puts("\tar rc $@ $^ "+v3Global.opt.protectLib()+".o\n"); + of.puts(v3Global.opt.protectLibName(false) + ": $(VK_OBJS) $(VK_GLOBAL_OBJS)\n"); + of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o " + + v3Global.opt.protectLib() + ".o " + v3Global.opt.protectLib() + ".cpp\n"); + of.puts("\tar rc $@ $^ " + v3Global.opt.protectLib() + ".o\n"); of.puts("\n"); - of.puts(v3Global.opt.protectLibName(true)+": $(VM_PREFIX)__ALL.a $(VK_GLOBAL_OBJS)\n"); - of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ "+v3Global.opt.protectLib()+".cpp $^\n"); + of.puts(v3Global.opt.protectLibName(true) + + ": $(VM_PREFIX)__ALL.a $(VK_GLOBAL_OBJS)\n"); + of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ " + + v3Global.opt.protectLib() + ".cpp $^\n"); of.puts("\n"); - of.puts("lib"+v3Global.opt.protectLib()+": "+v3Global.opt.protectLibName(false)+ - " "+v3Global.opt.protectLibName(true)+"\n"); + of.puts("lib" + v3Global.opt.protectLib() + ": " + v3Global.opt.protectLibName(false) + + " " + v3Global.opt.protectLibName(true) + "\n"); } of.puts("\n"); @@ -259,6 +267,6 @@ public: // Gate class functions void V3EmitMk::emitmk() { - UINFO(2,__FUNCTION__<<": "<verilogKwd() + " " + prefixNameProtect(nodep) + ";\n"); iterateChildren(nodep); putqs(nodep, "end" + nodep->verilogKwd() + "\n"); } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { - putfs(nodep, nodep->isFunction() ? "function":"task"); + putfs(nodep, nodep->isFunction() ? "function" : "task"); puts(" "); puts(nodep->prettyName()); puts(";\n"); - putqs(nodep, "begin\n"); // Only putfs the first time for each visitor; later for same node is putqs + // Only putfs the first time for each visitor; later for same node is putqs + putqs(nodep, "begin\n"); iterateAndNextNull(nodep->stmtsp()); putqs(nodep, "end\n"); } @@ -75,7 +74,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { if (nodep->name() == "") { putbs("begin\n"); } else { - putbs("begin : "+nodep->name()+"\n"); + putbs("begin : " + nodep->name() + "\n"); } iterateChildren(nodep); puts("end\n"); @@ -92,23 +91,31 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } virtual void visit(AstAlways* nodep) VL_OVERRIDE { putfs(nodep, "always "); - if (m_sensesp) iterateAndNextNull(m_sensesp); // In active - else iterateAndNextNull(nodep->sensesp()); + if (m_sensesp) { + iterateAndNextNull(m_sensesp); + } // In active + else { + iterateAndNextNull(nodep->sensesp()); + } putbs(" begin\n"); iterateAndNextNull(nodep->bodysp()); putqs(nodep, "end\n"); } virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { putfs(nodep, "/*verilator public_flat_rw "); - if (m_sensesp) iterateAndNextNull(m_sensesp); // In active - else iterateAndNextNull(nodep->sensesp()); + if (m_sensesp) { + iterateAndNextNull(m_sensesp); + } // In active + else { + iterateAndNextNull(nodep->sensesp()); + } putqs(nodep, " "); iterateAndNextNull(nodep->bodysp()); putqs(nodep, "*/\n"); } virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->lhsp()); - putfs(nodep, " "+nodep->verilogKwd()+" "); + putfs(nodep, " " + nodep->verilogKwd() + " "); iterateAndNextNull(nodep->rhsp()); if (!m_suppressSemi) puts(";\n"); } @@ -139,7 +146,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { virtual void visit(AstSenTree* nodep) VL_OVERRIDE { // AstSenItem is called for dumping in isolation by V3Order putfs(nodep, "@("); - for (AstNode* expp=nodep->sensesp(); expp; expp = expp->nextp()) { + for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) { iterate(expp); if (expp->nextp()) putqs(expp->nextp(), " or "); } @@ -178,13 +185,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { virtual void visit(AstCaseItem* nodep) VL_OVERRIDE { if (nodep->condsp()) { iterateAndNextNull(nodep->condsp()); - } else putbs("default"); + } else { + putbs("default"); + } putfs(nodep, ": begin "); iterateAndNextNull(nodep->bodysp()); putqs(nodep, "end\n"); } virtual void visit(AstComment* nodep) VL_OVERRIDE { - puts(string("// ")+nodep->name()+"\n"); + puts(string("// ") + nodep->name() + "\n"); iterateChildren(nodep); } virtual void visit(AstContinue* nodep) VL_OVERRIDE { @@ -195,20 +204,23 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { virtual void visit(AstCoverInc*) VL_OVERRIDE {} // N/A virtual void visit(AstCoverToggle*) VL_OVERRIDE {} // N/A - void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, - const string& text, AstNode* exprsp) { + void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text, + AstNode* exprsp) { putfs(nodep, nodep->verilogKwd()); putbs(" ("); - if (fileOrStrgp) { iterateAndNextNull(fileOrStrgp); putbs(","); } + if (fileOrStrgp) { + iterateAndNextNull(fileOrStrgp); + putbs(","); + } putsQuoted(text); - for (AstNode* expp=exprsp; expp; expp = expp->nextp()) { + for (AstNode* expp = exprsp; expp; expp = expp->nextp()) { puts(","); iterateAndNextNull(expp); } puts(");\n"); } virtual void visit(AstDisable* nodep) VL_OVERRIDE { - putbs("disable "+nodep->name()+";\n"); + putbs("disable " + nodep->name() + ";\n"); } virtual void visit(AstDisplay* nodep) VL_OVERRIDE { visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp()); @@ -251,10 +263,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { puts(");\n"); } virtual void visit(AstJumpGo* nodep) VL_OVERRIDE { - putbs("disable "+cvtToHex(nodep->labelp())+";\n"); + putbs("disable " + cvtToHex(nodep->labelp()) + ";\n"); } virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE { - putbs("begin : "+cvtToHex(nodep)+"\n"); + putbs("begin : " + cvtToHex(nodep) + "\n"); if (nodep->stmtsp()) iterateAndNextNull(nodep->stmtsp()); puts("end\n"); } @@ -264,8 +276,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep()); putbs(","); if (nodep->memp()) iterateAndNextNull(nodep->memp()); - if (nodep->lsbp()) { putbs(","); iterateAndNextNull(nodep->lsbp()); } - if (nodep->msbp()) { putbs(","); iterateAndNextNull(nodep->msbp()); } + if (nodep->lsbp()) { + putbs(","); + iterateAndNextNull(nodep->lsbp()); + } + if (nodep->msbp()) { + putbs(","); + iterateAndNextNull(nodep->msbp()); + } puts(");\n"); } virtual void visit(AstSysFuncAsTask* nodep) VL_OVERRIDE { @@ -340,12 +358,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { iterateAndNextNull(nodep->lhsp()); puts(";\n"); } - virtual void visit(AstStop* nodep) VL_OVERRIDE { - putfs(nodep, "$stop;\n"); - } - virtual void visit(AstFinish* nodep) VL_OVERRIDE { - putfs(nodep, "$finish;\n"); - } + virtual void visit(AstStop* nodep) VL_OVERRIDE { putfs(nodep, "$stop;\n"); } + virtual void visit(AstFinish* nodep) VL_OVERRIDE { putfs(nodep, "$finish;\n"); } virtual void visit(AstNodeSimpleText* nodep) VL_OVERRIDE { if (nodep->tracking() || m_trackText) { puts(nodep->text()); @@ -360,8 +374,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { if (nodep->commas() && childp->nextp()) puts(", "); } } - virtual void visit(AstScopeName* nodep) VL_OVERRIDE { - } + virtual void visit(AstScopeName* nodep) VL_OVERRIDE {} virtual void visit(AstCStmt* nodep) VL_OVERRIDE { putfs(nodep, "$_CSTMT("); iterateAndNextNull(nodep->bodysp()); @@ -384,8 +397,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } // Operators - virtual void emitVerilogFormat(AstNode* nodep, const string& format, - AstNode* lhsp=NULL, AstNode* rhsp=NULL, AstNode* thsp=NULL) { + virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = NULL, + AstNode* rhsp = NULL, AstNode* thsp = NULL) { // Look at emitVerilog() format for term/uni/dual/triops, // and write out appropriate text. // %f Potential fileline-if-change and line break @@ -397,16 +410,18 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { bool inPct = false; putbs(""); for (string::const_iterator pos = format.begin(); pos != format.end(); ++pos) { - if (pos[0]=='%') { + if (pos[0] == '%') { inPct = true; } else if (!inPct) { // Normal text - string s; s+=pos[0]; puts(s); + string s; + s += pos[0]; + puts(s); } else { // Format character inPct = false; switch (*pos) { - case '%': puts("%"); break; - case 'f': putfs(nodep, ""); break; - case 'k': putbs(""); break; + case '%': puts("%"); break; + case 'f': putfs(nodep, ""); break; + case 'k': putbs(""); break; case 'l': { UASSERT_OBJ(lhsp, nodep, "emitVerilog() references undef node"); iterateAndNextNull(lhsp); @@ -427,9 +442,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { iterateAndNextNull(nodep->dtypep()); break; } - default: - nodep->v3fatalSrc("Unknown emitVerilog format code: %"<v3fatalSrc("Unknown emitVerilog format code: %" << pos[0]); break; } } } @@ -445,7 +458,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp()); } virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE { - emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(), nodep->thsp()); + emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(), + nodep->thsp()); } virtual void visit(AstAttrOf* nodep) VL_OVERRIDE { putfs(nodep, "$_ATTROF("); @@ -460,8 +474,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { putfs(nodep, "`{"); int comma = 0; const AstInitArray::KeyItemMap& mapr = nodep->map(); - for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); - it != mapr.end(); ++it) { + for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) { if (comma++) putbs(", "); puts(cvtToStr(it->first)); puts(":"); @@ -472,23 +485,31 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } virtual void visit(AstNodeCond* nodep) VL_OVERRIDE { putbs("("); - iterateAndNextNull(nodep->condp()); putfs(nodep, " ? "); - iterateAndNextNull(nodep->expr1p()); putbs(" : "); - iterateAndNextNull(nodep->expr2p()); puts(")"); + iterateAndNextNull(nodep->condp()); + putfs(nodep, " ? "); + iterateAndNextNull(nodep->expr1p()); + putbs(" : "); + iterateAndNextNull(nodep->expr2p()); + puts(")"); } virtual void visit(AstRange* nodep) VL_OVERRIDE { puts("["); if (VN_IS(nodep->msbp(), Const) && VN_IS(nodep->lsbp(), Const)) { // Looks nicer if we print [1:0] rather than [32'sh1:32sh0] - puts(cvtToStr(VN_CAST(nodep->leftp(), Const)->toSInt())); puts(":"); - puts(cvtToStr(VN_CAST(nodep->rightp(), Const)->toSInt())); puts("]"); + puts(cvtToStr(VN_CAST(nodep->leftp(), Const)->toSInt())); + puts(":"); + puts(cvtToStr(VN_CAST(nodep->rightp(), Const)->toSInt())); + puts("]"); } else { - iterateAndNextNull(nodep->leftp()); puts(":"); - iterateAndNextNull(nodep->rightp()); puts("]"); + iterateAndNextNull(nodep->leftp()); + puts(":"); + iterateAndNextNull(nodep->rightp()); + puts("]"); } } virtual void visit(AstSel* nodep) VL_OVERRIDE { - iterateAndNextNull(nodep->fromp()); puts("["); + iterateAndNextNull(nodep->fromp()); + puts("["); if (VN_IS(nodep->lsbp(), Const)) { if (nodep->widthp()->isOne()) { if (VN_IS(nodep->lsbp(), Const)) { @@ -498,14 +519,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } } else { puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt() - + VN_CAST(nodep->widthp(), Const)->toSInt() - - 1)); + + VN_CAST(nodep->widthp(), Const)->toSInt() - 1)); puts(":"); puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt())); } } else { - iterateAndNextNull(nodep->lsbp()); putfs(nodep, "+:"); - iterateAndNextNull(nodep->widthp()); puts("]"); + iterateAndNextNull(nodep->lsbp()); + putfs(nodep, "+:"); + iterateAndNextNull(nodep->widthp()); + puts("]"); } puts("]"); } @@ -515,15 +537,23 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } virtual void visit(AstTypedef* nodep) VL_OVERRIDE { putfs(nodep, "typedef "); - iterateAndNextNull(nodep->dtypep()); puts(" "); + iterateAndNextNull(nodep->dtypep()); + puts(" "); puts(nodep->prettyName()); puts(";\n"); } virtual void visit(AstBasicDType* nodep) VL_OVERRIDE { if (nodep->isSigned()) putfs(nodep, "signed "); putfs(nodep, nodep->prettyName()); - if (nodep->rangep()) { puts(" "); iterateAndNextNull(nodep->rangep()); puts(" "); } - else if (nodep->isRanged()) { puts(" ["); puts(cvtToStr(nodep->msb())); puts(":0] "); } + if (nodep->rangep()) { + puts(" "); + iterateAndNextNull(nodep->rangep()); + puts(" "); + } else if (nodep->isRanged()) { + puts(" ["); + puts(cvtToStr(nodep->msb())); + puts(":0] "); + } } virtual void visit(AstConstDType* nodep) VL_OVERRIDE { putfs(nodep, "const "); @@ -534,7 +564,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { iterateAndNextNull(nodep->rangep()); } virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE { - puts(nodep->verilogKwd()+" "); + puts(nodep->verilogKwd() + " "); if (nodep->packed()) puts("packed "); puts("\n"); iterateAndNextNull(nodep->membersp()); @@ -547,16 +577,18 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { puts("}"); } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { - if (nodep->dotted()!="") { - putfs(nodep, nodep->dotted()); puts("."); puts(nodep->prettyName()); - } else { putfs(nodep, nodep->prettyName()); } + if (nodep->dotted() != "") { + putfs(nodep, nodep->dotted()); + puts("."); + puts(nodep->prettyName()); + } else { + putfs(nodep, nodep->prettyName()); + } puts("("); iterateAndNextNull(nodep->pinsp()); puts(")"); } - virtual void visit(AstArg* nodep) VL_OVERRIDE { - iterateAndNextNull(nodep->exprp()); - } + virtual void visit(AstArg* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->exprp()); } // Terminals virtual void visit(AstVarRef* nodep) VL_OVERRIDE { if (nodep->varScopep()) { @@ -576,18 +608,19 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } // Just iterate - virtual void visit(AstTopScope* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } - virtual void visit(AstScope* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } + virtual void visit(AstTopScope* nodep) VL_OVERRIDE { iterateChildren(nodep); } + virtual void visit(AstScope* nodep) VL_OVERRIDE { iterateChildren(nodep); } virtual void visit(AstVar* nodep) VL_OVERRIDE { putfs(nodep, nodep->verilogKwd()); puts(" "); - iterate(nodep->dtypep()); puts(" "); + iterate(nodep->dtypep()); + puts(" "); puts(nodep->prettyName()); - if (!m_suppressVarSemi) puts(";\n"); else puts("\n"); + if (!m_suppressVarSemi) { + puts(";\n"); + } else { + puts("\n"); + } } virtual void visit(AstActive* nodep) VL_OVERRIDE { m_sensesp = nodep->sensesp(); @@ -603,15 +636,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { virtual void visit(AstCell*) VL_OVERRIDE {} // Handled outside the Visit class // Default virtual void visit(AstNode* nodep) VL_OVERRIDE { - puts(string("\n???? // ")+nodep->prettyTypeName()+"\n"); + puts(string("\n???? // ") + nodep->prettyTypeName() + "\n"); iterateChildren(nodep); // Not v3fatalSrc so we keep processing - nodep->v3error("Internal: Unknown node type reached emitter: "<prettyTypeName()); + nodep->v3error("Internal: Unknown node type reached emitter: " << nodep->prettyTypeName()); } public: - bool m_suppressVarSemi; // Suppress emitting semicolon for AstVars - explicit EmitVBaseVisitor(AstSenTree* domainp=NULL) { + bool m_suppressVarSemi; // Suppress emitting semicolon for AstVars + explicit EmitVBaseVisitor(AstSenTree* domainp = NULL) { // Domain for printing one a ALWAYS under a ACTIVE m_suppressSemi = false; m_suppressVarSemi = false; @@ -625,17 +658,18 @@ public: class EmitVFileVisitor : public EmitVBaseVisitor { // MEMBERS - V3OutFile* m_ofp; + V3OutFile* m_ofp; // METHODS - V3OutFile* ofp() const { return m_ofp; } + V3OutFile* ofp() const { return m_ofp; } virtual void puts(const string& str) { ofp()->puts(str); } virtual void putbs(const string& str) { ofp()->putbs(str); } virtual void putfs(AstNode*, const string& str) { putbs(str); } virtual void putqs(AstNode*, const string& str) { putbs(str); } virtual void putsNoTracking(const string& str) { ofp()->putsNoTracking(str); } + public: - EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText=false, - bool suppressVarSemi=false) { + EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText = false, + bool suppressVarSemi = false) { m_ofp = ofp; m_trackText = trackText; m_suppressVarSemi = suppressVarSemi; @@ -649,13 +683,14 @@ public: class EmitVStreamVisitor : public EmitVBaseVisitor { // MEMBERS - std::ostream& m_os; + std::ostream& m_os; // METHODS - virtual void putsNoTracking(const string& str) { m_os<ascii()+":"; - m_os<ascii().length()+1)); - m_os<<" "; - m_os<ascii() + ":"; + m_os << V3OutFile::indentSpaces(m_flWidth - (m_prefixFl->ascii().length() + 1)); + m_os << " "; + m_os << m_prefix; } m_column++; - m_os<fileline(); // NETLIST's fileline instead of NULL to avoid NULL checks + m_prefixFl = v3Global.rootp() + ->fileline(); // NETLIST's fileline instead of NULL to avoid NULL checks } virtual ~EmitVPrefixedFormatter() { if (m_column) puts("\n"); @@ -707,7 +746,8 @@ public: class EmitVPrefixedVisitor : public EmitVBaseVisitor { // MEMBERS - EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the inheritance is another unused V3OutFormatter) + EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the + // inheritance is another unused V3OutFormatter) // METHODS virtual void putsNoTracking(const string& str) { m_formatter.putsNoTracking(str); } virtual void puts(const string& str) { m_formatter.puts(str); } @@ -728,7 +768,8 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor { public: EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth, AstSenTree* domainp, bool user3mark) - : EmitVBaseVisitor(domainp), m_formatter(os, prefix, flWidth) { + : EmitVBaseVisitor(domainp) + , m_formatter(os, prefix, flWidth) { if (user3mark) { AstUser3InUse::check(); } iterate(nodep); } @@ -739,13 +780,14 @@ public: // EmitV class functions void V3EmitV::emitv() { - UINFO(2,__FUNCTION__<<": "<modulesp(); modp; @@ -758,24 +800,22 @@ void V3EmitV::emitv() { } } -void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) { - EmitVStreamVisitor(nodep, os); -} +void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) { EmitVStreamVisitor(nodep, os); } -void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os, - const string& prefix, int flWidth, - AstSenTree* domainp, bool user3mark) { +void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix, + int flWidth, AstSenTree* domainp, bool user3mark) { EmitVPrefixedVisitor(nodep, os, prefix, flWidth, domainp, user3mark); } void V3EmitV::emitvFiles() { - UINFO(2,__FUNCTION__<<": "<filesp(); filep; filep = VN_CAST(filep->nextp(), NodeFile)) { AstVFile* vfilep = VN_CAST(filep, VFile); if (vfilep && vfilep->tblockp()) { V3OutVFile of(vfilep->name()); - of.puts("// DESCR" "IPTION: Verilator generated Verilog\n"); + of.puts("// DESCR" + "IPTION: Verilator generated Verilog\n"); EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true); } } diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index 6ae7651fe..a748aecdc 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -33,18 +33,18 @@ class EmitXmlFileVisitor : public AstNVisitor { // NODE STATE - //Entire netlist: + // Entire netlist: // AstNode::user1 -> uint64_t, number to connect crossrefs // MEMBERS - V3OutFile* m_ofp; - uint64_t m_id; + V3OutFile* m_ofp; + uint64_t m_id; // METHODS VL_DEBUG_FUNC; // Declare debug() // Outfile methods - V3OutFile* ofp() const { return m_ofp; } + V3OutFile* ofp() const { return m_ofp; } virtual void puts(const string& str) { ofp()->puts(str); } virtual void putbs(const string& str) { ofp()->putbs(str); } virtual void putfs(AstNode*, const string& str) { putbs(str); } @@ -62,29 +62,42 @@ class EmitXmlFileVisitor : public AstNVisitor { // XML methods void outputId(AstNode* nodep) { if (!nodep->user1()) { nodep->user1(++m_id); } - puts("\""+cvtToStr(nodep->user1())+"\""); + puts("\"" + cvtToStr(nodep->user1()) + "\""); } void outputTag(AstNode* nodep, string tag) { - if (tag=="") tag = VString::downcase(nodep->typeName()); - puts("<"+tag+" "+nodep->fileline()->xml()); - puts(" "+nodep->fileline()->xmlDetailedLocation()); - if (VN_IS(nodep, NodeDType)) { puts(" id="); outputId(nodep); } - if (nodep->name()!="") { puts(" name="); putsQuoted(nodep->prettyName()); } - if (nodep->tag()!="") { puts(" tag="); putsQuoted(nodep->tag()); } + if (tag == "") tag = VString::downcase(nodep->typeName()); + puts("<" + tag + " " + nodep->fileline()->xml()); + puts(" " + nodep->fileline()->xmlDetailedLocation()); + if (VN_IS(nodep, NodeDType)) { + puts(" id="); + outputId(nodep); + } + if (nodep->name() != "") { + puts(" name="); + putsQuoted(nodep->prettyName()); + } + if (nodep->tag() != "") { + puts(" tag="); + putsQuoted(nodep->tag()); + } if (AstNodeDType* dtp = VN_CAST(nodep, NodeDType)) { if (dtp->subDTypep()) { - puts(" sub_dtype_id="); outputId(dtp->subDTypep()->skipRefp()); + puts(" sub_dtype_id="); + outputId(dtp->subDTypep()->skipRefp()); } } else { - if (nodep->dtypep()) { puts(" dtype_id="); outputId(nodep->dtypep()->skipRefp()); } + if (nodep->dtypep()) { + puts(" dtype_id="); + outputId(nodep->dtypep()->skipRefp()); + } } } void outputChildrenEnd(AstNode* nodep, string tag) { - if (tag=="") tag = VString::downcase(nodep->typeName()); + if (tag == "") tag = VString::downcase(nodep->typeName()); if (nodep->op1p() || nodep->op2p() || nodep->op3p() || nodep->op4p()) { puts(">\n"); iterateChildren(nodep); - puts("\n"); + puts("\n"); } else { puts("/>\n"); } @@ -97,8 +110,10 @@ class EmitXmlFileVisitor : public AstNVisitor { } virtual void visit(AstCell* nodep) VL_OVERRIDE { outputTag(nodep, "instance"); // IEEE: vpiInstance - puts(" defName="); putsQuoted(nodep->modName()); // IEEE vpiDefName - puts(" origName="); putsQuoted(nodep->origName()); + puts(" defName="); + putsQuoted(nodep->modName()); // IEEE vpiDefName + puts(" origName="); + putsQuoted(nodep->origName()); outputChildrenEnd(nodep, "instance"); } virtual void visit(AstNetlist* nodep) VL_OVERRIDE { @@ -108,8 +123,10 @@ class EmitXmlFileVisitor : public AstNVisitor { } virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { outputTag(nodep, ""); - puts(" origName="); putsQuoted(nodep->origName()); - if (nodep->level()==1 || nodep->level()==2) // ==2 because we don't add wrapper when in XML mode + puts(" origName="); + putsQuoted(nodep->origName()); + if (nodep->level() == 1 + || nodep->level() == 2) // ==2 because we don't add wrapper when in XML mode puts(" topModule=\"1\""); // IEEE vpiTopModule if (nodep->modPublic()) puts(" public=\"true\""); outputChildrenEnd(nodep, ""); @@ -120,13 +137,16 @@ class EmitXmlFileVisitor : public AstNVisitor { string vt = nodep->dtypep()->name(); outputTag(nodep, ""); if (nodep->isIO()) { - puts(" dir="); putsQuoted(kw); - puts(" vartype="); putsQuoted(!vt.empty() - ? vt : typ == AstVarType::PORT ? "port" : "unknown"); + puts(" dir="); + putsQuoted(kw); + puts(" vartype="); + putsQuoted(!vt.empty() ? vt : typ == AstVarType::PORT ? "port" : "unknown"); } else { - puts(" vartype="); putsQuoted(!vt.empty() ? vt : kw); + puts(" vartype="); + putsQuoted(!vt.empty() ? vt : kw); } - puts(" origName="); putsQuoted(nodep->origName()); + puts(" origName="); + putsQuoted(nodep->origName()); // Attributes if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) puts(" clocker=\"true\""); @@ -137,8 +157,10 @@ class EmitXmlFileVisitor : public AstNVisitor { if (nodep->isSigPublic()) puts(" public=\"true\""); if (nodep->isSigUserRdPublic()) puts(" public_flat_rd=\"true\""); if (nodep->isSigUserRWPublic()) puts(" public_flat_rw=\"true\""); - if (nodep->isGParam()) puts(" param=\"true\""); - else if (nodep->isParam()) puts(" localparam=\"true\""); + if (nodep->isGParam()) + puts(" param=\"true\""); + else if (nodep->isParam()) + puts(" localparam=\"true\""); if (nodep->attrScBv()) puts(" sc_bv=\"true\""); if (nodep->attrScClocked()) puts(" sc_clock=\"true\""); if (nodep->attrSFormat()) puts(" sformat=\"true\""); @@ -148,27 +170,29 @@ class EmitXmlFileVisitor : public AstNVisitor { // What we call a pin in verilator is a port in the IEEE spec. outputTag(nodep, "port"); // IEEE: vpiPort if (nodep->modVarp()->isIO()) { - puts(" direction=\""+nodep->modVarp()->direction().xmlKwd()+"\""); + puts(" direction=\"" + nodep->modVarp()->direction().xmlKwd() + "\""); } - puts(" portIndex=\""+cvtToStr(nodep->pinNum())+"\""); // IEEE: vpiPortIndex + puts(" portIndex=\"" + cvtToStr(nodep->pinNum()) + "\""); // IEEE: vpiPortIndex // Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?) outputChildrenEnd(nodep, "port"); } virtual void visit(AstSenItem* nodep) VL_OVERRIDE { outputTag(nodep, ""); - puts(" edgeType=\""+cvtToStr(nodep->edgeType().ascii())+"\""); // IEEE vpiTopModule + puts(" edgeType=\"" + cvtToStr(nodep->edgeType().ascii()) + "\""); // IEEE vpiTopModule outputChildrenEnd(nodep, ""); } virtual void visit(AstModportVarRef* nodep) VL_OVERRIDE { // Dump direction for Modport references string kw = nodep->direction().xmlKwd(); outputTag(nodep, ""); - puts(" direction="); putsQuoted(kw); + puts(" direction="); + putsQuoted(kw); outputChildrenEnd(nodep, ""); } virtual void visit(AstVarXRef* nodep) VL_OVERRIDE { outputTag(nodep, ""); - puts(" dotted="); putsQuoted(nodep->dotted()); + puts(" dotted="); + putsQuoted(nodep->dotted()); outputChildrenEnd(nodep, ""); } @@ -176,8 +200,8 @@ class EmitXmlFileVisitor : public AstNVisitor { virtual void visit(AstBasicDType* nodep) VL_OVERRIDE { outputTag(nodep, "basicdtype"); if (nodep->isRanged()) { - puts(" left=\""+cvtToStr(nodep->left())+"\""); - puts(" right=\""+cvtToStr(nodep->right())+"\""); + puts(" left=\"" + cvtToStr(nodep->left()) + "\""); + puts(" right=\"" + cvtToStr(nodep->right()) + "\""); } puts("/>\n"); } @@ -185,29 +209,36 @@ class EmitXmlFileVisitor : public AstNVisitor { string mpn; outputTag(nodep, ""); if (nodep->isModport()) mpn = nodep->modportName(); - puts(" modportname="); putsQuoted(mpn); + puts(" modportname="); + putsQuoted(mpn); outputChildrenEnd(nodep, ""); } virtual void visit(AstDisplay* nodep) VL_OVERRIDE { outputTag(nodep, ""); - puts(" displaytype="); putsQuoted(nodep->verilogKwd()); + puts(" displaytype="); + putsQuoted(nodep->verilogKwd()); outputChildrenEnd(nodep, ""); } virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE { outputTag(nodep, ""); - puts(" displaytype="); putsQuoted(nodep->verilogKwd()); + puts(" displaytype="); + putsQuoted(nodep->verilogKwd()); outputChildrenEnd(nodep, ""); } virtual void visit(AstExtend* nodep) VL_OVERRIDE { outputTag(nodep, ""); - puts(" width="); putsQuoted(cvtToStr(nodep->width())); - puts(" widthminv="); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV())); + puts(" width="); + putsQuoted(cvtToStr(nodep->width())); + puts(" widthminv="); + putsQuoted(cvtToStr(nodep->lhsp()->widthMinV())); outputChildrenEnd(nodep, ""); } virtual void visit(AstExtendS* nodep) VL_OVERRIDE { outputTag(nodep, ""); - puts(" width="); putsQuoted(cvtToStr(nodep->width())); - puts(" widthminv="); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV())); + puts(" width="); + putsQuoted(cvtToStr(nodep->width())); + puts(" widthminv="); + putsQuoted(cvtToStr(nodep->lhsp()->widthMinV())); outputChildrenEnd(nodep, ""); } @@ -216,6 +247,7 @@ class EmitXmlFileVisitor : public AstNVisitor { outputTag(nodep, ""); outputChildrenEnd(nodep, ""); } + public: EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp) { m_ofp = ofp; @@ -246,8 +278,7 @@ private: virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { // Only list modules and interfaces // Assumes modules and interfaces list is already sorted level wise - if (!nodep->dead() - && (VN_IS(nodep, Module) || VN_IS(nodep, Iface)) + if (!nodep->dead() && (VN_IS(nodep, Module) || VN_IS(nodep, Iface)) && m_modulesCovered.insert(nodep->fileline()->filename()).second) { m_nodeModules.push_front(nodep->fileline()); } @@ -260,18 +291,19 @@ private: public: // CONSTRUCTORS ModuleFilesXmlVisitor(AstNetlist* nodep, std::ostream& os) - : m_os(os), m_modulesCovered(), m_nodeModules() { + : m_os(os) + , m_modulesCovered() + , m_nodeModules() { // Operate on whole netlist nodep->accept(*this); // Xml output - m_os<<"\n"; - for (std::deque::iterator it = m_nodeModules.begin(); - it != m_nodeModules.end(); ++it) { - m_os<<"filenameLetters() - <<"\" filename=\""<<(*it)->filename() - <<"\" language=\""<<(*it)->language().ascii()<<"\"/>\n"; + m_os << "\n"; + for (std::deque::iterator it = m_nodeModules.begin(); it != m_nodeModules.end(); + ++it) { + m_os << "filenameLetters() << "\" filename=\"" + << (*it)->filename() << "\" language=\"" << (*it)->language().ascii() << "\"/>\n"; } - m_os<<"\n"; + m_os << "\n"; } virtual ~ModuleFilesXmlVisitor() {} }; @@ -292,42 +324,38 @@ private: // VISITORS virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { if (nodep->level() >= 0 - && nodep->level() <=2 ) { // ==2 because we don't add wrapper when in XML mode - m_os<<"\n"; - m_os<<"fileline()->xml() - <<" "<fileline()->xmlDetailedLocation() - <<" name=\""<name()<<"\"" - <<" submodname=\""<name()<<"\"" - <<" hier=\""<name()<<"\""; + && nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode + m_os << "\n"; + m_os << "fileline()->xml() << " " + << nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\"" + << " submodname=\"" << nodep->name() << "\"" + << " hier=\"" << nodep->name() << "\""; m_hier = nodep->name() + "."; m_hasChildren = false; iterateChildren(nodep); if (m_hasChildren) { - m_os<<"\n"; + m_os << "\n"; } else { - m_os<<"/>\n"; + m_os << "/>\n"; } - m_os<<"\n"; + m_os << "\n"; } } virtual void visit(AstCell* nodep) VL_OVERRIDE { - if (nodep->modp()->dead()) { - return; - } - if (!m_hasChildren) m_os<<">\n"; - m_os<<"fileline()->xml() - <<" "<fileline()->xmlDetailedLocation() - <<" name=\""<name()<<"\"" - <<" submodname=\""<modName()<<"\"" - <<" hier=\""<name()<<"\""; + if (nodep->modp()->dead()) { return; } + if (!m_hasChildren) m_os << ">\n"; + m_os << "fileline()->xml() << " " + << nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\"" + << " submodname=\"" << nodep->modName() << "\"" + << " hier=\"" << m_hier + nodep->name() << "\""; std::string hier = m_hier; m_hier += nodep->name() + "."; m_hasChildren = false; iterateChildren(nodep->modp()); if (m_hasChildren) { - m_os<<"\n"; + m_os << "\n"; } else { - m_os<<"/>\n"; + m_os << "/>\n"; } m_hier = hier; m_hasChildren = true; @@ -338,7 +366,9 @@ private: public: // CONSTRUCTORS HierCellsXmlVisitor(AstNetlist* nodep, std::ostream& os) - : m_os(os), m_hier(""), m_hasChildren(false) { + : m_os(os) + , m_hier("") + , m_hasChildren(false) { // Operate on whole netlist nodep->accept(*this); } @@ -349,14 +379,15 @@ public: // EmitXml class functions void V3EmitXml::emitxml() { - UINFO(2,__FUNCTION__<<": "<\n"); + of.puts("\n"); of.puts("\n"); { std::stringstream sstr; @@ -365,10 +396,10 @@ void V3EmitXml::emitxml() { } { std::stringstream sstr; - ModuleFilesXmlVisitor moduleFilesVisitor (v3Global.rootp(), sstr); - HierCellsXmlVisitor cellsVisitor (v3Global.rootp(), sstr); + ModuleFilesXmlVisitor moduleFilesVisitor(v3Global.rootp(), sstr); + HierCellsXmlVisitor cellsVisitor(v3Global.rootp(), sstr); of.puts(sstr.str()); } - EmitXmlFileVisitor visitor (v3Global.rootp(), &of); + EmitXmlFileVisitor visitor(v3Global.rootp(), &of); of.puts("\n"); } diff --git a/src/V3Error.cpp b/src/V3Error.cpp index f5bed2005..e483c0699 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -14,12 +14,14 @@ // //************************************************************************* +// clang-format off #include "V3Error.h" #ifndef _V3ERROR_NO_GLOBAL_ # include "V3Ast.h" # include "V3Global.h" # include "V3Stats.h" #endif +// clang-format on #include @@ -43,7 +45,7 @@ V3Error::MessagesSet V3Error::s_messages; V3Error::ErrorExitCb V3Error::s_errorExitCb = NULL; struct v3errorIniter { - v3errorIniter() { V3Error::init(); } + v3errorIniter() { V3Error::init(); } }; v3errorIniter v3errorInit; @@ -52,10 +54,11 @@ v3errorIniter v3errorInit; V3ErrorCode::V3ErrorCode(const char* msgp) { // Return error encoding for given string, or ERROR, which is a bad code - for (int codei=V3ErrorCode::EC_MIN; codei20) numsp = 20; - out<<(spaces + numsp); + size_t numsp = out.str().length(); + if (numsp > 20) numsp = 20; + out << (spaces + numsp); return out.str(); } void V3Error::incErrors() { s_errCount++; if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse - v3fatalExit("Exiting due to too many errors encountered; --error-limit=" + v3fatalExit("Exiting due to too many errors encountered; --error-limit=" // << errorCount() << endl); } } @@ -96,8 +100,8 @@ void V3Error::incErrors() { void V3Error::abortIfWarnings() { bool exwarn = warnFatal() && warnCount(); if (errorCount() && exwarn) { - v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s), " - << warnCount() << " warning(s)\n"); + v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s), " // + << warnCount() << " warning(s)\n"); } else if (errorCount()) { v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s)\n"); } else if (exwarn) { @@ -106,30 +110,49 @@ void V3Error::abortIfWarnings() { } bool V3Error::isError(V3ErrorCode code, bool supp) { - if (supp) return false; - else if (code == V3ErrorCode::USERINFO) return false; - else if (code == V3ErrorCode::EC_INFO) return false; - else if (code == V3ErrorCode::EC_FATAL) return true; - else if (code == V3ErrorCode::EC_FATALEXIT) return true; - else if (code == V3ErrorCode::EC_FATALSRC) return true; - else if (code == V3ErrorCode::EC_ERROR) return true; - else if (code < V3ErrorCode::EC_FIRST_WARN - || s_pretendError[code]) return true; - else return false; + if (supp) { + return false; + } else if (code == V3ErrorCode::USERINFO) { + return false; + } else if (code == V3ErrorCode::EC_INFO) { + return false; + } else if (code == V3ErrorCode::EC_FATAL) { + return true; + } else if (code == V3ErrorCode::EC_FATALEXIT) { + return true; + } else if (code == V3ErrorCode::EC_FATALSRC) { + return true; + } else if (code == V3ErrorCode::EC_ERROR) { + return true; + } else if (code < V3ErrorCode::EC_FIRST_WARN || s_pretendError[code]) { + return true; + } else { + return false; + } } string V3Error::msgPrefix() { V3ErrorCode code = s_errorCode; bool supp = s_errorSuppressed; - if (supp) return "-arning-suppressed: "; - else if (code == V3ErrorCode::USERINFO) return "-Info: "; - else if (code == V3ErrorCode::EC_INFO) return "-Info: "; - else if (code == V3ErrorCode::EC_FATAL) return "%Error: "; - else if (code == V3ErrorCode::EC_FATALEXIT) return "%Error: "; - else if (code == V3ErrorCode::EC_FATALSRC) return "%Error: Internal Error: "; - else if (code == V3ErrorCode::EC_ERROR) return "%Error: "; - else if (isError(code, supp)) return "%Error-"+string(code.ascii())+": "; - else return "%Warning-"+string(code.ascii())+": "; + if (supp) { + return "-arning-suppressed: "; + } else if (code == V3ErrorCode::USERINFO) { + return "-Info: "; + } else if (code == V3ErrorCode::EC_INFO) { + return "-Info: "; + } else if (code == V3ErrorCode::EC_FATAL) { + return "%Error: "; + } else if (code == V3ErrorCode::EC_FATALEXIT) { + return "%Error: "; + } else if (code == V3ErrorCode::EC_FATALSRC) { + return "%Error: Internal Error: "; + } else if (code == V3ErrorCode::EC_ERROR) { + return "%Error: "; + } else if (isError(code, supp)) { + return "%Error-" + string(code.ascii()) + ": "; + } else { + return "%Warning-" + string(code.ascii()) + ": "; + } } //====================================================================== @@ -137,7 +160,7 @@ string V3Error::msgPrefix() { void V3Error::vlAbort() { if (V3Error::debugDefault()) { - std::cerr<=V3ErrorCode::EC_MIN) { + if (s_errorCode >= V3ErrorCode::EC_MIN) { #ifndef _V3ERROR_NO_GLOBAL_ - V3Stats::addStatSum(string("Warnings, Suppressed ")+s_errorCode.ascii(), 1); + V3Stats::addStatSum(string("Warnings, Suppressed ") + s_errorCode.ascii(), 1); #endif s_errorSuppressed = true; } } -string V3Error::warnMore() { - return string(msgPrefix().size(), ' '); -} +string V3Error::warnMore() { return string(msgPrefix().size(), ' '); } void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) { #if defined(__COVERITY__) || defined(__cppcheck__) - if (s_errorCode==V3ErrorCode::EC_FATAL) __coverity_panic__(x); + if (s_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x); #endif // Skip suppressed messages if (s_errorSuppressed // On debug, show only non default-off warning to prevent pages of warnings - && (!debug() || s_errorCode.defaultsOff())) return; - string msg = msgPrefix()+sstr.str(); + && (!debug() || s_errorCode.defaultsOff())) + return; + string msg = msgPrefix() + sstr.str(); if (s_errorSuppressed) { // If suppressed print only first line to reduce verbosity string::size_type pos; if ((pos = msg.find('\n')) != string::npos) { - msg.erase(pos, msg.length()-pos); + msg.erase(pos, msg.length() - pos); msg += "..."; } } @@ -180,15 +202,13 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) { { msg += '\n'; // Trailing newlines generally not put on messages so add string::size_type pos; - while ((pos = msg.find("\n\n")) != string::npos) { - msg.erase(pos+1, 1); - } + while ((pos = msg.find("\n\n")) != string::npos) msg.erase(pos + 1, 1); } // Suppress duplicate messages if (s_messages.find(msg) != s_messages.end()) return; s_messages.insert(msg); if (!locationStr.empty()) { - string locationMsg = warnMore()+locationStr+"\n"; + string locationMsg = warnMore() + locationStr + "\n"; size_t pos = msg.find("\n"); msg.insert(pos + 1, locationMsg); } @@ -199,44 +219,49 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) { #else true #endif - ) { + ) { std::cerr << msg; } - if (!s_errorSuppressed && !(s_errorCode==V3ErrorCode::EC_INFO - || s_errorCode==V3ErrorCode::USERINFO)) { - if (!s_describedEachWarn[s_errorCode] - && !s_pretendError[s_errorCode]) { + if (!s_errorSuppressed + && !(s_errorCode == V3ErrorCode::EC_INFO || s_errorCode == V3ErrorCode::USERINFO)) { + if (!s_describedEachWarn[s_errorCode] && !s_pretendError[s_errorCode]) { s_describedEachWarn[s_errorCode] = true; - if (s_errorCode>=V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) { - std::cerr<= V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) { + std::cerr << warnMore() << "... Use \"/* verilator lint_off " + << s_errorCode.ascii() + << " */\" and lint_on around source to disable this message." << endl; s_describedWarnings = true; } if (s_errorCode.dangerous()) { - std::cerr<(_e)) {} + explicit inline V3ErrorCode(int _e) + : m_e(static_cast(_e)) {} operator en() const { return m_e; } const char* ascii() const { + // clang-format off const char* names[] = { // Leading spaces indicate it can't be disabled. " MIN", " INFO", " FATAL", " FATALEXIT", " FATALSRC", " ERROR", @@ -159,50 +165,37 @@ public: "VARHIDDEN", "WIDTH", "WIDTHCONCAT", " MAX" }; + // clang-format on return names[m_e]; } // Warnings that default to off - bool defaultsOff() const { return ( m_e==IMPERFECTSCH || styleError()); } + bool defaultsOff() const { return (m_e == IMPERFECTSCH || styleError()); } // Warnings that warn about nasty side effects - bool dangerous() const { return ( m_e==COMBDLY ); } + bool dangerous() const { return (m_e == COMBDLY); } // Warnings we'll present to the user as errors // Later -Werror- options may make more of these. - bool pretendError() const { return ( m_e==ASSIGNIN || m_e==BLKANDNBLK - || m_e==BLKLOOPINIT - || m_e==CONTASSREG - || m_e==IMPURE - || m_e==PROCASSWIRE); } + bool pretendError() const { + return (m_e == ASSIGNIN || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG + || m_e == IMPURE || m_e == PROCASSWIRE); + } // Warnings to mention manual - bool mentionManual() const { return ( m_e==EC_FATALSRC || m_e==SYMRSVDWORD - || pretendError() ); } - + bool mentionManual() const { + return (m_e == EC_FATALSRC || m_e == SYMRSVDWORD || pretendError()); + } // Warnings that are lint only - bool lintError() const { return ( m_e==ALWCOMBORDER - || m_e==BSSPACE - || m_e==CASEINCOMPLETE || m_e==CASEOVERLAP - || m_e==CASEWITHX || m_e==CASEX - || m_e==CMPCONST - || m_e==COLONPLUS - || m_e==ENDLABEL - || m_e==IMPLICIT - || m_e==LITENDIAN - || m_e==PINMISSING - || m_e==REALCVT - || m_e==UNSIGNED - || m_e==WIDTH); } + bool lintError() const { + return (m_e == ALWCOMBORDER || m_e == BSSPACE || m_e == CASEINCOMPLETE + || m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CMPCONST + || m_e == COLONPLUS || m_e == ENDLABEL || m_e == IMPLICIT || m_e == LITENDIAN + || m_e == PINMISSING || m_e == REALCVT || m_e == UNSIGNED || m_e == WIDTH); + } // Warnings that are style only - bool styleError() const { return ( m_e==ASSIGNDLY // More than style, but for backward compatibility - || m_e==BLKSEQ - || m_e==DEFPARAM - || m_e==DECLFILENAME - || m_e==IMPORTSTAR - || m_e==INCABSPATH - || m_e==PINCONNECTEMPTY - || m_e==PINNOCONNECT - || m_e==SYNCASYNCNET - || m_e==UNDRIVEN - || m_e==UNUSED - || m_e==VARHIDDEN ); } + bool styleError() const { + return (m_e == ASSIGNDLY // More than style, but for backward compatibility + || m_e == BLKSEQ || m_e == DEFPARAM || m_e == DECLFILENAME || m_e == IMPORTSTAR + || m_e == INCABSPATH || m_e == PINCONNECTEMPTY || m_e == PINNOCONNECT + || m_e == SYNCASYNCNET || m_e == UNDRIVEN || m_e == UNUSED || m_e == VARHIDDEN); + } }; inline bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) { return lhs.m_e == rhs.m_e; @@ -221,28 +214,32 @@ class V3Error { typedef std::set MessagesSet; typedef void (*ErrorExitCb)(void); - private: - static bool s_describedWarnings; // Told user how to disable warns - static bool s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; // Told user specifics about this warning - static bool s_pretendError[V3ErrorCode::_ENUM_MAX]; // Pretend this warning is an error - static int s_debugDefault; // Option: --debugi Default debugging level - static int s_errorLimit; // Option: --error-limit Number of errors before exit - static bool s_warnFatal; // Option: --warnFatal Warnings are fatal - static int s_errCount; // Error count - static int s_warnCount; // Warning count - static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable - static std::ostringstream s_errorStr; // Error string being formed - static V3ErrorCode s_errorCode; // Error string being formed will abort - static bool s_errorContexted; // Error being formed got context - static bool s_errorSuppressed; // Error being formed should be suppressed - static MessagesSet s_messages; // What errors we've outputted - static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping +private: + static bool s_describedWarnings; // Told user how to disable warns + static bool + s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; // Told user specifics about this warning + static bool s_pretendError[V3ErrorCode::_ENUM_MAX]; // Pretend this warning is an error + static int s_debugDefault; // Option: --debugi Default debugging level + static int s_errorLimit; // Option: --error-limit Number of errors before exit + static bool s_warnFatal; // Option: --warnFatal Warnings are fatal + static int s_errCount; // Error count + static int s_warnCount; // Warning count + static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable + static std::ostringstream s_errorStr; // Error string being formed + static V3ErrorCode s_errorCode; // Error string being formed will abort + static bool s_errorContexted; // Error being formed got context + static bool s_errorSuppressed; // Error being formed should be suppressed + static MessagesSet s_messages; // What errors we've outputted + static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping - enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors + enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors - V3Error() { std::cerr<<("Static class"); abort(); } + V3Error() { + std::cerr << ("Static class"); + abort(); + } - public: +public: // CONSTRUCTORS // ACCESSORS static void debugDefault(int level) { s_debugDefault = level; } @@ -254,14 +251,16 @@ class V3Error { static string msgPrefix(); // returns %Error/%Warn static int errorCount() { return s_errCount; } static int warnCount() { return s_warnCount; } - static int errorOrWarnCount() { return errorCount()+warnCount(); } + static int errorOrWarnCount() { return errorCount() + warnCount(); } static bool errorContexted() { return s_errorContexted; } static void errorContexted(bool flag) { s_errorContexted = flag; } // METHODS static void incErrors(); static void incWarnings() { s_warnCount++; } static void init(); - static void abortIfErrors() { if (errorCount()) abortIfWarnings(); } + static void abortIfErrors() { + if (errorCount()) abortIfWarnings(); + } static void abortIfWarnings(); static void suppressThisWarning(); // Suppress next %Warn if user has it off static void pretendError(V3ErrorCode code, bool flag) { s_pretendError[code] = flag; } @@ -273,77 +272,109 @@ class V3Error { // When printing an error/warning, print prefix for multiline message static string warnMore(); /// When building an error, don't show context info - static string warnContextNone() { V3Error::errorContexted(true); return ""; } + static string warnContextNone() { + V3Error::errorContexted(true); + return ""; + } // Internals for v3error()/v3fatal() macros only // Error end takes the string stream to output, be careful to seek() as needed static void v3errorPrep(V3ErrorCode code) { - s_errorStr.str(""); s_errorCode = code; - s_errorContexted = false; s_errorSuppressed = false; } + s_errorStr.str(""); + s_errorCode = code; + s_errorContexted = false; + s_errorSuppressed = false; + } static std::ostringstream& v3errorStr() { return s_errorStr; } static void vlAbort(); - static void v3errorEnd(std::ostringstream& sstr, const string& locationStr = ""); // static, but often overridden in classes. + // static, but often overridden in classes. + static void v3errorEnd(std::ostringstream& sstr, const string& locationStr = ""); }; // Global versions, so that if the class doesn't define a operator, we get the functions anyways. inline int debug() { return V3Error::debugDefault(); } inline void v3errorEnd(std::ostringstream& sstr) { V3Error::v3errorEnd(sstr); } inline void v3errorEndFatal(std::ostringstream& sstr) { - V3Error::v3errorEnd(sstr); assert(0); VL_UNREACHABLE } + V3Error::v3errorEnd(sstr); + assert(0); + VL_UNREACHABLE +} // Theses allow errors using << operators: v3error("foo"<<"bar"); // Careful, you can't put () around msg, as you would in most macro definitions // Note the commas are the comma operator, not separating arguments. These are needed to ensure // evaluation order as otherwise we couldn't ensure v3errorPrep is called first. -#define v3warnCode(code,msg) \ - v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<= (level))) { \ - cout << "- " << V3Error::lineStr(__FILE__, __LINE__) << stmsg; } } + { \ + if (VL_UNCOVERABLE(debug() >= (level))) { \ + cout << "- " << V3Error::lineStr(__FILE__, __LINE__) << stmsg; \ + } \ + } #define UINFONL(level, stmsg) \ - { if (VL_UNCOVERABLE(debug() >= (level))) { cout << stmsg; } } + { \ + if (VL_UNCOVERABLE(debug() >= (level))) { cout << stmsg; } \ + } #ifdef VL_DEBUG -# define UDEBUGONLY(stmts) \ +#define UDEBUGONLY(stmts) \ { stmts } #else -# define UDEBUGONLY(stmts) \ - { if (false) { stmts } } +#define UDEBUGONLY(stmts) \ + { \ + if (false) { stmts } \ + } #endif // Assertion without object, generally UOBJASSERT preferred -#define UASSERT(condition,stmsg) \ - do { if (VL_UNCOVERABLE(!(condition))) { v3fatalSrc(stmsg); }} while (false) +#define UASSERT(condition, stmsg) \ + do { \ + if (VL_UNCOVERABLE(!(condition))) { v3fatalSrc(stmsg); } \ + } while (false) // Assertion with object -#define UASSERT_OBJ(condition,obj,stmsg) \ - do { if (VL_UNCOVERABLE(!(condition))) { (obj)->v3fatalSrc(stmsg); }} while (false) +#define UASSERT_OBJ(condition, obj, stmsg) \ + do { \ + if (VL_UNCOVERABLE(!(condition))) { (obj)->v3fatalSrc(stmsg); } \ + } while (false) // For use in V3Ast static functions only -#define UASSERT_STATIC(condition,stmsg) \ - do { if (VL_UNCOVERABLE(!(condition))) { \ - std::cerr<<"Internal Error: "<<__FILE__<<":"< {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}} if (rhsp->num().isFourState()) { rhsp->v3error("Unsupported: 4-state numbers in this context"); } - for (int w=0; wwidthWords(); w++) { - addWordAssign(nodep, w, new AstConst(nodep->fileline(), - AstConst::SizedEData(), - rhsp->num().edataWord(w))); + for (int w = 0; w < nodep->widthWords(); w++) { + addWordAssign( + nodep, w, + new AstConst(nodep->fileline(), AstConst::SizedEData(), rhsp->num().edataWord(w))); } return true; } //-------- Uniops bool expandWide(AstNodeAssign* nodep, AstVarRef* rhsp) { - UINFO(8," Wordize ASSIGN(VARREF) "<widthWords(); w++) { + UINFO(8, " Wordize ASSIGN(VARREF) " << nodep << endl); + for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, newAstWordSelClone(rhsp, w)); } return true; } bool expandWide(AstNodeAssign* nodep, AstArraySel* rhsp) { - UINFO(8," Wordize ASSIGN(ARRAYSEL) "<dtypep()->skipRefp(), UnpackArrayDType), nodep, "ArraySel with unpacked arrays should have been removed in V3Slice"); - for (int w=0; wwidthWords(); w++) { + for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, newAstWordSelClone(rhsp, w)); } return true; } bool expandWide(AstNodeAssign* nodep, AstNot* rhsp) { - UINFO(8," Wordize ASSIGN(NOT) "< {for each_word{ ASSIGN(WORDSEL(wide,#),NOT(WORDSEL(lhs,#))) }} - for (int w=0; wwidthWords(); w++) { - addWordAssign(nodep, w, new AstNot(rhsp->fileline(), - newAstWordSelClone(rhsp->lhsp(), w))); + for (int w = 0; w < nodep->widthWords(); w++) { + addWordAssign(nodep, w, + new AstNot(rhsp->fileline(), newAstWordSelClone(rhsp->lhsp(), w))); } return true; } //-------- Biops bool expandWide(AstNodeAssign* nodep, AstAnd* rhsp) { - UINFO(8," Wordize ASSIGN(AND) "<widthWords(); w++) { - addWordAssign(nodep, w, new AstAnd(nodep->fileline(), - newAstWordSelClone(rhsp->lhsp(), w), - newAstWordSelClone(rhsp->rhsp(), w))); + UINFO(8, " Wordize ASSIGN(AND) " << nodep << endl); + for (int w = 0; w < nodep->widthWords(); w++) { + addWordAssign(nodep, w, + new AstAnd(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w), + newAstWordSelClone(rhsp->rhsp(), w))); } return true; } bool expandWide(AstNodeAssign* nodep, AstOr* rhsp) { - UINFO(8," Wordize ASSIGN(OR) "<widthWords(); w++) { - addWordAssign(nodep, w, new AstOr(nodep->fileline(), - newAstWordSelClone(rhsp->lhsp(), w), - newAstWordSelClone(rhsp->rhsp(), w))); + UINFO(8, " Wordize ASSIGN(OR) " << nodep << endl); + for (int w = 0; w < nodep->widthWords(); w++) { + addWordAssign(nodep, w, + new AstOr(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w), + newAstWordSelClone(rhsp->rhsp(), w))); } return true; } bool expandWide(AstNodeAssign* nodep, AstXor* rhsp) { - UINFO(8," Wordize ASSIGN(XOR) "<widthWords(); w++) { - addWordAssign(nodep, w, new AstXor(nodep->fileline(), - newAstWordSelClone(rhsp->lhsp(), w), - newAstWordSelClone(rhsp->rhsp(), w))); + UINFO(8, " Wordize ASSIGN(XOR) " << nodep << endl); + for (int w = 0; w < nodep->widthWords(); w++) { + addWordAssign(nodep, w, + new AstXor(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w), + newAstWordSelClone(rhsp->rhsp(), w))); } return true; } bool expandWide(AstNodeAssign* nodep, AstXnor* rhsp) { - UINFO(8," Wordize ASSIGN(XNOR) "<widthWords(); w++) { - addWordAssign(nodep, w, new AstXnor(nodep->fileline(), - newAstWordSelClone(rhsp->lhsp(), w), - newAstWordSelClone(rhsp->rhsp(), w))); + UINFO(8, " Wordize ASSIGN(XNOR) " << nodep << endl); + for (int w = 0; w < nodep->widthWords(); w++) { + addWordAssign(nodep, w, + new AstXnor(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w), + newAstWordSelClone(rhsp->rhsp(), w))); } return true; } //-------- Triops bool expandWide(AstNodeAssign* nodep, AstNodeCond* rhsp) { - UINFO(8," Wordize ASSIGN(COND) "<widthWords(); w++) { - addWordAssign(nodep, w, new AstCond(nodep->fileline(), - rhsp->condp()->cloneTree(true), - newAstWordSelClone(rhsp->expr1p(), w), - newAstWordSelClone(rhsp->expr2p(), w))); + UINFO(8, " Wordize ASSIGN(COND) " << nodep << endl); + for (int w = 0; w < nodep->widthWords(); w++) { + addWordAssign(nodep, w, + new AstCond(nodep->fileline(), rhsp->condp()->cloneTree(true), + newAstWordSelClone(rhsp->expr1p(), w), + newAstWordSelClone(rhsp->expr2p(), w))); } return true; } @@ -316,7 +298,7 @@ private: } else if (lhsp->isWide()) { nodep->v3fatalSrc("extending larger thing into smaller?"); } else { - UINFO(8," EXTEND(q<-l) "<fileline(), lhsp, nodep); } } else { // Long @@ -328,12 +310,12 @@ private: } } bool expandWide(AstNodeAssign* nodep, AstExtend* rhsp) { - UINFO(8," Wordize ASSIGN(EXTEND) "<lhsp()->widthWords(); w++) { + for (w = 0; w < rhsp->lhsp()->widthWords(); w++) { addWordAssign(nodep, w, newAstWordSelClone(rhsp->lhsp(), w)); } - for (; wwidthWords(); w++) { + for (; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstConst(rhsp->fileline(), AstConst::SizedEData(), 0)); } return true; @@ -345,33 +327,29 @@ private: // Remember, Sel's may have non-integer rhs, so need to optimize for that! UASSERT_OBJ(nodep->widthMin() == nodep->widthConst(), nodep, "Width mismatch"); if (VN_IS(nodep->backp(), NodeAssign) - && nodep==VN_CAST(nodep->backp(), NodeAssign)->lhsp()) { + && nodep == VN_CAST(nodep->backp(), NodeAssign)->lhsp()) { // Sel is an LHS assignment select } else if (nodep->isWide()) { // See under ASSIGN(WIDE) - } - else if (nodep->fromp()->isWide()) { - UINFO(8," SEL(wide) "<fromp()->isWide()) { + UINFO(8, " SEL(wide) " << nodep << endl); // Selection amounts // Check for constant shifts & save some constification work later. // Grab lowest bit(s) - AstNode* lowwordp = new AstWordSel(nodep->fromp()->fileline(), - nodep->fromp()->cloneTree(true), - newSelBitWord(nodep->lsbp(), 0)); + AstNode* lowwordp + = new AstWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true), + newSelBitWord(nodep->lsbp(), 0)); if (nodep->isQuad() && !lowwordp->isQuad()) { lowwordp = new AstCCast(nodep->fileline(), lowwordp, nodep); } - AstNode* lowp = new AstShiftR(nodep->fileline(), - lowwordp, - newSelBitBit(nodep->lsbp()), + AstNode* lowp = new AstShiftR(nodep->fileline(), lowwordp, newSelBitBit(nodep->lsbp()), nodep->width()); // If > 1 bit, we might be crossing the word boundary AstNode* midp = NULL; - V3Number zero (nodep, longOrQuadWidth(nodep)); + V3Number zero(nodep, longOrQuadWidth(nodep)); if (nodep->widthConst() > 1) { AstNode* midwordp = // SEL(from,[1+wordnum]) - new AstWordSel(nodep->fromp()->fileline(), - nodep->fromp()->cloneTree(true), + new AstWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true), newSelBitWord(nodep->lsbp(), 1)); if (nodep->isQuad() && !midwordp->isQuad()) { midwordp = new AstCCast(nodep->fileline(), midwordp, nodep); @@ -380,23 +358,19 @@ private: // get shifted << by 32 bits // else we need to form the lower word, so we << by 31 or less // nbitsfromlow <= (lsb==0) ? 64-bitbit(lsb) : 32-bitbit(lsb) - AstNode* midshiftp = new AstSub(nodep->lsbp()->fileline(), - new AstConst(nodep->lsbp()->fileline(), - VL_EDATASIZE), - newSelBitBit(nodep->lsbp())); + AstNode* midshiftp + = new AstSub(nodep->lsbp()->fileline(), + new AstConst(nodep->lsbp()->fileline(), VL_EDATASIZE), + newSelBitBit(nodep->lsbp())); if (nodep->isQuad()) { - midshiftp = - new AstCond(nodep->fileline(), - new AstEq(nodep->fileline(), - new AstConst(nodep->fileline(), 0), - newSelBitBit(nodep->lsbp())), - new AstConst(nodep->lsbp()->fileline(), VL_EDATASIZE), - midshiftp); + midshiftp = new AstCond( + nodep->fileline(), + new AstEq(nodep->fileline(), new AstConst(nodep->fileline(), 0), + newSelBitBit(nodep->lsbp())), + new AstConst(nodep->lsbp()->fileline(), VL_EDATASIZE), midshiftp); } - AstNode* midmayp = new AstShiftL(nodep->fileline(), - midwordp, - midshiftp, - nodep->width()); + AstNode* midmayp + = new AstShiftL(nodep->fileline(), midwordp, midshiftp, nodep->width()); if (nodep->isQuad()) { midp = midmayp; // Always grab from two words } else { @@ -404,35 +378,30 @@ private: new AstEq(nodep->fileline(), new AstConst(nodep->fileline(), 0), newSelBitBit(nodep->lsbp())), - new AstConst(nodep->fileline(), zero), - midmayp); + new AstConst(nodep->fileline(), zero), midmayp); } } // If > 32 bits, we might be crossing the second word boundary AstNode* hip = NULL; if (nodep->widthConst() > VL_EDATASIZE) { AstNode* hiwordp = // SEL(from,[2+wordnum]) - new AstWordSel(nodep->fromp()->fileline(), - nodep->fromp()->cloneTree(true), + new AstWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true), newSelBitWord(nodep->lsbp(), 2)); if (nodep->isQuad() && !hiwordp->isQuad()) { hiwordp = new AstCCast(nodep->fileline(), hiwordp, nodep); } - AstNode* himayp = - new AstShiftL(nodep->fileline(), - hiwordp, - // nbitsfromlow_and_mid <= 64-bitbit(lsb) - new AstSub(nodep->lsbp()->fileline(), - new AstConst(nodep->lsbp()->fileline(), 64), - newSelBitBit(nodep->lsbp())), - nodep->width()); + AstNode* himayp + = new AstShiftL(nodep->fileline(), hiwordp, + // nbitsfromlow_and_mid <= 64-bitbit(lsb) + new AstSub(nodep->lsbp()->fileline(), + new AstConst(nodep->lsbp()->fileline(), 64), + newSelBitBit(nodep->lsbp())), + nodep->width()); // if (frombit==0) then ignore, else use it hip = new AstCond(nodep->fileline(), - new AstEq(nodep->fileline(), - new AstConst(nodep->fileline(), 0), + new AstEq(nodep->fileline(), new AstConst(nodep->fileline(), 0), newSelBitBit(nodep->lsbp())), - new AstConst(nodep->fileline(), zero), - himayp); + new AstConst(nodep->fileline(), zero), himayp); } AstNode* newp = lowp; @@ -440,18 +409,16 @@ private: if (hip) newp = new AstOr(nodep->fileline(), hip, newp); newp->dtypeFrom(nodep); VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); - } - else { // Long/Quad from Long/Quad - UINFO(8," SEL->SHIFT "<SHIFT " << nodep << endl); AstNode* fromp = nodep->fromp()->unlinkFrBack(); AstNode* lsbp = nodep->lsbp()->unlinkFrBack(); if (nodep->isQuad() && !fromp->isQuad()) { fromp = new AstCCast(nodep->fileline(), fromp, nodep); } - AstNode* newp = new AstShiftR(nodep->fileline(), - fromp, - dropCondBound(lsbp), - fromp->width()); // {large}>>32 requires 64-bit shift operation; then cast + AstNode* newp = new AstShiftR( + nodep->fileline(), fromp, dropCondBound(lsbp), + fromp->width()); // {large}>>32 requires 64-bit shift operation; then cast newp->dtypeFrom(fromp); if (!nodep->isQuad() && fromp->isQuad()) { newp = new AstCCast(newp->fileline(), newp, nodep); @@ -465,42 +432,35 @@ private: UASSERT_OBJ(nodep->widthMin() == rhsp->widthConst(), nodep, "Width mismatch"); if (VN_IS(rhsp->lsbp(), Const) && VL_BITBIT_E(rhsp->lsbConst()) == 0) { int lsb = rhsp->lsbConst(); - UINFO(8," Wordize ASSIGN(SEL,align) "<widthWords(); w++) { + UINFO(8, " Wordize ASSIGN(SEL,align) " << nodep << endl); + for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, newAstWordSelClone(rhsp->fromp(), w + VL_BITWORD_E(lsb))); } return true; } else { - UINFO(8," Wordize ASSIGN(EXTRACT,misalign) "<widthWords(); w++) { + UINFO(8, " Wordize ASSIGN(EXTRACT,misalign) " << nodep << endl); + for (int w = 0; w < nodep->widthWords(); w++) { // Grab lowest bits - AstNode* lowwordp = new AstWordSel(rhsp->fileline(), - rhsp->fromp()->cloneTree(true), - newSelBitWord(rhsp->lsbp(), w)); - AstNode* lowp = new AstShiftR(rhsp->fileline(), - lowwordp, - newSelBitBit(rhsp->lsbp()), - VL_EDATASIZE); + AstNode* lowwordp + = new AstWordSel(rhsp->fileline(), rhsp->fromp()->cloneTree(true), + newSelBitWord(rhsp->lsbp(), w)); + AstNode* lowp = new AstShiftR(rhsp->fileline(), lowwordp, + newSelBitBit(rhsp->lsbp()), VL_EDATASIZE); // Upper bits - V3Number zero (nodep, VL_EDATASIZE, 0); + V3Number zero(nodep, VL_EDATASIZE, 0); AstNode* midwordp = // SEL(from,[1+wordnum]) - new AstWordSel(rhsp->fromp()->fileline(), - rhsp->fromp()->cloneTree(true), - newSelBitWord(rhsp->lsbp(), w+1)); - AstNode* midshiftp = new AstSub(rhsp->lsbp()->fileline(), - new AstConst(rhsp->lsbp()->fileline(), - VL_EDATASIZE), - newSelBitBit(rhsp->lsbp())); - AstNode* midmayp = new AstShiftL(rhsp->fileline(), - midwordp, - midshiftp, - VL_EDATASIZE); - AstNode* midp = new AstCond(rhsp->fileline(), - new AstEq(rhsp->fileline(), - new AstConst(rhsp->fileline(), 0), - newSelBitBit(rhsp->lsbp())), - new AstConst(rhsp->fileline(), zero), - midmayp); + new AstWordSel(rhsp->fromp()->fileline(), rhsp->fromp()->cloneTree(true), + newSelBitWord(rhsp->lsbp(), w + 1)); + AstNode* midshiftp = new AstSub( + rhsp->lsbp()->fileline(), new AstConst(rhsp->lsbp()->fileline(), VL_EDATASIZE), + newSelBitBit(rhsp->lsbp())); + AstNode* midmayp + = new AstShiftL(rhsp->fileline(), midwordp, midshiftp, VL_EDATASIZE); + AstNode* midp + = new AstCond(rhsp->fileline(), + new AstEq(rhsp->fileline(), new AstConst(rhsp->fileline(), 0), + newSelBitBit(rhsp->lsbp())), + new AstConst(rhsp->fileline(), zero), midmayp); AstNode* newp = new AstOr(nodep->fileline(), midp, lowp); addWordAssign(nodep, w, newp); } @@ -524,99 +484,84 @@ private: AstNode* destp = lhsp->fromp()->unlinkFrBack(); int lsb = lhsp->lsbConst(); int msb = lhsp->msbConst(); - V3Number maskset (nodep, destp->widthMin()); - for (int bit=lsb; bit<(msb+1); bit++) maskset.setBit(bit, 1); - V3Number maskold (nodep, destp->widthMin()); maskold.opNot(maskset); + V3Number maskset(nodep, destp->widthMin()); + for (int bit = lsb; bit < (msb + 1); bit++) maskset.setBit(bit, 1); + V3Number maskold(nodep, destp->widthMin()); + maskold.opNot(maskset); if (destwide) { - UINFO(8," ASSIGNSEL(const,wide) "<widthWords(); w++) { + UINFO(8, " ASSIGNSEL(const,wide) " << nodep << endl); + for (int w = 0; w < destp->widthWords(); w++) { if (w >= VL_BITWORD_E(lsb) && w <= VL_BITWORD_E(msb)) { // else we would just be setting it to the same exact value AstNode* oldvalp = newAstWordSelClone(destp, w); fixCloneLvalue(oldvalp); if (!ones) { - oldvalp = new AstAnd(lhsp->fileline(), - new AstConst(lhsp->fileline(), - AstConst::SizedEData(), - maskold.edataWord(w)), - oldvalp); + oldvalp + = new AstAnd(lhsp->fileline(), + new AstConst(lhsp->fileline(), AstConst::SizedEData(), + maskold.edataWord(w)), + oldvalp); } - addWordAssign(nodep, w, - destp, - new AstOr(lhsp->fileline(), - oldvalp, - newWordGrabShift(lhsp->fileline(), w, - rhsp, lsb))); + addWordAssign(nodep, w, destp, + new AstOr(lhsp->fileline(), oldvalp, + newWordGrabShift(lhsp->fileline(), w, rhsp, lsb))); } } VL_DO_DANGLING(rhsp->deleteTree(), rhsp); VL_DO_DANGLING(destp->deleteTree(), destp); } else { - UINFO(8," ASSIGNSEL(const,narrow) "<isQuad() && !rhsp->isQuad()) { rhsp = new AstCCast(nodep->fileline(), rhsp, nodep); } AstNode* oldvalp = destp->cloneTree(true); fixCloneLvalue(oldvalp); if (!ones) { - oldvalp = new AstAnd(lhsp->fileline(), - new AstConst(lhsp->fileline(), maskold), + oldvalp = new AstAnd(lhsp->fileline(), new AstConst(lhsp->fileline(), maskold), oldvalp); } - AstNode* newp - = new AstOr(lhsp->fileline(), - oldvalp, - new AstShiftL(lhsp->fileline(), - rhsp, - new AstConst(lhsp->fileline(), lsb), - destp->width())); + AstNode* newp = new AstOr(lhsp->fileline(), oldvalp, + new AstShiftL(lhsp->fileline(), rhsp, + new AstConst(lhsp->fileline(), lsb), + destp->width())); newp = new AstAssign(nodep->fileline(), destp, newp); insertBefore(nodep, newp); } return true; - } - else { // non-const RHS - if (destwide && lhsp->widthConst()==1) { - UINFO(8," ASSIGNSEL(varlsb,wide,1bit) "<widthConst() == 1) { + UINFO(8, " ASSIGNSEL(varlsb,wide,1bit) " << nodep << endl); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNode* destp = lhsp->fromp()->unlinkFrBack(); - AstNode* oldvalp = new AstWordSel(lhsp->fileline(), - destp->cloneTree(true), + AstNode* oldvalp = new AstWordSel(lhsp->fileline(), destp->cloneTree(true), newSelBitWord(lhsp->lsbp(), 0)); fixCloneLvalue(oldvalp); if (!ones) { - oldvalp = new AstAnd - (lhsp->fileline(), - new AstNot(lhsp->fileline(), - new AstShiftL - (lhsp->fileline(), - new AstConst(nodep->fileline(), 1), - // newSelBitBit may exceed the MSB of this variable. - // That's ok as we'd just AND with a larger value, - // but oldval would clip the upper bits to sanity - newSelBitBit(lhsp->lsbp()), - VL_EDATASIZE)), - oldvalp); + oldvalp = new AstAnd( + lhsp->fileline(), + new AstNot( + lhsp->fileline(), + new AstShiftL(lhsp->fileline(), new AstConst(nodep->fileline(), 1), + // newSelBitBit may exceed the MSB of this variable. + // That's ok as we'd just AND with a larger value, + // but oldval would clip the upper bits to sanity + newSelBitBit(lhsp->lsbp()), VL_EDATASIZE)), + oldvalp); } // Restrict the shift amount to 0-31, see bug804. AstNode* shiftp = new AstAnd(nodep->fileline(), lhsp->lsbp()->cloneTree(true), new AstConst(nodep->fileline(), VL_EDATASIZE - 1)); - AstNode* newp = new AstOr(lhsp->fileline(), - oldvalp, - new AstShiftL(lhsp->fileline(), - rhsp, - shiftp, - VL_EDATASIZE)); - newp = new AstAssign(nodep->fileline(), - new AstWordSel(nodep->fileline(), - destp, - newSelBitWord(lhsp->lsbp(), 0)), - newp); + AstNode* newp + = new AstOr(lhsp->fileline(), oldvalp, + new AstShiftL(lhsp->fileline(), rhsp, shiftp, VL_EDATASIZE)); + newp = new AstAssign( + nodep->fileline(), + new AstWordSel(nodep->fileline(), destp, newSelBitWord(lhsp->lsbp(), 0)), + newp); insertBefore(nodep, newp); return true; - } - else if (destwide) { - UINFO(8," ASSIGNSEL(varlsb,wide) -- NoOp -- "<dumpTree(cout, "- old: "); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNode* destp = lhsp->fromp()->unlinkFrBack(); AstNode* oldvalp = destp->cloneTree(true); fixCloneLvalue(oldvalp); - V3Number maskwidth (nodep, destp->widthMin()); - for (int bit=0; bit < lhsp->widthConst(); bit++) maskwidth.setBit(bit, 1); + V3Number maskwidth(nodep, destp->widthMin()); + for (int bit = 0; bit < lhsp->widthConst(); bit++) maskwidth.setBit(bit, 1); if (destp->isQuad() && !rhsp->isQuad()) { rhsp = new AstCCast(nodep->fileline(), rhsp, nodep); } if (!ones) { - oldvalp = new AstAnd(lhsp->fileline(), - new AstNot(lhsp->fileline(), - new AstShiftL(lhsp->fileline(), - new AstConst(nodep->fileline(), - maskwidth), - lhsp->lsbp()->cloneTree(true), - destp->width())), - oldvalp); + oldvalp = new AstAnd( + lhsp->fileline(), + new AstNot(lhsp->fileline(), + new AstShiftL(lhsp->fileline(), + new AstConst(nodep->fileline(), maskwidth), + lhsp->lsbp()->cloneTree(true), destp->width())), + oldvalp); } AstNode* newp - = new AstOr(lhsp->fileline(), - oldvalp, - new AstShiftL(lhsp->fileline(), - rhsp, - lhsp->lsbp()->cloneTree(true), - destp->width())); + = new AstOr(lhsp->fileline(), oldvalp, + new AstShiftL(lhsp->fileline(), rhsp, + lhsp->lsbp()->cloneTree(true), destp->width())); newp = new AstAssign(nodep->fileline(), destp, newp); - //newp->dumpTree(cout, "- new: "); + // newp->dumpTree(cout, "- new: "); insertBefore(nodep, newp); return true; } @@ -672,7 +613,7 @@ private: if (nodep->isWide()) { // See under ASSIGN(WIDE) } else { - UINFO(8," CONCAT "<lhsp()->unlinkFrBack(); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); int rhsshift = rhsp->widthMin(); @@ -683,28 +624,26 @@ private: rhsp = new AstCCast(nodep->fileline(), rhsp, nodep); } AstNode* newp = new AstOr(nodep->fileline(), - new AstShiftL(nodep->fileline(), - lhsp, + new AstShiftL(nodep->fileline(), lhsp, new AstConst(nodep->fileline(), rhsshift), nodep->width()), - rhsp); + rhsp); newp->dtypeFrom(nodep); // Unsigned VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } } bool expandWide(AstNodeAssign* nodep, AstConcat* rhsp) { - UINFO(8," Wordize ASSIGN(CONCAT) "<rhsp()->widthMin(); // Sometimes doing the words backwards is preferable. // When we have x={x,foo} backwards is better, when x={foo,x} forward is better // However V3Subst tends to rip this up, so not worth optimizing now. - for (int w=0; wwidthWords(); w++) { + for (int w = 0; w < rhsp->widthWords(); w++) { addWordAssign(nodep, w, new AstOr(rhsp->fileline(), - newWordGrabShift(rhsp->fileline(), w, - rhsp->lhsp(), rhsshift), + newWordGrabShift(rhsp->fileline(), w, rhsp->lhsp(), rhsshift), newAstWordSelClone(rhsp->rhsp(), w))); } return true; @@ -719,11 +658,11 @@ private: AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNode* newp; int lhswidth = lhsp->widthMin(); - if (lhswidth==1) { - UINFO(8," REPLICATE(w1) "<fileline(), lhsp); } else { - UINFO(8," REPLICATE "<rhsp(), Const); UASSERT_OBJ(constp, nodep, "Replication value isn't a constant. Checked earlier!"); @@ -732,14 +671,13 @@ private: lhsp = new AstCCast(nodep->fileline(), lhsp, nodep); } newp = lhsp->cloneTree(true); - for (unsigned repnum=1; repnumfileline(), - new AstShiftL(nodep->fileline(), - lhsp->cloneTree(true), + new AstShiftL(nodep->fileline(), lhsp->cloneTree(true), new AstConst(nodep->fileline(), rhsshift), nodep->width()), - newp); + newp); newp->dtypeFrom(nodep); // Unsigned } VL_DO_DANGLING(lhsp->deleteTree(), lhsp); // Never used @@ -749,25 +687,24 @@ private: } } bool expandWide(AstNodeAssign* nodep, AstReplicate* rhsp) { - UINFO(8," Wordize ASSIGN(REPLICATE) "<lhsp(); int lhswidth = lhsp->widthMin(); const AstConst* constp = VN_CAST(rhsp->rhsp(), Const); UASSERT_OBJ(constp, rhsp, "Replication value isn't a constant. Checked earlier!"); uint32_t times = constp->toUInt(); - for (int w=0; wwidthWords(); w++) { + for (int w = 0; w < rhsp->widthWords(); w++) { AstNode* newp; - if (lhswidth==1) { + if (lhswidth == 1) { newp = new AstNegate(nodep->fileline(), lhsp->cloneTree(true)); newp->dtypeSetLogicSized(VL_EDATASIZE, AstNumeric::UNSIGNED); // Replicate always unsigned } else { newp = newAstWordSelClone(lhsp, w); - for (unsigned repnum=1; repnumfileline(), - newWordGrabShift(rhsp->fileline(), w, lhsp, - lhswidth*repnum), - newp); + for (unsigned repnum = 1; repnum < times; repnum++) { + newp = new AstOr( + nodep->fileline(), + newWordGrabShift(rhsp->fileline(), w, lhsp, lhswidth * repnum), newp); } } addWordAssign(nodep, w, newp); @@ -778,14 +715,13 @@ private: virtual void visit(AstChangeXor* nodep) VL_OVERRIDE { if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); - UINFO(8," Wordize ChangeXor "< (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}} AstNode* newp = NULL; - for (int w=0; wlhsp()->widthWords(); w++) { - AstNode* eqp = new AstXor(nodep->fileline(), - newAstWordSelClone(nodep->lhsp(), w), + for (int w = 0; w < nodep->lhsp()->widthWords(); w++) { + AstNode* eqp = new AstXor(nodep->fileline(), newAstWordSelClone(nodep->lhsp(), w), newAstWordSelClone(nodep->rhsp(), w)); - newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp)); + newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp)); } VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } @@ -794,23 +730,21 @@ private: if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->lhsp()->isWide()) { - UINFO(8," Wordize EQ/NEQ "< (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}} AstNode* newp = NULL; - for (int w=0; wlhsp()->widthWords(); w++) { - AstNode* eqp = new AstXor(nodep->fileline(), - newAstWordSelClone(nodep->lhsp(), w), + for (int w = 0; w < nodep->lhsp()->widthWords(); w++) { + AstNode* eqp = new AstXor(nodep->fileline(), newAstWordSelClone(nodep->lhsp(), w), newAstWordSelClone(nodep->rhsp(), w)); - newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp)); + newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp)); } if (VN_IS(nodep, Neq)) { - newp = new AstNeq(nodep->fileline(), - new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), - newp); + newp + = new AstNeq(nodep->fileline(), + new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp); } else { newp = new AstEq(nodep->fileline(), - new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), - newp); + new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp); } VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } @@ -822,19 +756,18 @@ private: if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->lhsp()->isWide()) { - UINFO(8," Wordize REDOR "< (0!={or{for each_word{WORDSEL(lhs,#)}}} AstNode* newp = NULL; - for (int w=0; wlhsp()->widthWords(); w++) { + for (int w = 0; w < nodep->lhsp()->widthWords(); w++) { AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w); - newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp)); + newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp)); } newp = new AstNeq(nodep->fileline(), - new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), - newp); + new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp); VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } else { - UINFO(8," REDOR->EQ "<EQ " << nodep << endl); AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNode* newp = new AstNeq(nodep->fileline(), new AstConst(nodep->fileline(), AstConst::WidthedValue(), @@ -847,12 +780,12 @@ private: if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->lhsp()->isWide()) { - UINFO(8," Wordize REDAND "< (0!={and{for each_word{WORDSEL(lhs,#)}}} AstNode* newp = NULL; - for (int w=0; wlhsp()->widthWords(); w++) { + for (int w = 0; w < nodep->lhsp()->widthWords(); w++) { AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w); - if (w==nodep->lhsp()->widthWords()-1) { + if (w == nodep->lhsp()->widthWords() - 1) { // Rather than doing a (slowish) ==##, we OR in the // bits that aren't part of the mask eqp = new AstOr(nodep->fileline(), @@ -861,18 +794,17 @@ private: // cppcheck-suppress memleak eqp); } - newp = (newp==NULL) ? eqp : (new AstAnd(nodep->fileline(), newp, eqp)); + newp = (newp == NULL) ? eqp : (new AstAnd(nodep->fileline(), newp, eqp)); } - newp = new AstEq(nodep->fileline(), - new AstConst(nodep->fileline(), AstConst::SizedEData(), - ~VL_MASK_E(0)), newp); + newp = new AstEq( + nodep->fileline(), + new AstConst(nodep->fileline(), AstConst::SizedEData(), ~VL_MASK_E(0)), newp); VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } else { - UINFO(8," REDAND->EQ "<EQ " << nodep << endl); AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNode* newp = new AstEq(nodep->fileline(), - new AstConst(nodep->fileline(), wordMask(lhsp)), - lhsp); + new AstConst(nodep->fileline(), wordMask(lhsp)), lhsp); VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } } @@ -880,15 +812,15 @@ private: if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->lhsp()->isWide()) { - UINFO(8," Wordize REDXOR "< (0!={redxor{for each_word{XOR(WORDSEL(lhs,#))}}} AstNode* newp = NULL; - for (int w=0; wlhsp()->widthWords(); w++) { + for (int w = 0; w < nodep->lhsp()->widthWords(); w++) { AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w); - newp = (newp==NULL) ? eqp : (new AstXor(nodep->fileline(), newp, eqp)); + newp = (newp == NULL) ? eqp : (new AstXor(nodep->fileline(), newp, eqp)); } newp = new AstRedXor(nodep->fileline(), newp); - UINFO(8," Wordize REDXORnew "<isWide() && ((VN_IS(nodep->lhsp(), VarRef) - || VN_IS(nodep->lhsp(), ArraySel))) + if (nodep->isWide() && ((VN_IS(nodep->lhsp(), VarRef) || VN_IS(nodep->lhsp(), ArraySel))) && !AstVar::scVarRecurse(nodep->lhsp()) // Need special function for SC && !AstVar::scVarRecurse(nodep->rhsp())) { if (AstConst* rhsp = VN_CAST(nodep->rhsp(), Const)) { @@ -943,9 +874,7 @@ private: did = expandLhs(nodep, lhsp); } // Cleanup common code - if (did) { - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } + if (did) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); m_stmtp = NULL; } @@ -969,9 +898,7 @@ public: // Expand class functions void V3Expand::expandAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3File.cpp b/src/V3File.cpp index dee1298f2..45527897e 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -33,6 +33,7 @@ #include #include +// clang-format off #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) # define INFILTER_PIPE // Allow pipe filtering. Needs fork() #endif @@ -52,11 +53,12 @@ #if defined(_WIN32) || defined(__MINGW32__) # include // open, read, write, close #endif +// clang-format on // If change this code, run a test with the below size set very small //#define INFILTER_IPC_BUFSIZ 16 -#define INFILTER_IPC_BUFSIZ (64*1024) // For debug, try this as a small number -#define INFILTER_CACHE_MAX (64*1024) // Maximum bytes to cache if same file read twice +#define INFILTER_IPC_BUFSIZ (64 * 1024) // For debug, try this as a small number +#define INFILTER_CACHE_MAX (64 * 1024) // Maximum bytes to cache if same file read twice //###################################################################### // V3File Internal state @@ -65,13 +67,15 @@ class V3FileDependImp { // TYPES class DependFile { // A single file - bool m_target; // True if write, else read - bool m_exists; - string m_filename; // Filename - struct stat m_stat; // Stat information + bool m_target; // True if write, else read + bool m_exists; + string m_filename; // Filename + struct stat m_stat; // Stat information public: DependFile(const string& filename, bool target) - : m_target(target), m_exists(true), m_filename(filename) { + : m_target(target) + , m_exists(true) + , m_filename(filename) { m_stat.st_ctime = 0; m_stat.st_mtime = 0; } @@ -89,16 +93,16 @@ class V3FileDependImp { if (!m_stat.st_mtime) { string fn = filename(); int err = stat(fn.c_str(), &m_stat); - if (err!=0) { + if (err != 0) { memset(&m_stat, 0, sizeof(m_stat)); m_stat.st_mtime = 1; m_exists = false; // Not an error... This can occur due to `line directives in the .vpp files - UINFO(1,"-Info: File not statable: "< ofp (V3File::new_ofstream(filename)); - if (ofp->fail()) v3fatal("Can't write "< ofp(V3File::new_ofstream(filename)); + if (ofp->fail()) v3fatal("Can't write " << filename); - for (std::set::iterator iter=m_filenameList.begin(); - iter!=m_filenameList.end(); ++iter) { - if (iter->target()) { - *ofp<filename()<<" "; - } + for (std::set::iterator iter = m_filenameList.begin(); + iter != m_filenameList.end(); ++iter) { + if (iter->target()) { *ofp << iter->filename() << " "; } } - *ofp<<" : "; - *ofp<::iterator iter=m_filenameList.begin(); - iter!=m_filenameList.end(); ++iter) { - if (!iter->target()) { - *ofp<filename()<<" "; - } + for (std::set::iterator iter = m_filenameList.begin(); + iter != m_filenameList.end(); ++iter) { + if (!iter->target()) { *ofp << iter->filename() << " "; } } - *ofp<::iterator iter=m_filenameList.begin(); - iter!=m_filenameList.end(); ++iter) { - if (!iter->target()) { - *ofp<filename()<<":"<::iterator iter = m_filenameList.begin(); + iter != m_filenameList.end(); ++iter) { + if (!iter->target()) { *ofp << iter->filename() << ":" << endl; } } } } inline std::vector V3FileDependImp::getAllDeps() const { std::vector r; - for (std::set::const_iterator iter=m_filenameList.begin(); - iter!=m_filenameList.end(); ++iter) { - if (!iter->target() && iter->exists()) { - r.push_back(iter->filename()); - } + for (std::set::const_iterator iter = m_filenameList.begin(); + iter != m_filenameList.end(); ++iter) { + if (!iter->target() && iter->exists()) { r.push_back(iter->filename()); } } return r; } inline void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) { - const vl_unique_ptr ofp (V3File::new_ofstream(filename)); - if (ofp->fail()) v3fatal("Can't write "< ofp(V3File::new_ofstream(filename)); + if (ofp->fail()) v3fatal("Can't write " << filename); string cmdline = stripQuotes(cmdlineIn); - *ofp<<"# DESCR"<<"IPTION: Verilator output: Timestamp data for --skip-identical. Delete at will."<::iterator iter=m_filenameList.begin(); - iter!=m_filenameList.end(); ++iter) { + for (std::set::iterator iter = m_filenameList.begin(); + iter != m_filenameList.end(); ++iter) { // Read stats of files we create after we're done making them // (except for this file, of course) DependFile* dfp = const_cast(&(*iter)); @@ -204,84 +203,97 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm off_t showSize = iter->size(); ino_t showIno = iter->ino(); if (dfp->filename() == filename) { - showSize = 0; showIno = 0; // We're writing it, so need to ignore it + showSize = 0; + showIno = 0; // We're writing it, so need to ignore it } - *ofp<<(iter->target()?"T":"S")<<" "; - *ofp<<" "<cstime(); - *ofp<<" "<cnstime(); - *ofp<<" "<mstime(); - *ofp<<" "<mnstime(); - *ofp<<" \""<filename()<<"\""; - *ofp<target() ? "T" : "S") << " "; + *ofp << " " << std::setw(8) << showSize; + *ofp << " " << std::setw(8) << showIno; + *ofp << " " << std::setw(11) << iter->cstime(); + *ofp << " " << std::setw(11) << iter->cnstime(); + *ofp << " " << std::setw(11) << iter->mstime(); + *ofp << " " << std::setw(11) << iter->mnstime(); + *ofp << " \"" << iter->filename() << "\""; + *ofp << endl; } } inline bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn) { - const vl_unique_ptr ifp (V3File::new_ifstream_nodepend(filename)); + const vl_unique_ptr ifp(V3File::new_ifstream_nodepend(filename)); if (ifp->fail()) { - UINFO(2," --check-times failed: no input "<>chkDir; - char quote; *ifp>>quote; + char chkDir; + *ifp >> chkDir; + char quote; + *ifp >> quote; string chkCmdline = V3Os::getline(*ifp, '"'); string cmdline = stripQuotes(cmdlineIn); if (cmdline != chkCmdline) { - UINFO(2," --check-times failed: different command line\n"); + UINFO(2, " --check-times failed: different command line\n"); return false; } } while (!ifp->eof()) { - char chkDir; *ifp>>chkDir; - off_t chkSize; *ifp>>chkSize; - ino_t chkIno; *ifp>>chkIno; + char chkDir; + *ifp >> chkDir; + off_t chkSize; + *ifp >> chkSize; + ino_t chkIno; + *ifp >> chkIno; if (ifp->eof()) break; // Needed to read final whitespace before found eof - time_t chkCstime; *ifp>>chkCstime; - time_t chkCnstime; *ifp>>chkCnstime; - time_t chkMstime; *ifp>>chkMstime; - time_t chkMnstime; *ifp>>chkMnstime; - char quote; *ifp>>quote; + time_t chkCstime; + *ifp >> chkCstime; + time_t chkCnstime; + *ifp >> chkCnstime; + time_t chkMstime; + *ifp >> chkMstime; + time_t chkMnstime; + *ifp >> chkMnstime; + char quote; + *ifp >> quote; string chkFilename = V3Os::getline(*ifp, '"'); V3Options::fileNfsFlush(chkFilename); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) struct stat chkStat; int err = stat(chkFilename.c_str(), &chkStat); - if (err!=0) { - UINFO(2," --check-times failed: missing "< V3File::getAllDeps() { - return dependImp.getAllDeps(); -} +void V3File::addSrcDepend(const string& filename) { dependImp.addSrcDepend(filename); } +void V3File::addTgtDepend(const string& filename) { dependImp.addTgtDepend(filename); } +void V3File::writeDepend(const string& filename) { dependImp.writeDepend(filename); } +std::vector V3File::getAllDeps() { return dependImp.getAllDeps(); } void V3File::writeTimes(const string& filename, const string& cmdlineIn) { dependImp.writeTimes(filename, cmdlineIn); } @@ -313,7 +317,8 @@ bool V3File::checkTimes(const string& filename, const string& cmdlineIn) { void V3File::createMakeDirFor(const string& filename) { if (filename != VL_DEV_NULL // If doesn't start with makeDir then some output file user requested - && filename.substr(0, v3Global.opt.makeDir().length()+1) == v3Global.opt.makeDir()+"/") { + && filename.substr(0, v3Global.opt.makeDir().length() + 1) + == v3Global.opt.makeDir() + "/") { createMakeDir(); } } @@ -329,41 +334,44 @@ void V3File::createMakeDir() { // VInFilterImp class VInFilterImp { - typedef std::map FileContentsMap; + typedef std::map FileContentsMap; typedef VInFilter::StrList StrList; - FileContentsMap m_contentsMap; // Cache of file contents - bool m_readEof; // Received EOF on read + FileContentsMap m_contentsMap; // Cache of file contents + bool m_readEof; // Received EOF on read #ifdef INFILTER_PIPE - pid_t m_pid; // fork() process id + pid_t m_pid; // fork() process id #else - int m_pid; // fork() process id - always zero as disabled + int m_pid; // fork() process id - always zero as disabled #endif - bool m_pidExited; - int m_pidStatus; - int m_writeFd; // File descriptor TO filter - int m_readFd; // File descriptor FROM filter + bool m_pidExited; + int m_pidStatus; + int m_writeFd; // File descriptor TO filter + int m_readFd; // File descriptor FROM filter private: // METHODS VL_DEBUG_FUNC; // Declare debug() bool readContents(const string& filename, StrList& outl) { - if (m_pid) return readContentsFilter(filename, outl); - else return readContentsFile(filename, outl); + if (m_pid) { + return readContentsFilter(filename, outl); + } else { + return readContentsFile(filename, outl); + } } bool readContentsFile(const string& filename, StrList& outl) { int fd = open(filename.c_str(), O_RDONLY); - if (fd<0) return false; + if (fd < 0) return false; m_readEof = false; readBlocks(fd, -1, outl); close(fd); return true; } bool readContentsFilter(const string& filename, StrList& outl) { - if (filename!="" || outl.empty()) {} // Prevent unused + if (filename != "" || outl.empty()) {} // Prevent unused #ifdef INFILTER_PIPE - writeFilter("read \""+filename+"\"\n"); + writeFilter("read \"" + filename + "\"\n"); string line = readFilterLine(); if (line.find("Content-Length") != string::npos) { int len = 0; @@ -371,7 +379,7 @@ private: readBlocks(m_readFd, len, outl); return true; } else { - if (line!="") v3error("--pipe-filter protocol error, unexpected: "<sizegot)) { + while (!m_readEof && (size < 0 || size > sizegot)) { ssize_t todo = INFILTER_IPC_BUFSIZ; - if (size>0 && size 0 && size < todo) todo = size; errno = 0; ssize_t got = read(fd, buf, todo); - //UINFO(9,"RD GOT g "<< got<<" e "<0) { + // UINFO(9,"RD GOT g "<< got<<" e "< 0) { outl.push_back(string(buf, got)); sizegot += got; - } - else if (errno == EINTR || errno == EAGAIN + } else if (errno == EINTR || errno == EAGAIN #ifdef EWOULDBLOCK - || errno == EWOULDBLOCK + || errno == EWOULDBLOCK #endif - ) { - checkFilter(false); V3Os::u_sleep(1000); continue; - } else { m_readEof = true; break; } + ) { + checkFilter(false); + V3Os::u_sleep(1000); + continue; + } else { + m_readEof = true; + break; + } } return out; } // cppcheck-suppress unusedFunction unusedPrivateFunction string readFilterLine() { // Slow, but we don't need it much - UINFO(9,"readFilterLine\n"); + UINFO(9, "readFilterLine\n"); string line; while (!m_readEof) { StrList outl; @@ -427,65 +441,81 @@ private: string onechar = listString(outl); line += onechar; if (onechar == "\n") { - if (line == "\n") { line = ""; continue; } - else break; + if (line == "\n") { + line = ""; + continue; + } else { + break; + } } } - UINFO(6,"filter-line-in: "<=6) { UINFO(6,"filter-out: "<= 6) { + UINFO(6, "filter-out: " << out); + if (out[out.length() - 1] != '\n') cout << endl; + } + if (!m_pid) { + v3error("--pipe-filter: write to closed file\n"); + m_readEof = true; + stop(); + } unsigned offset = 0; - while (!m_readEof && out.length()>offset) { + while (!m_readEof && out.length() > offset) { errno = 0; - int got = write(m_writeFd, (out.c_str())+offset, out.length()-offset); - //UINFO(9,"WR GOT g "<< got<<" e "<0) offset += got; - else if (errno == EINTR || errno == EAGAIN + int got = write(m_writeFd, (out.c_str()) + offset, out.length() - offset); + // UINFO(9,"WR GOT g "<< got<<" e "< 0) { + offset += got; + } else if (errno == EINTR || errno == EAGAIN #ifdef EWOULDBLOCK - || errno == EWOULDBLOCK + || errno == EWOULDBLOCK #endif - ) { - checkFilter(false); V3Os::u_sleep(1000); continue; + ) { + checkFilter(false); + V3Os::u_sleep(1000); + continue; + } else { + break; } - else break; } } // Start the filter void start(const string& command) { - if (command=="") { + if (command == "") { m_pid = 0; // Disabled } else { startFilter(command); } } void startFilter(const string& command) { - if (command=="") {} // Prevent Unused + if (command == "") {} // Prevent Unused #ifdef INFILTER_PIPE int fd_stdin[2], fd_stdout[2]; static const int P_RD = 0; static const int P_WR = 1; if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) { - v3fatal("--pipe-filter: Can't pipe: "<"<"<" + << fd_stdin[P_RD] << " stdout " << fd_stdout[P_WR] + << "->" << fd_stdout[P_RD] << endl); m_pid = pid; m_pidExited = false; m_pidStatus = 0; @@ -517,7 +546,7 @@ private: flags = fcntl(m_writeFd, F_GETFL, 0); fcntl(m_writeFd, F_SETFL, flags | O_NONBLOCK); } - UINFO(6,"startFilter complete\n"); + UINFO(6, "startFilter complete\n"); #else v3fatalSrc("--pipe-filter not implemented on this platform"); #endif @@ -527,16 +556,16 @@ private: if (m_pid) stopFilter(); } void stopFilter() { - UINFO(6,"Stopping filter process\n"); + UINFO(6, "Stopping filter process\n"); #ifdef INFILTER_PIPE close(m_writeFd); checkFilter(true); - if (!WIFEXITED(m_pidStatus) || WEXITSTATUS(m_pidStatus)!=0) { + if (!WIFEXITED(m_pidStatus) || WEXITSTATUS(m_pidStatus) != 0) { v3fatal("--pipe-filter returned bad status"); } m_pid = 0; close(m_readFd); - UINFO(6,"Closed\n"); + UINFO(6, "Closed\n"); #else v3fatalSrc("--pipe-filter not implemented on this platform"); #endif @@ -562,16 +591,12 @@ protected: } size_t listSize(StrList& sl) { size_t out = 0; - for (StrList::iterator it=sl.begin(); it!=sl.end(); ++it) { - out += it->length(); - } + for (StrList::iterator it = sl.begin(); it != sl.end(); ++it) out += it->length(); return out; } string listString(StrList& sl) { string out; - for (StrList::iterator it=sl.begin(); it!=sl.end(); ++it) { - out += *it; - } + for (StrList::iterator it = sl.begin(); it != sl.end(); ++it) out += *it; return out; } // CONSTRUCTORS @@ -592,7 +617,9 @@ protected: // Just dispatch to the implementation VInFilter::VInFilter(const string& command) { m_impp = new VInFilterImp(command); } -VInFilter::~VInFilter() { if (m_impp) VL_DO_CLEAR(delete m_impp, m_impp = NULL); } +VInFilter::~VInFilter() { + if (m_impp) VL_DO_CLEAR(delete m_impp, m_impp = NULL); +} bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl) { if (!m_impp) v3fatalSrc("readWholefile on invalid filter"); @@ -603,40 +630,46 @@ bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl) // V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code. V3OutFormatter::V3OutFormatter(const string& filename, V3OutFormatter::Language lang) - : m_filename(filename), m_lang(lang) - , m_lineno(1), m_column(0) - , m_nobreak(false), m_prependIndent(true), m_indentLevel(0), m_bracketLevel(0) { + : m_filename(filename) + , m_lang(lang) + , m_lineno(1) + , m_column(0) + , m_nobreak(false) + , m_prependIndent(true) + , m_indentLevel(0) + , m_bracketLevel(0) { m_blockIndent = v3Global.opt.decoration() ? 4 : 1; - m_commaWidth = v3Global.opt.decoration() ? 50 : 150; + m_commaWidth = v3Global.opt.decoration() ? 50 : 150; } //---------------------------------------------------------------------- const string V3OutFormatter::indentSpaces(int num) { // Indent the specified number of spaces. Use spaces. - static char str[MAXSPACE+20]; + static char str[MAXSPACE + 20]; char* cp = str; - if (num>MAXSPACE) num = MAXSPACE; - while (num>0) { + if (num > MAXSPACE) num = MAXSPACE; + while (num > 0) { *cp++ = ' '; - num --; + --num; } *cp++ = '\0'; - string st (str); + string st(str); return st; } bool V3OutFormatter::tokenStart(const char* cp, const char* cmp) { - while (*cmp == *cp) { cp++; cmp++; } + while (*cmp == *cp) { + ++cp; + ++cmp; + } if (*cmp) return false; if (*cp && !isspace(*cp)) return false; return true; } bool V3OutFormatter::tokenEnd(const char* cp) { - return (tokenStart(cp, "end") - || tokenStart(cp, "endcase") - || tokenStart(cp, "endmodule")); + return (tokenStart(cp, "end") || tokenStart(cp, "endcase") || tokenStart(cp, "endmodule")); } int V3OutFormatter::endLevels(const char* strg) { @@ -653,32 +686,26 @@ int V3OutFormatter::endLevels(const char* strg) { { // label/public/private: Deindent by 2 spaces const char* mp = cp; - for (; isalnum(*mp); mp++) ; - if (mp[0]==':' && mp[1]!=':') return (levels-m_blockIndent/2); + for (; isalnum(*mp); mp++) {} + if (mp[0] == ':' && mp[1] != ':') return (levels - m_blockIndent / 2); } } // We want "} else {" to be one level to the left of normal - for (const char* cp=strg; *cp; cp++) { + for (const char* cp = strg; *cp; cp++) { switch (*cp) { case '}': - case ')': - levels -= m_blockIndent; - break; + case ')': levels -= m_blockIndent; break; case '<': - if (m_lang==LA_XML) { + if (m_lang == LA_XML) { if (cp[1] == '/') levels -= m_blockIndent; } break; case 'e': - if (m_lang==LA_VERILOG && tokenEnd(cp)) { - levels -= m_blockIndent; - } + if (m_lang == LA_VERILOG && tokenEnd(cp)) levels -= m_blockIndent; break; case '\t': - case ' ': - break; // Continue - default: - return levels; // Letter + case ' ': break; // Continue + default: return levels; // Letter } } return levels; @@ -691,28 +718,26 @@ void V3OutFormatter::puts(const char* strg) { } bool wordstart = true; bool equalsForBracket = false; // Looking for "= {" - for (const char* cp=strg; *cp; cp++) { + for (const char* cp = strg; *cp; cp++) { putcNoTracking(*cp); switch (*cp) { case '\n': m_lineno++; wordstart = true; - if (cp[1]=='\0') { - m_prependIndent = true; // Add the indent later, may be a indentInc/indentDec called between now and then + if (cp[1] == '\0') { + // Add the indent later, may be a indentInc/indentDec + // called between now and then + m_prependIndent = true; } else { m_prependIndent = false; - putsNoTracking(indentSpaces(endLevels(cp+1))); + putsNoTracking(indentSpaces(endLevels(cp + 1))); } break; - case ' ': - wordstart = true; - break; - case '\t': - wordstart = true; - break; + case ' ': wordstart = true; break; + case '\t': wordstart = true; break; case '/': - if (m_lang==LA_C || m_lang==LA_VERILOG) { - if (cp>strg && cp[-1]=='/') { + if (m_lang == LA_C || m_lang == LA_VERILOG) { + if (cp > strg && cp[-1] == '/') { // Output ignoring contents to EOL cp++; while (*cp && cp[1] && cp[1] != '\n') putcNoTracking(*cp++); @@ -721,15 +746,16 @@ void V3OutFormatter::puts(const char* strg) { } break; case '{': - if (m_lang==LA_C && (equalsForBracket || m_bracketLevel)) { + if (m_lang == LA_C && (equalsForBracket || m_bracketLevel)) { // Break up large code inside "= { ..." - m_parenVec.push(m_indentLevel*m_blockIndent); // Line up continuation with block+1 + m_parenVec.push(m_indentLevel + * m_blockIndent); // Line up continuation with block+1 ++m_bracketLevel; } indentInc(); break; case '}': - if (m_bracketLevel>0) { + if (m_bracketLevel > 0) { m_parenVec.pop(); --m_bracketLevel; } @@ -738,9 +764,11 @@ void V3OutFormatter::puts(const char* strg) { case '(': indentInc(); if (v3Global.opt.decoration()) { - m_parenVec.push(m_column); // Line up continuation with open paren, plus one indent + // Line up continuation with open paren, plus one indent + m_parenVec.push(m_column); } else { - m_parenVec.push(m_indentLevel*m_blockIndent); // Line up continuation with block+1 + // Line up continuation with block+1 + m_parenVec.push(m_indentLevel * m_blockIndent); } break; case ')': @@ -748,59 +776,50 @@ void V3OutFormatter::puts(const char* strg) { indentDec(); break; case '<': - if (m_lang==LA_XML) { - if (cp[1] == '/') {} // Zero as the > will result in net decrease by one - else if (cp[1] == '!' || cp[1] == '?') { indentInc(); } // net same indent - else { indentInc(); indentInc(); } // net increase by one + if (m_lang == LA_XML) { + if (cp[1] == '/') { + // Zero as the > will result in net decrease by one + } else if (cp[1] == '!' || cp[1] == '?') { + indentInc(); // net same indent + } else { + indentInc(); // net increase by one + indentInc(); + } } break; case '>': - if (m_lang==LA_XML) { + if (m_lang == LA_XML) { indentDec(); - if (cp>strg && cp[-1]=='/') indentDec(); // < ..... /> stays same level + if (cp > strg && cp[-1] == '/') indentDec(); // < ..... /> stays same level } break; case 'b': - if (wordstart && m_lang==LA_VERILOG && tokenStart(cp, "begin")) { - indentInc(); - } + if (wordstart && m_lang == LA_VERILOG && tokenStart(cp, "begin")) indentInc(); wordstart = false; break; case 'c': - if (wordstart && m_lang==LA_VERILOG - && (tokenStart(cp, "case") - || tokenStart(cp, "casex") + if (wordstart && m_lang == LA_VERILOG + && (tokenStart(cp, "case") || tokenStart(cp, "casex") || tokenStart(cp, "casez"))) { indentInc(); } wordstart = false; break; case 'e': - if (wordstart && m_lang==LA_VERILOG && tokenEnd(cp)) { - indentDec(); - } + if (wordstart && m_lang == LA_VERILOG && tokenEnd(cp)) { indentDec(); } wordstart = false; break; case 'm': - if (wordstart && m_lang==LA_VERILOG && tokenStart(cp, "module")) { - indentInc(); - } - wordstart = false; - break; - default: + if (wordstart && m_lang == LA_VERILOG && tokenStart(cp, "module")) { indentInc(); } wordstart = false; break; + default: wordstart = false; break; } switch (*cp) { - case '=': - equalsForBracket = true; - break; - case ' ': - break; - default: - equalsForBracket = false; - break; + case '=': equalsForBracket = true; break; + case ' ': break; + default: equalsForBracket = false; break; } } } @@ -812,7 +831,7 @@ void V3OutFormatter::putBreakExpr() { // Add a line break if too wide void V3OutFormatter::putBreak() { if (!m_nobreak) { - //char s[1000]; sprintf(s, "{%d,%d}", m_column, m_parenVec.top()); putsNoTracking(s); + // char s[1000]; sprintf(s, "{%d,%d}", m_column, m_parenVec.top()); putsNoTracking(s); if (exceededWidth()) { putcNoTracking('\n'); if (!m_parenVec.empty()) putsNoTracking(indentSpaces(m_parenVec.top())); @@ -825,16 +844,14 @@ void V3OutFormatter::putsQuoted(const string& strg) { // Don't use to quote a filename for #include - #include doesn't \ escape. putcNoTracking('"'); string quoted = quoteNameControls(strg); - for (string::const_iterator cp=quoted.begin(); cp!=quoted.end(); ++cp) { + for (string::const_iterator cp = quoted.begin(); cp != quoted.end(); ++cp) { putcNoTracking(*cp); } putcNoTracking('"'); } void V3OutFormatter::putsNoTracking(const string& strg) { // Don't track {}'s, probably because it's a $display format string - for (string::const_iterator cp=strg.begin(); cp!=strg.end(); ++cp) { - putcNoTracking(*cp); - } + for (string::const_iterator cp = strg.begin(); cp != strg.end(); ++cp) putcNoTracking(*cp); } void V3OutFormatter::putcNoTracking(char chr) { @@ -844,15 +861,11 @@ void V3OutFormatter::putcNoTracking(char chr) { m_column = 0; m_nobreak = true; break; - case '\t': - m_column = ((m_column + 9)/8)*8; - break; + case '\t': m_column = ((m_column + 9) / 8) * 8; break; case ' ': case '(': case '|': - case '&': - m_column++; - break; + case '&': m_column++; break; default: m_column++; m_nobreak = false; @@ -865,43 +878,45 @@ string V3OutFormatter::quoteNameControls(const string& namein, V3OutFormatter::L // Encode control chars into output-appropriate escapes // Reverse is V3Parse::deQuote string out; - if (lang==LA_XML) { + if (lang == LA_XML) { // Encode chars into XML string - for (string::const_iterator pos=namein.begin(); pos!=namein.end(); ++pos) { - if (pos[0]=='"') { + for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) { + if (pos[0] == '"') { out += string("""); - } else if (pos[0]=='\'') { + } else if (pos[0] == '\'') { out += string("'"); - } else if (pos[0]=='<') { + } else if (pos[0] == '<') { out += string("<"); - } else if (pos[0]=='>') { + } else if (pos[0] == '>') { out += string(">"); - } else if (pos[0]=='&') { + } else if (pos[0] == '&') { out += string("&"); } else if (isprint(pos[0])) { out += pos[0]; } else { - char decimal[10]; sprintf(decimal, "&#%u;", (unsigned char)pos[0]); + char decimal[10]; + sprintf(decimal, "&#%u;", (unsigned char)pos[0]); out += decimal; } } } else { // Encode control chars into C style escapes - for (string::const_iterator pos=namein.begin(); pos!=namein.end(); ++pos) { - if (pos[0]=='\\' || pos[0]=='"') { - out += string("\\")+pos[0]; - } else if (pos[0]=='\n') { + for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) { + if (pos[0] == '\\' || pos[0] == '"') { + out += string("\\") + pos[0]; + } else if (pos[0] == '\n') { out += "\\n"; - } else if (pos[0]=='\r') { + } else if (pos[0] == '\r') { out += "\\r"; - } else if (pos[0]=='\t') { + } else if (pos[0] == '\t') { out += "\\t"; } else if (isprint(pos[0])) { out += pos[0]; } else { // This will also cover \a etc // Can't use %03o as messes up when signed - char octal[10]; sprintf(octal, "\\%o%o%o", (pos[0]>>6)&3, (pos[0]>>3)&7, pos[0]&7); + char octal[10]; + sprintf(octal, "\\%o%o%o", (pos[0] >> 6) & 3, (pos[0] >> 3) & 7, pos[0] & 7); out += octal; } } @@ -926,9 +941,7 @@ void V3OutFormatter::printf(const char* fmt...) { V3OutFile::V3OutFile(const string& filename, V3OutFormatter::Language lang) : V3OutFormatter(filename, lang) { - if ((m_fp = V3File::new_fopen_w(filename)) == NULL) { - v3fatal("Cannot write "< IdMap; + typedef std::map IdMap; IdMap m_nameMap; // Map of old name into new name typedef vl_unordered_set IdSet; IdSet m_newIdSet; // Which new names exist protected: // CONSTRUCTORS friend class VIdProtect; - static VIdProtectImp& singleton() { static VIdProtectImp s; return s; } + static VIdProtectImp& singleton() { + static VIdProtectImp s; + return s; + } + public: VIdProtectImp() { passthru("this"); @@ -981,10 +998,9 @@ public: IdMap::iterator it = m_nameMap.find(old); if (it != m_nameMap.end()) { // No way to go back and correct the older crypt name - UASSERT(old == it->second, "Passthru request for '" - +old+"' after already --protect-ids of it."); - } - else { + UASSERT(old == it->second, + "Passthru request for '" + old + "' after already --protect-ids of it."); + } else { m_nameMap.insert(make_pair(old, old)); m_newIdSet.insert(old); } @@ -993,19 +1009,20 @@ public: string protectIf(const string& old, bool doIt) { if (!v3Global.opt.protectIds() || old.empty() || !doIt) return old; IdMap::iterator it = m_nameMap.find(old); - if (it != m_nameMap.end()) return it->second; + if (it != m_nameMap.end()) + return it->second; else { string out; if (v3Global.opt.debugProtect()) { // This lets us see the symbol being protected to debug cases // where e.g. the definition is protect() but reference is // missing a protect() - out = "PS"+old; + out = "PS" + old; } else { - VHashSha256 digest (v3Global.opt.protectKeyDefaulted()); + VHashSha256 digest(v3Global.opt.protectKeyDefaulted()); digest.insert(old); // Add "PS" prefix (Protect Symbols) as cannot start symbol with number - out = "PS"+digest.digestSymbol(); + out = "PS" + digest.digestSymbol(); // See if we can shrink the digest symbol to something smaller for (size_t len = 6; len < out.size() - 3; len += 3) { string tryout = out.substr(0, len); @@ -1030,28 +1047,30 @@ public: // When C++11, use find_if and lambda string::size_type pos = string::npos; string separator; - trySep(old, start, " ", pos/*ref*/, separator/*ref*/); - trySep(old, start, ".", pos/*ref*/, separator/*ref*/); - trySep(old, start, "->", pos/*ref*/, separator/*ref*/); + trySep(old, start, " ", pos /*ref*/, separator /*ref*/); + trySep(old, start, ".", pos /*ref*/, separator /*ref*/); + trySep(old, start, "->", pos /*ref*/, separator /*ref*/); if (pos == string::npos) break; - out += protectIf(old.substr(start, pos-start), true) + separator; + out += protectIf(old.substr(start, pos - start), true) + separator; start = pos + separator.length(); } out += protectIf(old.substr(start), true); return out; } void writeMapFile(const string& filename) const { - V3OutXmlFile of (filename); + V3OutXmlFile of(filename); of.putsHeader(); - of.puts("\n"); + of.puts("\n"); of.puts("\n"); { for (IdMap::const_iterator it = m_nameMap.begin(); it != m_nameMap.end(); ++it) { - of.puts("second+"\" to=\""+it->first+"\"/>\n"); + of.puts("second + "\" to=\"" + it->first + "\"/>\n"); } } of.puts("\n"); } + private: void trySep(const string& old, string::size_type start, const string& trySep, string::size_type& posr, string& separatorr) { diff --git a/src/V3File.h b/src/V3File.h index c5cb7fe2f..dcbb7672e 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -40,11 +40,11 @@ public: static std::ifstream* new_ifstream_nodepend(const string& filename) { return new std::ifstream(filename.c_str()); } - static std::ofstream* new_ofstream(const string& filename, bool append=false) { + static std::ofstream* new_ofstream(const string& filename, bool append = false) { addTgtDepend(filename); return new_ofstream_nodepend(filename, append); } - static std::ofstream* new_ofstream_nodepend(const string& filename, bool append=false) { + static std::ofstream* new_ofstream_nodepend(const string& filename, bool append = false) { createMakeDirFor(filename); if (append) { return new std::ofstream(filename.c_str(), std::ios::app); @@ -86,6 +86,7 @@ private: // CONSTRUCTORS VL_UNCOPYABLE(VInFilter); + public: explicit VInFilter(const string& command); ~VInFilter(); @@ -100,12 +101,9 @@ public: class V3OutFormatter { // TYPES - enum MiscConsts { - MAXSPACE = 80}; // After this indent, stop indenting more + enum MiscConsts { MAXSPACE = 80 }; // After this indent, stop indenting more public: - enum AlignClass { - AL_AUTO = 0, - AL_STATIC = 1}; + enum AlignClass { AL_AUTO = 0, AL_STATIC = 1 }; enum Language { LA_C = 0, LA_VERILOG = 1, @@ -115,17 +113,17 @@ public: private: // MEMBERS - string m_filename; - Language m_lang; // Indenting Verilog code - int m_blockIndent; // Characters per block indent - int m_commaWidth; // Width after which to break at ,'s - int m_lineno; - int m_column; - int m_nobreak; // Basic operator or begin paren, don't break next - bool m_prependIndent; - int m_indentLevel; // Current {} indentation + string m_filename; + Language m_lang; // Indenting Verilog code + int m_blockIndent; // Characters per block indent + int m_commaWidth; // Width after which to break at ,'s + int m_lineno; + int m_column; + int m_nobreak; // Basic operator or begin paren, don't break next + bool m_prependIndent; + int m_indentLevel; // Current {} indentation std::stack m_parenVec; // Stack of columns where last ( was - int m_bracketLevel; // Intenting = { block, indicates number of {'s seen. + int m_bracketLevel; // Intenting = { block, indicates number of {'s seen. int endLevels(const char* strg); void putcNoTracking(char chr); @@ -146,18 +144,26 @@ public: void putsQuoted(const string& strg); void putBreak(); // Print linebreak if line is too wide void putBreakExpr(); // Print linebreak in expression if line is too wide - void putbs(const char* strg) { putBreakExpr(); puts(strg); } - void putbs(const string& strg) { putBreakExpr(); puts(strg); } + void putbs(const char* strg) { + putBreakExpr(); + puts(strg); + } + void putbs(const string& strg) { + putBreakExpr(); + puts(strg); + } bool exceededWidth() const { return m_column > m_commaWidth; } bool tokenStart(const char* cp, const char* cmp); bool tokenEnd(const char* cp); void indentInc() { m_indentLevel += m_blockIndent; } void indentDec() { m_indentLevel -= m_blockIndent; - UASSERT(m_indentLevel>=0, ": "<= 0, ": " << m_filename << ": Underflow of indentation"); } void blockInc() { m_parenVec.push(m_indentLevel + m_blockIndent); } - void blockDec() { if (!m_parenVec.empty()) m_parenVec.pop(); } + void blockDec() { + if (!m_parenVec.empty()) m_parenVec.pop(); + } // STATIC METHODS static const string indentSpaces(int num); // Add escaped characters to strings @@ -172,11 +178,13 @@ public: class V3OutFile : public V3OutFormatter { // MEMBERS - FILE* m_fp; + FILE* m_fp; + public: V3OutFile(const string& filename, V3OutFormatter::Language lang); virtual ~V3OutFile(); void putsForceIncs(); + private: // CALLBACKS virtual void putcOutput(char chr) { fputc(chr, m_fp); } @@ -213,7 +221,8 @@ public: class V3OutScFile : public V3OutCFile { public: - explicit V3OutScFile(const string& filename) : V3OutCFile(filename) {} + explicit V3OutScFile(const string& filename) + : V3OutCFile(filename) {} virtual ~V3OutScFile() {} virtual void putsHeader() { puts("// Verilated -*- SystemC -*-\n"); } virtual void putsIntTopInclude() { @@ -262,9 +271,9 @@ public: // METHODS // Rename to a new encoded string (unless earlier passthru'ed) static string protect(const string& old) { return protectIf(old, true); } - static string protectIf(const string& old, bool doIt=true); + static string protectIf(const string& old, bool doIt = true); // Rename words to a new encoded string - static string protectWordsIf(const string& old, bool doIt=true); + static string protectWordsIf(const string& old, bool doIt = true); // Write map of renames to output file static void writeMapFile(const string& filename); }; diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 85324f015..2fce3e34b 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -17,6 +17,7 @@ #include "config_build.h" #include "verilatedos.h" +// clang-format off #include "V3Error.h" #include "V3FileLine.h" #include "V3String.h" @@ -27,6 +28,7 @@ # include "V3Config.h" # include "V3File.h" #endif +// clang-format on #include #include @@ -39,11 +41,11 @@ const string FileLineSingleton::filenameLetters(int fileno) { const int size = 1 + (64 / 4); // Each letter retires more than 4 bits of a > 64 bit number char out[size]; - char* op = out+size-1; + char* op = out + size - 1; *--op = '\0'; // We build backwards int num = fileno; do { - *--op = 'a'+num%26; + *--op = 'a' + num % 26; num /= 26; } while (num); return op; @@ -70,13 +72,13 @@ int FileLineSingleton::nameToNumber(const string& filename) { //! Support XML output //! Experimental. Updated to also put out the language. void FileLineSingleton::fileNameNumMapDumpXml(std::ostream& os) { - os<<"\n"; + os << "\n"; for (FileNameNumMap::const_iterator it = m_namemap.begin(); it != m_namemap.end(); ++it) { - os<<"second) - <<"\" filename=\""<first, V3OutFormatter::LA_XML) - <<"\" language=\""<second).ascii()<<"\"/>\n"; + os << "second) << "\" filename=\"" + << V3OutFormatter::quoteNameControls(it->first, V3OutFormatter::LA_XML) + << "\" language=\"" << numberToLang(it->second).ascii() << "\"/>\n"; } - os<<"\n"; + os << "\n"; } //###################################################################### @@ -95,17 +97,18 @@ void VFileContent::pushText(const string& text) { } // Any leftover text is stored on largest line (might be "") - string leftover = m_lines.back() + text; m_lines.pop_back(); + string leftover = m_lines.back() + text; + m_lines.pop_back(); // Insert line-by-line string::size_type line_start = 0; while (true) { string::size_type line_end = leftover.find('\n', line_start); if (line_end != string::npos) { - string oneline (leftover, line_start, line_end-line_start+1); + string oneline(leftover, line_start, line_end - line_start + 1); m_lines.push_back(oneline); // Keeps newline - UINFO(9, "PushStream[ct"<= (int)m_lines.size())) { if (debug() || v3Global.opt.debugCheck()) { - return ("%Error-internal-contents-bad-ct"+cvtToStr(m_id) - +"-ln"+cvtToStr(lineno)); - } else return ""; + return ("%Error-internal-contents-bad-ct" + cvtToStr(m_id) + "-ln" + cvtToStr(lineno)); + } else { + return ""; + } } string text = m_lines[lineno]; - UINFO(9, "Get Stream[ct"<ascii(); + if (!contentp) { + os << "ct0"; + } else { + os << contentp->ascii(); + } return os; } @@ -149,7 +156,7 @@ FileLine::FileLine(FileLine::EmptySecret) { m_parent = NULL; m_warnOn = 0; - for (int codei=V3ErrorCode::EC_MIN; codei= 3) fail = true; @@ -219,7 +229,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { v3error("`line was not properly formed with '`line number \"filename\" level'\n"); } - //printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str()); + // printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str()); } void FileLine::forwardToken(const char* textp, size_t size, bool trackLines) { @@ -254,50 +264,46 @@ FileLine* FileLine::copyOrSameFileLine() { const string FileLine::filebasename() const { string name = filename(); string::size_type pos; - if ((pos = name.rfind('/')) != string::npos) { - name.erase(0, pos+1); - } + if ((pos = name.rfind('/')) != string::npos) name.erase(0, pos + 1); return name; } const string FileLine::filebasenameNoExt() const { string name = filebasename(); string::size_type pos; - if ((pos = name.find('.')) != string::npos) { - name = name.substr(0, pos); - } + if ((pos = name.find('.')) != string::npos) name = name.substr(0, pos); return name; } const string FileLine::profileFuncname() const { // Return string that is OK as a function name - for profiling - string name = filebasenameNoExt(); + string name = filebasenameNoExt(); string::size_type pos; - while ((pos = name.find_first_not_of("abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_")) + while ((pos = name.find_first_not_of( + "abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_")) != string::npos) { name.replace(pos, 1, "_"); } - name += "__l"+cvtToStr(lastLineno()); + name += "__l" + cvtToStr(lastLineno()); return name; } string FileLine::asciiLineCol() const { - return (cvtToStr(firstLineno())+"-"+cvtToStr(lastLineno()) - +":"+cvtToStr(firstColumn())+"-"+cvtToStr(lastColumn()) - +"["+(m_contentp ? m_contentp->ascii() : "ct0") - +"+"+cvtToStr(m_contentLineno)+"]"); + return (cvtToStr(firstLineno()) + "-" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn()) + + "-" + cvtToStr(lastColumn()) + "[" + (m_contentp ? m_contentp->ascii() : "ct0") + "+" + + cvtToStr(m_contentLineno) + "]"); } string FileLine::ascii() const { // For most errors especially in the parser the lastLineno is more accurate than firstLineno return filename() + ":" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn()); } std::ostream& operator<<(std::ostream& os, FileLine* fileline) { - os <ascii()<<": "<ascii() << ": " << std::hex; + return (os); } bool FileLine::warnOff(const string& msg, bool flag) { - V3ErrorCode code (msg.c_str()); + V3ErrorCode code(msg.c_str()); if (code < V3ErrorCode::EC_FIRST_WARN) { return false; #ifndef _V3ERROR_NO_GLOBAL_ @@ -312,14 +318,14 @@ bool FileLine::warnOff(const string& msg, bool flag) { } void FileLine::warnLintOff(bool flag) { - for (int codei=V3ErrorCode::EC_MIN; codeiwarnIsOff(code)) { warnOff(code, true); } } @@ -345,31 +352,33 @@ void FileLine::modifyStateInherit(const FileLine* fromp) { void FileLine::v3errorEnd(std::ostringstream& sstr, const string& locationStr) { std::ostringstream nsstr; - if (lastLineno()) nsstr<= static_cast(lastColumn() - 1)) { string linestr = cvtToStr(firstLineno()); - while (linestr.size() < 5) - linestr = ' ' + linestr; + while (linestr.size() < 5) linestr = ' ' + linestr; out += linestr + " | " + sourceLine + "\n"; out += std::string(linestr.size(), ' ') + " | "; out += string((firstColumn() - 1), ' ') + '^'; @@ -458,7 +466,7 @@ void FileLine::deleteAllRemaining() { // only when leak checking we'll track them all and cleanup. while (true) { FileLineCheckSet::iterator it = fileLineLeakChecks.begin(); - if (it==fileLineLeakChecks.end()) break; + if (it == fileLineLeakChecks.end()) break; delete *it; // Operator delete will remove the iterated object from the list. // Eventually the list will be empty and terminate the loop. diff --git a/src/V3FileLine.h b/src/V3FileLine.h index de09fc0f1..d5d1833cd 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -39,22 +39,27 @@ class FileLine; //! source file (each with its own unique filename number). class FileLineSingleton { // TYPES - typedef std::map FileNameNumMap; - typedef std::map FileLangNumMap; + typedef std::map FileNameNumMap; + typedef std::map FileLangNumMap; // MEMBERS - FileNameNumMap m_namemap; // filenameno for each filename - std::deque m_names; // filename text for each filenameno + FileNameNumMap m_namemap; // filenameno for each filename + std::deque m_names; // filename text for each filenameno std::deque m_languages; // language for each filenameno // CONSTRUCTORS - FileLineSingleton() { } - ~FileLineSingleton() { } + FileLineSingleton() {} + ~FileLineSingleton() {} + protected: friend class FileLine; int nameToNumber(const string& filename); const string numberToName(int filenameno) const { return m_names[filenameno]; } const V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; } void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; } - void clear() { m_namemap.clear(); m_names.clear(); m_languages.clear(); } + void clear() { + m_namemap.clear(); + m_names.clear(); + m_languages.clear(); + } void fileNameNumMapDumpXml(std::ostream& os); static const string filenameLetters(int fileno); }; @@ -65,12 +70,15 @@ class VFileContent { int m_id; // Content ID number std::deque m_lines; // Source text lines public: - VFileContent() { static int s_id = 0; m_id = ++s_id; } - ~VFileContent() { } + VFileContent() { + static int s_id = 0; + m_id = ++s_id; + } + ~VFileContent() {} // METHODS void pushText(const string& text); // Add arbitrary text (need not be line-by-line) string getLine(int lineno) const; - string ascii() const { return "ct"+cvtToStr(m_id); } + string ascii() const { return "ct" + cvtToStr(m_id); } static int debug(); }; std::ostream& operator<<(std::ostream& os, VFileContent* contentp); @@ -104,6 +112,7 @@ protected: friend class V3PreLex; friend class V3PreProcImp; friend class V3PreShellImp; + private: // CONSTRUCTORS static FileLineSingleton& singleton() { @@ -114,6 +123,7 @@ private: static FileLine* defFilelinep = new FileLine(FileLine::EmptySecret()); return *defFilelinep; } + public: explicit FileLine(const string& filename) : m_firstLineno(0) @@ -139,24 +149,33 @@ public: explicit FileLine(EmptySecret); FileLine* copyOrSameFileLine(); static void deleteAllRemaining(); - ~FileLine() { } + ~FileLine() {} #ifdef VL_LEAK_CHECKS static void* operator new(size_t size); static void operator delete(void* obj, size_t size); #endif // METHODS void newContent(); - void lineno(int num) { m_firstLineno = num; m_lastLineno = num; - m_firstColumn = m_lastColumn = 1; } + void lineno(int num) { + m_firstLineno = num; + m_lastLineno = num; + m_firstColumn = m_lastColumn = 1; + } void language(V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); } void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); } void parent(FileLine* fileline) { m_parent = fileline; } void lineDirective(const char* textp, int& enterExitRef); - void linenoInc() { m_lastLineno++; m_lastColumn = 1; m_contentLineno++; } - void startToken() { m_firstLineno = m_lastLineno; - m_firstColumn = m_lastColumn; } + void linenoInc() { + m_lastLineno++; + m_lastColumn = 1; + m_contentLineno++; + } + void startToken() { + m_firstLineno = m_lastLineno; + m_firstColumn = m_lastColumn; + } // Advance last line/column based on given text - void forwardToken(const char* textp, size_t size, bool trackLines=true); + void forwardToken(const char* textp, size_t size, bool trackLines = true); int firstLineno() const { return m_firstLineno; } int firstColumn() const { return m_firstColumn; } int lastLineno() const { return m_lastLineno; } @@ -172,13 +191,16 @@ public: string ascii() const; string asciiLineCol() const; const string filename() const { return singleton().numberToName(m_filenameno); } - bool filenameIsGlobal() const { return (filename() == commandLineFilename() - || filename() == builtInFilename()); } + bool filenameIsGlobal() const { + return (filename() == commandLineFilename() || filename() == builtInFilename()); + } const string filenameLetters() const { return singleton().filenameLetters(m_filenameno); } const string filebasename() const; const string filebasenameNoExt() const; const string profileFuncname() const; - const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lastLineno())+"\""; } + const string xml() const { + return "fl=\"" + filenameLetters() + cvtToStr(lastLineno()) + "\""; + } const string xmlDetailedLocation() const; string lineDirectiveStrg(int enterExit) const; @@ -202,16 +224,15 @@ public: // and match what GCC outputs static string commandLineFilename() { return ""; } static string builtInFilename() { return ""; } - static void globalWarnLintOff(bool flag) { - defaultFileLine().warnLintOff(flag); } - static void globalWarnStyleOff(bool flag) { - defaultFileLine().warnStyleOff(flag); } + static void globalWarnLintOff(bool flag) { defaultFileLine().warnLintOff(flag); } + static void globalWarnStyleOff(bool flag) { defaultFileLine().warnStyleOff(flag); } static void globalWarnOff(V3ErrorCode code, bool flag) { - defaultFileLine().warnOff(code, flag); } + defaultFileLine().warnOff(code, flag); + } static bool globalWarnOff(const string& code, bool flag) { - return defaultFileLine().warnOff(code, flag); } - static void fileNameNumMapDumpXml(std::ostream& os) { - singleton().fileNameNumMapDumpXml(os); } + return defaultFileLine().warnOff(code, flag); + } + static void fileNameNumMapDumpXml(std::ostream& os) { singleton().fileNameNumMapDumpXml(os); } // METHODS - Called from netlist // Merge warning disables from another fileline @@ -237,13 +258,11 @@ public: /// Simplified information vs warnContextPrimary() to make dump clearer string warnContextSecondary() const { return warnContext(true); } bool operator==(const FileLine& rhs) const { - return (m_firstLineno == rhs.m_firstLineno - && m_firstColumn == rhs.m_firstColumn - && m_lastLineno == rhs.m_lastLineno - && m_lastColumn == rhs.m_lastColumn - && m_filenameno == rhs.m_filenameno - && m_warnOn == rhs.m_warnOn); + return (m_firstLineno == rhs.m_firstLineno && m_firstColumn == rhs.m_firstColumn + && m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn + && m_filenameno == rhs.m_filenameno && m_warnOn == rhs.m_warnOn); } + private: void v3errorEndFatalGuts(std::ostringstream& str); string warnContext(bool secondary) const; @@ -251,7 +270,9 @@ private: std::ostream& operator<<(std::ostream& os, FileLine* fileline); inline void FileLine::v3errorEndFatal(std::ostringstream& str) { - v3errorEnd(str); assert(0); VL_UNREACHABLE + v3errorEnd(str); + assert(0); + VL_UNREACHABLE } #endif // Guard diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 117145039..6f9128d94 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -42,7 +42,7 @@ typedef std::list GateVarRefList; -#define GATE_DEDUP_MAX_DEPTH 20 +#define GATE_DEDUP_MAX_DEPTH 20 //###################################################################### @@ -70,40 +70,43 @@ public: // Support classes class GateEitherVertex : public V3GraphVertex { - AstScope* m_scopep; // Scope vertex refers to - bool m_reducible; // True if this node should be able to be eliminated - bool m_dedupable; // True if this node should be able to be deduped - bool m_consumed; // Output goes to something meaningful + AstScope* m_scopep; // Scope vertex refers to + bool m_reducible; // True if this node should be able to be eliminated + bool m_dedupable; // True if this node should be able to be deduped + bool m_consumed; // Output goes to something meaningful public: GateEitherVertex(V3Graph* graphp, AstScope* scopep) - : V3GraphVertex(graphp), m_scopep(scopep), m_reducible(true) - , m_dedupable(true), m_consumed(false) {} + : V3GraphVertex(graphp) + , m_scopep(scopep) + , m_reducible(true) + , m_dedupable(true) + , m_consumed(false) {} virtual ~GateEitherVertex() {} // ACCESSORS - virtual string dotStyle() const { return m_consumed?"":"dotted"; } + virtual string dotStyle() const { return m_consumed ? "" : "dotted"; } AstScope* scopep() const { return m_scopep; } bool reducible() const { return m_reducible; } bool dedupable() const { return m_dedupable; } void setConsumed(const char* consumedReason) { m_consumed = true; - //UINFO(0,"\t\tSetConsumed "<inNextp()) { ret = dynamic_cast(edgep->fromp())->accept(v, vu); @@ -114,7 +117,7 @@ public: // Note: This behaves differently than iterateInEdges() in that it will traverse // all edges that exist when it is initially called, whereas // iterateInEdges() will stop traversing edges if one is deleted - VNUser iterateCurrentOutEdges(GateGraphBaseVisitor& v, VNUser vu=VNUser(0)) { + VNUser iterateCurrentOutEdges(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) { VNUser ret = VNUser(0); V3GraphEdge* next_edgep = NULL; for (V3GraphEdge* edgep = outBeginp(); edgep; edgep = next_edgep) { @@ -128,23 +131,30 @@ public: class GateVarVertex : public GateEitherVertex { AstVarScope* m_varScp; - bool m_isTop; - bool m_isClock; - AstNode* m_rstSyncNodep; // Used as reset and not in SenItem, in clocked always - AstNode* m_rstAsyncNodep; // Used as reset and in SenItem, in clocked always + bool m_isTop; + bool m_isClock; + AstNode* m_rstSyncNodep; // Used as reset and not in SenItem, in clocked always + AstNode* m_rstAsyncNodep; // Used as reset and in SenItem, in clocked always public: GateVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) - : GateEitherVertex(graphp, scopep), m_varScp(varScp), m_isTop(false) - , m_isClock(false), m_rstSyncNodep(NULL), m_rstAsyncNodep(NULL) {} + : GateEitherVertex(graphp, scopep) + , m_varScp(varScp) + , m_isTop(false) + , m_isClock(false) + , m_rstSyncNodep(NULL) + , m_rstAsyncNodep(NULL) {} virtual ~GateVarVertex() {} // ACCESSORS AstVarScope* varScp() const { return m_varScp; } - virtual string name() const { return (cvtToHex(m_varScp)+" "+varScp()->name()); } + virtual string name() const { return (cvtToHex(m_varScp) + " " + varScp()->name()); } virtual string dotColor() const { return "blue"; } bool isTop() const { return m_isTop; } void setIsTop() { m_isTop = true; } bool isClock() const { return m_isClock; } - void setIsClock() { m_isClock = true; setConsumed("isclk"); } + void setIsClock() { + m_isClock = true; + setConsumed("isclk"); + } AstNode* rstSyncNodep() const { return m_rstSyncNodep; } void rstSyncNodep(AstNode* nodep) { m_rstSyncNodep = nodep; } AstNode* rstAsyncNodep() const { return m_rstAsyncNodep; } @@ -158,26 +168,29 @@ public: setIsClock(); } } - VNUser accept(GateGraphBaseVisitor& v, VNUser vu=VNUser(0)) { return v.visit(this, vu); } + VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) { return v.visit(this, vu); } }; class GateLogicVertex : public GateEitherVertex { - AstNode* m_nodep; - AstActive* m_activep; // Under what active; NULL is ok (under cfunc or such) - bool m_slow; // In slow block + AstNode* m_nodep; + AstActive* m_activep; // Under what active; NULL is ok (under cfunc or such) + bool m_slow; // In slow block public: - GateLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, - AstActive* activep, bool slow) - : GateEitherVertex(graphp ,scopep), m_nodep(nodep), m_activep(activep), m_slow(slow) {} + GateLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstActive* activep, + bool slow) + : GateEitherVertex(graphp, scopep) + , m_nodep(nodep) + , m_activep(activep) + , m_slow(slow) {} virtual ~GateLogicVertex() {} // ACCESSORS - virtual string name() const { return (cvtToHex(m_nodep)+"@"+scopep()->prettyName()); } + virtual string name() const { return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); } virtual string dotColor() const { return "purple"; } virtual FileLine* fileline() const { return nodep()->fileline(); } AstNode* nodep() const { return m_nodep; } AstActive* activep() const { return m_activep; } - bool slow() const { return m_slow; } - VNUser accept(GateGraphBaseVisitor& v, VNUser vu=VNUser(0)) { return v.visit(this, vu); } + bool slow() const { return m_slow; } + VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) { return v.visit(this, vu); } }; //###################################################################### @@ -186,20 +199,20 @@ public: class GateOkVisitor : public GateBaseVisitor { private: // RETURN STATE - bool m_isSimple; // Set false when we know it isn't simple - GateVarRefList m_rhsVarRefs; // VarRefs on rhs of assignment - AstNode* m_substTreep; // What to replace the variable with + bool m_isSimple; // Set false when we know it isn't simple + GateVarRefList m_rhsVarRefs; // VarRefs on rhs of assignment + AstNode* m_substTreep; // What to replace the variable with // STATE - bool m_buffersOnly; // Set when we only allow simple buffering, no equations (for clocks) - AstNodeVarRef* m_lhsVarRef; // VarRef on lhs of assignment (what we're replacing) - bool m_dedupe; // Set when we use isGateDedupable instead of isGateOptimizable - int m_ops; // Operation count + bool m_buffersOnly; // Set when we only allow simple buffering, no equations (for clocks) + AstNodeVarRef* m_lhsVarRef; // VarRef on lhs of assignment (what we're replacing) + bool m_dedupe; // Set when we use isGateDedupable instead of isGateOptimizable + int m_ops; // Operation count // METHODS void clearSimple(const char* because) { if (m_isSimple) { m_isSimple = false; - UINFO(9, "Clear simple "<rhsp(), Not) && VN_IS(VN_CAST(nodep->rhsp(), Not)->lhsp(), VarRef) - && VN_CAST(VN_CAST(nodep->rhsp(), Not)->lhsp(), VarRef)->varp()->isUsedClock()) - )) { + && VN_CAST(VN_CAST(nodep->rhsp(), Not)->lhsp(), VarRef) + ->varp() + ->isUsedClock()))) { clearSimple("Not a buffer (goes to a clock)"); } } @@ -252,16 +266,14 @@ private: virtual void visit(AstNode* nodep) VL_OVERRIDE { // *** Special iterator if (!m_isSimple) return; // Fastpath - if (++m_ops > v3Global.opt.gateStmts()) { - clearSimple("--gate-stmts exceeded"); - } - if (!(m_dedupe ? nodep->isGateDedupable() : nodep->isGateOptimizable()) - || !nodep->isPure() - || nodep->isBrancher()) { - UINFO(5, "Non optimizable type: "< v3Global.opt.gateStmts()) { clearSimple("--gate-stmts exceeded"); } + if (!(m_dedupe ? nodep->isGateDedupable() : nodep->isGateOptimizable()) // + || !nodep->isPure() || nodep->isBrancher()) { + UINFO(5, "Non optimizable type: " << nodep << endl); clearSimple("Non optimizable type"); + } else { + iterateChildren(nodep); } - else iterateChildren(nodep); } public: @@ -276,26 +288,20 @@ public: // Iterate iterate(nodep); // Check results - if (!m_substTreep) { - clearSimple("No assignment found\n"); - } - for (GateVarRefList::const_iterator it = m_rhsVarRefs.begin(); - it != m_rhsVarRefs.end(); ++it) { + if (!m_substTreep) { clearSimple("No assignment found\n"); } + for (GateVarRefList::const_iterator it = m_rhsVarRefs.begin(); it != m_rhsVarRefs.end(); + ++it) { if (m_lhsVarRef && m_lhsVarRef->varScopep() == (*it)->varScopep()) { clearSimple("Circular logic\n"); // Oh my, we'll get a UNOPTFLAT much later. } } - if (debug()>=9 && !m_isSimple) { - nodep->dumpTree(cout, " gate!Ok: "); - } + if (debug() >= 9 && !m_isSimple) nodep->dumpTree(cout, " gate!Ok: "); } virtual ~GateOkVisitor() {} // PUBLIC METHODS bool isSimple() const { return m_isSimple; } AstNode* substTree() const { return m_substTreep; } - const GateVarRefList& rhsVarRefs() const { - return m_rhsVarRefs; - } + const GateVarRefList& rhsVarRefs() const { return m_rhsVarRefs; } }; //###################################################################### @@ -304,39 +310,41 @@ public: class GateVisitor : public GateBaseVisitor { private: // NODE STATE - //Entire netlist: + // Entire netlist: // AstVarScope::user1p -> GateVarVertex* for usage var, 0=not set yet // {statement}Node::user1p -> GateLogicVertex* for this statement // AstVarScope::user2 -> bool: Signal used in SenItem in *this* always statement // AstVar::user2 -> bool: Warned about SYNCASYNCNET // AstNodeVarRef::user2 -> bool: ConcatOffset visited - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; // STATE - V3Graph m_graph; // Scoreboard of var usages/dependencies - GateLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored - AstScope* m_scopep; // Current scope being processed - AstNodeModule* m_modp; // Current module - AstActive* m_activep; // Current active - bool m_activeReducible; // Is activation block reducible? - bool m_inSenItem; // Underneath AstSenItem; any varrefs are clocks - bool m_inSlow; // Inside a slow structure - VDouble0 m_statSigs; // Statistic tracking - VDouble0 m_statRefs; // Statistic tracking - VDouble0 m_statDedupLogic; // Statistic tracking - VDouble0 m_statAssignMerged; // Statistic tracking + V3Graph m_graph; // Scoreboard of var usages/dependencies + GateLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored + AstScope* m_scopep; // Current scope being processed + AstNodeModule* m_modp; // Current module + AstActive* m_activep; // Current active + bool m_activeReducible; // Is activation block reducible? + bool m_inSenItem; // Underneath AstSenItem; any varrefs are clocks + bool m_inSlow; // Inside a slow structure + VDouble0 m_statSigs; // Statistic tracking + VDouble0 m_statRefs; // Statistic tracking + VDouble0 m_statDedupLogic; // Statistic tracking + VDouble0 m_statAssignMerged; // Statistic tracking // METHODS - void iterateNewStmt(AstNode* nodep, const char* nonReducibleReason, const char* consumeReason) { + void iterateNewStmt(AstNode* nodep, const char* nonReducibleReason, + const char* consumeReason) { if (m_scopep) { - UINFO(5," STMT "<clearReducibleAndDedupable(nonReducibleReason); } else if (!m_activeReducible) { - m_logicVertexp->clearReducible("Block Unreducible"); // Sequential logic is dedupable + // Sequential logic is dedupable + m_logicVertexp->clearReducible("Block Unreducible"); } if (consumeReason) m_logicVertexp->setConsumed(consumeReason); if (VN_IS(nodep, SenItem)) m_logicVertexp->setConsumed("senItem"); @@ -348,7 +356,7 @@ private: GateVarVertex* makeVarVertex(AstVarScope* varscp) { GateVarVertex* vertexp = reinterpret_cast(varscp->user1p()); if (!vertexp) { - UINFO(6,"New vertex "<user1p(vertexp); if (varscp->varp()->isSigPublic()) { @@ -362,7 +370,7 @@ private: vertexp->clearReducibleAndDedupable("isTop"); vertexp->setConsumed("isTop"); } - if (varscp->varp()->isUsedClock()) vertexp->setConsumed("clock"); + if (varscp->varp()->isUsedClock()) vertexp->setConsumed("clock"); } return vertexp; } @@ -382,15 +390,15 @@ private: // VISITORS virtual void visit(AstNetlist* nodep) VL_OVERRIDE { iterateChildren(nodep); - //if (debug()>6) m_graph.dump(); - if (debug()>6) m_graph.dumpDotFilePrefixed("gate_pre"); + // if (debug() > 6) m_graph.dump(); + if (debug() > 6) m_graph.dumpDotFilePrefixed("gate_pre"); warnSignals(); // Before loss of sync/async pointers // Decompose clock vectors -- need to do this before removing redundant edges decomposeClkVectors(); m_graph.removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue); m_graph.dumpDotFilePrefixed("gate_simp"); // Find gate interconnect and optimize - m_graph.userClearVertices(); // vertex->user(): bool. True indicates we've set it as consumed + m_graph.userClearVertices(); // vertex->user(): bool. Indicates we've set it as consumed // Get rid of buffers first, optimizeSignals(false); // Then propagate more complicated equations @@ -421,7 +429,7 @@ private: m_modp = origModp; } virtual void visit(AstScope* nodep) VL_OVERRIDE { - UINFO(4," SCOPE "<hasClocked()); // Seq logic outputs aren't reducible m_activep = nodep; AstNode::user2ClearTree(); @@ -444,13 +452,12 @@ private: AstVarScope* varscp = nodep->varScopep(); UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp"); GateVarVertex* vvertexp = makeVarVertex(varscp); - UINFO(5," VARREF to "<setIsClock(); // For SYNCASYNCNET varscp->user2(true); - } - else if (m_activep && m_activep->hasClocked() && !nodep->lvalue()) { + } else if (m_activep && m_activep->hasClocked() && !nodep->lvalue()) { if (varscp->user2()) { if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep); } else { @@ -467,7 +474,7 @@ private: } } virtual void visit(AstAlways* nodep) VL_OVERRIDE { - iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL); + iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? NULL : "Multiple Stmts"), NULL); } virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { bool lastslow = m_inSlow; @@ -497,13 +504,13 @@ private: virtual void visit(AstInitial* nodep) VL_OVERRIDE { bool lastslow = m_inSlow; m_inSlow = true; - iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL); + iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? NULL : "Multiple Stmts"), NULL); m_inSlow = lastslow; } - virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { + virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // iterateNewStmt(nodep, NULL, NULL); } - virtual void visit(AstAssignW* nodep) VL_OVERRIDE { + virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // iterateNewStmt(nodep, NULL, NULL); } virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { @@ -517,7 +524,7 @@ private: } virtual void visit(AstConcat* nodep) VL_OVERRIDE { UASSERT_OBJ(!(VN_IS(nodep->backp(), NodeAssign) - && VN_CAST(nodep->backp(), NodeAssign)->lhsp()==nodep), + && VN_CAST(nodep->backp(), NodeAssign)->lhsp() == nodep), nodep, "Concat on LHS of assignment; V3Const should have deleted it"); iterateChildren(nodep); } @@ -552,36 +559,36 @@ public: //---------------------------------------------------------------------- void GateVisitor::optimizeSignals(bool allowMultiIn) { - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (GateVarVertex* vvertexp = dynamic_cast(itp)) { if (vvertexp->inEmpty()) { vvertexp->clearReducibleAndDedupable("inEmpty"); // Can't deal with no sources if (!vvertexp->isTop() // Ok if top inputs are driverless && !vvertexp->varScp()->varp()->valuep() && !vvertexp->varScp()->varp()->isSigPublic()) { - UINFO(4, "No drivers "<varScp()<varScp() << endl); if (false) { // If we warned here after constant propagation, what the user considered // reasonable logic may have disappeared. Issuing a warning would // thus be confusing. V3Undriven now handles this. - vvertexp->varScp()->varp()->v3warn - (UNDRIVEN, "Signal has no drivers: '" - <scopep()->prettyName()<<"." - <varScp()->varp()->prettyName()<<"'"); + vvertexp->varScp()->varp()->v3warn( + UNDRIVEN, "Signal has no drivers: '" + << vvertexp->scopep()->prettyName() << "." + << vvertexp->varScp()->varp()->prettyName() << "'"); } } - } - else if (!vvertexp->inSize1()) { - vvertexp->clearReducibleAndDedupable("size!1"); // Can't deal with more than one src + } else if (!vvertexp->inSize1()) { + // Can't deal with more than one src + vvertexp->clearReducibleAndDedupable("size!1"); } // Reduce it? if (!vvertexp->reducible()) { - UINFO(8, "SigNotRed "<name()<name() << endl); } else { - UINFO(8, "Sig "<name()< - (vvertexp->inBeginp()->fromp()); - UINFO(8, " From "<name()<name() << endl); + GateLogicVertex* logicVertexp + = dynamic_cast(vvertexp->inBeginp()->fromp()); + UINFO(8, " From " << logicVertexp->name() << endl); AstNode* logicp = logicVertexp->nodep(); if (logicVertexp->reducible()) { // Can we eliminate? @@ -593,8 +600,8 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) { if (!allowMultiIn) doit = false; // Doit if one input, or not used, or used only once, ignoring traces int n = 0; - for (V3GraphEdge* edgep = vvertexp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; + edgep = edgep->outNextp()) { GateLogicVertex* consumeVertexp = dynamic_cast(edgep->top()); if (!consumeVertexp->slow()) { // Not tracing or other slow path junk @@ -602,7 +609,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) { n += edgep->weight(); } } - if (n>1) { + if (n > 1) { doit = false; break; } @@ -610,40 +617,39 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) { } // Process it if (!doit) { - if (allowMultiIn && (debug()>=9)) { - UINFO(9, "Not ok simp"<outBeginp() - <<" on"<<(vvertexp->outBeginp()?vvertexp->outBeginp()->outNextp():0) - <<" "<name() - <outBeginp(); - edgep; edgep = edgep->outNextp()) { + if (allowMultiIn && (debug() >= 9)) { + UINFO(9, "Not ok simp" << okVisitor.isSimple() << " mi" << multiInputs + << " ob" << vvertexp->outBeginp() << " on" + << (vvertexp->outBeginp() + ? vvertexp->outBeginp()->outNextp() + : 0) + << " " << vvertexp->name() << endl); + for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; + edgep = edgep->outNextp()) { GateLogicVertex* consumeVertexp = dynamic_cast(edgep->top()); - UINFO(9, " edge "<nodep()<nodep() + << endl); } - for (V3GraphEdge* edgep = vvertexp->inBeginp(); - edgep; edgep = edgep->inNextp()) { + for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; + edgep = edgep->inNextp()) { GateLogicVertex* consumeVertexp = dynamic_cast(edgep->fromp()); - UINFO(9, " edge "<nodep()<nodep() << endl); } } - } - else { + } else { AstNode* substp = okVisitor.substTree(); - if (debug()>=5) logicp->dumpTree(cout, " elimVar: "); - if (debug()>=5) substp->dumpTree(cout, " subst: "); + if (debug() >= 5) logicp->dumpTree(cout, " elimVar: "); + if (debug() >= 5) substp->dumpTree(cout, " subst: "); ++m_statSigs; bool removedAllUsages = true; - for (V3GraphEdge* edgep = vvertexp->outBeginp(); - edgep; ) { + for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep;) { GateLogicVertex* consumeVertexp = dynamic_cast(edgep->top()); AstNode* consumerp = consumeVertexp->nodep(); - if (!elimLogicOkOutputs(consumeVertexp, okVisitor/*ref*/)) { + if (!elimLogicOkOutputs(consumeVertexp, okVisitor /*ref*/)) { // Cannot optimize this replacement removedAllUsages = false; edgep = edgep->outNextp(); @@ -655,7 +661,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) { for (GateVarRefList::const_iterator it = rhsVarRefs.begin(); it != rhsVarRefs.end(); ++it) { AstVarScope* newvarscp = (*it)->varScopep(); - UINFO(9," Point-to-new vertex "<varScopep(); varscopes.insert(vscp); } @@ -711,7 +716,7 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp, GateVarVertex* consVVertexp = dynamic_cast(edgep->top()); AstVarScope* vscp = consVVertexp->varScp(); if (varscopes.find(vscp) != varscopes.end()) { - UINFO(9," Block-unopt, insertion generates input vscp "<verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (GateVarVertex* vvertexp = dynamic_cast(itp)) { // Take the Comments/assigns that were moved to the VarScope and change them to a // simple value assignment AstVarScope* vscp = vvertexp->varScp(); if (vscp->valuep() && !VN_IS(vscp->valuep(), NodeMath)) { - //if (debug()>9) vscp->dumpTree(cout, "-vscPre: "); + // if (debug() > 9) vscp->dumpTree(cout, "-vscPre: "); while (AstNode* delp = VN_CAST(vscp->valuep(), Comment)) { VL_DO_DANGLING(delp->unlinkFrBack()->deleteTree(), delp); } @@ -747,9 +752,8 @@ void GateVisitor::replaceAssigns() { delp->replaceWith(rhsp); VL_DO_DANGLING(delp->deleteTree(), delp); } - //if (debug()>9) {vscp->dumpTree(cout, "-vscDone: "); cout<valuep(), NodeMath) - || vscp->valuep()->nextp()) { + // if (debug() > 9) {vscp->dumpTree(cout, "-vscDone: "); cout<valuep(), NodeMath) || vscp->valuep()->nextp()) { vscp->dumpTree(std::cerr, "vscStrange: "); vscp->v3fatalSrc("Value of varscope not mathematical"); } @@ -763,12 +767,10 @@ void GateVisitor::replaceAssigns() { void GateVisitor::consumedMark() { // Propagate consumed signals backwards to all producers into a consumed node m_graph.userClearVertices(); - for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { GateEitherVertex* evertexp = static_cast(vertexp); - if (!evertexp->user() && evertexp->consumed()) { - consumedMarkRecurse(evertexp); - } + if (!evertexp->user() && evertexp->consumed()) consumedMarkRecurse(evertexp); } } @@ -786,11 +788,11 @@ void GateVisitor::consumedMarkRecurse(GateEitherVertex* vertexp) { void GateVisitor::consumedMove() { // Remove unused logic (logic that doesn't hit a combo block or a display statement) // We need the "usually" block logic to do a better job at this - for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { if (GateVarVertex* vvertexp = dynamic_cast(vertexp)) { if (!vvertexp->consumed() && !vvertexp->user()) { - UINFO(8, "Unconsumed "<varScp()<varScp() << endl); } } if (GateLogicVertex* lvertexp = dynamic_cast(vertexp)) { @@ -799,7 +801,7 @@ void GateVisitor::consumedMove() { if (!lvertexp->consumed() && oldactp) { // Eventually: Move the statement to a new active block // with "tracing-on" sensitivity - UINFO(8," Remove unconsumed "<unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); } @@ -811,7 +813,7 @@ void GateVisitor::consumedMove() { void GateVisitor::warnSignals() { AstNode::user2ClearTree(); - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (GateVarVertex* vvertexp = dynamic_cast(itp)) { AstVarScope* vscp = vvertexp->varScp(); AstNode* sp = vvertexp->rstSyncNodep(); @@ -823,15 +825,15 @@ void GateVisitor::warnSignals() { // Instead we'll disable if any disabled if (!vscp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET) && !ap->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET) - && !sp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET) - ) { + && !sp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET)) { vscp->varp()->user2(true); // Warn only once per signal - vscp->v3warn(SYNCASYNCNET, "Signal flopped as both synchronous and async: " - <prettyNameQ()<warnOther()<<"... Location of async usage"<warnContextPrimary()<warnOther()<<"... Location of sync usage"<warnContextSecondary()); + vscp->v3warn(SYNCASYNCNET, + "Signal flopped as both synchronous and async: " + << vscp->prettyNameQ() << endl + << ap->warnOther() << "... Location of async usage" << endl + << ap->warnContextPrimary() << endl + << sp->warnOther() << "... Location of sync usage" << endl + << sp->warnContextSecondary()); } } } @@ -847,10 +849,10 @@ class GateElimVisitor : public GateBaseVisitor { private: // NODE STATE // STATE - AstVarScope* m_elimVarScp; // Variable being eliminated - AstNode* m_replaceTreep; // What to replace the variable with - bool m_didReplace; // Did we do any replacements - GateDedupeVarVisitor* m_varVisp; // Callback to keep hash up to date + AstVarScope* m_elimVarScp; // Variable being eliminated + AstNode* m_replaceTreep; // What to replace the variable with + bool m_didReplace; // Did we do any replacements + GateDedupeVarVisitor* m_varVisp; // Callback to keep hash up to date // METHODS void hashReplace(AstNode* oldp, AstNode* newp); @@ -865,11 +867,10 @@ private: UASSERT_OBJ(!nodep->lvalue(), nodep, "Can't replace lvalue assignments with const var"); AstNode* substp = m_replaceTreep->cloneTree(false); - UASSERT_OBJ(!(VN_IS(nodep, NodeVarRef) - && VN_IS(substp, NodeVarRef) - && nodep->same(substp)), - // Prevent an infinite loop... - substp, "Replacing node with itself; perhaps circular logic?"); + UASSERT_OBJ( + !(VN_IS(nodep, NodeVarRef) && VN_IS(substp, NodeVarRef) && nodep->same(substp)), + // Prevent an infinite loop... + substp, "Replacing node with itself; perhaps circular logic?"); // Which fileline() to use? // If replacing with logic, an error/warning is likely to want to point to the logic // IE what we're replacing with. @@ -903,14 +904,14 @@ public: }; void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* consumerp) { - if (debug()>=5) consumerp->dumpTree(cout, " elimUsePre: "); - GateElimVisitor elimVisitor (consumerp, varscp, substp, NULL); + if (debug() >= 5) consumerp->dumpTree(cout, " elimUsePre: "); + GateElimVisitor elimVisitor(consumerp, varscp, substp, NULL); if (elimVisitor.didReplace()) { - if (debug()>=9) consumerp->dumpTree(cout, " elimUseCns: "); - //Caution: Can't let V3Const change our handle to consumerp, such as by + if (debug() >= 9) consumerp->dumpTree(cout, " elimUseCns: "); + // Caution: Can't let V3Const change our handle to consumerp, such as by // optimizing away this assignment, etc. consumerp = V3Const::constifyEdit(consumerp); - if (debug()>=5) consumerp->dumpTree(cout, " elimUseDne: "); + if (debug() >= 5) consumerp->dumpTree(cout, " elimUseDne: "); // Some previous input edges may have disappeared, perhaps all of them. // If we remove the edges we can further optimize // See e.g t_var_overzero.v. @@ -934,32 +935,29 @@ private: // Set to NULL if this assign's tree was later replaced // AstUser1InUse m_inuser1; (Allocated for use in GateVisitor) // AstUser2InUse m_inuser2; (Allocated for use in GateVisitor) - AstUser3InUse m_inuser3; + AstUser3InUse m_inuser3; // AstUser4InUse m_inuser4; (Allocated for use in V3Hashed) - AstUser5InUse m_inuser5; + AstUser5InUse m_inuser5; - V3Hashed m_hashed; // Hash, contains rhs of assigns - NodeSet m_nodeDeleteds; // Any node in this hash was deleted + V3Hashed m_hashed; // Hash, contains rhs of assigns + NodeSet m_nodeDeleteds; // Any node in this hash was deleted VL_DEBUG_FUNC; // Declare debug() void hash(AstNode* nodep) { // !NULL && the object is hashable - if (nodep && !nodep->sameHash().isIllegal()) { - m_hashed.hash(nodep); - } + if (nodep && !nodep->sameHash().isIllegal()) m_hashed.hash(nodep); } bool sameHash(AstNode* node1p, AstNode* node2p) { - return (node1p && node2p - && !node1p->sameHash().isIllegal() - && !node2p->sameHash().isIllegal() - && m_hashed.sameNodes(node1p, node2p)); + return (node1p && node2p && !node1p->sameHash().isIllegal() + && !node2p->sameHash().isIllegal() && m_hashed.sameNodes(node1p, node2p)); } bool same(AstNode* node1p, AstNode* node2p) { return node1p == node2p || sameHash(node1p, node2p); } + public: - GateDedupeHash() { } + GateDedupeHash() {} ~GateDedupeHash() { if (v3Global.opt.debugCheck()) check(); } @@ -968,7 +966,7 @@ public: // This might be a variable on the lhs of the duplicate tree, // or could be a rhs variable in a tree we're not replacing (or not yet anyways) void hashReplace(AstNode* oldp, AstNode* newp) { - UINFO(9,"replacing "<<(void*)oldp<<" with "<<(void*)newp<user3p(), node2p->user3p()) - && same(node1p->user5p(), node2p->user5p()) - && node1p->user2p()->type() == node2p->user2p()->type(); + return same(node1p->user3p(), node2p->user3p()) && same(node1p->user5p(), node2p->user5p()) + && node1p->user2p()->type() == node2p->user2p()->type(); } AstNodeAssign* hashAndFindDupe(AstNodeAssign* assignp, AstNode* extra1p, AstNode* extra2p) { // Legal for extra1p/2p to be NULL, we'll compare with other assigns with extras also NULL - AstNode *rhsp = assignp->rhsp(); + AstNode* rhsp = assignp->rhsp(); rhsp->user2p(assignp); rhsp->user3p(extra1p); rhsp->user5p(extra2p); @@ -1029,10 +1026,10 @@ public: if (!isReplaced(nodep)) { // This class won't break if activep isn't an active, or // ifVar isn't a var, but this is checking the caller's construction. - UASSERT_OBJ(!activep || (!VN_DELETED(activep) && VN_IS(activep, Active)), - nodep, "V3Hashed check failed, lost active pointer"); - UASSERT_OBJ(!condVarp || !VN_DELETED(condVarp), - nodep, "V3Hashed check failed, lost if pointer"); + UASSERT_OBJ(!activep || (!VN_DELETED(activep) && VN_IS(activep, Active)), nodep, + "V3Hashed check failed, lost active pointer"); + UASSERT_OBJ(!condVarp || !VN_DELETED(condVarp), nodep, + "V3Hashed check failed, lost if pointer"); } } } @@ -1054,11 +1051,11 @@ class GateDedupeVarVisitor : public GateBaseVisitor { // Any other ordering or node type, except for an AstComment, makes it not dedupable private: // STATE - GateDedupeHash m_ghash; // Hash used to find dupes of rhs of assign - AstNodeAssign* m_assignp; // Assign found for dedupe - AstNode* m_ifCondp; // IF condition that assign is under - bool m_always; // Assign is under an always - bool m_dedupable; // Determined the assign to be dedupable + GateDedupeHash m_ghash; // Hash used to find dupes of rhs of assign + AstNodeAssign* m_assignp; // Assign found for dedupe + AstNode* m_ifCondp; // IF condition that assign is under + bool m_always; // Assign is under an always + bool m_dedupable; // Determined the assign to be dedupable // VISITORS virtual void visit(AstNodeAssign* assignp) VL_OVERRIDE { @@ -1088,7 +1085,8 @@ private: // foo = ...; // or foo <= ...; virtual void visit(AstNodeIf* ifp) VL_OVERRIDE { if (m_dedupable) { - if (m_always && !m_ifCondp && !ifp->elsesp()) { //we're under an always, this is the first IF, and there's no else + if (m_always && !m_ifCondp && !ifp->elsesp()) { + // we're under an always, this is the first IF, and there's no else m_ifCondp = ifp->condp(); iterateAndNextNull(ifp->ifsp()); } else { @@ -1099,8 +1097,7 @@ private: virtual void visit(AstComment*) VL_OVERRIDE {} // NOP //-------------------- - // Default - virtual void visit(AstNode*) VL_OVERRIDE { + virtual void visit(AstNode*) VL_OVERRIDE { // m_dedupable = false; } @@ -1112,7 +1109,7 @@ public: m_always = false; m_dedupable = true; } - ~GateDedupeVarVisitor() { } + ~GateDedupeVarVisitor() {} // PUBLIC METHODS AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) { m_assignp = NULL; @@ -1124,8 +1121,8 @@ public: AstNode* lhsp = m_assignp->lhsp(); // Possible todo, handle more complex lhs expressions if (AstNodeVarRef* lhsVarRefp = VN_CAST(lhsp, NodeVarRef)) { - UASSERT_OBJ(lhsVarRefp->varScopep() == consumerVarScopep, - consumerVarScopep, "Consumer doesn't match lhs of assign"); + UASSERT_OBJ(lhsVarRefp->varScopep() == consumerVarScopep, consumerVarScopep, + "Consumer doesn't match lhs of assign"); if (AstNodeAssign* dup = m_ghash.hashAndFindDupe(m_assignp, activep, m_ifCondp)) { return static_cast(dup->lhsp()); } @@ -1133,18 +1130,14 @@ public: } return NULL; } - void hashReplace(AstNode* oldp, AstNode* newp) { - m_ghash.hashReplace(oldp, newp); - } + void hashReplace(AstNode* oldp, AstNode* newp) { m_ghash.hashReplace(oldp, newp); } }; //###################################################################### void GateElimVisitor::hashReplace(AstNode* oldp, AstNode* newp) { - UINFO(9,"hashReplace "<<(void*)oldp<<" -> "<<(void*)newp<hashReplace(oldp, newp); - } + UINFO(9, "hashReplace " << (void*)oldp << " -> " << (void*)newp << endl); + if (m_varVisp) m_varVisp->hashReplace(oldp, newp); } //###################################################################### @@ -1155,46 +1148,52 @@ private: // NODE STATE // AstVarScope::user2p -> bool: already visited // AstUser2InUse m_inuser2; (Allocated for use in GateVisitor) - VDouble0 m_numDeduped; // Statistic tracking - GateDedupeVarVisitor m_varVisitor; // Looks for a dupe of the logic - int m_depth; // Iteration depth + VDouble0 m_numDeduped; // Statistic tracking + GateDedupeVarVisitor m_varVisitor; // Looks for a dupe of the logic + int m_depth; // Iteration depth virtual VNUser visit(GateVarVertex* vvertexp, VNUser) { // Check that we haven't been here before - if (m_depth > GATE_DEDUP_MAX_DEPTH) return VNUser(0); // Break loops; before user2 set so hit this vertex later + if (m_depth > GATE_DEDUP_MAX_DEPTH) + return VNUser(0); // Break loops; before user2 set so hit this vertex later if (vvertexp->varScp()->user2()) return VNUser(0); vvertexp->varScp()->user2(true); m_depth++; if (vvertexp->inSize1()) { - AstNodeVarRef* dupVarRefp = static_cast - (vvertexp->iterateInEdges(*this, VNUser(vvertexp)).toNodep()); + AstNodeVarRef* dupVarRefp = static_cast( + vvertexp->iterateInEdges(*this, VNUser(vvertexp)).toNodep()); if (dupVarRefp) { // visit(GateLogicVertex*...) returned match V3GraphEdge* edgep = vvertexp->inBeginp(); GateLogicVertex* lvertexp = static_cast(edgep->fromp()); UASSERT_OBJ(vvertexp->dedupable(), vvertexp->varScp(), - "GateLogicVertex* visit should have returned NULL if consumer var vertex is not dedupable."); + "GateLogicVertex* visit should have returned NULL " + "if consumer var vertex is not dedupable."); GateOkVisitor okVisitor(lvertexp->nodep(), false, true); if (okVisitor.isSimple()) { AstVarScope* dupVarScopep = dupVarRefp->varScopep(); GateVarVertex* dupVvertexp = reinterpret_cast(dupVarScopep->user1p()); - UINFO(4,"replacing " << vvertexp << " with " << dupVvertexp << endl); + UINFO(4, "replacing " << vvertexp << " with " << dupVvertexp << endl); ++m_numDeduped; // Replace all of this varvertex's consumers with dupVarRefp - for (V3GraphEdge* outedgep = vvertexp->outBeginp(); outedgep; ) { + for (V3GraphEdge* outedgep = vvertexp->outBeginp(); outedgep;) { GateLogicVertex* consumeVertexp = dynamic_cast(outedgep->top()); AstNode* consumerp = consumeVertexp->nodep(); m_graphp->dumpDotFilePrefixed("gate_preelim"); - UINFO(9, "elim src vtx"<nodep()<varScp()<nodep() << endl); + UINFO(9, + "elim cons vtx" << consumeVertexp << " node " << consumerp << endl); + UINFO(9, "elim var vtx " << vvertexp << " node " << vvertexp->varScp() + << endl); + UINFO(9, "replace with " << dupVarRefp << endl); if (lvertexp == consumeVertexp) { UINFO(9, "skipping as self-recirculates\n"); } else { - GateElimVisitor elimVisitor(consumerp, vvertexp->varScp(), dupVarRefp, &m_varVisitor); + GateElimVisitor elimVisitor(consumerp, vvertexp->varScp(), dupVarRefp, + &m_varVisitor); } outedgep = outedgep->relinkFromp(dupVvertexp); } @@ -1251,17 +1250,15 @@ void GateVisitor::dedupe() { AstNode::user2ClearTree(); GateDedupeGraphVisitor deduper(&m_graph); // Traverse starting from each of the clocks - UINFO(9,"Gate dedupe() clocks:\n"); - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + UINFO(9, "Gate dedupe() clocks:\n"); + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (GateVarVertex* vvertexp = dynamic_cast(itp)) { - if (vvertexp->isClock()) { - deduper.dedupeTree(vvertexp); - } + if (vvertexp->isClock()) deduper.dedupeTree(vvertexp); } } // Traverse starting from each of the outputs - UINFO(9,"Gate dedupe() outputs:\n"); - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + UINFO(9, "Gate dedupe() outputs:\n"); + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (GateVarVertex* vvertexp = dynamic_cast(itp)) { if (vvertexp->isTop() && vvertexp->varScp()->varp()->isWritable()) { deduper.dedupeTree(vvertexp); @@ -1271,7 +1268,6 @@ void GateVisitor::dedupe() { m_statDedupLogic += deduper.numDeduped(); } - //###################################################################### // Recurse through the graph, try to merge assigns @@ -1279,10 +1275,9 @@ class GateMergeAssignsGraphVisitor : public GateGraphBaseVisitor { private: // NODE STATE AstNodeAssign* m_assignp; - AstActive* m_activep; + AstActive* m_activep; GateLogicVertex* m_logicvp; - VDouble0 m_numMergedAssigns; // Statistic tracking - + VDouble0 m_numMergedAssigns; // Statistic tracking // assemble two Sel into one if possible AstSel* merge(AstSel* pre, AstSel* cur) { @@ -1296,22 +1291,24 @@ private: const AstConst* cstart = VN_CAST(cur->lsbp(), Const); const AstConst* cwidth = VN_CAST(cur->widthp(), Const); if (!pstart || !pwidth || !cstart || !cwidth) return NULL; // too complicated - if (cur->lsbConst()+cur->widthConst() == pre->lsbConst()) { + if (cur->lsbConst() + cur->widthConst() == pre->lsbConst()) { return new AstSel(curVarRefp->fileline(), curVarRefp->cloneTree(false), - cur->lsbConst(), pre->widthConst()+cur->widthConst()); - } else return NULL; + cur->lsbConst(), pre->widthConst() + cur->widthConst()); + } else { + return NULL; + } } - virtual VNUser visit(GateVarVertex *vvertexp, VNUser) { - for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; ) { + virtual VNUser visit(GateVarVertex* vvertexp, VNUser) { + for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;) { V3GraphEdge* oldedgep = edgep; edgep = edgep->inNextp(); // for recursive since the edge could be deleted if (GateLogicVertex* lvertexp = dynamic_cast(oldedgep->fromp())) { if (AstNodeAssign* assignp = VN_CAST(lvertexp->nodep(), NodeAssign)) { - //if (lvertexp->outSize1() && VN_IS(assignp->lhsp(), Sel)) { + // if (lvertexp->outSize1() && VN_IS(assignp->lhsp(), Sel)) { if (VN_IS(assignp->lhsp(), Sel) && lvertexp->outSize1()) { UINFO(9, "assing to the nodep[" - <lhsp(), Sel)->lsbConst()<<"]"<lhsp(), Sel)->lsbConst() << "]" << endl); // first assign with Sel-lhs if (!m_activep) m_activep = lvertexp->activep(); if (!m_logicvp) m_logicvp = lvertexp; @@ -1330,28 +1327,29 @@ private: if (!preselp || !curselp) continue; if (AstSel* newselp = merge(preselp, curselp)) { - UINFO(5, "assemble to new sel: "<replaceWith(newselp); VL_DO_DANGLING(preselp->deleteTree(), preselp); // create new rhs for pre assignment - AstNode* newrhsp = new AstConcat( - m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false), - assignp->rhsp()->cloneTree(false)); + AstNode* newrhsp = new AstConcat(m_assignp->rhsp()->fileline(), + m_assignp->rhsp()->cloneTree(false), + assignp->rhsp()->cloneTree(false)); AstNode* oldrhsp = m_assignp->rhsp(); oldrhsp->replaceWith(newrhsp); VL_DO_DANGLING(oldrhsp->deleteTree(), oldrhsp); - m_assignp->dtypeChgWidthSigned(m_assignp->width()+assignp->width(), - m_assignp->width()+assignp->width(), + m_assignp->dtypeChgWidthSigned(m_assignp->width() + assignp->width(), + m_assignp->width() + assignp->width(), AstNumeric::SIGNED); // don't need to delete, will be handled - //assignp->unlinkFrBack(); VL_DO_DANGLING(assignp->deleteTree(), assignp); + // assignp->unlinkFrBack(); VL_DO_DANGLING(assignp->deleteTree(), + // assignp); // update the graph { // delete all inedges to lvertexp if (!lvertexp->inEmpty()) { - for (V3GraphEdge* ledgep = lvertexp->inBeginp(); ledgep; ) { + for (V3GraphEdge* ledgep = lvertexp->inBeginp(); ledgep;) { V3GraphEdge* oedgep = ledgep; ledgep = ledgep->inNextp(); GateEitherVertex* fromvp @@ -1374,8 +1372,7 @@ private: } return VNUser(0); } - - virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) { + virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) { // return VNUser(0); } @@ -1388,19 +1385,16 @@ public: m_numMergedAssigns = 0; m_graphp = graphp; } - void mergeAssignsTree(GateVarVertex* vvertexp) { - vvertexp->accept(*this); - } + void mergeAssignsTree(GateVarVertex* vvertexp) { vvertexp->accept(*this); } VDouble0 numMergedAssigns() { return m_numMergedAssigns; } }; - //---------------------------------------------------------------------- void GateVisitor::mergeAssigns() { UINFO(6, "mergeAssigns\n"); GateMergeAssignsGraphVisitor merger(&m_graph); - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (GateVarVertex* vvertexp = dynamic_cast(itp)) { merger.mergeAssignsTree(vvertexp); } @@ -1414,26 +1408,26 @@ void GateVisitor::mergeAssigns() { class GateConcatVisitor : public GateBaseVisitor { private: // STATE - AstVarScope* m_vscp; // Varscope we're trying to find - int m_offset; // Current offset of varscope - int m_found_offset; // Found offset of varscope - bool m_found; // Offset found + AstVarScope* m_vscp; // Varscope we're trying to find + int m_offset; // Current offset of varscope + int m_found_offset; // Found offset of varscope + bool m_found; // Offset found // VISITORS virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE { - UINFO(9,"CLK DECOMP Concat search var (off = "<varScopep() == m_vscp && !nodep->user2() && !m_found) { // A concatenation may use the same var multiple times // But the graph will initially have an edge per instance nodep->user2(true); m_found_offset = m_offset; m_found = true; - UINFO(9,"CLK DECOMP Concat found var (off = "<dtypep()->width(); } virtual void visit(AstConcat* nodep) VL_OVERRIDE { - UINFO(9,"CLK DECOMP Concat search (off = "<rhsp()); iterate(nodep->lhsp()); } @@ -1456,8 +1450,9 @@ public: m_found = false; // Iterate iterate(concatp); - UINFO(9,"CLK DECOMP Concat Offset (found = "< bool: already visited - int m_seen_clk_vectors; - AstVarScope* m_clk_vsp; - GateVarVertex* m_clk_vvertexp; - GateConcatVisitor m_concat_visitor; - int m_total_seen_clk_vectors; - int m_total_decomposed_clk_vectors; + int m_seen_clk_vectors; + AstVarScope* m_clk_vsp; + GateVarVertex* m_clk_vvertexp; + GateConcatVisitor m_concat_visitor; + int m_total_seen_clk_vectors; + int m_total_decomposed_clk_vectors; virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) { // Check that we haven't been here before AstVarScope* vsp = vvertexp->varScp(); if (vsp->user2SetOnce()) return VNUser(0); - UINFO(9,"CLK DECOMP Var - "<varp()->width() > 1) { m_seen_clk_vectors++; m_total_seen_clk_vectors++; @@ -1500,9 +1495,7 @@ private: GateClkDecompState* currState = reinterpret_cast(vu.c()); GateClkDecompState nextState(currState->m_offset, vsp); vvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState)); - if (vsp->varp()->width() > 1) { - m_seen_clk_vectors--; - } + if (vsp->varp()->width() > 1) --m_seen_clk_vectors; vsp->user2(false); return VNUser(0); } @@ -1511,14 +1504,14 @@ private: GateClkDecompState* currState = reinterpret_cast(vu.c()); int clk_offset = currState->m_offset; if (const AstAssignW* assignp = VN_CAST(lvertexp->nodep(), AssignW)) { - UINFO(9,"CLK DECOMP Logic (off = "<rhsp(), Sel)) { if (VN_IS(rselp->lsbp(), Const) && VN_IS(rselp->widthp(), Const)) { if (clk_offset < rselp->lsbConst() || clk_offset > rselp->msbConst()) { - UINFO(9,"CLK DECOMP Sel [ "<msbConst() - <<" : "<lsbConst()<<" ] dropped clock (" - <msbConst() << " : " + << rselp->lsbConst() << " ] dropped clock (" + << clk_offset << ")" << endl); return VNUser(0); } clk_offset -= rselp->lsbConst(); @@ -1526,7 +1519,7 @@ private: return VNUser(0); } } else if (AstConcat* catp = VN_CAST(assignp->rhsp(), Concat)) { - UINFO(9,"CLK DECOMP Concat searching - "<lhsp()<lhsp() << endl); int concat_offset; if (!m_concat_visitor.concatOffset(catp, currState->m_last_vsp, concat_offset)) { return VNUser(0); @@ -1542,13 +1535,14 @@ private: } else if (const AstVarRef* vrp = VN_CAST(assignp->lhsp(), VarRef)) { if (vrp->dtypep()->width() == 1 && m_seen_clk_vectors) { if (clk_offset != 0) { - UINFO(9,"Should only make it here with clk_offset = 0"<lhsp()<<" <-> "<lhsp() << " <-> " << m_clk_vsp + << endl); AstNode* rhsp = assignp->rhsp(); rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false)); - for (V3GraphEdge* edgep = lvertexp->inBeginp(); edgep; ) { + for (V3GraphEdge* edgep = lvertexp->inBeginp(); edgep;) { VL_DO_DANGLING(edgep->unlinkDelete(), edgep); } new V3GraphEdge(m_graphp, m_clk_vvertexp, lvertexp, 1); @@ -1572,10 +1566,11 @@ public: } virtual ~GateClkDecompGraphVisitor() { V3Stats::addStat("Optimizations, Clocker seen vectors", m_total_seen_clk_vectors); - V3Stats::addStat("Optimizations, Clocker decomposed vectors", m_total_decomposed_clk_vectors); + V3Stats::addStat("Optimizations, Clocker decomposed vectors", + m_total_decomposed_clk_vectors); } void clkDecomp(GateVarVertex* vvertexp) { - UINFO(9,"CLK DECOMP Starting Var - "<varScp(); m_clk_vvertexp = vvertexp; @@ -1585,17 +1580,17 @@ public: }; void GateVisitor::decomposeClkVectors() { - UINFO(9,"Starting clock decomposition"<verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (GateVarVertex* vertp = dynamic_cast(itp)) { AstVarScope* vsp = vertp->varScp(); if (vsp->varp()->attrClocker() == VVarAttrClocker::CLOCKER_YES) { if (vsp->varp()->width() > 1) { - UINFO(9,"Clocker > 1 bit, not decomposing: "< 1 bit, not decomposing: " << vsp << endl); } else { - UINFO(9,"CLK DECOMP - "<valuep(), NodeAssign)) { - UINFO(5," Removeassign "<rhsp(); valuep->unlinkFrBack(); assp->replaceWith(valuep); @@ -1626,9 +1620,7 @@ private: public: // CONSTRUCTORS - explicit GateDeassignVisitor(AstNode* nodep) { - iterate(nodep); - } + explicit GateDeassignVisitor(AstNode* nodep) { iterate(nodep); } virtual ~GateDeassignVisitor() {} }; @@ -1636,10 +1628,10 @@ public: // Gate class functions void V3Gate::gateAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3GenClk.cpp b/src/V3GenClk.cpp index 8d7d53614..5cef03170 100644 --- a/src/V3GenClk.cpp +++ b/src/V3GenClk.cpp @@ -45,13 +45,13 @@ private: // Cleared on top scope // AstVarScope::user2() -> AstVarScope*. Signal replacing activation with // AstVarRef::user3() -> bool. Signal is replaced activation (already done) - AstUser2InUse m_inuser2; - AstUser3InUse m_inuser3; + AstUser2InUse m_inuser2; + AstUser3InUse m_inuser3; // STATE - AstActive* m_activep; // Inside activate statement - AstNodeModule* m_topModp; // Top module - AstScope* m_scopetopp; // Scope under TOPSCOPE + AstActive* m_activep; // Inside activate statement + AstNodeModule* m_topModp; // Top module + AstScope* m_scopetopp; // Scope under TOPSCOPE // METHODS AstVarScope* genInpClk(AstVarScope* vscp) { @@ -59,18 +59,19 @@ private: return VN_CAST(vscp->user2p(), VarScope); } else { AstVar* varp = vscp->varp(); - string newvarname = "__VinpClk__"+vscp->scopep()->nameDotless()+"__"+varp->name(); + string newvarname + = "__VinpClk__" + vscp->scopep()->nameDotless() + "__" + varp->name(); // Create: VARREF(inpclk) // ... // ASSIGN(VARREF(inpclk), VARREF(var)) - AstVar* newvarp = new AstVar(varp->fileline(), - AstVarType::MODULETEMP, newvarname, varp); + AstVar* newvarp + = new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp); m_topModp->addStmtp(newvarp); AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp); m_scopetopp->addVarp(newvscp); - AstAssign* asninitp = new AstAssign(vscp->fileline(), - new AstVarRef(vscp->fileline(), newvscp, true), - new AstVarRef(vscp->fileline(), vscp, false)); + AstAssign* asninitp + = new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true), + new AstVarRef(vscp->fileline(), vscp, false)); m_scopetopp->addFinalClkp(asninitp); // vscp->user2p(newvscp); @@ -96,7 +97,7 @@ private: if (m_activep && !nodep->user3()) { nodep->user3(true); if (vscp->isCircular()) { - UINFO(8," VarActReplace "<fileline(), newvscp, nodep->lvalue()); @@ -112,9 +113,7 @@ private: m_activep = NULL; iterateChildren(nodep); } - virtual void visit(AstCFunc* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } + virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateChildren(nodep); } //----- virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } @@ -138,13 +137,13 @@ private: // NODE STATE // Cleared on top scope // AstVarScope::user() -> bool. Set when the var has been used as clock - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE - AstActive* m_activep; // Inside activate statement - bool m_tracingCall; // Iterating into a call to a cfunc - AstNodeAssign* m_assignp; // Inside assigndly statement - AstNodeModule* m_topModp; // Top module + AstActive* m_activep; // Inside activate statement + bool m_tracingCall; // Iterating into a call to a cfunc + AstNodeAssign* m_assignp; // Inside assigndly statement + AstNodeModule* m_topModp; // Top module // VISITORS virtual void visit(AstTopScope* nodep) VL_OVERRIDE { @@ -153,7 +152,7 @@ private: { // Make the new clock signals and replace any activate references // See rename, it does some AstNode::userClearTree()'s - GenClkRenameVisitor visitor (nodep, m_topModp); + GenClkRenameVisitor visitor(nodep, m_topModp); } } virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { @@ -188,24 +187,24 @@ private: AstVarScope* vscp = nodep->varScopep(); UASSERT_OBJ(vscp, nodep, "Scope not assigned"); if (m_activep) { - UINFO(8," VarAct "<user1(true); } if (m_assignp && nodep->lvalue() && vscp->user1()) { // Variable was previously used as a clock, and is now being set // Thus a unordered generated clock... - UINFO(8," VarSetAct "<circular(true); } } virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { - //UINFO(8,"ASS "<sensesp(), nodep, "Unlinked"); iterateChildren(nodep->sensesp()); // iterateAndNext? @@ -233,9 +232,7 @@ public: // GenClk class functions void V3GenClk::genClkAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index 108acd9ca..fc2cc08f5 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -34,13 +34,17 @@ int V3Graph::debug() { return std::max(V3Error::debugDefault(), s_debug); } // Vertices V3GraphVertex::V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old) - : m_fanout(old.m_fanout), m_color(old.m_color), m_rank(old.m_rank) { + : m_fanout(old.m_fanout) + , m_color(old.m_color) + , m_rank(old.m_rank) { m_userp = NULL; verticesPushBack(graphp); } V3GraphVertex::V3GraphVertex(V3Graph* graphp) - : m_fanout(0), m_color(0), m_rank(0) { + : m_fanout(0) + , m_color(0) + , m_rank(0) { m_userp = NULL; verticesPushBack(graphp); } @@ -68,13 +72,13 @@ void V3GraphVertex::unlinkDelete(V3Graph* graphp) { // Unlink from vertex list m_vertices.unlink(graphp->m_vertices, this); // Delete - delete this; //this=NULL; + delete this; // this=NULL; } void V3GraphVertex::rerouteEdges(V3Graph* graphp) { // Make new edges for each from/to pair - for (V3GraphEdge* iedgep = inBeginp(); iedgep; iedgep=iedgep->inNextp()) { - for (V3GraphEdge* oedgep = outBeginp(); oedgep; oedgep=oedgep->outNextp()) { + for (V3GraphEdge* iedgep = inBeginp(); iedgep; iedgep = iedgep->inNextp()) { + for (V3GraphEdge* oedgep = outBeginp(); oedgep; oedgep = oedgep->outNextp()) { new V3GraphEdge(graphp, iedgep->fromp(), oedgep->top(), std::min(iedgep->weight(), oedgep->weight()), iedgep->cutable() && oedgep->cutable()); @@ -84,13 +88,8 @@ void V3GraphVertex::rerouteEdges(V3Graph* graphp) { unlinkEdges(graphp); } -bool V3GraphVertex::inSize1() const { - return !inEmpty() && inBeginp()->inNextp()==NULL; -} - -bool V3GraphVertex::outSize1() const { - return !outEmpty() && outBeginp()->outNextp()==NULL; -} +bool V3GraphVertex::inSize1() const { return !inEmpty() && !inBeginp()->inNextp(); } +bool V3GraphVertex::outSize1() const { return !outEmpty() && !outBeginp()->outNextp(); } uint32_t V3GraphVertex::inHash() const { // We want the same hash ignoring the order of edges. @@ -98,7 +97,7 @@ uint32_t V3GraphVertex::inHash() const { // However with XOR multiple edges to the same source will cancel out, // so we use ADD. (Generally call this only after removing duplicates though) uint32_t hash = 0; - for (V3GraphEdge* edgep = this->inBeginp(); edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = this->inBeginp(); edgep; edgep = edgep->inNextp()) { hash += cvtToHash(edgep->fromp()); } return hash; @@ -106,14 +105,13 @@ uint32_t V3GraphVertex::inHash() const { uint32_t V3GraphVertex::outHash() const { uint32_t hash = 0; - for (V3GraphEdge* edgep = this->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = this->outBeginp(); edgep; edgep = edgep->outNextp()) { hash += cvtToHash(edgep->top()); } return hash; } -V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, - const V3GraphVertex* waywardp) { +V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, const V3GraphVertex* waywardp) { // O(edges) linear search. Searches search both nodes' edge lists in // parallel. The lists probably aren't _both_ huge, so this is // unlikely to blow up even on fairly nasty graphs. @@ -131,10 +129,10 @@ V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, void V3GraphVertex::v3errorEnd(std::ostringstream& str) const { std::ostringstream nsstr; - nsstr<rank(); - if (vertexp->fanout()!=0.0) os<<" f"<fanout(); - if (vertexp->color()) os<<" c"<color(); + os << " VERTEX=" << vertexp->name(); + if (vertexp->rank()) os << " r" << vertexp->rank(); + if (vertexp->fanout() != 0.0) os << " f" << vertexp->fanout(); + if (vertexp->color()) os << " c" << vertexp->color(); return os; } @@ -158,8 +158,7 @@ std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp) { //###################################################################### // Edges -void V3GraphEdge::init(V3Graph* graphp, - V3GraphVertex* fromp, V3GraphVertex* top, int weight, +void V3GraphEdge::init(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable) { UASSERT(fromp, "Null from pointer"); UASSERT(top, "Null to pointer"); @@ -174,7 +173,7 @@ void V3GraphEdge::init(V3Graph* graphp, } V3GraphEdge* V3GraphEdge::relinkFromp(V3GraphVertex* newFromp) { - V3GraphEdge *oldNxt = outNextp(); + V3GraphEdge* oldNxt = outNextp(); m_outs.unlink(m_fromp->m_outs, this); m_fromp = newFromp; outPushBack(); @@ -187,7 +186,7 @@ void V3GraphEdge::unlinkDelete() { // Unlink to side m_ins.unlink(m_top->m_ins, this); // Delete - delete this; //this=NULL; + delete this; // this=NULL; } void V3GraphEdge::outPushBack() { @@ -210,14 +209,12 @@ V3Graph::V3Graph() { verticesUnlink(); } -V3Graph::~V3Graph() { - clear(); -} +V3Graph::~V3Graph() { clear(); } void V3Graph::clear() { // Empty it of all points, as if making a new object // Delete the old edges - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; /*BELOW*/) { V3GraphEdge* nextp = edgep->outNextp(); VL_DO_DANGLING(delete edgep, edgep); @@ -241,7 +238,7 @@ void V3Graph::userClearVertices() { // the graph pointer given a vertex.) For now we don't call this often, and // the extra code on each read of user() would probably slow things // down more than help. - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { vertexp->user(0); vertexp->userp(NULL); // Its a union, but might be different size than user() } @@ -249,8 +246,8 @@ void V3Graph::userClearVertices() { void V3Graph::userClearEdges() { // Clear user() in all of tree - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { edgep->user(0); edgep->userp(NULL); // Its a union, but might be different size than user() } @@ -259,7 +256,7 @@ void V3Graph::userClearEdges() { void V3Graph::clearColors() { // Reset colors - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { vertexp->m_color = 0; } } @@ -268,72 +265,70 @@ void V3Graph::clearColors() { // Dumping void V3Graph::loopsMessageCb(V3GraphVertex* vertexp) { - vertexp->v3fatalSrc("Loops detected in graph: "<v3fatalSrc("Loops detected in graph: " << vertexp); } void V3Graph::loopsVertexCb(V3GraphVertex* vertexp) { // Needed here as V3GraphVertex<< isn't defined until later in header - if (debug()) std::cerr<<"-Info-Loop: "<verticesNextp()) { - os<<"\tNode: "<name(); - if (vertexp->color()) os<<" color="<color(); - os<verticesNextp()) { + os << "\tNode: " << vertexp->name(); + if (vertexp->color()) os << " color=" << vertexp->color(); + os << endl; // Print edges - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { dumpEdge(os, vertexp, edgep); } - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { dumpEdge(os, vertexp, edgep); } } } void V3Graph::dumpEdge(std::ostream& os, V3GraphVertex* vertexp, V3GraphEdge* edgep) { - if (edgep->weight() - && (edgep->fromp() == vertexp - || edgep->top() == vertexp)) { - os<<"\t\t"; - if (edgep->fromp() == vertexp) os << "-> "<top()->name(); - if (edgep->top() == vertexp) os << "<- "<fromp()->name(); - if (edgep->cutable()) os<<" [CUTABLE]"; - os<weight() && (edgep->fromp() == vertexp || edgep->top() == vertexp)) { + os << "\t\t"; + if (edgep->fromp() == vertexp) os << "-> " << edgep->top()->name(); + if (edgep->top() == vertexp) os << "<- " << edgep->fromp()->name(); + if (edgep->cutable()) os << " [CUTABLE]"; + os << endl; } } void V3Graph::dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph) const { if (v3Global.opt.dumpTree()) { - dumpDotFile(v3Global.debugFilename(nameComment)+".dot", colorAsSubgraph); + dumpDotFile(v3Global.debugFilename(nameComment) + ".dot", colorAsSubgraph); } } //! Variant of dumpDotFilePrefixed without --dump option check void V3Graph::dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph) const { - dumpDotFile(v3Global.debugFilename(nameComment)+".dot", colorAsSubgraph); + dumpDotFile(v3Global.debugFilename(nameComment) + ".dot", colorAsSubgraph); } void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const { // This generates a file used by graphviz, https://www.graphviz.org // "hardcoded" parameters: - const vl_unique_ptr logp (V3File::new_ofstream(filename)); - if (logp->fail()) v3fatal("Can't write "< logp(V3File::new_ofstream(filename)); + if (logp->fail()) v3fatal("Can't write " << filename); // Header - *logp<<"digraph v3graph {\n"; - *logp<<"\tgraph\t[label=\""< SubgraphMmap; + typedef std::multimap SubgraphMmap; SubgraphMmap subgraphs; - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { string vertexSubgraph = (colorAsSubgraph && vertexp->color()) ? cvtToStr(vertexp->color()) : ""; subgraphs.insert(make_pair(vertexSubgraph, vertexp)); @@ -341,7 +336,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const { // We use a map here, as we don't want to corrupt anything (userp) in the graph, // and we don't care if this is slow. - std::map numMap; + std::map numMap; // Print vertices int n = 0; @@ -351,42 +346,41 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const { V3GraphVertex* vertexp = it->second; numMap[vertexp] = n; if (subgr != vertexSubgraph) { - if (subgr!="") *logp<<"\t};\n"; + if (subgr != "") *logp << "\t};\n"; subgr = vertexSubgraph; - if (subgr!="") *logp<<"\tsubgraph cluster_"<dotName()<<(n++) - <<"\t[fontsize=8 " - <<"label=\""<<(vertexp->name()!="" ? vertexp->name() : "\\N"); - if (vertexp->rank()) *logp<<" r"<rank(); - if (vertexp->fanout()!=0.0) *logp<<" f"<fanout(); - if (vertexp->color()) *logp<<"\\n c"<color(); - *logp<<"\""; - *logp<<", color="<dotColor(); - if (vertexp->dotStyle()!="") *logp<<", style="<dotStyle(); - if (vertexp->dotShape()!="") *logp<<", shape="<dotShape(); - *logp<<"];\n"; + if (subgr != "") *logp << "\t"; + *logp << "\tn" << vertexp->dotName() << (n++) << "\t[fontsize=8 " + << "label=\"" << (vertexp->name() != "" ? vertexp->name() : "\\N"); + if (vertexp->rank()) *logp << " r" << vertexp->rank(); + if (vertexp->fanout() != 0.0) *logp << " f" << vertexp->fanout(); + if (vertexp->color()) *logp << "\\n c" << vertexp->color(); + *logp << "\""; + *logp << ", color=" << vertexp->dotColor(); + if (vertexp->dotStyle() != "") *logp << ", style=" << vertexp->dotStyle(); + if (vertexp->dotShape() != "") *logp << ", shape=" << vertexp->dotShape(); + *logp << "];\n"; } - if (subgr!="") *logp<<"\t};\n"; + if (subgr != "") *logp << "\t};\n"; // Print edges - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (edgep->weight()) { int fromVnum = numMap[edgep->fromp()]; - int toVnum = numMap[edgep->top()]; - *logp<<"\tn"<fromp()->dotName()< n"<top()->dotName()<name()!="" ? edgep->name() : "\\E")<<"\"" - <<"fontsize=8 label=\"" - <<(edgep->dotLabel()!="" ? edgep->dotLabel() : "")<<"\"" - <<" weight="<weight() - <<" color="<dotColor(); - if (edgep->dotStyle()!="") *logp<<" style="<dotStyle(); - //if (edgep->cutable()) { *logp<<",constraint=false"; } // to rank without following edges - *logp<<"];\n"; + int toVnum = numMap[edgep->top()]; + *logp << "\tn" << edgep->fromp()->dotName() << fromVnum << " -> n" + << edgep->top()->dotName() << toVnum + << " [" + //<<"fontsize=8 label=\""<<(edgep->name()!="" ? edgep->name() : "\\E")<<"\"" + << "fontsize=8 label=\"" + << (edgep->dotLabel() != "" ? edgep->dotLabel() : "") << "\"" + << " weight=" << edgep->weight() << " color=" << edgep->dotColor(); + if (edgep->dotStyle() != "") *logp << " style=" << edgep->dotStyle(); + // if (edgep->cutable()) { *logp<<",constraint=false"; } // to rank without + // following edges + *logp << "];\n"; } } } @@ -396,5 +390,5 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const { *logp << "}\n"; logp->close(); - cout << "dot -Tpdf -o ~/a.pdf "< m_work; // List of vertices with optimization work left - uint32_t m_storedRank; // Rank held until commit to edge placement - bool m_onWorkList; // True if already on list of work to do - bool m_deleted; // True if deleted + V3ListEnt m_work; // List of vertices with optimization work left + uint32_t m_storedRank; // Rank held until commit to edge placement + bool m_onWorkList; // True if already on list of work to do + bool m_deleted; // True if deleted public: - GraphAcycVertex(V3Graph* graphp, V3GraphVertex* origVertexp) - : V3GraphVertex(graphp), m_origVertexp(origVertexp) - , m_storedRank(0), m_onWorkList(false), m_deleted(false) { - } + : V3GraphVertex(graphp) + , m_origVertexp(origVertexp) + , m_storedRank(0) + , m_onWorkList(false) + , m_deleted(false) {} virtual ~GraphAcycVertex() {} V3GraphVertex* origVertexp() const { return m_origVertexp; } void setDelete() { m_deleted = true; } @@ -60,25 +61,25 @@ class GraphAcycEdge : public V3GraphEdge { // userp() is always used to point to the head original graph edge private: typedef std::list OrigEdgeList; // List of orig edges, see also GraphAcyc's decl - V3GraphEdge* origEdgep() const { + V3GraphEdge* origEdgep() const { OrigEdgeList* oEListp = static_cast(userp()); - if (!oEListp) v3fatalSrc("No original edge associated with acyc edge "<front()); } + public: - GraphAcycEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, - int weight, bool cutable=false) - : V3GraphEdge(graphp, fromp, top, weight, cutable) { - } + GraphAcycEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, + bool cutable = false) + : V3GraphEdge(graphp, fromp, top, weight, cutable) {} virtual ~GraphAcycEdge() {} // yellow=we might still cut it, else oldEdge: yellowGreen=made uncutable, red=uncutable - virtual string dotColor() const { return (cutable()?"yellow":origEdgep()->dotColor()); } + virtual string dotColor() const { return (cutable() ? "yellow" : origEdgep()->dotColor()); } }; //-------------------------------------------------------------------- struct GraphAcycEdgeCmp { - inline bool operator() (const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { + inline bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { if (lhsp->weight() > rhsp->weight()) return 1; // LHS goes first if (lhsp->weight() < rhsp->weight()) return 0; // RHS goes first return 0; @@ -90,7 +91,8 @@ struct GraphAcycEdgeCmp { // CLASSES class GraphAcyc { private: - typedef std::list OrigEdgeList; // List of orig edges, see also GraphAcycEdge's decl + typedef std::list + OrigEdgeList; // List of orig edges, see also GraphAcycEdge's decl // GRAPH USERS // origGraph // GraphVertex::user() GraphAycVerted* New graph node @@ -98,12 +100,12 @@ private: // GraphEdge::user() OrigEdgeList* Old graph edges // GraphVertex::user bool Detection of loops in simplifyDupIterate // MEMBERS - V3Graph* m_origGraphp; // Original graph - V3Graph m_breakGraph; // Graph with only breakable edges represented - V3List m_work; // List of vertices with optimization work left + V3Graph* m_origGraphp; // Original graph + V3Graph m_breakGraph; // Graph with only breakable edges represented + V3List m_work; // List of vertices with optimization work left std::vector m_origEdgeDelp; // List of deletions to do when done - V3EdgeFuncP m_origEdgeFuncp; // Function that says we follow this edge (in original graph) - uint32_t m_placeStep; // Number that user() must be equal to to indicate processing + V3EdgeFuncP m_origEdgeFuncp; // Function that says we follow this edge (in original graph) + uint32_t m_placeStep; // Number that user() must be equal to to indicate processing static int debug() { return V3Graph::debug(); } @@ -127,8 +129,8 @@ private: } V3GraphEdge* edgeFromEdge(V3GraphEdge* oldedgep, V3GraphVertex* fromp, V3GraphVertex* top) { // Make new breakGraph edge, with old edge as a template - GraphAcycEdge* newEdgep = new GraphAcycEdge(&m_breakGraph, fromp, top, - oldedgep->weight(), oldedgep->cutable()); + GraphAcycEdge* newEdgep = new GraphAcycEdge(&m_breakGraph, fromp, top, oldedgep->weight(), + oldedgep->cutable()); newEdgep->userp(oldedgep->userp()); // Keep pointer to OrigEdgeList return newEdgep; } @@ -153,16 +155,18 @@ private: } void cutOrigEdge(V3GraphEdge* breakEdgep, const char* why) { // From the break edge, cut edges in original graph it represents - UINFO(8,why<<" CUT "<fromp()<fromp() << endl); breakEdgep->cut(); OrigEdgeList* oEListp = static_cast(breakEdgep->userp()); - if (!oEListp) v3fatalSrc("No original edge associated with cutting edge " - <begin(); it != oEListp->end(); ++it) { V3GraphEdge* origEdgep = *it; origEdgep->cut(); - UINFO(8," "<fromp()<<" ->"<top()<fromp() << " ->" << origEdgep->top() << endl); } } // Work Queue @@ -178,7 +182,9 @@ private: void workPop() { GraphAcycVertex* avertexp = workBeginp(); avertexp->m_onWorkList = false; - avertexp->m_work.unlink(m_work, avertexp); } + avertexp->m_work.unlink(m_work, avertexp); + } + public: // CONSTRUCTORS GraphAcyc(V3Graph* origGraphp, V3EdgeFuncP edgeFuncp) { @@ -205,8 +211,8 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) { // For each old node, make a new graph node for optimization origGraphp->userClearVertices(); origGraphp->userClearEdges(); - for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); - overtexp; overtexp = overtexp->verticesNextp()) { + for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); overtexp; + overtexp = overtexp->verticesNextp()) { if (overtexp->color()) { GraphAcycVertex* avertexp = new GraphAcycVertex(&m_breakGraph, overtexp); overtexp->userp(avertexp); // Stash so can look up later @@ -214,8 +220,8 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) { } // Build edges between logic vertices - for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); - overtexp; overtexp = overtexp->verticesNextp()) { + for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); overtexp; + overtexp = overtexp->verticesNextp()) { if (overtexp->color()) { GraphAcycVertex* avertexp = static_cast(overtexp->userp()); buildGraphIterate(overtexp, avertexp); @@ -225,15 +231,15 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) { void GraphAcyc::buildGraphIterate(V3GraphVertex* overtexp, GraphAcycVertex* avertexp) { // Make new edges - for (V3GraphEdge* edgep = overtexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = overtexp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (origFollowEdge(edgep)) { // not cut V3GraphVertex* toVertexp = edgep->top(); if (toVertexp->color()) { GraphAcycVertex* toAVertexp = static_cast(toVertexp->userp()); // Replicate the old edge into the new graph // There may be multiple edges between same pairs of vertices - V3GraphEdge* breakEdgep = new GraphAcycEdge - (&m_breakGraph, avertexp, toAVertexp, edgep->weight(), edgep->cutable()); + V3GraphEdge* breakEdgep = new GraphAcycEdge(&m_breakGraph, avertexp, toAVertexp, + edgep->weight(), edgep->cutable()); addOrigEdgep(breakEdgep, edgep); // So can find original edge } } @@ -242,8 +248,8 @@ void GraphAcyc::buildGraphIterate(V3GraphVertex* overtexp, GraphAcycVertex* aver void GraphAcyc::simplify(bool allowCut) { // Add all nodes to list of work to do - for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp(); - vertexp; vertexp = vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { workPush(vertexp); } // Optimize till everything finished @@ -267,7 +273,8 @@ void GraphAcyc::simplify(bool allowCut) { void GraphAcyc::deleteMarked() { // Delete nodes marked for removal - for (V3GraphVertex* nextp, *vertexp = m_breakGraph.verticesBeginp(); vertexp; vertexp=nextp) { + for (V3GraphVertex *nextp, *vertexp = m_breakGraph.verticesBeginp(); vertexp; + vertexp = nextp) { nextp = vertexp->verticesNextp(); GraphAcycVertex* avertexp = static_cast(vertexp); if (avertexp->isDelete()) { @@ -281,18 +288,18 @@ void GraphAcyc::simplifyNone(GraphAcycVertex* avertexp) { // Likewise, vertices with no outputs if (avertexp->isDelete()) return; if (avertexp->inEmpty() || avertexp->outEmpty()) { - UINFO(9," SimplifyNoneRemove "<setDelete(); // Mark so we won't delete it twice // Remove edges while (V3GraphEdge* edgep = avertexp->outBeginp()) { V3GraphVertex* otherVertexp = edgep->top(); - //UINFO(9," out "<unlinkDelete(), edgep); workPush(otherVertexp); } while (V3GraphEdge* edgep = avertexp->inBeginp()) { V3GraphVertex* otherVertexp = edgep->fromp(); - //UINFO(9," in "<unlinkDelete(), edgep); workPush(otherVertexp); } @@ -309,23 +316,25 @@ void GraphAcyc::simplifyOne(GraphAcycVertex* avertexp) { V3GraphVertex* outVertexp = outEdgep->top(); // The in and out may be the same node; we'll make a loop // The in OR out may be THIS node; we can't delete it then. - if (inVertexp!=avertexp && outVertexp!=avertexp) { - UINFO(9," SimplifyOneRemove "<setDelete(); // Mark so we won't delete it twice // Make a new edge connecting the two vertices directly // If both are breakable, we pick the one with less weight, else it's arbitrary // We can forget about the origEdge list for the "non-selected" set of edges, // as we need to break only one set or the other set of edges, not both. // (This is why we must give preference to the cutable set.) - V3GraphEdge* templateEdgep = ( (inEdgep->cutable() - && (!outEdgep->cutable() - || inEdgep->weight()weight() )) - ? inEdgep : outEdgep); + V3GraphEdge* templateEdgep + = ((inEdgep->cutable() + && (!outEdgep->cutable() || inEdgep->weight() < outEdgep->weight())) + ? inEdgep + : outEdgep); // cppcheck-suppress leakReturnValNotUsed edgeFromEdge(templateEdgep, inVertexp, outVertexp); // Remove old edge VL_DO_DANGLING(inEdgep->unlinkDelete(), inEdgep); - VL_DO_DANGLING(outEdgep->unlinkDelete(), outEdgep); VL_DANGLING(templateEdgep); + VL_DO_DANGLING(outEdgep->unlinkDelete(), outEdgep); + VL_DANGLING(templateEdgep); workPush(inVertexp); workPush(outVertexp); } @@ -340,16 +349,17 @@ void GraphAcyc::simplifyOut(GraphAcycVertex* avertexp) { V3GraphEdge* outEdgep = avertexp->outBeginp(); if (!outEdgep->cutable()) { V3GraphVertex* outVertexp = outEdgep->top(); - UINFO(9," SimplifyOutRemove "<setDelete(); // Mark so we won't delete it twice - for (V3GraphEdge* nextp, *inEdgep = avertexp->inBeginp(); inEdgep; inEdgep=nextp) { + for (V3GraphEdge *nextp, *inEdgep = avertexp->inBeginp(); inEdgep; inEdgep = nextp) { nextp = inEdgep->inNextp(); V3GraphVertex* inVertexp = inEdgep->fromp(); if (inVertexp == avertexp) { - if (debug()) v3error("Non-cutable edge forms a loop, vertex="<reportLoops(&V3GraphEdge::followNotCutable, - avertexp->origVertexp()); // calls OrderGraph::loopsVertexCb + m_origGraphp->reportLoops( + &V3GraphEdge::followNotCutable, + avertexp->origVertexp()); // calls OrderGraph::loopsVertexCb // Things are unlikely to end well at this point, // but we'll try something to get to further errors... inEdgep->cutable(true); @@ -372,11 +382,11 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) { // Remove redundant edges if (avertexp->isDelete()) return; // Clear marks - for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { edgep->top()->userp(NULL); } // Mark edges and detect duplications - for (V3GraphEdge* nextp, *edgep = avertexp->outBeginp(); edgep; edgep=nextp) { + for (V3GraphEdge *nextp, *edgep = avertexp->outBeginp(); edgep; edgep = nextp) { nextp = edgep->outNextp(); V3GraphVertex* outVertexp = edgep->top(); V3GraphEdge* prevEdgep = static_cast(outVertexp->userp()); @@ -384,16 +394,16 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) { if (!prevEdgep->cutable()) { // !cutable duplicates prev !cutable: we can ignore it, redundant // cutable duplicates prev !cutable: know it's not a relevant loop, ignore it - UINFO(8," DelDupEdge "< "<top()< " << edgep->top() << endl); VL_DO_DANGLING(edgep->unlinkDelete(), edgep); } else if (!edgep->cutable()) { // !cutable duplicates prev cutable: delete the earlier cutable - UINFO(8," DelDupPrev "< "<top()< " << prevEdgep->top() << endl); VL_DO_DANGLING(prevEdgep->unlinkDelete(), prevEdgep); outVertexp->userp(edgep); } else { // cutable duplicates prev cutable: combine weights - UINFO(8," DelDupComb "< "<top()< " << edgep->top() << endl); prevEdgep->weight(prevEdgep->weight() + edgep->weight()); addOrigEdgep(prevEdgep, edgep); VL_DO_DANGLING(edgep->unlinkDelete(), edgep); @@ -410,9 +420,9 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) { void GraphAcyc::cutBasic(GraphAcycVertex* avertexp) { // Detect and cleanup any loops from node to itself if (avertexp->isDelete()) return; - for (V3GraphEdge* nextp, *edgep = avertexp->outBeginp(); edgep; edgep=nextp) { + for (V3GraphEdge *nextp, *edgep = avertexp->outBeginp(); edgep; edgep = nextp) { nextp = edgep->outNextp(); - if (edgep->cutable() && edgep->top()==avertexp) { + if (edgep->cutable() && edgep->top() == avertexp) { cutOrigEdge(edgep, " Cut Basic"); VL_DO_DANGLING(edgep->unlinkDelete(), edgep); workPush(avertexp); @@ -424,14 +434,14 @@ void GraphAcyc::cutBackward(GraphAcycVertex* avertexp) { // If a cutable edge is from A->B, and there's a non-cutable edge B->A, then must cut! if (avertexp->isDelete()) return; // Clear marks - for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { edgep->top()->user(false); } - for (V3GraphEdge* edgep = avertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = avertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { if (!edgep->cutable()) edgep->fromp()->user(true); } // Detect duplications - for (V3GraphEdge* nextp, *edgep = avertexp->outBeginp(); edgep; edgep=nextp) { + for (V3GraphEdge *nextp, *edgep = avertexp->outBeginp(); edgep; edgep = nextp) { nextp = edgep->outNextp(); if (edgep->cutable() && edgep->top()->user()) { cutOrigEdge(edgep, " Cut A->B->A"); @@ -446,25 +456,22 @@ void GraphAcyc::place() { // Make a list of all cutable edges in the graph int numEdges = 0; - for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp(); - vertexp; vertexp = vertexp->verticesNextp()) { - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { - if (edgep->weight() && edgep->cutable()) { - numEdges++; - } + for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { + if (edgep->weight() && edgep->cutable()) ++numEdges; } } - UINFO(4, " Cutable edges = "<weight()<<" "<fromp()<weight() << " " << edgep->fromp() + << endl); // Make the edge uncutable so we detect it in placement edgep->cutable(false); // Vertex::m_user begin: number indicates this edge was completed // Try to assign ranks, presuming this edge is in place // If we come across user()==placestep, we've detected a loop and must back out - bool loop = placeIterate(static_cast(edgep->top()), - edgep->fromp()->rank()+1); + bool loop + = placeIterate(static_cast(edgep->top()), edgep->fromp()->rank() + 1); if (!loop) { // No loop, we can keep it as uncutable // Commit the new ranks we calculated // Just cleanup the list. If this is slow, we can add another set of // user counters to avoid cleaning up the list. - while (workBeginp()) { - workPop(); - } + while (workBeginp()) workPop(); } else { // Adding this edge would cause a loop, kill it edgep->cutable(true); // So graph still looks pretty @@ -526,9 +532,9 @@ bool GraphAcyc::placeIterate(GraphAcycVertex* vertexp, uint32_t currentRank) { } vertexp->rank(currentRank); // Follow all edges and increase their ranks - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (edgep->weight() && !edgep->cutable()) { - if (placeIterate(static_cast(edgep->top()), currentRank+1)) { + if (placeIterate(static_cast(edgep->top()), currentRank + 1)) { // We don't need to reset user(); we'll use a different placeStep for the next edge return true; // Loop detected } @@ -551,33 +557,33 @@ void GraphAcyc::main() { // edges (and thus can't represent loops - if we did the unbreakable // marking right, anyways) buildGraph(m_origGraphp); - if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_pre"); + if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_pre"); // Perform simple optimizations before any cuttings simplify(false); - if (debug()>=5) m_breakGraph.dumpDotFilePrefixed("acyc_simp"); + if (debug() >= 5) m_breakGraph.dumpDotFilePrefixed("acyc_simp"); UINFO(4, " Cutting trivial loops\n"); simplify(true); - if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_mid"); + if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_mid"); UINFO(4, " Ranking\n"); m_breakGraph.rank(&V3GraphEdge::followNotCutable); - if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_rank"); + if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_rank"); UINFO(4, " Placement\n"); place(); - if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_place"); + if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_place"); UINFO(4, " Final Ranking\n"); // Only needed to assert there are no loops in completed graph m_breakGraph.rank(&V3GraphEdge::followAlwaysTrue); - if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_done"); + if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_done"); } void V3Graph::acyclic(V3EdgeFuncP edgeFuncp) { UINFO(4, "Acyclic\n"); - GraphAcyc acyc (this, edgeFuncp); + GraphAcyc acyc(this, edgeFuncp); acyc.main(); UINFO(4, "Acyclic done\n"); } diff --git a/src/V3GraphAlg.cpp b/src/V3GraphAlg.cpp index 9120f8f98..95db5be4f 100644 --- a/src/V3GraphAlg.cpp +++ b/src/V3GraphAlg.cpp @@ -36,15 +36,15 @@ void V3Graph::deleteCutableOnlyEdges() { // Vertex::m_user begin: indicates can be deleted // Pass 1, mark those. Don't delete now, as we don't want to rip out whole trees - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { vertexp->user(true); - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { if (!edgep->cutable()) { vertexp->user(false); // Can't delete it break; } } - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (!edgep->cutable()) { vertexp->user(false); // Can't delete it break; @@ -54,10 +54,10 @@ void V3Graph::deleteCutableOnlyEdges() { // Pass 2, delete those marked // Rather than doing a delete() we set the weight to 0 which disconnects the edge. - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { if (vertexp->user()) { - //UINFO(7,"Disconnect "<name()<outBeginp(); edgep; edgep=edgep->outNextp()) { + // UINFO(7, "Disconnect " << vertexp->name() << endl); + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { edgep->cut(); } } @@ -71,21 +71,21 @@ void V3Graph::deleteCutableOnlyEdges() { // Algorithms - weakly connected components class GraphRemoveRedundant : GraphAlg<> { - bool m_sumWeights; ///< Sum, rather then maximize weights + bool m_sumWeights; ///< Sum, rather then maximize weights private: void main() { - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { vertexIterate(vertexp); } } void vertexIterate(V3GraphVertex* vertexp) { // Clear marks - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { edgep->top()->userp(NULL); } // Mark edges and detect duplications - for (V3GraphEdge* nextp, *edgep = vertexp->outBeginp(); edgep; edgep=nextp) { + for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep = nextp) { nextp = edgep->outNextp(); if (followEdge(edgep)) { V3GraphVertex* outVertexp = edgep->top(); @@ -100,7 +100,8 @@ private: saveOld = true; // old !cutable more important than new } else { saveOld = true; - if (!m_sumWeights && (prevEdgep->weight() < edgep->weight())) { // Keep max weight + if (!m_sumWeights + && (prevEdgep->weight() < edgep->weight())) { // Keep max weight prevEdgep->weight(edgep->weight()); } } @@ -116,9 +117,11 @@ private: } } } + public: GraphRemoveRedundant(V3Graph* graphp, V3EdgeFuncP edgeFuncp, bool sumWeights) - : GraphAlg<>(graphp, edgeFuncp), m_sumWeights(sumWeights) { + : GraphAlg<>(graphp, edgeFuncp) + , m_sumWeights(sumWeights) { main(); } ~GraphRemoveRedundant() {} @@ -141,33 +144,26 @@ public: : GraphAlg<>(graphp, NULL) {} void go() { GraphPathChecker checker(m_graphp); - for (V3GraphVertex* vxp = m_graphp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (V3GraphVertex* vxp = m_graphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { V3GraphEdge* deletep = NULL; - for (V3GraphEdge* edgep = vxp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (deletep) VL_DO_CLEAR(deletep->unlinkDelete(), deletep = NULL); // It should be safe to modify the graph, despite using // the GraphPathChecker, as none of the modifications will // change what can be reached from what, nor should they // change the rank or CP of any node. - if (checker.isTransitiveEdge(edgep)) { - deletep = edgep; - } - } - if (deletep) { - VL_DO_DANGLING(deletep->unlinkDelete(), deletep); + if (checker.isTransitiveEdge(edgep)) deletep = edgep; } + if (deletep) VL_DO_DANGLING(deletep->unlinkDelete(), deletep); } } + private: VL_DEBUG_FUNC; // Declare debug() VL_UNCOPYABLE(GraphAlgRemoveTransitiveEdges); }; -void V3Graph::removeTransitiveEdges() { - GraphAlgRemoveTransitiveEdges(this).go(); -} +void V3Graph::removeTransitiveEdges() { GraphAlgRemoveTransitiveEdges(this).go(); } //###################################################################### //###################################################################### @@ -180,9 +176,9 @@ private: m_graphp->clearColors(); // Color graph uint32_t currentColor = 0; - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { - currentColor ++; + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { + currentColor++; vertexIterate(vertexp, currentColor); } } @@ -192,17 +188,14 @@ private: // then visit each of its edges, giving them the same color if (vertexp->color()) return; // Already colored it vertexp->color(currentColor); - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { - if (followEdge(edgep)) { - vertexIterate(edgep->top(), currentColor); - } + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { + if (followEdge(edgep)) vertexIterate(edgep->top(), currentColor); } - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { - if (followEdge(edgep)) { - vertexIterate(edgep->fromp(), currentColor); - } + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { + if (followEdge(edgep)) vertexIterate(edgep->fromp(), currentColor); } } + public: GraphAlgWeakly(V3Graph* graphp, V3EdgeFuncP edgeFuncp) : GraphAlg<>(graphp, edgeFuncp) { @@ -211,9 +204,7 @@ public: ~GraphAlgWeakly() {} }; -void V3Graph::weaklyConnected(V3EdgeFuncP edgeFuncp) { - GraphAlgWeakly(this, edgeFuncp); -} +void V3Graph::weaklyConnected(V3EdgeFuncP edgeFuncp) { GraphAlgWeakly(this, edgeFuncp); } //###################################################################### //###################################################################### @@ -231,14 +222,14 @@ private: // Vertex::color // Output subtree number (fully processed) // Clear info - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { vertexp->color(0); vertexp->user(0); } // Color graph - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { if (!vertexp->user()) { m_currentDfs++; vertexIterate(vertexp); @@ -246,10 +237,10 @@ private: } // If there's a single vertex of a color, it doesn't need a subgraph // This simplifies the consumer's code, and reduces graph debugging clutter - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { bool onecolor = true; - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (followEdge(edgep)) { if (vertexp->color() == edgep->top()->color()) { onecolor = false; @@ -265,7 +256,7 @@ private: uint32_t thisDfsNum = m_currentDfs++; vertexp->user(thisDfsNum); vertexp->color(0); - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (followEdge(edgep)) { V3GraphVertex* top = edgep->top(); if (!top->user()) { // Dest not computed yet @@ -291,6 +282,7 @@ private: m_callTrace.push_back(vertexp); } } + public: GraphAlgStrongly(V3Graph* graphp, V3EdgeFuncP edgeFuncp) : GraphAlg<>(graphp, edgeFuncp) { @@ -300,9 +292,7 @@ public: ~GraphAlgStrongly() {} }; -void V3Graph::stronglyConnected(V3EdgeFuncP edgeFuncp) { - GraphAlgStrongly(this, edgeFuncp); -} +void V3Graph::stronglyConnected(V3EdgeFuncP edgeFuncp) { GraphAlgStrongly(this, edgeFuncp); } //###################################################################### //###################################################################### @@ -314,16 +304,14 @@ private: // Rank each vertex, ignoring cutable edges // Vertex::m_user begin: 1 indicates processing, 2 indicates completed // Clear existing ranks - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { vertexp->rank(0); vertexp->user(0); } - for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { - if (!vertexp->user()) { - vertexIterate(vertexp, 1); - } + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { + if (!vertexp->user()) { vertexIterate(vertexp, 1); } } } @@ -339,13 +327,14 @@ private: if (vertexp->rank() >= currentRank) return; // Already processed it vertexp->user(1); vertexp->rank(currentRank); - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (followEdge(edgep)) { vertexIterate(edgep->top(), currentRank + vertexp->rankAdder()); } } vertexp->user(2); } + public: GraphAlgRank(V3Graph* graphp, V3EdgeFuncP edgeFuncp) : GraphAlg<>(graphp, edgeFuncp) { @@ -354,13 +343,9 @@ public: ~GraphAlgRank() {} }; -void V3Graph::rank() { - GraphAlgRank(this, &V3GraphEdge::followAlwaysTrue); -} +void V3Graph::rank() { GraphAlgRank(this, &V3GraphEdge::followAlwaysTrue); } -void V3Graph::rank(V3EdgeFuncP edgeFuncp) { - GraphAlgRank(this, edgeFuncp); -} +void V3Graph::rank(V3EdgeFuncP edgeFuncp) { GraphAlgRank(this, edgeFuncp); } //###################################################################### //###################################################################### @@ -389,7 +374,7 @@ private: m_callTrace[currentRank++] = vertexp; if (vertexp->user() == 1) { - for (unsigned i=0; iloopsVertexCb(m_callTrace[i]); } m_done = true; @@ -397,13 +382,12 @@ private: } if (vertexp->user() == 2) return; // Already processed it vertexp->user(1); - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { - if (followEdge(edgep)) { - vertexIterate(edgep->top(), currentRank); - } + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { + if (followEdge(edgep)) vertexIterate(edgep->top(), currentRank); } vertexp->user(2); } + public: GraphAlgRLoops(V3Graph* graphp, V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) : GraphAlg<>(graphp, edgeFuncp) { @@ -417,7 +401,6 @@ void V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) { GraphAlgRLoops(this, edgeFuncp, vertexp); } - //###################################################################### //###################################################################### // Algorithms - subtrees @@ -434,14 +417,12 @@ private: newVertexp = vertexp->clone(m_loopGraphp); vertexp->userp(newVertexp); - for (V3GraphEdge* edgep = vertexp->outBeginp(); - edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (followEdge(edgep)) { V3GraphEdge* newEdgep = static_cast(edgep->userp()); if (!newEdgep) { V3GraphVertex* newTop = vertexIterateAll(edgep->top()); - newEdgep = edgep->clone(m_loopGraphp, newVertexp, - newTop); + newEdgep = edgep->clone(m_loopGraphp, newVertexp, newTop); edgep->userp(newEdgep); } } @@ -451,21 +432,21 @@ private: } public: - GraphAlgSubtrees(V3Graph* graphp, V3Graph* loopGraphp, - V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) - : GraphAlg<>(graphp, edgeFuncp), m_loopGraphp(loopGraphp) { + GraphAlgSubtrees(V3Graph* graphp, V3Graph* loopGraphp, V3EdgeFuncP edgeFuncp, + V3GraphVertex* vertexp) + : GraphAlg<>(graphp, edgeFuncp) + , m_loopGraphp(loopGraphp) { // Vertex::m_userp - New vertex if we have seen this vertex already // Edge::m_userp - New edge if we have seen this edge already m_graphp->userClearVertices(); m_graphp->userClearEdges(); - (void) vertexIterateAll(vertexp); + (void)vertexIterateAll(vertexp); } ~GraphAlgSubtrees() {} }; //! Report the entire connected graph with a loop or loops -void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, - V3Graph* loopGraphp) { +void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, V3Graph* loopGraphp) { GraphAlgSubtrees(this, loopGraphp, edgeFuncp, vertexp); } @@ -474,7 +455,7 @@ void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, // Algorithms - make non cutable void V3Graph::makeEdgesNonCutable(V3EdgeFuncP edgeFuncp) { - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { // Only need one direction, we'll always see the other at some point... for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { if (edgep->cutable() && edgep->weight() && (edgeFuncp)(edgep)) { @@ -489,12 +470,12 @@ void V3Graph::makeEdgesNonCutable(V3EdgeFuncP edgeFuncp) { // Algorithms - sorting struct GraphSortVertexCmp { - inline bool operator() (const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { + inline bool operator()(const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { return lhsp->sortCmp(rhsp) < 0; } }; struct GraphSortEdgeCmp { - inline bool operator() (const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { + inline bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { return lhsp->sortCmp(rhsp) < 0; } }; @@ -502,12 +483,12 @@ struct GraphSortEdgeCmp { void V3Graph::sortVertices() { // Sort list of vertices by rank, then fanout std::vector vertices; - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { vertices.push_back(vertexp); } std::stable_sort(vertices.begin(), vertices.end(), GraphSortVertexCmp()); this->verticesUnlink(); - for (std::vector::iterator it = vertices.begin(); it!=vertices.end(); ++it) { + for (std::vector::iterator it = vertices.begin(); it != vertices.end(); ++it) { (*it)->verticesPushBack(this); } } @@ -515,7 +496,7 @@ void V3Graph::sortVertices() { void V3Graph::sortEdges() { // Sort edges by rank then fanout of node they point to std::vector edges; - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { // Make a vector for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { edges.push_back(edgep); @@ -527,7 +508,8 @@ void V3Graph::sortEdges() { // We know the vector contains all of the edges that were // there originally (didn't delete or add) vertexp->outUnlink(); - for (std::vector::const_iterator it = edges.begin(); it!=edges.end(); ++it) { + for (std::vector::const_iterator it = edges.begin(); it != edges.end(); + ++it) { (*it)->outPushBack(); } // Prep for next @@ -544,7 +526,7 @@ void V3Graph::sortEdges() { // (Results in better dcache packing.) void V3Graph::order() { - UINFO(2,"Order:\n"); + UINFO(2, "Order:\n"); // Compute rankings again rank(&V3GraphEdge::followAlwaysTrue); @@ -555,10 +537,8 @@ void V3Graph::orderPreRanked() { // Compute fanouts // Vertex::m_user begin: 1 indicates processing, 2 indicates completed userClearVertices(); - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { - if (!vertexp->user()) { - orderDFSIterate(vertexp); - } + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { + if (!vertexp->user()) orderDFSIterate(vertexp); } // Sort list of vertices by rank, then fanout. Fanout is a bit of a @@ -581,7 +561,7 @@ double V3Graph::orderDFSIterate(V3GraphVertex* vertexp) { } // Just count inbound edges for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - if (edgep->weight()) fanout ++; + if (edgep->weight()) ++fanout; } vertexp->fanout(fanout); vertexp->user(2); diff --git a/src/V3GraphTest.cpp b/src/V3GraphTest.cpp index 3a6d3fcd3..232cb01b0 100644 --- a/src/V3GraphTest.cpp +++ b/src/V3GraphTest.cpp @@ -38,9 +38,7 @@ protected: // Utilities void dump() { - if (debug()>=9) { - m_graph.dumpDotFilePrefixed("v3graphtest_"+name()); - } + if (debug() >= 9) m_graph.dumpDotFilePrefixed("v3graphtest_" + name()); } public: @@ -56,9 +54,11 @@ public: class V3GraphTestVertex : public V3GraphVertex { string m_name; + public: V3GraphTestVertex(V3Graph* graphp, const string& name) - : V3GraphVertex(graphp), m_name(name) {} + : V3GraphVertex(graphp) + , m_name(name) {} virtual ~V3GraphTestVertex() {} // ACCESSORS virtual string name() const { return m_name; } @@ -84,13 +84,13 @@ public: V3Graph* gp = &m_graph; // Verify we break edges at a good point // A simple alg would make 3 breaks, below only requires b->i to break - V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*"); - V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a"); - V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b"); - V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1"); - V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2"); - V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3"); - V3GraphTestVertex* q = new V3GraphTestVarVertex(gp, "q"); + V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*"); + V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a"); + V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b"); + V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1"); + V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2"); + V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3"); + V3GraphTestVertex* q = new V3GraphTestVarVertex(gp, "q"); new V3GraphEdge(gp, i, a, 2, true); new V3GraphEdge(gp, a, b, 2, true); new V3GraphEdge(gp, b, g1, 2, true); @@ -106,11 +106,11 @@ public: gp->stronglyConnected(&V3GraphEdge::followAlwaysTrue); dump(); - UASSERT(i->color()!=a->color() && a->color() != g2->color() && g2->color() != q->color(), + UASSERT(i->color() != a->color() && a->color() != g2->color() && g2->color() != q->color(), "SelfTest: Separate colors not assigned"); - UASSERT(a->color()==b->color() && a->color()==g1->color(), + UASSERT(a->color() == b->color() && a->color() == g1->color(), "SelfTest: Strongly connected nodes not colored together"); - UASSERT(g2->color()==g3->color(), + UASSERT(g2->color() == g3->color(), "SelfTest: Strongly connected nodes not colored together"); } }; @@ -122,12 +122,12 @@ public: V3Graph* gp = &m_graph; // Verify we break edges at a good point // A simple alg would make 3 breaks, below only requires b->i to break - V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*"); - V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a"); - V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b"); - V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1"); - V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2"); - V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3"); + V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*"); + V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a"); + V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b"); + V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1"); + V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2"); + V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3"); new V3GraphEdge(gp, i, a, 2, true); new V3GraphEdge(gp, a, b, 2, true); new V3GraphEdge(gp, b, g1, 2, true); @@ -149,20 +149,20 @@ public: virtual void runTest() { V3Graph* gp = &m_graph; - V3GraphTestVertex* clk = new V3GraphTestVarVertex(gp, "$clk"); + V3GraphTestVertex* clk = new V3GraphTestVarVertex(gp, "$clk"); - V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "$a"); - V3GraphTestVertex* a_dly = new V3GraphTestVarVertex(gp, "$a_dly"); - V3GraphTestVertex* a_dlyblk= new V3GraphTestVarVertex(gp, "$a_dlyblk"); - V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "$b"); - V3GraphTestVertex* b_dly = new V3GraphTestVarVertex(gp, "$b_dly"); - V3GraphTestVertex* b_dlyblk= new V3GraphTestVarVertex(gp, "$b_dlyblk"); - V3GraphTestVertex* c = new V3GraphTestVarVertex(gp, "$c"); - V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "$i"); + V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "$a"); + V3GraphTestVertex* a_dly = new V3GraphTestVarVertex(gp, "$a_dly"); + V3GraphTestVertex* a_dlyblk = new V3GraphTestVarVertex(gp, "$a_dlyblk"); + V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "$b"); + V3GraphTestVertex* b_dly = new V3GraphTestVarVertex(gp, "$b_dly"); + V3GraphTestVertex* b_dlyblk = new V3GraphTestVarVertex(gp, "$b_dlyblk"); + V3GraphTestVertex* c = new V3GraphTestVarVertex(gp, "$c"); + V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "$i"); - V3GraphTestVertex* ap = new V3GraphTestVarVertex(gp, "$a_pre"); - V3GraphTestVertex* bp = new V3GraphTestVarVertex(gp, "$b_pre"); - V3GraphTestVertex* cp = new V3GraphTestVarVertex(gp, "$c_pre"); + V3GraphTestVertex* ap = new V3GraphTestVarVertex(gp, "$a_pre"); + V3GraphTestVertex* bp = new V3GraphTestVarVertex(gp, "$b_pre"); + V3GraphTestVertex* cp = new V3GraphTestVarVertex(gp, "$c_pre"); V3GraphTestVertex* n; @@ -177,26 +177,27 @@ public: // Desired order between different _DLY blocks so we can elim temporaries // implemented by cutable "pre" signal dependencies - - n = new V3GraphTestVertex(gp, "*INPUTS*"); { + n = new V3GraphTestVertex(gp, "*INPUTS*"); + { new V3GraphEdge(gp, n, clk, 2); new V3GraphEdge(gp, n, i, 2); } - V3GraphTestVertex* posedge = n = new V3GraphTestVertex(gp, "*posedge clk*"); { - new V3GraphEdge(gp, clk, n, 2); - } + V3GraphTestVertex* posedge = n = new V3GraphTestVertex(gp, "*posedge clk*"); + { new V3GraphEdge(gp, clk, n, 2); } // AssignPre's VarRefs on LHS: generate special BLK // normal: VarRefs on LHS: generate normal // underSBlock: VarRefs on RHS: consume 'pre' (required to save cutable tests) - n = new V3GraphTestVertex(gp, "a_dlystart(true); - DfaTestVertex* sl = new DfaTestVertex(gp, "sL"); - DfaTestVertex* srs = new DfaTestVertex(gp, "sR*"); - DfaTestVertex* sls = new DfaTestVertex(gp, "sL*"); - DfaTestVertex* sr = new DfaTestVertex(gp, "sR"); - DfaTestVertex* sz = new DfaTestVertex(gp, "sZ"); - DfaTestVertex* sac = new DfaTestVertex(gp, "*ACCEPT*"); sac->accepting(true); + DfaTestVertex* st = new DfaTestVertex(gp, "*START*"); + st->start(true); + DfaTestVertex* sl = new DfaTestVertex(gp, "sL"); + DfaTestVertex* srs = new DfaTestVertex(gp, "sR*"); + DfaTestVertex* sls = new DfaTestVertex(gp, "sL*"); + DfaTestVertex* sr = new DfaTestVertex(gp, "sR"); + DfaTestVertex* sz = new DfaTestVertex(gp, "sZ"); + DfaTestVertex* sac = new DfaTestVertex(gp, "*ACCEPT*"); + sac->accepting(true); VNUser L = VNUser::fromInt(0xaa); VNUser R = VNUser::fromInt(0xbb); VNUser Z = VNUser::fromInt(0xcc); - new DfaEdge(gp, st, sl, DfaEdge::EPSILON()); - new DfaEdge(gp, sl, srs, L); + new DfaEdge(gp, st, sl, DfaEdge::EPSILON()); + new DfaEdge(gp, sl, srs, L); new DfaEdge(gp, srs, srs, R); - new DfaEdge(gp, srs, sz, Z); - new DfaEdge(gp, sz, sac, DfaEdge::EPSILON()); + new DfaEdge(gp, srs, sz, Z); + new DfaEdge(gp, sz, sac, DfaEdge::EPSILON()); - new DfaEdge(gp, st, sls, DfaEdge::EPSILON()); + new DfaEdge(gp, st, sls, DfaEdge::EPSILON()); new DfaEdge(gp, sls, sls, L); - new DfaEdge(gp, sls, sr, R); - new DfaEdge(gp, sr, sz, Z); - new DfaEdge(gp, sz, sac, DfaEdge::EPSILON()); + new DfaEdge(gp, sls, sr, R); + new DfaEdge(gp, sr, sz, Z); + new DfaEdge(gp, sz, sac, DfaEdge::EPSILON()); dump(); gp->nfaToDfa(); @@ -335,18 +345,22 @@ public: } }; +// clang-format off #ifdef GRAPH_IMPORT # include "graph_export.cpp" #endif +// clang-format on //====================================================================== void V3Graph::selfTest() { // Execute all of the tests - UINFO(2,__FUNCTION__<<": "< V3Hash. Hash value of this node (hash of 0 is illegal) - //AstUser4InUse in V3Hashed.h + // AstUser4InUse in V3Hashed.h // STATE - V3Hash m_lowerHash; // Hash of the statement we're building - bool m_cacheInUser4; // Use user4 to cache each V3Hash? + V3Hash m_lowerHash; // Hash of the statement we're building + bool m_cacheInUser4; // Use user4 to cache each V3Hash? // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -55,10 +55,12 @@ private: void nodeHashIterate(AstNode* nodep) { V3Hash thisHash; if (!m_cacheInUser4 || !nodep->user4()) { - UASSERT_OBJ(!(VN_IS(nodep->backp(), CFunc) - && !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))), nodep, - "Node "<prettyTypeName() - <<" in statement position but not marked stmt (node under function)"); + UASSERT_OBJ( + !(VN_IS(nodep->backp(), CFunc) + && !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))), + nodep, + "Node " << nodep->prettyTypeName() + << " in statement position but not marked stmt (node under function)"); V3Hash oldHash = m_lowerHash; { m_lowerHash = nodep->sameHash(); @@ -66,20 +68,19 @@ private: "sameHash function undefined (returns 0) for node under CFunc."); // For identical nodes, the type should be the same thus // dtypep should be the same too - m_lowerHash = V3Hash(m_lowerHash, V3Hash(nodep->type()<<6, - V3Hash(nodep->dtypep()))); + m_lowerHash + = V3Hash(m_lowerHash, V3Hash(nodep->type() << 6, V3Hash(nodep->dtypep()))); // Now update m_lowerHash for our children's (and next children) contributions iterateChildren(nodep); // Store the hash value nodep->user4(m_lowerHash.fullValue()); - //UINFO(9, " hashnode "<user4p()) { - HashedVisitor visitor (nodep); - } + UINFO(8, " hashI " << nodep << endl); + if (!nodep->user4p()) { HashedVisitor visitor(nodep); } } bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) { @@ -135,7 +134,7 @@ bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) { void V3Hashed::erase(iterator it) { AstNode* nodep = iteratorNodep(it); - UINFO(8," erase "<user4p(), nodep, "Called removeNode on non-hashed node"); m_hashMmap.erase(it); nodep->user4p(NULL); // So we don't allow removeNode again @@ -149,24 +148,22 @@ void V3Hashed::check() { } void V3Hashed::dumpFilePrefixed(const string& nameComment, bool tree) { - if (v3Global.opt.dumpTree()) { - dumpFile(v3Global.debugFilename(nameComment)+".hash", tree); - } + if (v3Global.opt.dumpTree()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree); } void V3Hashed::dumpFile(const string& filename, bool tree) { - const vl_unique_ptr logp (V3File::new_ofstream(filename)); - if (logp->fail()) v3fatal("Can't write "< logp(V3File::new_ofstream(filename)); + if (logp->fail()) v3fatal("Can't write " << filename); - std::map dist; + std::map dist; V3Hash lasthash; int num_in_bucket = 0; - for (HashMmap::iterator it=begin(); 1; ++it) { - if (it==end() || lasthash != it->first) { - if (it!=end()) lasthash = it->first; + for (HashMmap::iterator it = begin(); 1; ++it) { + if (it == end() || lasthash != it->first) { + if (it != end()) lasthash = it->first; if (num_in_bucket) { - if (dist.find(num_in_bucket)==dist.end()) { + if (dist.find(num_in_bucket) == dist.end()) { dist.insert(make_pair(num_in_bucket, 1)); } else { ++dist[num_in_bucket]; @@ -174,22 +171,23 @@ void V3Hashed::dumpFile(const string& filename, bool tree) { } num_in_bucket = 0; } - if (it==end()) break; + if (it == end()) break; num_in_bucket++; } - *logp <<"\n*** STATS:\n"<::iterator it=dist.begin(); it!=dist.end(); ++it) { - *logp<<" "<first<<" "<second<::iterator it = dist.begin(); it != dist.end(); ++it) { + *logp << " " << std::setw(9) << it->first << " " << std::setw(12) << it->second + << endl; } - *logp <<"\n*** Dump:\n"<first) { lasthash = it->first; - *logp <<" "<first<first << endl; } - *logp <<"\t"<second<second << endl; // Dumping the entire tree may make nearly N^2 sized dumps, // because the nodes under this one may also be in the hash table! if (tree) it->second->dumpTree(*logp, " "); @@ -197,14 +195,13 @@ void V3Hashed::dumpFile(const string& filename, bool tree) { } V3Hashed::iterator V3Hashed::findDuplicate(AstNode* nodep, V3HashedUserSame* checkp) { - UINFO(8," findD "<user4p(), nodep, "Called findDuplicate on non-hashed node"); - std::pair eqrange + std::pair eqrange = mmap().equal_range(nodeHash(nodep)); for (HashMmap::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) { AstNode* node2p = eqit->second; - if (nodep != node2p - && (!checkp || checkp->isSame(nodep, node2p)) + if (nodep != node2p && (!checkp || checkp->isSame(nodep, node2p)) && sameNodes(nodep, node2p)) { return eqit; } diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index f1721588a..13aa8735b 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -127,11 +127,10 @@ private: } virtual void visit(AstPragma* nodep) VL_OVERRIDE { if (nodep->pragType() == AstPragmaType::INLINE_MODULE) { - // UINFO(0,"PRAG MARK "<v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE - } else if (m_modp->user2() == CIL_MAYBE - || m_modp->user2() == CIL_NOTSOFT) { + } else if (m_modp->user2() == CIL_MAYBE || m_modp->user2() == CIL_NOTSOFT) { m_modp->user2(CIL_USER); } // Remove so don't propagate to upper cell... @@ -199,14 +198,13 @@ private: // If a mod*#refs is < this # nodes, can inline it bool doit = ((allowed == CIL_USER) || ((allowed == CIL_MAYBE) - && (refs == 1 - || statements < INLINE_MODS_SMALLER + && (refs == 1 || statements < INLINE_MODS_SMALLER || v3Global.opt.inlineMult() < 1 || refs * statements < v3Global.opt.inlineMult()))); // Packages aren't really "under" anything so they confuse this algorithm if (VN_IS(modp, Package)) doit = false; UINFO(4, " Inline=" << doit << " Possible=" << allowed << " Refs=" << refs - << " Stmts=" << statements << " " << modp << endl); + << " Stmts=" << statements << " " << modp << endl); modp->user1(doit); } } @@ -247,9 +245,7 @@ private: VL_DEBUG_FUNC; // Declare debug() // VISITORS - virtual void visit(AstCell* nodep) VL_OVERRIDE { - nodep->user4p(nodep->clonep()); - } + virtual void visit(AstCell* nodep) VL_OVERRIDE { nodep->user4p(nodep->clonep()); } //-------------------- virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate @@ -328,36 +324,30 @@ private: // remove the change detection on the output variable. UINFO(9, "public pin assign: " << exprvarrefp << endl); UASSERT_OBJ(!nodep->isNonOutput(), nodep, "Outputs only - inputs use AssignAlias"); - m_modp->addStmtp( - new AstAssignW(nodep->fileline(), - new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true), - new AstVarRef(nodep->fileline(), nodep, false))); + m_modp->addStmtp(new AstAssignW( + nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true), + new AstVarRef(nodep->fileline(), nodep, false))); } else if (nodep->isSigPublic() && VN_IS(nodep->dtypep(), UnpackArrayDType)) { // Public variable at this end and it is an unpacked array. We need to assign // instead of aliased, because otherwise it will pass V3Slice and invalid // code will be emitted. UINFO(9, "assign to public and unpacked: " << nodep << endl); - m_modp->addStmtp( - new AstAssignW(nodep->fileline(), - new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true), - new AstVarRef(nodep->fileline(), nodep, false))); + m_modp->addStmtp(new AstAssignW( + nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true), + new AstVarRef(nodep->fileline(), nodep, false))); } else if (nodep->isIfaceRef()) { - m_modp->addStmtp( - new AstAssignVarScope(nodep->fileline(), - new AstVarRef(nodep->fileline(), nodep, true), - new AstVarRef(nodep->fileline(), - exprvarrefp->varp(), false))); + m_modp->addStmtp(new AstAssignVarScope( + nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true), + new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false))); AstNode* nodebp = exprvarrefp->varp(); nodep->fileline()->modifyStateInherit(nodebp->fileline()); nodebp->fileline()->modifyStateInherit(nodep->fileline()); } else { // Do to inlining child's variable now within the same // module, so a AstVarRef not AstVarXRef below - m_modp->addStmtp( - new AstAssignAlias(nodep->fileline(), - new AstVarRef(nodep->fileline(), nodep, true), - new AstVarRef(nodep->fileline(), - exprvarrefp->varp(), false))); + m_modp->addStmtp(new AstAssignAlias( + nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true), + new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false))); AstNode* nodebp = exprvarrefp->varp(); nodep->fileline()->modifyStateInherit(nodebp->fileline()); nodebp->fileline()->modifyStateInherit(nodep->fileline()); @@ -406,7 +396,8 @@ private: virtual void visit(AstVarRef* nodep) VL_OVERRIDE { if (nodep->varp()->user2p() // It's being converted to an alias. && !nodep->varp()->user3() - && !VN_IS(nodep->backp(), AssignAlias)) { // Don't constant propagate aliases (we just made) + // Don't constant propagate aliases (we just made) + && !VN_IS(nodep->backp(), AssignAlias)) { AstConst* exprconstp = VN_CAST(nodep->varp()->user2p(), Const); AstVarRef* exprvarrefp = VN_CAST(nodep->varp()->user2p(), VarRef); if (exprconstp) { @@ -551,10 +542,10 @@ private: } // Clone original module - if (debug() >= 9) { nodep->dumpTree(cout, "inlcell:"); } - // if (debug()>=9) { nodep->modp()->dumpTree(cout,"oldmod:"); } + if (debug() >= 9) nodep->dumpTree(cout, "inlcell:"); + // if (debug() >= 9) nodep->modp()->dumpTree(cout, "oldmod:"); AstNodeModule* newmodp = nodep->modp()->cloneTree(false); - if (debug() >= 9) { newmodp->dumpTree(cout, "newmod:"); } + if (debug() >= 9) newmodp->dumpTree(cout, "newmod:"); // Clear var markings and find cell cross references AstNode::user2ClearTree(); AstNode::user4ClearTree(); @@ -575,8 +566,9 @@ private: UASSERT_OBJ(pinNewVarp, pinOldVarp, "Cloning failed"); AstNode* connectRefp = pinp->exprp(); - UASSERT_OBJ(VN_IS(connectRefp, Const) || VN_IS(connectRefp, VarRef), pinp, - "Unknown interconnect type; pinReconnectSimple should have cleared up"); + UASSERT_OBJ( + VN_IS(connectRefp, Const) || VN_IS(connectRefp, VarRef), pinp, + "Unknown interconnect type; pinReconnectSimple should have cleared up"); V3Inst::checkOutputShort(pinp); // Propagate any attributes across the interconnect @@ -624,7 +616,7 @@ public: m_modp = NULL; iterate(nodep); } - virtual ~InlineVisitor() { + virtual ~InlineVisitor() { // V3Stats::addStat("Optimizations, Inlined cells", m_statCells); } }; @@ -668,8 +660,7 @@ private: if (!irdtp) continue; AstCell* cellp; - if ((cellp = VN_CAST(fromVarp->user1p(), Cell)) - || (cellp = irdtp->cellp())) { + if ((cellp = VN_CAST(fromVarp->user1p(), Cell)) || (cellp = irdtp->cellp())) { varp->user1p(cellp); string alias = m_scope + "__DOT__" + pinp->name(); cellp->addIntfRefp(new AstIntfRef(pinp->fileline(), alias)); diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index caa68d056..aa602b75e 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -41,19 +41,19 @@ private: // NODE STATE // Cleared each Cell: // AstPin::user1p() -> bool. True if created assignment already - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE - AstCell* m_cellp; // Current cell + AstCell* m_cellp; // Current cell // METHODS VL_DEBUG_FUNC; // Declare debug() // VISITORS virtual void visit(AstCell* nodep) VL_OVERRIDE { - UINFO(4," CELL "< ASSIGNW(VARXREF(p),expr) (if sub's input) // or ASSIGNW(expr,VARXREF(p)) (if sub's output) - UINFO(4," PIN "<user1()) { // Simplify it V3Inst::pinReconnectSimple(nodep, m_cellp, false); } if (!nodep->exprp()) return; // No-connect - if (debug()>=9) nodep->dumpTree(cout, " Pin_oldb: "); + if (debug() >= 9) nodep->dumpTree(cout, " Pin_oldb: "); V3Inst::checkOutputShort(nodep); // Use user1p on the PIN to indicate we created an assign for this pin if (!nodep->user1SetOnce()) { @@ -78,27 +78,28 @@ private: if (nodep->modVarp()->isInoutish()) { nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator"); } else if (nodep->modVarp()->isWritable()) { - AstNode* rhsp = new AstVarXRef(exprp->fileline(), - nodep->modVarp(), m_cellp->name(), false); + AstNode* rhsp + = new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false); AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp); m_cellp->addNextHere(assp); } else if (nodep->modVarp()->isNonOutput()) { // Don't bother moving constants now, // we'll be pushing the const down to the cell soon enough. - AstNode* assp = new AstAssignW - (exprp->fileline(), - new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true), - exprp); + AstNode* assp = new AstAssignW( + exprp->fileline(), + new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true), + exprp); m_cellp->addNextHere(assp); - if (debug()>=9) assp->dumpTree(cout, " _new: "); + if (debug() >= 9) assp->dumpTree(cout, " _new: "); } else if (nodep->modVarp()->isIfaceRef() || (VN_IS(nodep->modVarp()->subDTypep(), UnpackArrayDType) - && VN_IS(VN_CAST(nodep->modVarp()->subDTypep(), - UnpackArrayDType)->subDTypep(), IfaceRefDType))) { + && VN_IS(VN_CAST(nodep->modVarp()->subDTypep(), UnpackArrayDType) + ->subDTypep(), + IfaceRefDType))) { // Create an AstAssignVarScope for Vars to Cells so we can // link with their scope later - AstNode* lhsp = new AstVarXRef(exprp->fileline(), - nodep->modVarp(), m_cellp->name(), false); + AstNode* lhsp + = new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false); const AstVarRef* refp = VN_CAST(exprp, VarRef); const AstVarXRef* xrefp = VN_CAST(exprp, VarXRef); UASSERT_OBJ(refp || xrefp, exprp, @@ -117,7 +118,8 @@ private: virtual void visit(AstUdpTable* nodep) VL_OVERRIDE { if (!v3Global.opt.bboxUnsup()) { // If we support primitives, update V3Undriven to remove special case - nodep->v3error("Unsupported: Verilog 1995 UDP Tables. Use --bbox-unsup to ignore tables."); + nodep->v3error("Unsupported: Verilog 1995 UDP Tables. " + "Use --bbox-unsup to ignore tables."); } } @@ -145,15 +147,15 @@ class InstDeModVarVisitor : public AstNVisitor { // Expand all module variables, and save names for later reference private: // STATE - typedef std::map VarNameMap; - VarNameMap m_modVarNameMap; // Per module, name of cloned variables + typedef std::map VarNameMap; + VarNameMap m_modVarNameMap; // Per module, name of cloned variables VL_DEBUG_FUNC; // Declare debug() // VISITORS virtual void visit(AstVar* nodep) VL_OVERRIDE { if (VN_IS(nodep->dtypep(), IfaceRefDType)) { - UINFO(8," dm-1-VAR "<name(), nodep)); } AstVar* find(const string& name) { @@ -176,15 +178,17 @@ public: } } void dump() { - for (VarNameMap::iterator it=m_modVarNameMap.begin(); it!=m_modVarNameMap.end(); ++it) { - cout<<"-namemap: "<first<<" -> "<second<first << " -> " << it->second << endl; } } + public: // CONSTRUCTORS explicit InstDeModVarVisitor() {} void main(AstNodeModule* nodep) { - UINFO(8," dmMODULE "< VarNameMap; + typedef std::map VarNameMap; VL_DEBUG_FUNC; // Declare debug() @@ -209,12 +213,12 @@ private: virtual void visit(AstVar* nodep) VL_OVERRIDE { if (VN_IS(nodep->dtypep(), UnpackArrayDType) && VN_IS(VN_CAST(nodep->dtypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) { - UINFO(8," dv-vec-VAR "<dtypep(), UnpackArrayDType); AstNode* prevp = NULL; for (int i = arrdtype->lsb(); i <= arrdtype->msb(); ++i) { string varNewName = nodep->name() + "__BRA__" + cvtToStr(i) + "__KET__"; - UINFO(8,"VAR name insert "<subDTypep(), IfaceRefDType)->cloneTree(false); @@ -234,13 +238,16 @@ private: } } if (prevp) nodep->addNextHere(prevp); - if (prevp && debug()==9) { prevp->dumpTree(cout, "newintf: "); cout << endl; } + if (prevp && debug() == 9) { + prevp->dumpTree(cout, "newintf: "); + cout << endl; + } } iterateChildren(nodep); } virtual void visit(AstCell* nodep) VL_OVERRIDE { - UINFO(4," CELL "<modp(), nodep, "Unlinked"); m_deModVars.main(nodep->modp()); @@ -249,14 +256,14 @@ private: m_cellRangep = nodep->rangep(); AstVar* ifaceVarp = VN_CAST(nodep->nextp(), Var); - bool isIface = ifaceVarp - && VN_IS(ifaceVarp->dtypep(), UnpackArrayDType) - && VN_IS(VN_CAST(ifaceVarp->dtypep(), - UnpackArrayDType)->subDTypep(), IfaceRefDType); + bool isIface = ifaceVarp && VN_IS(ifaceVarp->dtypep(), UnpackArrayDType) + && VN_IS(VN_CAST(ifaceVarp->dtypep(), UnpackArrayDType)->subDTypep(), + IfaceRefDType); // Make all of the required clones for (int i = 0; i < m_cellRangep->elementsConst(); i++) { - m_instSelNum = m_cellRangep->littleEndian() ? (m_cellRangep->elementsConst() - 1 - i) : i; + m_instSelNum + = m_cellRangep->littleEndian() ? (m_cellRangep->elementsConst() - 1 - i) : i; int instNum = m_cellRangep->lsbConst() + i; AstCell* newp = nodep->cloneTree(false); @@ -266,15 +273,16 @@ private: // Somewhat illogically, we need to rename the original name of the cell too. // as that is the name users expect for dotting // The spec says we add [x], but that won't work in C... - newp->name(newp->name()+"__BRA__"+cvtToStr(instNum)+"__KET__"); - newp->origName(newp->origName()+"__BRA__"+cvtToStr(instNum)+"__KET__"); - UINFO(8," CELL loop "<name(newp->name() + "__BRA__" + cvtToStr(instNum) + "__KET__"); + newp->origName(newp->origName() + "__BRA__" + cvtToStr(instNum) + "__KET__"); + UINFO(8, " CELL loop " << newp << endl); // If this AstCell is actually an interface instantiation, also clone the IfaceRef // within the same parent module as the cell if (isIface) { AstUnpackArrayDType* arrdtype = VN_CAST(ifaceVarp->dtypep(), UnpackArrayDType); - AstIfaceRefDType* origIfaceRefp = VN_CAST(arrdtype->subDTypep(), IfaceRefDType); + AstIfaceRefDType* origIfaceRefp + = VN_CAST(arrdtype->subDTypep(), IfaceRefDType); origIfaceRefp->cellp(NULL); AstVar* varNewp = ifaceVarp->cloneTree(false); AstIfaceRefDType* ifaceRefp @@ -283,14 +291,21 @@ private: ifaceRefp->cellp(newp); ifaceRefp->cellName(newp->name()); varNewp->name(varNewp->name() + "__BRA__" + cvtToStr(instNum) + "__KET__"); - varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(instNum) + "__KET__"); + varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(instNum) + + "__KET__"); varNewp->dtypep(ifaceRefp); newp->addNextHere(varNewp); - if (debug()==9) { varNewp->dumpTree(cout, "newintf: "); cout << endl; } + if (debug() == 9) { + varNewp->dumpTree(cout, "newintf: "); + cout << endl; + } } // Fixup pins iterateAndNextNull(newp->pinsp()); - if (debug()==9) { newp->dumpTree(cout, "newcell: "); cout<dumpTree(cout, "newcell: "); + cout << endl; + } } // Done. Delete original @@ -299,7 +314,8 @@ private: ifaceVarp->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(ifaceVarp), ifaceVarp); } - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { m_cellRangep = NULL; iterateChildren(nodep); @@ -310,66 +326,66 @@ private: // Any non-direct pins need reconnection with a part-select if (!nodep->exprp()) return; // No-connect if (m_cellRangep) { - UINFO(4," PIN "<modVarp()->width(); int expwidth = nodep->exprp()->width(); - std::pair pinDim = nodep->modVarp()->dtypep()->dimensions(false); - std::pair expDim = nodep->exprp()->dtypep()->dimensions(false); - UINFO(4," PINVAR "<modVarp()<exprp()< pinDim = nodep->modVarp()->dtypep()->dimensions(false); + std::pair expDim = nodep->exprp()->dtypep()->dimensions(false); + UINFO(4, " PINVAR " << nodep->modVarp() << endl); + UINFO(4, " EXP " << nodep->exprp() << endl); + UINFO(4, " pinwidth ew=" << expwidth << " pw=" << pinwidth << " ed=" << expDim.first + << "," << expDim.second << " pd=" << pinDim.first << "," + << pinDim.second << endl); + if (expDim.first == pinDim.first && expDim.second == pinDim.second + 1) { // Connection to array, where array dimensions match the instant dimension AstRange* rangep = VN_CAST(nodep->exprp()->dtypep(), UnpackArrayDType)->rangep(); int arraySelNum = rangep->littleEndian() - ? (rangep->elementsConst() - 1 - m_instSelNum) : m_instSelNum; + ? (rangep->elementsConst() - 1 - m_instSelNum) + : m_instSelNum; AstNode* exprp = nodep->exprp()->unlinkFrBack(); exprp = new AstArraySel(exprp->fileline(), exprp, arraySelNum); nodep->exprp(exprp); } else if (expwidth == pinwidth) { // NOP: Arrayed instants: widths match so connect to each instance - } else if (expwidth == pinwidth*m_cellRangep->elementsConst()) { + } else if (expwidth == pinwidth * m_cellRangep->elementsConst()) { // Arrayed instants: one bit for each of the instants (each // assign is 1 pinwidth wide) if (m_cellRangep->littleEndian()) { nodep->exprp()->v3warn( LITENDIAN, "Little endian cell range connecting to vector: MSB < LSB of cell range: " - <lsbConst()<<":"<msbConst()); + << m_cellRangep->lsbConst() << ":" << m_cellRangep->msbConst()); } AstNode* exprp = nodep->exprp()->unlinkFrBack(); bool inputPin = nodep->modVarp()->isNonOutput(); - if (!inputPin && !VN_IS(exprp, VarRef) - && !VN_IS(exprp, Concat) // V3Const will collapse the SEL with the one we're about to make - && !VN_IS(exprp, Sel)) { // V3Const will collapse the SEL with the one we're about to make - nodep->v3error("Unsupported: Per-bit array instantiations with output connections to non-wires."); + if (!inputPin + && !VN_IS(exprp, VarRef) + // V3Const will collapse the SEL with the one we're about to make + && !VN_IS(exprp, Concat) && !VN_IS(exprp, Sel)) { + nodep->v3error("Unsupported: Per-bit array instantiations with output " + "connections to non-wires."); // Note spec allows more complicated matches such as slices and such } - exprp = new AstSel(exprp->fileline(), exprp, - pinwidth*m_instSelNum, - pinwidth); + exprp = new AstSel(exprp->fileline(), exprp, pinwidth * m_instSelNum, pinwidth); nodep->exprp(exprp); } else { nodep->v3fatalSrc("Width mismatch; V3Width should have errored out."); } } else if (AstArraySel* arrselp = VN_CAST(nodep->exprp(), ArraySel)) { if (AstUnpackArrayDType* arrp = VN_CAST(arrselp->lhsp()->dtypep(), UnpackArrayDType)) { - if (!VN_IS(arrp->subDTypep(), IfaceRefDType)) - return; + if (!VN_IS(arrp->subDTypep(), IfaceRefDType)) return; V3Const::constifyParamsEdit(arrselp->rhsp()); const AstConst* constp = VN_CAST(arrselp->rhsp(), Const); if (!constp) { - nodep->v3error("Unsupported: Non-constant index when passing interface to module"); + nodep->v3error( + "Unsupported: Non-constant index when passing interface to module"); return; } string index = AstNode::encodeNumber(constp->toSInt()); AstVarRef* varrefp = VN_CAST(arrselp->lhsp(), VarRef); - AstVarXRef* newp = new AstVarXRef(nodep->fileline(), - varrefp->name()+"__BRA__"+index+"__KET__", - "", true); + AstVarXRef* newp = new AstVarXRef( + nodep->fileline(), varrefp->name() + "__BRA__" + index + "__KET__", "", true); newp->dtypep(nodep->modVarp()->dtypep()); newp->packagep(varrefp->packagep()); arrselp->addNextHere(newp); @@ -378,8 +394,7 @@ private: } else { AstVar* pinVarp = nodep->modVarp(); AstUnpackArrayDType* pinArrp = VN_CAST(pinVarp->dtypep(), UnpackArrayDType); - if (!pinArrp || !VN_IS(pinArrp->subDTypep(), IfaceRefDType)) - return; + if (!pinArrp || !VN_IS(pinArrp->subDTypep(), IfaceRefDType)) return; AstNode* prevp = NULL; AstNode* prevPinp = NULL; // Clone the var referenced by the pin, and clone each var referenced by the varref @@ -406,9 +421,9 @@ private: } } if (!varNewp) { - if (debug()>=9) m_deModVars.dump(); + if (debug() >= 9) m_deModVars.dump(); nodep->v3fatalSrc("Module dearray failed for " - <width() > rhsp->width()) { - rhsp = (rhsp->isSigned() - ? static_cast(new AstExtendS(fl, rhsp)) - : static_cast(new AstExtend (fl, rhsp))); - rhsp->dtypeFrom(cmpWidthp); // Need proper widthMin, which may differ from AstSel created above + rhsp = (rhsp->isSigned() ? static_cast(new AstExtendS(fl, rhsp)) + : static_cast(new AstExtend(fl, rhsp))); + // Need proper widthMin, which may differ from AstSel created above + rhsp->dtypeFrom(cmpWidthp); } else if (cmpWidthp->width() < rhsp->width()) { rhsp = new AstSel(fl, rhsp, 0, cmpWidthp->width()); - rhsp->dtypeFrom(cmpWidthp); // Need proper widthMin, which may differ from AstSel created above + // Need proper widthMin, which may differ from AstSel created above + rhsp->dtypeFrom(cmpWidthp); } // else don't change dtype, as might be e.g. array of something return rhsp; } public: - static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, - bool forTristate, bool alwaysCvt) { + static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate, + bool alwaysCvt) { // If a pin connection is "simple" leave it as-is // Else create a intermediate wire to perform the interconnect // Return the new assignment, if one was made @@ -504,40 +520,33 @@ public: AstAssignW* assignp = NULL; if (connectRefp) connBasicp = VN_CAST(connectRefp->varp()->dtypep(), BasicDType); // - if (!alwaysCvt - && connectRefp - && connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep()) + if (!alwaysCvt && connectRefp && connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep()) && !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types // Done. Same data type - } else if (!alwaysCvt - && connectRefp - && connectRefp->varp()->isIfaceRef()) { + } else if (!alwaysCvt && connectRefp && connectRefp->varp()->isIfaceRef()) { // Done. Interface - } else if (!alwaysCvt - && connectXRefp - && connectXRefp->varp() + } else if (!alwaysCvt && connectXRefp && connectXRefp->varp() && connectXRefp->varp()->isIfaceRef()) { - } else if (!alwaysCvt - && connBasicp - && pinBasicp + } else if (!alwaysCvt && connBasicp && pinBasicp && connBasicp->width() == pinBasicp->width() && connBasicp->lsb() == pinBasicp->lsb() - && !connectRefp->varp()->isSc() // Need the signal as a 'shell' to convert types + && !connectRefp->varp() + ->isSc() // Need the signal as a 'shell' to convert types && connBasicp->width() == pinVarp->width()) { // Done. One to one interconnect won't need a temporary variable. } else if (!alwaysCvt && !forTristate && VN_IS(pinp->exprp(), Const)) { // Done. Constant. } else { // Make a new temp wire - //if (1||debug()>=9) { pinp->dumpTree(cout, "-in_pin:"); } + // if (1 || debug() >= 9) { pinp->dumpTree(cout, "-in_pin:"); } V3Inst::checkOutputShort(pinp); AstNode* pinexprp = pinp->exprp()->unlinkFrBack(); - string newvarname = (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp") - // Prevent name conflict if both tri & non-tri add signals - +(forTristate?"t":"") - +"__"+cellp->name()+"__"+pinp->name()); - AstVar* newvarp = new AstVar(pinVarp->fileline(), - AstVarType::MODULETEMP, newvarname, pinVarp); + string newvarname + = (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp") + // Prevent name conflict if both tri & non-tri add signals + + (forTristate ? "t" : "") + "__" + cellp->name() + "__" + pinp->name()); + AstVar* newvarp + = new AstVar(pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp); // Important to add statement next to cell, in case there is a // generate with same named cell cellp->addNextHere(newvarp); @@ -547,8 +556,8 @@ public: } else if (pinVarp->isWritable()) { // See also V3Inst AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false); - UINFO(5,"pinRecon width "<width()<<" >? " - <width()<<" >? "<width()<width() << " >? " << rhsp->width() << " >? " + << pinexprp->width() << endl); rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp); pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true)); AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp); @@ -556,13 +565,12 @@ public: } else { // V3 width should have range/extended to make the widths correct assignp = new AstAssignW(pinp->fileline(), - new AstVarRef(pinp->fileline(), newvarp, true), - pinexprp); + new AstVarRef(pinp->fileline(), newvarp, true), pinexprp); pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, false)); } if (assignp) cellp->addNextHere(assignp); - //if (debug()) { pinp->dumpTree(cout, "- out:"); } - //if (debug()) { assignp->dumpTree(cout, "- aout:"); } + // if (debug()) { pinp->dumpTree(cout, "- out:"); } + // if (debug()) { assignp->dumpTree(cout, "- aout:"); } } return assignp; } @@ -571,20 +579,19 @@ public: //###################################################################### // Inst class functions -AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, - bool forTristate, bool alwaysCvt) { +AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate, + bool alwaysCvt) { return InstStatic::pinReconnectSimple(pinp, cellp, forTristate, alwaysCvt); } void V3Inst::checkOutputShort(AstPin* nodep) { if (nodep->modVarp()->direction() == VDirection::OUTPUT) { - if (VN_IS(nodep->exprp(), Const) - || VN_IS(nodep->exprp(), Extend) + if (VN_IS(nodep->exprp(), Const) || VN_IS(nodep->exprp(), Extend) || (VN_IS(nodep->exprp(), Concat) && (VN_IS(VN_CAST(nodep->exprp(), Concat)->lhsp(), Const)))) { // Uses v3warn for error, as might be found multiple times nodep->v3warn(E_PORTSHORT, "Output port is connected to a constant pin," - " electrical short"); + " electrical short"); } } } @@ -593,17 +600,13 @@ void V3Inst::checkOutputShort(AstPin* nodep) { // Inst class visitor void V3Inst::instAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } void V3Inst::dearrayAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 6); } diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 08f674015..f8788bafe 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -42,7 +42,7 @@ class LifeState { // NODE STATE // See below - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE public: @@ -56,8 +56,8 @@ public: ~LifeState() { V3Stats::addStatSum("Optimizations, Lifetime assign deletions", m_statAssnDel); V3Stats::addStatSum("Optimizations, Lifetime constant prop", m_statAssnCon); - for (std::vector::iterator it = m_unlinkps.begin(); - it != m_unlinkps.end(); ++it) { + for (std::vector::iterator it = m_unlinkps.begin(); it != m_unlinkps.end(); + ++it) { (*it)->unlinkFrBack(); (*it)->deleteTree(); } @@ -70,10 +70,12 @@ public: // Structure for each variable encountered class LifeVarEntry { - AstNodeAssign* m_assignp; // Last assignment to this varscope, NULL if no longer relevant - AstConst* m_constp; // Known constant value - bool m_setBeforeUse; // First access was a set (and thus block above may have a set that can be deleted - bool m_everSet; // Was ever assigned (and thus above block may not preserve constant propagation) + AstNodeAssign* m_assignp; // Last assignment to this varscope, NULL if no longer relevant + AstConst* m_constp; // Known constant value + // First access was a set (and thus block above may have a set that can be deleted + bool m_setBeforeUse; + // Was ever assigned (and thus above block may not preserve constant propagation) + bool m_everSet; inline void init(bool setBeforeUse) { m_assignp = NULL; @@ -81,19 +83,23 @@ class LifeVarEntry { m_setBeforeUse = setBeforeUse; m_everSet = false; } + public: class SIMPLEASSIGN {}; class COMPLEXASSIGN {}; class CONSUMED {}; LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp) { - init(true); simpleAssign(assp); + init(true); + simpleAssign(assp); } explicit LifeVarEntry(COMPLEXASSIGN) { - init(false); complexAssign(); + init(false); + complexAssign(); } explicit LifeVarEntry(CONSUMED) { - init(false); consumed(); + init(false); + consumed(); } ~LifeVarEntry() {} inline void simpleAssign(AstNodeAssign* assp) { // New simple A=.... assignment @@ -127,9 +133,9 @@ class LifeBlock { // LIFE MAP // For each basic block, we'll make a new map of what variables that if/else is changing typedef std::map LifeMap; - LifeMap m_map; // Current active lifetime map for current scope - LifeBlock* m_aboveLifep; // Upper life, or NULL - LifeState* m_statep; // Current global state + LifeMap m_map; // Current active lifetime map for current scope + LifeBlock* m_aboveLifep; // Upper life, or NULL + LifeState* m_statep; // Current global state VL_DEBUG_FUNC; // Declare debug() @@ -148,11 +154,11 @@ public: // we just don't optimize any public sigs // Check the var entry, and remove if appropriate if (AstNode* oldassp = entp->assignp()) { - UINFO(7," PREV: "<4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK "); + if (debug() > 4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK "); entp->complexAssign(); VL_DO_DANGLING(m_statep->pushUnlinkDeletep(oldassp), oldassp); ++m_statep->m_statAssnDel; @@ -161,8 +167,8 @@ public: } void simpleAssign(AstVarScope* nodep, AstNodeAssign* assp) { // Do we have a old assignment we can nuke? - UINFO(4," ASSIGNof: "<second.complexAssign(); @@ -189,14 +195,14 @@ public: if (!varrefp->varp()->isSigPublic()) { // Aha, variable is constant; substitute in. // We'll later constant propagate - UINFO(4," replaceconst: "<replaceWith(constp->cloneTree(false)); VL_DO_DANGLING(varrefp->deleteTree(), varrefp); ++m_statep->m_statAssnCon; return; // **DONE, no longer a var reference** } } - UINFO(4," usage: "<second.consumed(); } else { m_map.insert(make_pair(nodep, LifeVarEntry(LifeVarEntry::CONSUMED()))); @@ -205,7 +211,7 @@ public: void complexAssignFind(AstVarScope* nodep) { LifeMap::iterator it = m_map.find(nodep); if (it != m_map.end()) { - UINFO(4," casfind: "<first<first << endl); it->second.complexAssign(); } else { m_map.insert(make_pair(nodep, LifeVarEntry(LifeVarEntry::COMPLEXASSIGN()))); @@ -222,7 +228,7 @@ public: void lifeToAbove() { // Any varrefs under a if/else branch affect statements outside and after the if/else if (!m_aboveLifep) v3fatalSrc("Pushing life when already at the top level"); - for (LifeMap::iterator it = m_map.begin(); it!=m_map.end(); ++it) { + for (LifeMap::iterator it = m_map.begin(); it != m_map.end(); ++it) { AstVarScope* nodep = it->first; m_aboveLifep->complexAssignFind(nodep); if (it->second.everSet()) { @@ -236,36 +242,33 @@ public: } void dualBranch(LifeBlock* life1p, LifeBlock* life2p) { // Find any common sets on both branches of IF and propagate upwards - //life1p->lifeDump(); - //life2p->lifeDump(); + // life1p->lifeDump(); + // life2p->lifeDump(); AstNode::user1ClearTree(); // user1p() used on entire tree - for (LifeMap::iterator it = life1p->m_map.begin(); it!=life1p->m_map.end(); ++it) { + for (LifeMap::iterator it = life1p->m_map.begin(); it != life1p->m_map.end(); ++it) { // When the if branch sets a var before it's used, mark that variable if (it->second.setBeforeUse()) it->first->user1(1); } - for (LifeMap::iterator it = life2p->m_map.begin(); it!=life2p->m_map.end(); ++it) { + for (LifeMap::iterator it = life2p->m_map.begin(); it != life2p->m_map.end(); ++it) { // When the else branch sets a var before it's used AstVarScope* nodep = it->first; if (it->second.setBeforeUse() && nodep->user1()) { // Both branches set the var, we can remove the assignment before the IF. - UINFO(4,"DUALBRANCH "<lifeDump(); + // this->lifeDump(); } // DEBUG void lifeDump() { - UINFO(5, " LifeMap:"<second.setBeforeUse()?"[F] ":" ") - <first<second.assignp()) { - UINFO(5, " Ass: "<second.assignp()<second.setBeforeUse() ? "[F] " : " ") << it->first + << endl); + if (it->second.assignp()) { // + UINFO(5, " Ass: " << it->second.assignp() << endl); } } } @@ -277,16 +280,16 @@ public: class LifeVisitor : public AstNVisitor { private: // STATE - LifeState* m_statep; // Current state - bool m_sideEffect; // Side effects discovered in assign RHS - bool m_noopt; // Disable optimization of variables in this block - bool m_tracingCall; // Iterating into a CCall to a CFunc + LifeState* m_statep; // Current state + bool m_sideEffect; // Side effects discovered in assign RHS + bool m_noopt; // Disable optimization of variables in this block + bool m_tracingCall; // Iterating into a CCall to a CFunc // LIFE MAP // For each basic block, we'll make a new map of what variables that if/else is changing typedef std::map LifeMap; // cppcheck-suppress memleak // cppcheck bug - it is deleted - LifeBlock* m_lifep; // Current active lifetime map for current scope + LifeBlock* m_lifep; // Current active lifetime map for current scope // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -333,11 +336,11 @@ private: //---- Track control flow changes virtual void visit(AstNodeIf* nodep) VL_OVERRIDE { - UINFO(4," IF "<condp()); LifeBlock* prevLifep = m_lifep; - LifeBlock* ifLifep = new LifeBlock(prevLifep, m_statep); + LifeBlock* ifLifep = new LifeBlock(prevLifep, m_statep); LifeBlock* elseLifep = new LifeBlock(prevLifep, m_statep); { m_lifep = ifLifep; @@ -348,7 +351,7 @@ private: iterateAndNextNull(nodep->elsesp()); } m_lifep = prevLifep; - UINFO(4," join "<dualBranch(ifLifep, elseLifep); // For the next assignments, clear any variables that were read or written in the block @@ -380,7 +383,7 @@ private: iterateAndNextNull(nodep->incsp()); } m_lifep = prevLifep; - UINFO(4," joinfor"<lifeToAbove(); bodyLifep->lifeToAbove(); @@ -401,22 +404,23 @@ private: m_lifep = prevLifep; m_noopt = prev_noopt; } - UINFO(4," joinjump"<lifeToAbove(); VL_DO_DANGLING(delete bodyLifep, bodyLifep); } virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE { - //UINFO(4," CCALL "<funcp()->entryPoint()) { // else is non-inline or public function we optimize separately + // else is non-inline or public function we optimize separately + if (!nodep->funcp()->entryPoint()) { m_tracingCall = true; iterate(nodep->funcp()); } } virtual void visit(AstCFunc* nodep) VL_OVERRIDE { - //UINFO(4," CFUNC "<entryPoint()) return; m_tracingCall = false; if (nodep->dpiImport() && !nodep->pure()) { @@ -439,7 +443,7 @@ private: public: // CONSTRUCTORS LifeVisitor(AstNode* nodep, LifeState* statep) { - UINFO(4," LifeVisitor on "<entryPoint()) { // Usage model 1: Simulate all C code, doing lifetime analysis - LifeVisitor visitor (nodep, m_statep); + LifeVisitor visitor(nodep, m_statep); } } virtual void visit(AstAlways* nodep) VL_OVERRIDE { // Usage model 2: Cleanup basic blocks - LifeVisitor visitor (nodep, m_statep); + LifeVisitor visitor(nodep, m_statep); } virtual void visit(AstInitial* nodep) VL_OVERRIDE { // Usage model 2: Cleanup basic blocks - LifeVisitor visitor (nodep, m_statep); + LifeVisitor visitor(nodep, m_statep); } virtual void visit(AstFinal* nodep) VL_OVERRIDE { // Usage model 2: Cleanup basic blocks - LifeVisitor visitor (nodep, m_statep); + LifeVisitor visitor(nodep, m_statep); } virtual void visit(AstVar*) VL_OVERRIDE {} // Accelerate virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate @@ -502,10 +506,10 @@ public: // Life class functions void V3Life::lifeAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index b50adc9e2..da75454bb 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -43,7 +43,7 @@ class LifePostElimVisitor : public AstNVisitor { private: - bool m_tracingCall; // Iterating into a CCall to a CFunc + bool m_tracingCall; // Iterating into a CCall to a CFunc // NODE STATE // INPUT: @@ -58,7 +58,7 @@ private: AstVarScope* vscp = nodep->varScopep(); UASSERT_OBJ(vscp, nodep, "Scope not assigned"); if (AstVarScope* newvscp = reinterpret_cast(vscp->user4p())) { - UINFO(9, " Replace "<fileline(), newvscp, nodep->lvalue()); nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -105,11 +105,15 @@ public: struct LifeLocation { const ExecMTask* mtaskp; uint32_t sequence; + public: - LifeLocation() : mtaskp(NULL), sequence(0) {} + LifeLocation() + : mtaskp(NULL) + , sequence(0) {} LifeLocation(const ExecMTask* mtaskp_, uint32_t sequence_) - : mtaskp(mtaskp_), sequence(sequence_) {} - bool operator< (const LifeLocation& b) const { + : mtaskp(mtaskp_) + , sequence(sequence_) {} + bool operator<(const LifeLocation& b) const { unsigned a_id = mtaskp ? mtaskp->id() : 0; unsigned b_id = b.mtaskp ? b.mtaskp->id() : 0; if (a_id < b_id) { return true; } @@ -121,9 +125,11 @@ public: struct LifePostLocation { LifeLocation loc; AstAssignPost* nodep; - LifePostLocation() : nodep(NULL) {} + LifePostLocation() + : nodep(NULL) {} LifePostLocation(LifeLocation loc_, AstAssignPost* nodep_) - : loc(loc_), nodep(nodep_) {} + : loc(loc_) + , nodep(nodep_) {} }; //###################################################################### @@ -134,27 +140,27 @@ private: // NODE STATE // Cleared on entire tree // AstVarScope::user4() -> AstVarScope*: Passed to LifePostElim to substitute this var - AstUser4InUse m_inuser4; + AstUser4InUse m_inuser4; // STATE - uint32_t m_sequence; // Sequence number of assigns/varrefs, + uint32_t m_sequence; // Sequence number of assigns/varrefs, // // local to the current MTask. - const ExecMTask* m_execMTaskp; // Current ExecMTask being processed, + const ExecMTask* m_execMTaskp; // Current ExecMTask being processed, // // or NULL for serial code. - VDouble0 m_statAssnDel; // Statistic tracking - bool m_tracingCall; // Currently tracing a CCall to a CFunc + VDouble0 m_statAssnDel; // Statistic tracking + bool m_tracingCall; // Currently tracing a CCall to a CFunc // Map each varscope to one or more locations where it's accessed. // These maps will not include any ASSIGNPOST accesses: typedef vl_unordered_map > LocMap; - LocMap m_reads; // VarScope read locations - LocMap m_writes; // VarScope write locations + LocMap m_reads; // VarScope read locations + LocMap m_writes; // VarScope write locations // Map each dly var to its AstAssignPost* node and the location thereof typedef vl_unordered_map PostLocMap; - PostLocMap m_assignposts; // AssignPost dly var locations + PostLocMap m_assignposts; // AssignPost dly var locations - const V3Graph* m_mtasksGraphp; // Mtask tracking graph + const V3Graph* m_mtasksGraphp; // Mtask tracking graph vl_unique_ptr m_checker; // METHODS @@ -164,8 +170,7 @@ private: if (a.mtaskp == b.mtaskp) return a.sequence < b.sequence; return m_checker->pathExistsFrom(a.mtaskp, b.mtaskp); } - bool outsideCriticalArea(LifeLocation loc, - const std::set& dlyVarAssigns, + bool outsideCriticalArea(LifeLocation loc, const std::set& dlyVarAssigns, LifeLocation assignPostLoc) { // If loc is before all of dlyVarAssigns, return true. // ("Before" means certain to be ordered before them at execution time.) @@ -189,8 +194,7 @@ private: return true; } void squashAssignposts() { - for (PostLocMap::iterator it = m_assignposts.begin(); - it != m_assignposts.end(); ++it) { + for (PostLocMap::iterator it = m_assignposts.begin(); it != m_assignposts.end(); ++it) { LifePostLocation* app = &it->second; AstVarRef* lhsp = VN_CAST(app->nodep->lhsp(), VarRef); // original var AstVarRef* rhsp = VN_CAST(app->nodep->rhsp(), VarRef); // dly var @@ -246,7 +250,7 @@ private: if (!canScrunch) continue; // Delete and mark so LifePostElimVisitor will get it - UINFO(4," DELETE "<nodep<nodep << endl); dlyVarp->user4p(origVarp); VL_DO_DANGLING(app->nodep->unlinkFrBack()->deleteTree(), app->nodep); ++m_statAssnDel; @@ -262,8 +266,7 @@ private: iterateChildren(nodep); if (v3Global.opt.mtasks()) { - UASSERT_OBJ(m_mtasksGraphp, nodep, - "Should have initted m_mtasksGraphp by now"); + UASSERT_OBJ(m_mtasksGraphp, nodep, "Should have initted m_mtasksGraphp by now"); m_checker.reset(new GraphPathChecker(m_mtasksGraphp)); } else { UASSERT_OBJ(!m_mtasksGraphp, nodep, @@ -277,7 +280,7 @@ private: squashAssignposts(); // Replace any node4p varscopes with the new scope - LifePostElimVisitor visitor (nodep); + LifePostElimVisitor visitor(nodep); } virtual void visit(AstVarRef* nodep) VL_OVERRIDE { // Consumption/generation of a variable, @@ -325,8 +328,8 @@ private: virtual void visit(AstExecGraph* nodep) VL_OVERRIDE { // Treat the ExecGraph like a call to each mtask body m_mtasksGraphp = nodep->depGraphp(); - for (V3GraphVertex* mtaskVxp = m_mtasksGraphp->verticesBeginp(); - mtaskVxp; mtaskVxp = mtaskVxp->verticesNextp()) { + for (V3GraphVertex* mtaskVxp = m_mtasksGraphp->verticesBeginp(); mtaskVxp; + mtaskVxp = mtaskVxp->verticesNextp()) { ExecMTask* mtaskp = dynamic_cast(mtaskVxp); m_execMTaskp = mtaskp; m_sequence = 0; @@ -361,10 +364,8 @@ public: // LifePost class functions void V3LifePost::lifepostAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index 009b3f005..17fe78662 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -51,16 +51,18 @@ public: class LinkCellsVertex : public V3GraphVertex { AstNodeModule* m_modp; + public: LinkCellsVertex(V3Graph* graphp, AstNodeModule* modp) - : V3GraphVertex(graphp), m_modp(modp) {} + : V3GraphVertex(graphp) + , m_modp(modp) {} virtual ~LinkCellsVertex() {} AstNodeModule* modp() const { return m_modp; } virtual string name() const { return modp()->name(); } virtual FileLine* fileline() const { return modp()->fileline(); } // Recursive modules get space for maximum recursion virtual uint32_t rankAdder() const { - return m_modp->recursiveClone() ? (1+v3Global.opt.moduleRecursionDepth()) : 1; + return m_modp->recursiveClone() ? (1 + v3Global.opt.moduleRecursionDepth()) : 1; } }; @@ -74,10 +76,12 @@ public: void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) { if (LinkCellsVertex* vvertexp = dynamic_cast(vertexp)) { - vvertexp->modp()->v3error("Unsupported: Recursive multiple modules (module instantiates something leading back to itself): " - <modp()->prettyNameQ()<modp()->v3error( + "Unsupported: Recursive multiple modules (module instantiates " + "something leading back to itself): " + << vvertexp->modp()->prettyNameQ() << endl + << V3Error::warnMore() + << "... note: self-recursion (module instantiating itself directly) is supported."); V3Error::abortIfErrors(); } else { // Everything should match above, but... v3fatalSrc("Recursive instantiations"); @@ -97,19 +101,19 @@ private: // AstCell::user2() // bool clone renaming completed // Allocated across all readFiles in V3Global::readFiles: // AstNode::user4p() // VSymEnt* Package and typedef symbol names - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; // STATE - VInFilter* m_filterp; // Parser filter - V3ParseSym* m_parseSymp; // Parser symbol table + VInFilter* m_filterp; // Parser filter + V3ParseSym* m_parseSymp; // Parser symbol table // Below state needs to be preserved between each module call. - AstNodeModule* m_modp; // Current module - VSymGraph m_mods; // Symbol table of all module names - LinkCellsGraph m_graph; // Linked graph of all cell interconnects - LibraryVertex* m_libVertexp; // Vertex at root of all libraries - V3GraphVertex* m_topVertexp; // Vertex of top module + AstNodeModule* m_modp; // Current module + VSymGraph m_mods; // Symbol table of all module names + LinkCellsGraph m_graph; // Linked graph of all cell interconnects + LibraryVertex* m_libVertexp; // Vertex at root of all libraries + V3GraphVertex* m_topVertexp; // Vertex of top module vl_unordered_set m_declfnWarned; // Files we issued DECLFILENAME on VL_DEBUG_FUNC; // Declare debug() @@ -117,16 +121,17 @@ private: // METHODS V3GraphVertex* vertex(AstNodeModule* nodep) { // Return corresponding vertex for this module - if (!nodep->user1p()) { - nodep->user1p(new LinkCellsVertex(&m_graph, nodep)); - } + if (!nodep->user1p()) nodep->user1p(new LinkCellsVertex(&m_graph, nodep)); return (nodep->user1u().toGraphVertex()); } AstNodeModule* findModuleSym(const string& modName) { VSymEnt* foundp = m_mods.rootp()->findIdFallback(modName); - if (!foundp) return NULL; - else return VN_CAST(foundp->nodep(), NodeModule); + if (!foundp) { + return NULL; + } else { + return VN_CAST(foundp->nodep(), NodeModule); + } } AstNodeModule* resolveModule(AstNode* nodep, const string& modName) { @@ -136,7 +141,7 @@ private: // If file not found, make AstNotFoundModule, rather than error out. // We'll throw the error when we know the module will really be needed. string prettyName = AstNode::prettyName(modName); - V3Parse parser (v3Global.rootp(), m_filterp, m_parseSymp); + V3Parse parser(v3Global.rootp(), m_filterp, m_parseSymp); // true below -> other simulators treat modules in link-found files as library cells parser.parseFile(nodep->fileline(), prettyName, true, ""); V3Error::abortIfErrors(); @@ -147,7 +152,7 @@ private: if (!modp) { // This shouldn't throw a message as parseFile will create // a AstNotFoundModule for us - nodep->v3error("Can't resolve module reference: '"<v3error("Can't resolve module reference: '" << prettyName << "'"); } } return modp; @@ -162,11 +167,11 @@ private: m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); m_graph.dumpDotFilePrefixed("linkcells"); m_graph.rank(); - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (LinkCellsVertex* vvertexp = dynamic_cast(itp)) { // +1 so we leave level 1 for the new wrapper we'll make in a moment AstNodeModule* modp = vvertexp->modp(); - modp->level(vvertexp->rank()+1); + modp->level(vvertexp->rank() + 1); if (vvertexp == m_topVertexp && modp->level() != 2) { AstNodeModule* abovep = NULL; if (V3GraphEdge* edgep = vvertexp->inBeginp()) { @@ -175,15 +180,16 @@ private: abovep = eFromVertexp->modp(); } } - v3error("Specified --top-module '"<prettyName() : "UNKNOWN")<<"'"); + v3error("Specified --top-module '" + << v3Global.opt.topModule() + << "' isn't at the top level, it's under another cell '" + << (abovep ? abovep->prettyName() : "UNKNOWN") << "'"); } } } - if (v3Global.opt.topModule()!="" - && !m_topVertexp) { - v3error("Specified --top-module '"<fileline()->filename()) == m_declfnWarned.end()) { m_declfnWarned.insert(nodep->fileline()->filename()); nodep->v3warn(DECLFILENAME, "Filename '" - << nodep->fileline()->filebasenameNoExt() - << "' does not match " << nodep->typeName() - << " name: " << nodep->prettyNameQ()); + << nodep->fileline()->filebasenameNoExt() + << "' does not match " << nodep->typeName() + << " name: " << nodep->prettyNameQ()); } } if (VN_IS(nodep, Iface) || VN_IS(nodep, Package)) { @@ -215,7 +221,7 @@ private: nodep->inLibrary(false); // Safer to make sure it doesn't disappear } if (v3Global.opt.topModule() == "" ? nodep->inLibrary() // Library cells are lower - : !topMatch) { // Any non-specified module is lower + : !topMatch) { // Any non-specified module is lower // Put under a fake vertex so that the graph ranking won't indicate // this is a top level module if (!m_libVertexp) m_libVertexp = new LibraryVertex(&m_graph); @@ -230,7 +236,7 @@ private: virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE { // Cell: Resolve its filename. If necessary, parse it. - UINFO(4,"Link IfaceRef: "<ifaceName()); @@ -241,7 +247,7 @@ private: if (!nodep->cellp()) nodep->ifacep(VN_CAST(modp, Iface)); } else if (VN_IS(modp, NotFoundModule)) { // Will error out later } else { - nodep->v3error("Non-interface used as an interface: "<prettyNameQ()); + nodep->v3error("Non-interface used as an interface: " << nodep->prettyNameQ()); } } // Note cannot do modport resolution here; modports are allowed underneath generates @@ -260,7 +266,7 @@ private: // TODO this doesn't allow bind to dotted hier names, that would require // this move to post param, which would mean we do not auto-read modules // and means we cannot compute module levels until later. - UINFO(4,"Link Bind: "<name()); if (modp) { AstNode* cellsp = nodep->cellsp()->unlinkFrBackWithNext(); @@ -268,7 +274,8 @@ private: AstNodeModule* oldModp = m_modp; { m_modp = modp; - modp->addStmtp(cellsp); // Important that this adds to end, as next iterate assumes does all cells + // Important that this adds to end, as next iterate assumes does all cells + modp->addStmtp(cellsp); iterateAndNextNull(cellsp); } m_modp = oldModp; @@ -281,19 +288,18 @@ private: // Execute only once. Complication is that cloning may result in // user1 being set (for pre-clone) so check if user1() matches the // m_mod, if 0 never did it, if !=, it is an unprocessed clone - bool cloned = (nodep->user1p() && nodep->user1p()!=m_modp); - if (nodep->user1p()==m_modp) return; // AstBind and AstNodeModule may call a cell twice + bool cloned = (nodep->user1p() && nodep->user1p() != m_modp); + if (nodep->user1p() == m_modp) return; // AstBind and AstNodeModule may call a cell twice nodep->user1p(m_modp); // if (!nodep->modp() || cloned) { - UINFO(4,"Link Cell: "<modName()); if (cellmodp) { - if (cellmodp == m_modp - || cellmodp->user2p() == m_modp) { - UINFO(1,"Self-recursive module "<user2p() == m_modp) { + UINFO(1, "Self-recursive module " << cellmodp << endl); cellmodp->recursive(true); nodep->recursive(true); if (!cellmodp->recursiveClone()) { @@ -307,27 +313,25 @@ private: AstNodeModule* otherModp = VN_CAST(cellmodp->user2p(), NodeModule); if (!otherModp) { otherModp = cellmodp->cloneTree(false); - otherModp->name(otherModp->name()+"__Vrcm"); + otherModp->name(otherModp->name() + "__Vrcm"); otherModp->user1p(NULL); // Need new vertex otherModp->user2p(cellmodp); otherModp->recursiveClone(true); // user1 etc will retain its pre-clone value cellmodp->user2p(otherModp); v3Global.rootp()->addModulep(otherModp); - new V3GraphEdge(&m_graph, vertex(cellmodp), - vertex(otherModp), 1, false); + new V3GraphEdge(&m_graph, vertex(cellmodp), vertex(otherModp), 1, + false); } cellmodp = otherModp; nodep->modp(cellmodp); - } - else { + } else { // In the Vrcm, which needs to point back to Vrcm flavor // The cell already has the correct resolution (to Vrcm) nodep->modp(cellmodp); // We don't create a V3GraphEdge (as it would be circular) } - } - else { // Non-recursive + } else { // Non-recursive // Track module depths, so can sort list from parent down to children nodep->modp(cellmodp); new V3GraphEdge(&m_graph, vertex(m_modp), vertex(cellmodp), 1, false); @@ -336,19 +340,17 @@ private: } // Remove AstCell(AstPin("",NULL)), it's a side effect of how we parse "()" // the empty middle is identical to the empty rule that must find pins in "(,)". - if (nodep->pinsp() && !nodep->pinsp()->nextp() - && nodep->pinsp()->name() == "" + if (nodep->pinsp() && !nodep->pinsp()->nextp() && nodep->pinsp()->name() == "" && !nodep->pinsp()->exprp()) { pushDeletep(nodep->pinsp()->unlinkFrBackWithNext()); } - if (nodep->paramsp() && !nodep->paramsp()->nextp() - && nodep->paramsp()->name() == "" + if (nodep->paramsp() && !nodep->paramsp()->nextp() && nodep->paramsp()->name() == "" && !nodep->paramsp()->exprp()) { pushDeletep(nodep->paramsp()->unlinkFrBackWithNext()); } // Convert .* to list of pins bool pinStar = false; - for (AstPin* nextp, *pinp = nodep->pinsp(); pinp; pinp=nextp) { + for (AstPin *nextp, *pinp = nodep->pinsp(); pinp; pinp = nextp) { nextp = VN_CAST(pinp->nextp(), Pin); if (pinp->dotStar()) { if (pinStar) pinp->v3error("Duplicate .* in a cell"); @@ -358,40 +360,41 @@ private: } } // Convert unnamed pins to pin number based assignments - for (AstPin* pinp = nodep->pinsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) { - if (pinp->name()=="") pinp->name("__pinNumber"+cvtToStr(pinp->pinNum())); + for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { + if (pinp->name() == "") pinp->name("__pinNumber" + cvtToStr(pinp->pinNum())); } - for (AstPin* pinp = nodep->paramsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) { + for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { pinp->param(true); - if (pinp->name()=="") pinp->name("__paramNumber"+cvtToStr(pinp->pinNum())); + if (pinp->name() == "") pinp->name("__paramNumber" + cvtToStr(pinp->pinNum())); } if (nodep->modp()) { nodep->modName(nodep->modp()->name()); // Note what pins exist vl_unordered_set ports; // Symbol table of all connected port names - for (AstPin* pinp = nodep->pinsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) { - if (pinp->name()=="") pinp->v3error("Connect by position is illegal in .* connected cells"); + for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { + if (pinp->name() == "") + pinp->v3error("Connect by position is illegal in .* connected cells"); if (!pinp->exprp()) { if (pinp->name().substr(0, 11) == "__pinNumber") { - pinp->v3warn(PINNOCONNECT, "Cell pin is not connected: " - <prettyNameQ()); + pinp->v3warn(PINNOCONNECT, + "Cell pin is not connected: " << pinp->prettyNameQ()); } else { pinp->v3warn(PINCONNECTEMPTY, "Cell pin connected by name with empty reference: " - <prettyNameQ()); + << pinp->prettyNameQ()); } } ports.insert(pinp->name()); } // We search ports, rather than in/out declarations as they aren't resolved yet, // and it's easier to do it now than in V3LinkDot when we'd need to repeat steps. - for (AstNode* portnodep = nodep->modp()->stmtsp(); - portnodep; portnodep=portnodep->nextp()) { + for (AstNode* portnodep = nodep->modp()->stmtsp(); portnodep; + portnodep = portnodep->nextp()) { if (const AstPort* portp = VN_CAST(portnodep, Port)) { if (ports.find(portp->name()) == ports.end() - && ports.find("__pinNumber"+cvtToStr(portp->pinNum())) == ports.end()) { + && ports.find("__pinNumber" + cvtToStr(portp->pinNum())) == ports.end()) { if (pinStar) { - UINFO(9," need .* PORT "<fileline(), 0, portp->name(), new AstParseRef(nodep->fileline(), @@ -400,8 +403,8 @@ private: newp->svImplicit(true); nodep->addPinsp(newp); } else { // warn on the CELL that needs it, not the port - nodep->v3warn(PINMISSING, "Cell has missing pin: " - <prettyNameQ()); + nodep->v3warn(PINMISSING, + "Cell has missing pin: " << portp->prettyNameQ()); AstPin* newp = new AstPin(nodep->fileline(), 0, portp->name(), NULL); nodep->addPinsp(newp); } @@ -413,8 +416,9 @@ private: // Cell really is the parent's instantiation of an interface, not a normal module // Make sure we have a variable to refer to this cell, so can . // in the same way that a child does. Rename though to avoid conflict with cell. - // This is quite similar to how classes work; when unpacked classes are better supported - // may remap interfaces to be more like a class. + // This is quite similar to how classes work; when unpacked + // classes are better supported may remap interfaces to be more + // like a class. if (!nodep->hasIfaceVar()) { string varName = nodep->name() + "__Viftop"; // V3LinkDot looks for this naming AstIfaceRefDType* idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(), @@ -425,8 +429,8 @@ private: AstVar* varp; if (nodep->rangep()) { AstNodeArrayDType* arrp - = new AstUnpackArrayDType(nodep->fileline(), VFlagChildDType(), - idtypep, nodep->rangep()->cloneTree(true)); + = new AstUnpackArrayDType(nodep->fileline(), VFlagChildDType(), idtypep, + nodep->rangep()->cloneTree(true)); varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName, VFlagChildDType(), arrp); } else { @@ -438,10 +442,8 @@ private: nodep->hasIfaceVar(true); } } - if (nodep->modp()) { - iterateChildren(nodep); - } - UINFO(4," Link Cell done: "<modp()) { iterateChildren(nodep); } + UINFO(4, " Link Cell done: " << nodep << endl); } // Accelerate the recursion @@ -452,17 +454,18 @@ private: // METHODS void readModNames() { // Look at all modules, and store pointers to all module names - for (AstNodeModule* nextp,* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nextp) { + for (AstNodeModule *nextp, *nodep = v3Global.rootp()->modulesp(); nodep; nodep = nextp) { nextp = VN_CAST(nodep->nextp(), NodeModule); AstNodeModule* foundp = findModuleSym(nodep->name()); if (foundp && foundp != nodep) { if (!(foundp->fileline()->warnIsOff(V3ErrorCode::MODDUP) || nodep->fileline()->warnIsOff(V3ErrorCode::MODDUP))) { nodep->v3warn(MODDUP, "Duplicate declaration of module: " - <prettyNameQ()<warnContextPrimary()<warnOther()<<"... Location of original declaration"<warnContextSecondary()); + << nodep->prettyNameQ() << endl + << nodep->warnContextPrimary() << endl + << foundp->warnOther() + << "... Location of original declaration" << endl + << foundp->warnContextSecondary()); } nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -470,7 +473,7 @@ private: m_mods.rootp()->insert(nodep->name(), new VSymEnt(&m_mods, nodep)); } } - //if (debug()>=9) m_mods.dump(cout, "-syms: "); + // if (debug() >= 9) m_mods.dump(cout, "-syms: "); } public: @@ -491,6 +494,6 @@ public: // Link class functions void V3LinkCells::link(AstNetlist* nodep, VInFilter* filterp, V3ParseSym* parseSymp) { - UINFO(4,__FUNCTION__<<": "< NameScopeSymMap; - typedef std::map ScopeAliasMap; - typedef std::set > ImplicitNameSet; + typedef std::multimap NameScopeSymMap; + typedef std::map ScopeAliasMap; + typedef std::set > ImplicitNameSet; typedef std::vector IfaceVarSyms; - typedef std::vector > IfaceModSyms; + typedef std::vector > IfaceModSyms; - static LinkDotState* s_errorThisp; // Last self, for error reporting only + static LinkDotState* s_errorThisp; // Last self, for error reporting only // MEMBERS - VSymGraph m_syms; // Symbol table - VSymEnt* m_dunitEntp; // $unit entry - NameScopeSymMap m_nameScopeSymMap; // Map of scope referenced by non-pretty textual name - ImplicitNameSet m_implicitNameSet; // For [module][signalname] if we can implicitly create it - ScopeAliasMap m_scopeAliasMap[SAMN__MAX]; // Map of aliases - IfaceVarSyms m_ifaceVarSyms; // List of AstIfaceRefDType's to be imported - IfaceModSyms m_ifaceModSyms; // List of AstIface+Symbols to be processed - bool m_forPrimary; // First link - bool m_forPrearray; // Compress cell__[array] refs - bool m_forScopeCreation; // Remove VarXRefs for V3Scope + VSymGraph m_syms; // Symbol table + VSymEnt* m_dunitEntp; // $unit entry + NameScopeSymMap m_nameScopeSymMap; // Map of scope referenced by non-pretty textual name + ImplicitNameSet m_implicitNameSet; // For [module][signalname] if we can implicitly create it + ScopeAliasMap m_scopeAliasMap[SAMN__MAX]; // Map of aliases + IfaceVarSyms m_ifaceVarSyms; // List of AstIfaceRefDType's to be imported + IfaceModSyms m_ifaceModSyms; // List of AstIface+Symbols to be processed + bool m_forPrimary; // First link + bool m_forPrearray; // Compress cell__[array] refs + bool m_forScopeCreation; // Remove VarXRefs for V3Scope public: - // METHODS VL_DEBUG_FUNC; // Declare debug() - void dump(const string& nameComment="linkdot", bool force=false) { - if (debug()>=6 || force) { - string filename = v3Global.debugFilename(nameComment)+".txt"; - const vl_unique_ptr logp (V3File::new_ofstream(filename)); - if (logp->fail()) v3fatal("Can't write "<= 6 || force) { + string filename = v3Global.debugFilename(nameComment) + ".txt"; + const vl_unique_ptr logp(V3File::new_ofstream(filename)); + if (logp->fail()) v3fatal("Can't write " << filename); std::ostream& os = *logp; m_syms.dump(os); bool first = true; - for (int samn=0; samnfirst<<" ("<first->nodep()->typeName() - <<") <- "<second<<" "<second->nodep()<first << " (" + << it->first->nodep()->typeName() << ") <- " << it->second << " " + << it->second->nodep() << endl; } } } @@ -207,9 +201,9 @@ public: // CONSTRUCTORS LinkDotState(AstNetlist* rootp, VLinkDotStep step) : m_syms(rootp) { - UINFO(4,__FUNCTION__<<": "<prettyTypeName(); + if (VN_IS(nodep, Var)) { + return "variable"; + } else if (VN_IS(nodep, Cell)) { + return "cell"; + } else if (VN_IS(nodep, Task)) { + return "task"; + } else if (VN_IS(nodep, Func)) { + return "function"; + } else if (VN_IS(nodep, Begin)) { + return "block"; + } else if (VN_IS(nodep, Iface)) { + return "interface"; + } else if (VN_IS(nodep, ParamTypeDType)) { + return "parameter type"; + } else { + return nodep->prettyTypeName(); + } } VSymEnt* rootEntp() const { return m_syms.rootp(); } @@ -251,7 +254,7 @@ public: AstNode* fnodep = foundp ? foundp->nodep() : NULL; if (!fnodep) { // Not found, will add in a moment. - } else if (nodep==fnodep) { // Already inserted. + } else if (nodep == fnodep) { // Already inserted. // Good. } else if (foundp->imported()) { // From package // We don't throw VARHIDDEN as if the import is later the symbol @@ -261,29 +264,29 @@ public: // Begin: ... blocks often replicate under genif/genfor, so simply // suppress duplicate checks. See t_gen_forif.v for an example. } else { - UINFO(4,"name "<name - UINFO(4,"Var1 "<name + UINFO(4, "Var1 " << nodep << endl); + UINFO(4, "Var2 " << fnodep << endl); if (nodep->type() == fnodep->type()) { - nodep->v3error("Duplicate declaration of "<prettyNameQ()<warnContextPrimary()<warnOther()<<"... Location of original declaration\n" - <warnContextSecondary()); + nodep->v3error("Duplicate declaration of " + << nodeTextType(fnodep) << ": " << nodep->prettyNameQ() << endl + << nodep->warnContextPrimary() << endl + << fnodep->warnOther() << "... Location of original declaration\n" + << fnodep->warnContextSecondary()); } else { - nodep->v3error("Unsupported in C: "<prettyNameQ()<warnContextPrimary()<warnOther()<<"... Location of original declaration\n" - <warnContextSecondary()); + nodep->v3error("Unsupported in C: " + << ucfirst(nodeTextType(nodep)) << " has the same name as " + << nodeTextType(fnodep) << ": " << nodep->prettyNameQ() << endl + << nodep->warnContextPrimary() << endl + << fnodep->warnOther() << "... Location of original declaration\n" + << fnodep->warnContextSecondary()); } } } void insertDUnit(AstNetlist* nodep) { // $unit on top scope VSymEnt* symp = new VSymEnt(&m_syms, nodep); - UINFO(9," INSERTdunit se"<parentp(rootEntp()); // Needed so backward search can find name of top module symp->fallbackp(NULL); rootEntp()->insert("$unit ", symp); // Space so can never name conflict with user code @@ -294,7 +297,8 @@ public: VSymEnt* insertTopCell(AstNodeModule* nodep, const string& scopename) { // Only called on the module at the very top of the hierarchy VSymEnt* symp = new VSymEnt(&m_syms, nodep); - UINFO(9," INSERTtop se"<parentp(rootEntp()); // Needed so backward search can find name of top module symp->fallbackp(dunitEntp()); // Needed so can find $unit stuff nodep->user1p(symp); @@ -303,13 +307,13 @@ public: if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp)); return symp; } - VSymEnt* insertCell(VSymEnt* abovep, VSymEnt* modSymp, - AstCell* nodep, const string& scopename) { + VSymEnt* insertCell(VSymEnt* abovep, VSymEnt* modSymp, AstCell* nodep, + const string& scopename) { UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node"); VSymEnt* symp = new VSymEnt(&m_syms, nodep); - UINFO(9," INSERTcel se"<symPrefix(nodep->name() + "__DOT__"); nodep->user1p(symp); checkDuplicate(abovep, nodep, nodep->name()); abovep->reinsert(basename, symp); @@ -358,15 +362,13 @@ public: // However, cells walk the graph, so cells will appear under the begin/ftask itself UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node"); VSymEnt* symp = new VSymEnt(&m_syms, nodep); - UINFO(9," INSERTblk se"<reinsert(name, symp); return symp; @@ -375,8 +377,8 @@ public: AstNodeModule* packagep) { UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node"); VSymEnt* symp = new VSymEnt(&m_syms, nodep); - UINFO(9," INSERTsym se"<subDTypep()); UASSERT_OBJ(ifacerefp, varp, "Non-ifacerefs on list!"); if (!ifacerefp->ifaceViaCellp()) { - if (!ifacerefp->cellp()) { // Probably a NotFoundModule, or a normal module if made mistake + if (!ifacerefp->cellp()) { // Probably a NotFoundModule, or a normal module if + // made mistake ifacerefp->v3error("Cannot find file containing interface: " - <ifaceName())); + << AstNode::prettyNameQ(ifacerefp->ifaceName())); continue; } else { ifacerefp->v3fatalSrc("Unlinked interface"); } } else if (ifacerefp->ifaceViaCellp()->dead()) { ifacerefp->v3error("Parent cell's interface is not found: " - <ifaceName())); + << AstNode::prettyNameQ(ifacerefp->ifaceName())); continue; } VSymEnt* ifaceSymp = getNodeSym(ifacerefp->ifaceViaCellp()); @@ -466,20 +467,20 @@ public: bool ok = false; if (foundp) { if (AstModport* modportp = VN_CAST(foundp->nodep(), Modport)) { - UINFO(4,"Link Modport: "<modportp(modportp); ifOrPortSymp = foundp; ok = true; } } if (!ok) { - string suggest = suggestSymFallback( - ifaceSymp, ifacerefp->modportName(), LinkNodeMatcherModport()); - ifacerefp->modportFileline() - ->v3error("Modport not found under interface " - <prettyNameQ(ifacerefp->ifaceName())<<": " - <prettyNameQ(ifacerefp->modportName())<warnMore()+suggest)); + string suggest = suggestSymFallback(ifaceSymp, ifacerefp->modportName(), + LinkNodeMatcherModport()); + ifacerefp->modportFileline()->v3error( + "Modport not found under interface " + << ifacerefp->prettyNameQ(ifacerefp->ifaceName()) << ": " + << ifacerefp->prettyNameQ(ifacerefp->modportName()) << endl + << (suggest.empty() ? "" : ifacerefp->warnMore() + suggest)); } } // Alias won't expand until interfaces and modport names are known; see notes at top @@ -492,52 +493,59 @@ public: // Track and later insert scope aliases; an interface referenced by // a child cell connecting to that interface // Typically lhsp=VAR w/dtype IFACEREF, rhsp=IFACE cell - UINFO(9," insertScopeAlias se"<nodep(), Cell) - && !VN_IS(VN_CAST(rhsp->nodep(), Cell)->modp(), Iface)), - rhsp->nodep(), "Got a non-IFACE alias RHS"); + UINFO(9, " insertScopeAlias se" << cvtToHex(lhsp) << " se" << cvtToHex(rhsp) << endl); + UASSERT_OBJ( + !(VN_IS(rhsp->nodep(), Cell) && !VN_IS(VN_CAST(rhsp->nodep(), Cell)->modp(), Iface)), + rhsp->nodep(), "Got a non-IFACE alias RHS"); m_scopeAliasMap[samn].insert(make_pair(lhsp, rhsp)); } void computeScopeAliases() { - UINFO(9,"computeIfaceAliases\n"); - for (int samn=0; samnfirst; VSymEnt* srcp = lhsp; while (true) { // Follow chain of aliases up to highest level non-alias ScopeAliasMap::iterator it2 = m_scopeAliasMap[samn].find(srcp); - if (it2 != m_scopeAliasMap[samn].end()) { srcp = it2->second; continue; } - else break; + if (it2 != m_scopeAliasMap[samn].end()) { + srcp = it2->second; + continue; + } else + break; } - UINFO(9," iiasa: Insert alias se"<nodep()->typeName() - <<") <- se"<nodep()<nodep()->typeName() + << ") <- se" << srcp << " " << srcp->nodep() + << endl); + // srcp should be an interface reference pointing to the interface we want to + // import lhsp->importFromIface(symsp(), srcp); // Allow access to objects not permissible to be listed in a modport if (VN_IS(srcp->nodep(), Modport)) { lhsp->importFromIface(symsp(), srcp->parentp(), true); } } - //m_scopeAliasMap[samn].clear(); // Done with it, but put into debug file + // m_scopeAliasMap[samn].clear(); // Done with it, but put into debug file } } + private: VSymEnt* findWithAltFallback(VSymEnt* symp, const string& name, const string& altname) { VSymEnt* findp = symp->findIdFallback(name); if (findp) return findp; if (altname != "") { - UINFO(8," alt fallback\n"); + UINFO(8, " alt fallback\n"); findp = symp->findIdFallback(altname); } return findp; } + public: - VSymEnt* findDotted(VSymEnt* lookupSymp, const string& dotname, - string& baddot, VSymEnt*& okSymp) { + VSymEnt* findDotted(VSymEnt* lookupSymp, const string& dotname, string& baddot, + VSymEnt*& okSymp) { // Given a dotted hierarchy name, return where in scope it is // Note when dotname=="" we just fall through and return lookupSymp - UINFO(8," dottedFind se"<nodep(), Cell) : NULL; // Replicated below - AstCellInline* inlinep = lookupSymp ? VN_CAST(lookupSymp->nodep(), CellInline) : NULL; // Replicated below + AstCell* cellp + = lookupSymp ? VN_CAST(lookupSymp->nodep(), Cell) : NULL; // Replicated below + AstCellInline* inlinep = lookupSymp ? VN_CAST(lookupSymp->nodep(), CellInline) + : NULL; // Replicated below if (VSymEnt* findSymp = findWithAltFallback(lookupSymp, ident, altIdent)) { lookupSymp = findSymp; } // Check this module - cur modname else if ((cellp && cellp->modp()->origName() == ident) - || (inlinep && inlinep->origModName() == ident)) {} + || (inlinep && inlinep->origModName() == ident)) { + } // Move up and check cellname + modname else { bool crossedCell = false; // Crossed a cell boundary while (lookupSymp) { lookupSymp = lookupSymp->parentp(); - cellp = lookupSymp ? VN_CAST(lookupSymp->nodep(), Cell) : NULL; // Replicated above - inlinep = lookupSymp ? VN_CAST(lookupSymp->nodep(), CellInline) : NULL; // Replicated above + cellp = lookupSymp ? VN_CAST(lookupSymp->nodep(), Cell) + : NULL; // Replicated above + inlinep = lookupSymp ? VN_CAST(lookupSymp->nodep(), CellInline) + : NULL; // Replicated above if (lookupSymp) { - UINFO(9," Up to "<modp()->origName() == ident) || (inlinep && inlinep->origModName() == ident)) { break; - } - else if (VSymEnt* findSymp - = findWithAltFallback(lookupSymp, ident, altIdent)) { + } else if (VSymEnt* findSymp + = findWithAltFallback(lookupSymp, ident, altIdent)) { lookupSymp = findSymp; if (crossedCell && VN_IS(lookupSymp->nodep(), Var)) { - UINFO(9," Not found but matches var name in parent " - <symPrefix()=="") ? "" : " as ") - <<((lookupSymp->symPrefix()=="") ? "" : lookupSymp->symPrefix()+dotname) - <<" at se"<symPrefix() == "") ? "" : " as ") + << ((lookupSymp->symPrefix() == "") ? "" : lookupSymp->symPrefix() + dotname) + << " at se" << lookupSymp << endl); string prefix = lookupSymp->symPrefix(); VSymEnt* foundp = NULL; while (!foundp) { @@ -660,8 +670,7 @@ public: lookupSymp->candidateIdFallback(&speller, &matcher); return speller.bestCandidateMsg(name); } - string suggestSymFlat(VSymEnt* lookupSymp, const string& name, - const VNodeMatcher& matcher) { + string suggestSymFlat(VSymEnt* lookupSymp, const string& name, const VNodeMatcher& matcher) { if (!lookupSymp) return ""; VSpellCheck speller; lookupSymp->candidateIdFlat(&speller, &matcher); @@ -677,14 +686,14 @@ class LinkDotFindVisitor : public AstNVisitor { // STATE LinkDotState* m_statep; // State to pass between visitors, including symbol table AstNodeModule* m_packagep; // Current package - VSymEnt* m_modSymp; // Symbol Entry for current module - VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert - string m_scope; // Scope text - AstBegin* m_beginp; // Current Begin/end block - AstNodeFTask* m_ftaskp; // Current function/task - bool m_inRecursion; // Inside a recursive module - int m_paramNum; // Parameter number, for position based connection - int m_beginNum; // Begin block number, 0=none seen + VSymEnt* m_modSymp; // Symbol Entry for current module + VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert + string m_scope; // Scope text + AstBegin* m_beginp; // Current Begin/end block + AstNodeFTask* m_ftaskp; // Current function/task + bool m_inRecursion; // Inside a recursive module + int m_paramNum; // Parameter number, for position based connection + int m_beginNum; // Begin block number, 0=none seen bool m_explicitNew; // Hit a "new" function int m_modBeginNum; // Begin block number in module, 0=none seen @@ -697,13 +706,10 @@ class LinkDotFindVisitor : public AstNVisitor { // This is a string string v = literal.substr(1, literal.find('"', 1) - 1); return new AstConst(fl, AstConst::VerilogStringLiteral(), v); - } else if ((literal.find('.') != string::npos) - || (literal.find('e') != string::npos)) { + } else if ((literal.find('.') != string::npos) || (literal.find('e') != string::npos)) { // This may be a real double v = V3ParseImp::parseDouble(literal.c_str(), literal.length(), &success); - if (success) { - return new AstConst(fl, AstConst::RealDouble(), v); - } + if (success) return new AstConst(fl, AstConst::RealDouble(), v); } if (!success) { // This is either an integer or an error @@ -735,7 +741,7 @@ class LinkDotFindVisitor : public AstNVisitor { virtual void visit(AstNetlist* nodep) VL_OVERRIDE { // Process $unit or other packages // Not needed - dotted references not allowed from inside packages - //for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); + // for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); // nodep; nodep=VN_CAST(nodep->nextp(), NodeModule)) { // if (VN_IS(nodep, Package)) {}} @@ -749,17 +755,13 @@ class LinkDotFindVisitor : public AstNVisitor { // (sorted before this is called). // This may not be the module with isTop() set, as early in the steps, // wrapTop may have not been created yet. - if (!nodep->modulesp()) { - nodep->v3error("No top level module found"); - } + if (!nodep->modulesp()) nodep->v3error("No top level module found"); for (AstNodeModule* modp = nodep->modulesp(); modp && modp->level() <= 2; modp = VN_CAST(modp->nextp(), NodeModule)) { - UINFO(8,"Top Module: "<insertTopCell(modp, m_scope); - { - iterate(modp); - } + { iterate(modp); } m_scope = ""; m_curSymp = m_modSymp = NULL; } @@ -768,7 +770,7 @@ class LinkDotFindVisitor : public AstNVisitor { virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { // Called on top module from Netlist, other modules from the cell creating them, // and packages - UINFO(8," "<user2()) { - nodep->v3error("Unsupported: Identically recursive module (module instantiates itself, without changing parameters): " - <origName())); + nodep->v3error("Unsupported: Identically recursive module (module instantiates " + "itself, without changing parameters): " + << AstNode::prettyNameQ(nodep->origName())); } else if (doit) { - UINFO(4," Link Module: "<dead(), nodep, "Module in cell tree mislabeled as dead?"); VSymEnt* upperSymp = m_curSymp ? m_curSymp : m_statep->rootEntp(); AstPackage* pkgp = VN_CAST(nodep, Package); @@ -795,9 +798,9 @@ class LinkDotFindVisitor : public AstNVisitor { nodep->user1p(m_curSymp); } else { m_scope = nodep->name(); - m_curSymp = m_modSymp - = m_statep->insertBlock(upperSymp, nodep->name()+"::", nodep, m_packagep); - UINFO(9, "New module scope "<insertBlock( + upperSymp, nodep->name() + "::", nodep, m_packagep); + UINFO(9, "New module scope " << m_curSymp << endl); } } // @@ -817,34 +820,34 @@ class LinkDotFindVisitor : public AstNVisitor { } else { // !doit // Will be optimized away later // Can't remove now, as our backwards iterator will throw up - UINFO(5, "Module not under any CELL or top - dead module: "<name(); m_curSymp = m_modSymp = m_statep->insertBlock(upperSymp, nodep->name(), nodep, m_packagep); m_statep->insertMap(m_curSymp, m_scope); - UINFO(9, "New module scope "<recursive() && m_inRecursion) return; iterateChildren(nodep); @@ -892,11 +895,11 @@ class LinkDotFindVisitor : public AstNVisitor { VSymEnt* okSymp; aboveSymp = m_statep->findDotted(aboveSymp, scope, baddot, okSymp); UASSERT_OBJ(aboveSymp, nodep, - "Can't find cell insertion point at " - <prettyNameQ()); + "Can't find cell insertion point at " << AstNode::prettyNameQ(baddot) + << " in: " << nodep->prettyNameQ()); } { - m_scope = m_scope+"."+nodep->name(); + m_scope = m_scope + "." + nodep->name(); m_curSymp = m_modSymp = m_statep->insertCell(aboveSymp, m_modSymp, nodep, m_scope); m_beginp = NULL; m_inRecursion = nodep->recursive(); @@ -911,20 +914,20 @@ class LinkDotFindVisitor : public AstNVisitor { m_inRecursion = oldRecursion; } virtual void visit(AstCellInline* nodep) VL_OVERRIDE { - UINFO(5," CELLINLINE under "<name(); string::size_type pos; if ((pos = dottedname.rfind("__DOT__")) != string::npos) { string dotted = dottedname.substr(0, pos); - string ident = dottedname.substr(pos+strlen("__DOT__")); + string ident = dottedname.substr(pos + strlen("__DOT__")); string baddot; VSymEnt* okSymp; aboveSymp = m_statep->findDotted(aboveSymp, dotted, baddot, okSymp); UASSERT_OBJ(aboveSymp, nodep, "Can't find cellinline insertion point at " - <prettyNameQ()); + << AstNode::prettyNameQ(baddot) << " in: " << nodep->prettyNameQ()); m_statep->insertInline(aboveSymp, m_modSymp, nodep, ident); } else { // No __DOT__, just directly underneath m_statep->insertInline(aboveSymp, m_modSymp, nodep, nodep->name()); @@ -935,25 +938,25 @@ class LinkDotFindVisitor : public AstNVisitor { iterateChildren(nodep); } virtual void visit(AstBegin* nodep) VL_OVERRIDE { - UINFO(5," "<forPrimary() && !nodep->user4SetOnce()) { if (nodep->name() == "genblk") { ++m_beginNum; - nodep->name(nodep->name()+cvtToStr(m_beginNum)); + nodep->name(nodep->name() + cvtToStr(m_beginNum)); } } // All blocks are numbered in the standard, IE we start with "genblk1" even if only one. - if (nodep->name()=="" && nodep->unnamed()) { + if (nodep->name() == "" && nodep->unnamed()) { // Unnamed blocks are only important when they contain var // decls, so search for them. (Otherwise adding all the // unnamed#'s would just confuse tracing variables in // places such as tasks, where "task ...; begin ... end" // are common. - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (VN_IS(stmtp, Var)) { ++m_modBeginNum; - nodep->name("unnamedblk"+cvtToStr(m_modBeginNum)); + nodep->name("unnamedblk" + cvtToStr(m_modBeginNum)); break; } } @@ -979,7 +982,7 @@ class LinkDotFindVisitor : public AstNVisitor { } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { // NodeTask: Remember its name for later resolution - UINFO(5," "<name() == "new") m_explicitNew = true; // Remember the existing symbol table scope @@ -991,13 +994,15 @@ class LinkDotFindVisitor : public AstNVisitor { // Convert the func's range to the output variable // This should probably be done in the Parser instead, as then we could // just attach normal signal attributes to it. - if (nodep->fvarp() - && !VN_IS(nodep->fvarp(), Var)) { + if (nodep->fvarp() && !VN_IS(nodep->fvarp(), Var)) { AstNodeDType* dtypep = VN_CAST(nodep->fvarp(), NodeDType); // If unspecified, function returns one bit; however when we // support NEW() it could also return the class reference. - if (dtypep) dtypep->unlinkFrBack(); - else dtypep = new AstBasicDType(nodep->fileline(), AstBasicDTypeKwd::LOGIC); + if (dtypep) { + dtypep->unlinkFrBack(); + } else { + dtypep = new AstBasicDType(nodep->fileline(), AstBasicDTypeKwd::LOGIC); + } AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::VAR, nodep->name(), VFlagChildDType(), dtypep); // Not dtype resolved yet newvarp->direction(VDirection::OUTPUT); @@ -1006,7 +1011,7 @@ class LinkDotFindVisitor : public AstNVisitor { newvarp->attrIsolateAssign(nodep->attrIsolateAssign()); nodep->addFvarp(newvarp); // Explicit insert required, as the var name shadows the upper level's task name - m_statep->insertSym(m_curSymp, newvarp->name(), newvarp, NULL/*packagep*/); + m_statep->insertSym(m_curSymp, newvarp->name(), newvarp, NULL /*packagep*/); } m_ftaskp = nodep; iterateChildren(nodep); @@ -1035,16 +1040,17 @@ class LinkDotFindVisitor : public AstNVisitor { ins = true; } else if (!findvarp && foundp && m_curSymp->findIdFlat(nodep->name())) { nodep->v3error("Unsupported in C: Variable has same name as " - <nodep()) - <<": "<prettyNameQ()); + << LinkDotState::nodeTextType(foundp->nodep()) << ": " + << nodep->prettyNameQ()); } else if (findvarp != nodep) { - UINFO(4,"DupVar: "<nodep()<parentp())<nodep() << endl); + UINFO(4, " found cur=se" << cvtToHex(m_curSymp) << " ;; parent=se" + << cvtToHex(foundp->parentp()) << endl); if (foundp->parentp() == m_curSymp // Only when on same level && !foundp->imported()) { // and not from package - bool nansiBad = ((findvarp->isDeclTyped() && nodep->isDeclTyped()) - || (findvarp->isIO() && nodep->isIO())); // e.g. !(output && output) + bool nansiBad + = ((findvarp->isDeclTyped() && nodep->isDeclTyped()) + || (findvarp->isIO() && nodep->isIO())); // e.g. !(output && output) bool ansiBad = findvarp->isAnsi() || nodep->isAnsi(); // dup illegal with ANSI if (ansiBad || nansiBad) { bool ansiWarn = ansiBad && !nansiBad; @@ -1053,14 +1059,16 @@ class LinkDotFindVisitor : public AstNVisitor { if (didAnsiWarn++) ansiWarn = false; } nodep->v3error("Duplicate declaration of signal: " - <prettyNameQ()<warnMore() + "... note: ANSI ports must have" - " type declared with the I/O (IEEE 1800-2017 23.2.2.2)\n" - : "") - <warnContextPrimary()<warnOther()<<"... Location of original declaration"<warnContextSecondary()); + << nodep->prettyNameQ() << endl + << (ansiWarn ? nodep->warnMore() + + "... note: ANSI ports must have" + " type declared with the I/O (IEEE " + "1800-2017 23.2.2.2)\n" + : "") + << nodep->warnContextPrimary() << endl + << findvarp->warnOther() + << "... Location of original declaration" << endl + << findvarp->warnContextSecondary()); // Combining most likely reduce other errors findvarp->combineType(nodep); findvarp->fileline()->modifyStateInherit(nodep->fileline()); @@ -1083,15 +1091,17 @@ class LinkDotFindVisitor : public AstNVisitor { } else { // User can disable the message at either point if (!(m_ftaskp && m_ftaskp->dpiImport()) - && (!m_ftaskp || m_ftaskp != foundp->nodep()) // Not the function's variable hiding function + && (!m_ftaskp || m_ftaskp != foundp->nodep()) // Not the function's + // variable hiding function && !nodep->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN) && !foundp->nodep()->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) { - nodep->v3warn(VARHIDDEN, "Declaration of signal hides declaration in upper scope: " - <prettyNameQ()<warnContextPrimary()<nodep()->warnOther() - <<"... Location of original declaration\n" - <nodep()->warnContextSecondary()); + nodep->v3warn(VARHIDDEN, + "Declaration of signal hides declaration in upper scope: " + << nodep->prettyNameQ() << endl + << nodep->warnContextPrimary() << endl + << foundp->nodep()->warnOther() + << "... Location of original declaration\n" + << foundp->nodep()->warnContextSecondary()); } ins = true; } @@ -1103,15 +1113,16 @@ class LinkDotFindVisitor : public AstNVisitor { // We first search if the parameter is overwritten and then replace it with a // new value. It will keep the same FileLine information. if (v3Global.opt.hasParameter(nodep->name())) { - AstVar* newp = new AstVar(nodep->fileline(), - AstVarType(AstVarType::GPARAM), - nodep->name(), nodep); + AstVar* newp + = new AstVar(nodep->fileline(), AstVarType(AstVarType::GPARAM), + nodep->name(), nodep); string svalue = v3Global.opt.parameter(nodep->name()); if (AstNode* valuep = parseParamLiteral(nodep->fileline(), svalue)) { newp->valuep(valuep); - UINFO(9," replace parameter "<replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + UINFO(9, " replace parameter " << nodep << endl); + UINFO(9, " with " << newp << endl); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); nodep = newp; } } @@ -1119,9 +1130,8 @@ class LinkDotFindVisitor : public AstNVisitor { VSymEnt* insp = m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); if (m_statep->forPrimary() && nodep->isGParam()) { m_paramNum++; - VSymEnt* symp = m_statep->insertSym(m_curSymp, - "__paramNumber"+cvtToStr(m_paramNum), - nodep, m_packagep); + VSymEnt* symp = m_statep->insertSym( + m_curSymp, "__paramNumber" + cvtToStr(m_paramNum), nodep, m_packagep); symp->exported(false); } AstIfaceRefDType* ifacerefp = LinkDotState::ifaceRefFromArray(nodep->subDTypep()); @@ -1166,65 +1176,66 @@ class LinkDotFindVisitor : public AstNVisitor { if (!foundp) { ins = true; } else if (findvarp != nodep) { - UINFO(4,"DupVar: "<parentp() == m_curSymp // Only when on same level && !foundp->imported()) { // and not from package - nodep->v3error("Duplicate declaration of enum value: "<prettyName()<warnContextPrimary()<nodep()->warnOther()<<"... Location of original declaration\n" - <nodep()->warnContextSecondary()); + nodep->v3error("Duplicate declaration of enum value: " + << nodep->prettyName() << endl + << nodep->warnContextPrimary() << endl + << foundp->nodep()->warnOther() + << "... Location of original declaration\n" + << foundp->nodep()->warnContextSecondary()); } else { // User can disable the message at either point if (!nodep->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN) && !foundp->nodep()->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) { - nodep->v3warn(VARHIDDEN, "Declaration of enum value hides declaration in upper scope: " - <prettyName()<warnContextPrimary()<nodep()->warnOther() - <<"... Location of original declaration\n" - <warnContextSecondary()); + nodep->v3warn(VARHIDDEN, + "Declaration of enum value hides declaration in upper scope: " + << nodep->prettyName() << endl + << nodep->warnContextPrimary() << endl + << foundp->nodep()->warnOther() + << "... Location of original declaration\n" + << nodep->warnContextSecondary()); } ins = true; } } - if (ins) { - m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); - } + if (ins) m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); } virtual void visit(AstPackageImport* nodep) VL_OVERRIDE { - UINFO(4," Link: "<getNodeSym(nodep->packagep()); - if (nodep->name()=="*") { + if (nodep->name() == "*") { if (m_curSymp == m_statep->dunitEntp()) { nodep->v3warn(IMPORTSTAR, "Import::* in $unit scope may pollute global namespace"); } } else { VSymEnt* impp = srcp->findIdFlat(nodep->name()); if (!impp) { - nodep->v3error("Import object not found: '" - <packagep()->prettyName()<<"::"<prettyName()<<"'"); + nodep->v3error("Import object not found: '" << nodep->packagep()->prettyName() + << "::" << nodep->prettyName() << "'"); } } m_curSymp->importFromPackage(m_statep->symsp(), srcp, nodep->name()); - UINFO(9," Link Done: "<getNodeSym(nodep->packagep()); - if (nodep->name()!="*") { + if (nodep->name() != "*") { VSymEnt* impp = srcp->findIdFlat(nodep->name()); if (!impp) { - nodep->v3error("Export object not found: '" - <packagep()->prettyName()<<"::"<prettyName()<<"'"); + nodep->v3error("Export object not found: '" << nodep->packagep()->prettyName() + << "::" << nodep->prettyName() << "'"); } } m_curSymp->exportFromPackage(m_statep->symsp(), srcp, nodep->name()); - UINFO(9," Link Done: "<exportStarStar(m_statep->symsp()); // No longer needed, but can't delete until any multi-instantiated modules are expanded } @@ -1234,7 +1245,7 @@ class LinkDotFindVisitor : public AstNVisitor { public: // CONSTRUCTORS LinkDotFindVisitor(AstNetlist* rootp, LinkDotState* statep) { - UINFO(4,__FUNCTION__<<": "< See LinkDotState // STATE - LinkDotState* m_statep; // State to pass between visitors, including symbol table - AstNodeModule* m_modp; // Current module + LinkDotState* m_statep; // State to pass between visitors, including symbol table + AstNodeModule* m_modp; // Current module int debug() { return LinkDotState::debug(); } @@ -1272,8 +1283,7 @@ private: // Create implicit variable as needed if (VN_IS(nodep, Dot)) { // Not creating a simple implied type, // and implying something else would just confuse later errors - } - else if (VN_IS(nodep, VarRef) || VN_IS(nodep, ParseRef)) { + } else if (VN_IS(nodep, VarRef) || VN_IS(nodep, ParseRef)) { // To prevent user errors, we should only do single bit // implicit vars, however some netlists (MIPS) expect single // bit implicit wires to get created with range 0:0 etc. @@ -1293,9 +1303,9 @@ private: // VISITs virtual void visit(AstTypeTable*) VL_OVERRIDE {} virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { - UINFO(5," "<dead() || !nodep->user4()) { - UINFO(4,"Mark dead module "<forPrearray(), nodep, "Dead module persisted past where should have removed"); // Don't remove now, because we may have a tree of @@ -1321,21 +1331,19 @@ private: virtual void visit(AstDefParam* nodep) VL_OVERRIDE { iterateChildren(nodep); nodep->v3warn(DEFPARAM, "Suggest replace defparam assignment with Verilog 2001 #(." - <prettyName()<<"(...etc...))"); + << nodep->prettyName() << "(...etc...))"); VSymEnt* foundp = m_statep->getNodeSym(nodep)->findIdFallback(nodep->path()); AstCell* cellp = foundp ? VN_CAST(foundp->nodep(), Cell) : NULL; if (!cellp) { - nodep->v3error("In defparam, cell "<path()<<" never declared"); + nodep->v3error("In defparam, cell " << nodep->path() << " never declared"); } else { AstNode* exprp = nodep->rhsp()->unlinkFrBack(); - UINFO(9,"Defparam cell "<path()<<"."<name() - <<" attach-to "<path() << "." << nodep->name() << " attach-to " + << cellp << " <= " << exprp << endl); // Don't need to check the name of the defparam exists. V3Param does. AstPin* pinp = new AstPin(nodep->fileline(), -1, // Pin# not relevant - nodep->name(), - exprp); + nodep->name(), exprp); cellp->addParamsp(pinp); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } @@ -1347,21 +1355,22 @@ private: VSymEnt* foundp = m_statep->getNodeSym(m_modp)->findIdFlat(nodep->name()); AstVar* refp = foundp ? VN_CAST(foundp->nodep(), Var) : NULL; if (!refp) { - nodep->v3error("Input/output/inout declaration not found for port: " - <prettyNameQ()); + nodep->v3error( + "Input/output/inout declaration not found for port: " << nodep->prettyNameQ()); } else if (!refp->isIO() && !refp->isIfaceRef()) { - nodep->v3error("Pin is not an in/out/inout/interface: "<prettyNameQ()); + nodep->v3error("Pin is not an in/out/inout/interface: " << nodep->prettyNameQ()); } else { if (refp->user4()) { - nodep->v3error("Duplicate declaration of port: "<prettyNameQ()<warnContextPrimary()<warnOther()<<"... Location of original declaration\n" - <warnContextSecondary()); + nodep->v3error("Duplicate declaration of port: " + << nodep->prettyNameQ() << endl + << nodep->warnContextPrimary() << endl + << refp->warnOther() << "... Location of original declaration\n" + << refp->warnContextSecondary()); } refp->user4(true); VSymEnt* symp = m_statep->insertSym(m_statep->getNodeSym(m_modp), - "__pinNumber"+cvtToStr(nodep->pinNum()), - refp, NULL/*packagep*/); + "__pinNumber" + cvtToStr(nodep->pinNum()), refp, + NULL /*packagep*/); symp->exported(false); } // Ports not needed any more @@ -1411,7 +1420,7 @@ private: public: // CONSTRUCTORS LinkDotParamVisitor(AstNetlist* rootp, LinkDotState* statep) { - UINFO(4,__FUNCTION__<<": "<forScopeCreation(), nodep, "Scopes should only exist right after V3Scope"); // Using the CELL names, we created all hierarchy. We now need to match this Scope @@ -1452,29 +1460,29 @@ class LinkDotScopeVisitor : public AstNVisitor { virtual void visit(AstVarScope* nodep) VL_OVERRIDE { if (!nodep->varp()->isFuncLocal() && !nodep->varp()->isClassMember()) { VSymEnt* varSymp = m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL); - if (nodep->varp()->isIfaceRef() - && nodep->varp()->isIfaceParent()) { - UINFO(9,"Iface parent ref var "<varp()->name()<<" "<varp()->isIfaceRef() && nodep->varp()->isIfaceParent()) { + UINFO(9, "Iface parent ref var " << nodep->varp()->name() << " " << nodep << endl); // Find the interface cell the var references AstIfaceRefDType* dtypep = LinkDotState::ifaceRefFromArray(nodep->varp()->dtypep()); UASSERT_OBJ(dtypep, nodep, "Non AstIfaceRefDType on isIfaceRef() var"); - UINFO(9,"Iface parent dtype "<cellName(); - string baddot; VSymEnt* okSymp; + string baddot; + VSymEnt* okSymp; VSymEnt* cellSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp); UASSERT_OBJ(cellSymp, nodep, - "No symbol for interface cell: "<prettyNameQ(ifcellname)); - UINFO(5, " Found interface cell: se"<nodep()<modportName()!="") { + "No symbol for interface cell: " << nodep->prettyNameQ(ifcellname)); + UINFO(5, " Found interface cell: se" << cvtToHex(cellSymp) << " " + << cellSymp->nodep() << endl); + if (dtypep->modportName() != "") { VSymEnt* mpSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp); UASSERT_OBJ(mpSymp, nodep, "No symbol for interface modport: " - <prettyNameQ(dtypep->modportName())); + << nodep->prettyNameQ(dtypep->modportName())); cellSymp = mpSymp; - UINFO(5, " Found modport cell: se" - <nodep()<nodep() << endl); } // Interface reference; need to put whole thing into // symtable, but can't clone it now as we may have a later @@ -1491,40 +1499,43 @@ class LinkDotScopeVisitor : public AstNVisitor { virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // Track aliases created by V3Inline; if we get a VARXREF(aliased_from) // we'll need to replace it with a VARXREF(aliased_to) - if (debug()>=9) nodep->dumpTree(cout, "- alias: "); + if (debug() >= 9) nodep->dumpTree(cout, "- alias: "); AstVarScope* fromVscp = VN_CAST(nodep->lhsp(), VarRef)->varScopep(); - AstVarScope* toVscp = VN_CAST(nodep->rhsp(), VarRef)->varScopep(); + AstVarScope* toVscp = VN_CAST(nodep->rhsp(), VarRef)->varScopep(); UASSERT_OBJ(fromVscp && toVscp, nodep, "Bad alias scopes"); fromVscp->user2p(toVscp); iterateChildren(nodep); } virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE { - UINFO(5,"ASSIGNVARSCOPE "<=9) nodep->dumpTree(cout, "- avs: "); + UINFO(5, "ASSIGNVARSCOPE " << nodep << endl); + if (debug() >= 9) nodep->dumpTree(cout, "- avs: "); VSymEnt* rhsSymp; { AstVarRef* refp = VN_CAST(nodep->rhsp(), VarRef); AstVarXRef* xrefp = VN_CAST(nodep->rhsp(), VarXRef); UASSERT_OBJ(refp || xrefp, nodep, "Unsupported: Non Var(X)Ref attached to interface pin"); - string inl = ((xrefp && xrefp->inlinedDots().size()) - ? (xrefp->inlinedDots() + "__DOT__") : ""); + string inl + = ((xrefp && xrefp->inlinedDots().size()) ? (xrefp->inlinedDots() + "__DOT__") + : ""); VSymEnt* symp = NULL; string scopename; while (!symp) { - scopename = refp ? refp->name() : (inl.size() ? (inl + xrefp->name()) - : xrefp->name()); - string baddot; VSymEnt* okSymp; + scopename + = refp ? refp->name() : (inl.size() ? (inl + xrefp->name()) : xrefp->name()); + string baddot; + VSymEnt* okSymp; symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp); - if (inl == "") - break; + if (inl == "") break; inl = LinkDotState::removeLastInlineScope(inl); } - if (!symp) UINFO(9,"No symbol for interface alias rhs (" - <nodep()<nodep() << endl); rhsSymp = symp; } VSymEnt* lhsSymp; @@ -1534,12 +1545,13 @@ class LinkDotScopeVisitor : public AstNVisitor { UASSERT_OBJ(refp || xrefp, nodep, "Unsupported: Non Var(X)Ref attached to interface pin"); - string scopename = refp ? refp->varp()->name() : xrefp->dotted()+"."+xrefp->name(); - string baddot; VSymEnt* okSymp; + string scopename = refp ? refp->varp()->name() : xrefp->dotted() + "." + xrefp->name(); + string baddot; + VSymEnt* okSymp; VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp); UASSERT_OBJ(symp, nodep, "No symbol for interface alias lhs"); - UINFO(5, " Found a linked scope LHS: "<nodep()<nodep() << endl); lhsSymp = symp; } // Remember the alias - can't do it yet because we may have additional symbols to be added, @@ -1558,7 +1570,7 @@ class LinkDotScopeVisitor : public AstNVisitor { public: // CONSTRUCTORS LinkDotScopeVisitor(AstNetlist* rootp, LinkDotState* statep) { - UINFO(4,__FUNCTION__<<": "<isExport()) nodep->v3error("Unsupported: modport export"); VSymEnt* symp = m_curSymp->findIdFallback(nodep->name()); if (!symp) { - nodep->v3error("Modport item not found: "<prettyNameQ()); + nodep->v3error("Modport item not found: " << nodep->prettyNameQ()); } else if (AstNodeFTask* ftaskp = VN_CAST(symp->nodep(), NodeFTask)) { // Make symbol under modport that points at the _interface_'s var, not the modport. nodep->ftaskp(ftaskp); - VSymEnt* subSymp = m_statep->insertSym(m_curSymp, nodep->name(), - ftaskp, NULL/*package*/); + VSymEnt* subSymp + = m_statep->insertSym(m_curSymp, nodep->name(), ftaskp, NULL /*package*/); m_statep->insertScopeAlias(LinkDotState::SAMN_MODPORT, subSymp, symp); } else { - nodep->v3error("Modport item is not a function/task: "<prettyNameQ()); + nodep->v3error("Modport item is not a function/task: " << nodep->prettyNameQ()); } if (m_statep->forScopeCreation()) { // Done with AstModportFTaskRef. // Delete to prevent problems if we dead-delete pointed to ftask - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } virtual void visit(AstModportVarRef* nodep) VL_OVERRIDE { - UINFO(5," fiv: "<findIdFallback(nodep->name()); if (!symp) { - nodep->v3error("Modport item not found: "<prettyNameQ()); + nodep->v3error("Modport item not found: " << nodep->prettyNameQ()); } else if (AstVar* varp = VN_CAST(symp->nodep(), Var)) { // Make symbol under modport that points at the _interface_'s var via the modport. // (Need modport still to test input/output markings) nodep->varp(varp); - m_statep->insertSym(m_curSymp, nodep->name(), nodep, NULL/*package*/); + m_statep->insertSym(m_curSymp, nodep->name(), nodep, NULL /*package*/); } else if (AstVarScope* vscp = VN_CAST(symp->nodep(), VarScope)) { // Make symbol under modport that points at the _interface_'s var, not the modport. nodep->varp(vscp->varp()); - m_statep->insertSym(m_curSymp, nodep->name(), vscp, NULL/*package*/); + m_statep->insertSym(m_curSymp, nodep->name(), vscp, NULL /*package*/); } else { - nodep->v3error("Modport item is not a variable: "<prettyNameQ()); + nodep->v3error("Modport item is not a variable: " << nodep->prettyNameQ()); } if (m_statep->forScopeCreation()) { // Done with AstModportVarRef. // Delete to prevent problems if we dead-delete pointed to variable - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } @@ -1643,7 +1657,7 @@ class LinkDotIfaceVisitor : public AstNVisitor { public: // CONSTRUCTORS LinkDotIfaceVisitor(AstIface* nodep, VSymEnt* curSymp, LinkDotState* statep) { - UINFO(4,__FUNCTION__<<": "<first; VSymEnt* symp = it->second; LinkDotIfaceVisitor(nodep, symp, this); @@ -1672,49 +1686,54 @@ private: // *::user4() -> See LinkDotState // Cleared on Cell // AstVar::user5() // bool. True if pin used in this cell - AstUser3InUse m_inuser3; - AstUser5InUse m_inuser5; + AstUser3InUse m_inuser3; + AstUser5InUse m_inuser5; // TYPES - enum DotPosition { DP_NONE=0, // Not under a DOT - DP_PACKAGE, // {package}:: DOT - DP_SCOPE, // [DOT...] {scope-or-var} DOT - DP_FINAL, // [DOT...] {var-or-func-or-dtype} with no following dots - DP_MEMBER }; // DOT {member-name} [DOT...] + enum DotPosition { + DP_NONE = 0, // Not under a DOT + DP_PACKAGE, // {package}:: DOT + DP_SCOPE, // [DOT...] {scope-or-var} DOT + DP_FINAL, // [DOT...] {var-or-func-or-dtype} with no following dots + DP_MEMBER + }; // DOT {member-name} [DOT...] // STATE - LinkDotState* m_statep; // State, including dotted symbol table - VSymEnt* m_curSymp; // SymEnt for current lookup point - VSymEnt* m_modSymp; // SymEnt for current module - VSymEnt* m_pinSymp; // SymEnt for pin lookups - AstCell* m_cellp; // Current cell - AstNodeModule* m_modp; // Current module - AstNodeFTask* m_ftaskp; // Current function/task - int m_modportNum; // Uniqueify modport numbers + LinkDotState* m_statep; // State, including dotted symbol table + VSymEnt* m_curSymp; // SymEnt for current lookup point + VSymEnt* m_modSymp; // SymEnt for current module + VSymEnt* m_pinSymp; // SymEnt for pin lookups + AstCell* m_cellp; // Current cell + AstNodeModule* m_modp; // Current module + AstNodeFTask* m_ftaskp; // Current function/task + int m_modportNum; // Uniqueify modport numbers struct DotStates { - DotPosition m_dotPos; // Scope part of dotted resolution - VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup - AstDot* m_dotp; // Current dot - bool m_unresolved; // Unresolved, needs help from V3Param - AstNode* m_unlinkedScope;// Unresolved scope, needs corresponding VarXRef - bool m_dotErr; // Error found in dotted resolution, ignore upwards - string m_dotText; // String of dotted names found in below parseref + DotPosition m_dotPos; // Scope part of dotted resolution + VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup + AstDot* m_dotp; // Current dot + bool m_unresolved; // Unresolved, needs help from V3Param + AstNode* m_unlinkedScope; // Unresolved scope, needs corresponding VarXRef + bool m_dotErr; // Error found in dotted resolution, ignore upwards + string m_dotText; // String of dotted names found in below parseref DotStates() { init(NULL); } ~DotStates() {} void init(VSymEnt* curSymp) { - m_dotPos = DP_NONE; m_dotSymp = curSymp; m_dotp = NULL; - m_dotErr = false; m_dotText = ""; - m_unresolved = false; m_unlinkedScope = NULL; + m_dotPos = DP_NONE; + m_dotSymp = curSymp; + m_dotp = NULL; + m_dotErr = false; + m_dotText = ""; + m_unresolved = false; + m_unlinkedScope = NULL; } string ascii() const { - static const char* const names[] - = { "NONE", "PACKAGE", "SCOPE", "FINAL", "MEMBER" }; + static const char* const names[] = {"NONE", "PACKAGE", "SCOPE", "FINAL", "MEMBER"}; std::ostringstream sstr; - sstr<<"ds="<prettyNameQ()<warnMore()+suggest)); + string suggest = m_statep->suggestSymFallback(moduleSymp, nodep->name(), + LinkNodeMatcherVar()); + nodep->v3error("Signal definition not found, and implicit disabled with " + "`default_nettype: " + << nodep->prettyNameQ() << endl + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); } // Bypass looking for suggestions if IMPLICIT is turned off // as there could be thousands of these suppressed in large netlists else if (!nodep->fileline()->warnIsOff(V3ErrorCode::IMPLICIT)) { - string suggest = m_statep->suggestSymFallback( - moduleSymp, nodep->name(), LinkNodeMatcherVar()); - nodep->v3warn(IMPLICIT, "Signal definition not found, creating implicitly: " - <prettyNameQ()<warnMore()+suggest)); + string suggest = m_statep->suggestSymFallback(moduleSymp, nodep->name(), + LinkNodeMatcherVar()); + nodep->v3warn(IMPLICIT, + "Signal definition not found, creating implicitly: " + << nodep->prettyNameQ() << endl + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); } } - AstVar* newp = new AstVar(nodep->fileline(), AstVarType::WIRE, - nodep->name(), VFlagLogicPacked(), 1); + AstVar* newp = new AstVar(nodep->fileline(), AstVarType::WIRE, nodep->name(), + VFlagLogicPacked(), 1); newp->trace(modp->modTrace()); nodep->varp(newp); modp->addStmtp(newp); // Link it to signal list, must add the variable under the module; // current scope might be lower now - m_statep->insertSym(moduleSymp, newp->name(), newp, NULL/*packagep*/); + m_statep->insertSym(moduleSymp, newp->name(), newp, NULL /*packagep*/); } } AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, bool lvalue) { @@ -1765,7 +1786,7 @@ private: AstModportVarRef* snodep = VN_CAST(symp->nodep(), ModportVarRef); AstVar* varp = snodep->varp(); if (lvalue && snodep->direction().isReadOnly()) { - nodep->v3error("Attempt to drive input-only modport: "<prettyNameQ()); + nodep->v3error("Attempt to drive input-only modport: " << nodep->prettyNameQ()); } // else other simulators don't warn about reading, and IEEE doesn't say illegal return varp; } else { @@ -1773,26 +1794,26 @@ private: } } void taskFuncSwapCheck(AstNodeFTaskRef* nodep) { - if (nodep->taskp() && VN_IS(nodep->taskp(), Task) - && VN_IS(nodep, FuncRef)) nodep->v3error("Illegal call of a task as a function: " - <prettyNameQ()); + if (nodep->taskp() && VN_IS(nodep->taskp(), Task) && VN_IS(nodep, FuncRef)) { + nodep->v3error("Illegal call of a task as a function: " << nodep->prettyNameQ()); + } } inline void checkNoDot(AstNode* nodep) { if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) { - //UINFO(9,"ds="<v3error("Syntax Error: Not expecting "<type()<<" under a " - <backp()->type()<<" in dotted expression"); + // UINFO(9, "ds=" << m_ds.ascii() << endl); + nodep->v3error("Syntax Error: Not expecting " << nodep->type() << " under a " + << nodep->backp()->type() + << " in dotted expression"); m_ds.m_dotErr = true; } } - AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, - AstIface* ifacep, AstModport* modportp) { + AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep, + AstModport* modportp) { // Create iface variable, using duplicate var when under same module scope - string varName - = ifacep->name()+"__Vmp__"+modportp->name()+"__Viftop"+cvtToStr(++m_modportNum); - AstIfaceRefDType* idtypep - = new AstIfaceRefDType(fl, modportp->fileline(), - cellp->name(), ifacep->name(), modportp->name()); + string varName = ifacep->name() + "__Vmp__" + modportp->name() + "__Viftop" + + cvtToStr(++m_modportNum); + AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, modportp->fileline(), cellp->name(), + ifacep->name(), modportp->name()); idtypep->cellp(cellp); AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep); varp->isIfaceParent(true); @@ -1800,12 +1821,12 @@ private: return varp; } void markAndCheckPinDup(AstNode* nodep, AstNode* refp, const char* whatp) { - if (refp->user5p() && refp->user5p()!=nodep) { - nodep->v3error("Duplicate "<prettyNameQ()<warnContextPrimary()<user5p()->warnOther() - <<"... Location of original "<user5p()->warnContextSecondary()); + if (refp->user5p() && refp->user5p() != nodep) { + nodep->v3error("Duplicate " << whatp << " connection: " << nodep->prettyNameQ() << endl + << nodep->warnContextPrimary() << endl + << refp->user5p()->warnOther() + << "... Location of original " << whatp << " connection\n" + << refp->user5p()->warnContextSecondary()); } else { refp->user5p(nodep); } @@ -1820,9 +1841,10 @@ private: virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { if (nodep->dead()) return; checkNoDot(nodep); - UINFO(8," "<getNodeSym(nodep); // Until overridden by a SCOPE + m_ds.m_dotSymp = m_curSymp = m_modSymp + = m_statep->getNodeSym(nodep); // Until overridden by a SCOPE m_cellp = NULL; m_modp = nodep; m_modportNum = 0; @@ -1831,7 +1853,7 @@ private: m_ds.m_dotSymp = m_curSymp = m_modSymp = NULL; } virtual void visit(AstScope* nodep) VL_OVERRIDE { - UINFO(8," "<forScopeCreation() && !v3Global.opt.vpi()) { - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } virtual void visit(AstCell* nodep) VL_OVERRIDE { @@ -1865,9 +1888,9 @@ private: // instantiator's symbols else { m_pinSymp = m_statep->getNodeSym(nodep->modp()); - UINFO(4,"(Backto) Link Cell: "<dumpTree(cout, "linkcell:"); } - //if (debug()) { nodep->modp()->dumpTree(cout, "linkcemd:"); } + UINFO(4, "(Backto) Link Cell: " << nodep << endl); + // if (debug()) nodep->dumpTree(cout, "linkcell:"); + // if (debug()) nodep->modp()->dumpTree(cout, "linkcemd:"); iterateChildren(nodep); m_pinSymp = NULL; } @@ -1891,29 +1914,26 @@ private: return; } string suggest - = (nodep->param() - ? m_statep->suggestSymFlat( - m_pinSymp, nodep->name(), LinkNodeMatcherVarParam()) - : m_statep->suggestSymFlat( - m_pinSymp, nodep->name(), LinkNodeMatcherVarIO())); - nodep->v3error(ucfirst(whatp)<<" not found: "<prettyNameQ()<warnMore()+suggest)); - } - else if (AstVar* refp = VN_CAST(foundp->nodep(), Var)) { + = (nodep->param() ? m_statep->suggestSymFlat(m_pinSymp, nodep->name(), + LinkNodeMatcherVarParam()) + : m_statep->suggestSymFlat(m_pinSymp, nodep->name(), + LinkNodeMatcherVarIO())); + nodep->v3error(ucfirst(whatp) + << " not found: " << nodep->prettyNameQ() << endl + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); + } else if (AstVar* refp = VN_CAST(foundp->nodep(), Var)) { if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) { - nodep->v3error(ucfirst(whatp)<<" is not an in/out/inout/param/interface: " - <prettyNameQ()); + nodep->v3error(ucfirst(whatp) << " is not an in/out/inout/param/interface: " + << nodep->prettyNameQ()); } else { nodep->modVarp(refp); markAndCheckPinDup(nodep, refp, whatp); } - } - else if (AstParamTypeDType* refp = VN_CAST(foundp->nodep(), ParamTypeDType)) { + } else if (AstParamTypeDType* refp = VN_CAST(foundp->nodep(), ParamTypeDType)) { nodep->modPTypep(refp); markAndCheckPinDup(nodep, refp, whatp); - } - else { - nodep->v3error(ucfirst(whatp)<<" not found: "<prettyNameQ()); + } else { + nodep->v3error(ucfirst(whatp) << " not found: " << nodep->prettyNameQ()); } } // Early return() above when deleted @@ -1925,12 +1945,12 @@ private: // DOT(PACKAGEREF, PARSEREF(text)) // DOT(DOT(DOT(PARSEREF(text), ... if (nodep->user3SetOnce()) return; - UINFO(8," "<=9) nodep->dumpTree("-dot-in: "); + if (debug() >= 9) nodep->dumpTree("-dot-in: "); m_ds.init(m_curSymp); // Start from current point } m_ds.m_dotp = nodep; // Always, not just at start @@ -1938,23 +1958,24 @@ private: // m_ds.m_dotText communicates the cell prefix between stages if (VN_IS(nodep->lhsp(), PackageRef)) { - //if (!start) { nodep->lhsp()->v3error("Package reference may not be embedded in dotted reference"); m_ds.m_dotErr=true; } + // if (!start) { nodep->lhsp()->v3error("Package reference may not be embedded in + // dotted reference"); m_ds.m_dotErr=true; } m_ds.m_dotPos = DP_PACKAGE; } else { m_ds.m_dotPos = DP_SCOPE; iterateAndNextNull(nodep->lhsp()); - //if (debug()>=9) nodep->dumpTree("-dot-lho: "); + // if (debug()>=9) nodep->dumpTree("-dot-lho: "); } - if (m_ds.m_unresolved && (VN_IS(nodep->lhsp(), CellRef) - || VN_IS(nodep->lhsp(), CellArrayRef))) { + if (m_ds.m_unresolved + && (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) { m_ds.m_unlinkedScope = nodep->lhsp(); } if (!m_ds.m_dotErr) { // Once something wrong, give up // Top 'final' dot RHS is final RHS, else it's a // DOT(DOT(x,*here*),real-rhs) which we consider a RHS - if (start && m_ds.m_dotPos==DP_SCOPE) m_ds.m_dotPos = DP_FINAL; + if (start && m_ds.m_dotPos == DP_SCOPE) m_ds.m_dotPos = DP_FINAL; iterateAndNextNull(nodep->rhsp()); - //if (debug()>=9) nodep->dumpTree("-dot-rho: "); + // if (debug() >= 9) nodep->dumpTree("-dot-rho: "); } if (start) { AstNode* newp; @@ -1964,7 +1985,7 @@ private: // RHS is what we're left with newp = nodep->rhsp()->unlinkFrBack(); } - if (debug()>=9) newp->dumpTree("-dot-out: "); + if (debug() >= 9) newp->dumpTree("-dot-out: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { // Dot midpoint @@ -1986,13 +2007,13 @@ private: } virtual void visit(AstParseRef* nodep) VL_OVERRIDE { if (nodep->user3SetOnce()) return; - UINFO(9," linkPARSEREF "<forPrimary() || m_statep->forPrearray(), - nodep, "ParseRefs should no longer exist"); + UASSERT_OBJ(m_statep->forPrimary() || m_statep->forPrearray(), nodep, + "ParseRefs should no longer exist"); DotStates lastStates = m_ds; bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed if (start) { @@ -2002,13 +2023,14 @@ private: if (m_ds.m_dotPos == DP_MEMBER) { // Found a Var, everything following is membership. {scope}.{var}.HERE {member} AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack(); - AstNode* newp = new AstMemberSel(nodep->fileline(), varEtcp, - VFlagChildDType(), nodep->name()); - if (m_ds.m_dotErr) nodep->unlinkFrBack(); // Avoid circular node loop on errors - else nodep->replaceWith(newp); + AstNode* newp + = new AstMemberSel(nodep->fileline(), varEtcp, VFlagChildDType(), nodep->name()); + if (m_ds.m_dotErr) + nodep->unlinkFrBack(); // Avoid circular node loop on errors + else + nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else { + } else { // string expectWhat; bool allowScope = false; @@ -2019,8 +2041,8 @@ private: expectWhat = "scope/variable"; allowScope = true; allowVar = true; - UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), PackageRef), - m_ds.m_dotp->lhsp(), "Bad package link"); + UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), PackageRef), m_ds.m_dotp->lhsp(), + "Bad package link"); packagep = VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep(); UASSERT_OBJ(packagep, m_ds.m_dotp->lhsp(), "Bad package link"); m_ds.m_dotSymp = m_statep->getNodeSym(packagep); @@ -2031,12 +2053,11 @@ private: expectWhat = "scope/variable"; allowScope = true; allowVar = true; - } else if (m_ds.m_dotPos == DP_NONE - || m_ds.m_dotPos == DP_FINAL) { + } else if (m_ds.m_dotPos == DP_NONE || m_ds.m_dotPos == DP_FINAL) { expectWhat = "variable"; allowVar = true; } else { - UINFO(1,"ds="<findDotted(m_ds.m_dotSymp, - nodep->name(), baddot, okSymp); // Maybe NULL + foundp = m_statep->findDotted(m_ds.m_dotSymp, nodep->name(), baddot, + okSymp); // Maybe NULL } else { foundp = m_ds.m_dotSymp->findIdFallback(nodep->name()); } - if (foundp) UINFO(9," found=se"<parentp(); // Container of the var; probably a module or generate begin - string findName = nodep->name()+"__Viftop"; + VSymEnt* parentEntp + = cellEntp->parentp(); // Container of the var; probably a module or + // generate begin + string findName = nodep->name() + "__Viftop"; VSymEnt* ifaceSymp = parentEntp->findIdFallback(findName); AstVar* ifaceRefVarp = ifaceSymp ? VN_CAST(ifaceSymp->nodep(), Var) : NULL; UASSERT_OBJ(ifaceRefVarp, nodep, - "Can't find interface var ref: "<name()); m_ds.m_dotSymp = foundp; m_ds.m_dotPos = DP_SCOPE; - UINFO(9," cell -> iface varref "<nodep()<fileline(), - ifaceRefVarp, false); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + UINFO(9, " cell -> iface varref " << foundp->nodep() << endl); + AstNode* newp + = new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, false); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (VN_IS(cellp->modp(), NotFoundModule)) { cellp->modNameFileline()->v3error("Cannot find file containing interface: " - <modp()->prettyNameQ()); + << cellp->modp()->prettyNameQ()); } } - } - else if (AstVar* varp = foundToVarp(foundp, nodep, false)) { + } else if (AstVar* varp = foundToVarp(foundp, nodep, false)) { AstIfaceRefDType* ifacerefp = LinkDotState::ifaceRefFromArray(varp->subDTypep()); if (ifacerefp) { UASSERT_OBJ(ifacerefp->ifaceViaCellp(), ifacerefp, "Unlinked interface"); // Really this is a scope reference into an interface - UINFO(9,"varref-ifaceref "<name()); m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp()); m_ds.m_dotPos = DP_SCOPE; ok = true; AstNode* newp = new AstVarRef(nodep->fileline(), varp, false); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (allowVar) { + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (allowVar) { AstNode* newp; if (m_ds.m_dotText != "") { - AstVarXRef* refp = new AstVarXRef(nodep->fileline(), nodep->name(), - m_ds.m_dotText, false); // lvalue'ness computed later + AstVarXRef* refp + = new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText, + false); // lvalue'ness computed later refp->varp(varp); if (varp->attrSplitVar()) { - refp->v3warn(SPLITVAR, varp->prettyNameQ() - << " has split_var metacomment but will not be split because" - << " it is accessed from another module via a dot."); + refp->v3warn( + SPLITVAR, + varp->prettyNameQ() + << " has split_var metacomment but will not be split because" + << " it is accessed from another module via a dot."); varp->attrSplitVar(false); } m_ds.m_dotText = ""; @@ -2128,62 +2153,61 @@ private: newp = refp; } else { newp = new AstUnlinkedRef(nodep->fileline(), - VN_CAST(refp, VarXRef), - refp->name(), + VN_CAST(refp, VarXRef), refp->name(), m_ds.m_unlinkedScope->unlinkFrBack()); m_ds.m_unlinkedScope = NULL; m_ds.m_unresolved = false; - } + } } else { newp = refp; } } else { - AstVarRef* refp = new AstVarRef(nodep->fileline(), varp, false); // lvalue'ness computed later + AstVarRef* refp = new AstVarRef(nodep->fileline(), varp, + false); // lvalue'ness computed later refp->packagep(foundp->packagep()); newp = refp; } - UINFO(9," new "<replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + UINFO(9, " new " << newp << endl); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); m_ds.m_dotPos = DP_MEMBER; ok = true; } - } - else if (AstModport* modportp = VN_CAST(foundp->nodep(), Modport)) { + } else if (AstModport* modportp = VN_CAST(foundp->nodep(), Modport)) { // A scope reference into an interface's modport (not // necessarily at a pin connection) - UINFO(9,"cell-ref-to-modport "<nodep()<nodep() << endl); // Iface was the previously dotted component - if (!m_ds.m_dotSymp - || !VN_IS(m_ds.m_dotSymp->nodep(), Cell) + if (!m_ds.m_dotSymp || !VN_IS(m_ds.m_dotSymp->nodep(), Cell) || !VN_CAST(m_ds.m_dotSymp->nodep(), Cell)->modp() || !VN_IS(VN_CAST(m_ds.m_dotSymp->nodep(), Cell)->modp(), Iface)) { nodep->v3error("Modport not referenced as ." - <prettyNameQ()); + << modportp->prettyNameQ()); } else if (!VN_CAST(m_ds.m_dotSymp->nodep(), Cell)->modp() || !VN_IS(VN_CAST(m_ds.m_dotSymp->nodep(), Cell)->modp(), Iface)) { nodep->v3error("Modport not referenced from underneath an interface: " - <prettyNameQ()); + << modportp->prettyNameQ()); } else { AstCell* cellp = VN_CAST(m_ds.m_dotSymp->nodep(), Cell); UASSERT_OBJ(cellp, nodep, "Modport not referenced from a cell"); AstIface* ifacep = VN_CAST(cellp->modp(), Iface); - //string cellName = m_ds.m_dotText; // Use cellp->name + // string cellName = m_ds.m_dotText; // Use cellp->name m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name()); m_ds.m_dotSymp = m_statep->getNodeSym(modportp); m_ds.m_dotPos = DP_SCOPE; ok = true; - AstVar* varp = makeIfaceModportVar(nodep->fileline(), - cellp, ifacep, modportp); + AstVar* varp = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp); AstVarRef* refp = new AstVarRef(varp->fileline(), varp, false); - nodep->replaceWith(refp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->replaceWith(refp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } - } - else if (AstEnumItem* valuep = VN_CAST(foundp->nodep(), EnumItem)) { + } else if (AstEnumItem* valuep = VN_CAST(foundp->nodep(), EnumItem)) { if (allowVar) { - AstNode* newp = new AstEnumItemRef(nodep->fileline(), - valuep, foundp->packagep()); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + AstNode* newp + = new AstEnumItemRef(nodep->fileline(), valuep, foundp->packagep()); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); ok = true; m_ds.m_dotText = ""; } @@ -2192,37 +2216,38 @@ private: if (!ok) { // Cells/interfaces can't be implicit bool isCell = foundp ? VN_IS(foundp->nodep(), Cell) : false; - bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText=="" && !isCell); + bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText == "" && !isCell); bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name())); if (err) { if (foundp) { nodep->v3error("Found definition of '" - <prettyName() - <<"'"<<" as a "<nodep()->typeName() - <<" but expected a "<prettyName() << "'" + << " as a " << foundp->nodep()->typeName() + << " but expected a " << expectWhat); + } else if (m_ds.m_dotText == "") { + UINFO(7, " ErrParseRef curSymp=se" << cvtToHex(m_curSymp) + << " ds=" << m_ds.ascii() << endl); string suggest = m_statep->suggestSymFallback( m_ds.m_dotSymp, nodep->name(), VNodeMatcher()); - nodep->v3error("Can't find definition of "<prettyNameQ()<warnMore()+suggest)); + nodep->v3error("Can't find definition of " + << expectWhat << ": " << nodep->prettyNameQ() << endl + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); } else { nodep->v3error("Can't find definition of " - <<(!baddot.empty() ? AstNode::prettyNameQ(baddot) - : nodep->prettyNameQ()) - <<" in dotted "<prettyName()<<"'"); + << (!baddot.empty() ? AstNode::prettyNameQ(baddot) + : nodep->prettyNameQ()) + << " in dotted " << expectWhat << ": '" + << m_ds.m_dotText + "." + nodep->prettyName() << "'"); if (okSymp) { okSymp->cellErrorScopes(nodep, AstNode::prettyName(m_ds.m_dotText)); } } m_ds.m_dotErr = true; } - if (checkImplicit) { // Else if a scope is allowed, making a signal won't help error cascade + if (checkImplicit) { // Create if implicit, and also if error (so only complain once) + // Else if a scope is allowed, making a signal won't help error cascade AstVarRef* newp = new AstVarRef(nodep->fileline(), nodep->name(), false); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -2230,9 +2255,7 @@ private: } } } - if (start) { - m_ds = lastStates; - } + if (start) m_ds = lastStates; } virtual void visit(AstVarRef* nodep) VL_OVERRIDE { // VarRef: Resolve its reference @@ -2241,15 +2264,16 @@ private: // No checkNoDot; created and iterated from a parseRef iterateChildren(nodep); if (!nodep->varp()) { - UINFO(9," linkVarRef se"<findIdFallback(nodep->name()); if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : NULL) { nodep->varp(varp); - nodep->packagep(foundp->packagep()); // Generally set by parse, but might be an import + // Generally set by parse, but might be an import + nodep->packagep(foundp->packagep()); } if (!nodep->varp()) { - nodep->v3error("Can't find definition of signal, again: "<prettyNameQ()); + nodep->v3error("Can't find definition of signal, again: " << nodep->prettyNameQ()); } } } @@ -2258,33 +2282,38 @@ private: // We always link even if varp() is set, because the module we choose may change // due to creating new modules, flattening, etc. if (nodep->user3SetOnce()) return; - UINFO(8," "<varp(NULL); // Module that is not in hierarchy. We'll be dead code eliminating it later. + // Module that is not in hierarchy. We'll be dead code eliminating it later. + UINFO(9, "Dead module for " << nodep << endl); + nodep->varp(NULL); } else { string baddot; VSymEnt* okSymp; VSymEnt* dotSymp = m_curSymp; // Start search at current scope - if (nodep->inlinedDots()!="") { // Correct for current scope - dotSymp = m_modSymp; // Dotted lookup is always relative to module, as maybe variable name lower down with same scope name we want to ignore (t_math_divw) + if (nodep->inlinedDots() != "") { // Correct for current scope + // Dotted lookup is always relative to module, as maybe + // variable name lower down with same scope name we want to + // ignore (t_math_divw) + dotSymp = m_modSymp; string inl = AstNode::dedotName(nodep->inlinedDots()); dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp); UASSERT_OBJ(dotSymp, nodep, - "Couldn't resolve inlined scope " - <inlinedDots()); + "Couldn't resolve inlined scope " << AstNode::prettyNameQ(baddot) + << " in: " << nodep->inlinedDots()); } - dotSymp = m_statep->findDotted(dotSymp, nodep->dotted(), baddot, okSymp); // Maybe NULL + dotSymp + = m_statep->findDotted(dotSymp, nodep->dotted(), baddot, okSymp); // Maybe NULL if (!m_statep->forScopeCreation()) { VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot); AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : NULL; nodep->varp(varp); - UINFO(7," Resolved "<varp()) { nodep->v3error("Can't find definition of " - <dotted()+"."+nodep->prettyName()<<"'"); + << AstNode::prettyNameQ(baddot) << " in dotted signal: '" + << nodep->dotted() + "." + nodep->prettyName() << "'"); okSymp->cellErrorScopes(nodep); return; } @@ -2293,8 +2322,8 @@ private: // this and convert to normal VarRefs if (!m_statep->forPrearray() && !m_statep->forScopeCreation()) { if (VN_IS(nodep->dtypep(), IfaceRefDType)) { - AstVarRef* newrefp = new AstVarRef(nodep->fileline(), - nodep->varp(), nodep->lvalue()); + AstVarRef* newrefp + = new AstVarRef(nodep->fileline(), nodep->varp(), nodep->lvalue()); nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -2304,24 +2333,24 @@ private: AstVarScope* vscp = foundp ? VN_CAST(foundp->nodep(), VarScope) : NULL; if (!vscp) { nodep->v3error("Can't find varpin scope of " - <dotted()+"."+nodep->prettyName()<<"'"); + << AstNode::prettyNameQ(baddot) << " in dotted signal: '" + << nodep->dotted() + "." + nodep->prettyName() << "'"); okSymp->cellErrorScopes(nodep); } else { while (vscp->user2p()) { // If V3Inline aliased it, pick up the new signal - UINFO(7," Resolved pre-alias "<user2p(), VarScope); } // Convert the VarXRef to a VarRef, so we don't need // later optimizations to deal with VarXRef. nodep->varp(vscp->varp()); nodep->varScopep(vscp); - UINFO(7," Resolved "<fileline(), vscp, nodep->lvalue()); nodep->replaceWith(newvscp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - UINFO(9," new "<forPrimary() && nodep->isIO() && !m_ftaskp && !nodep->user4()) { - nodep->v3error("Input/output/inout does not appear in port list: " - <prettyNameQ()); + nodep->v3error( + "Input/output/inout does not appear in port list: " << nodep->prettyNameQ()); } } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { if (nodep->user3SetOnce()) return; - UINFO(8," "<lhsp(), PackageRef), - m_ds.m_dotp->lhsp(), "Bad package link"); - UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep(), - m_ds.m_dotp->lhsp(), "Bad package link"); + UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), PackageRef), m_ds.m_dotp->lhsp(), + "Bad package link"); + UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep(), m_ds.m_dotp->lhsp(), + "Bad package link"); nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep()); m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = NULL; @@ -2362,8 +2391,7 @@ private: if (m_ds.m_unresolved && m_ds.m_unlinkedScope) { AstNodeFTaskRef* newftaskp = nodep->cloneTree(false); newftaskp->dotted(m_ds.m_dotText); - AstNode* newp = new AstUnlinkedRef(nodep->fileline(), newftaskp, - nodep->name(), + AstNode* newp = new AstUnlinkedRef(nodep->fileline(), newftaskp, nodep->name(), m_ds.m_unlinkedScope->unlinkFrBack()); m_ds.m_unlinkedScope = NULL; m_ds.m_unresolved = false; @@ -2378,8 +2406,8 @@ private: AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack(); AstNode* argsp = NULL; if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext(); - AstNode* newp = new AstMethodCall(nodep->fileline(), varEtcp, - VFlagChildDType(), nodep->name(), argsp); + AstNode* newp = new AstMethodCall(nodep->fileline(), varEtcp, VFlagChildDType(), + nodep->name(), argsp); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); return; @@ -2389,9 +2417,10 @@ private: if (nodep->packagep() && nodep->taskp()) { // References into packages don't care about cell hierarchy. } else if (!m_modSymp) { - UINFO(9,"Dead module for "<taskp(NULL); // Module that is not in hierarchy. We'll be dead code eliminating it later. - } else if (nodep->dotted()=="" && nodep->taskp()) { + // Module that is not in hierarchy. We'll be dead code eliminating it later. + UINFO(9, "Dead module for " << nodep << endl); + nodep->taskp(NULL); + } else if (nodep->dotted() == "" && nodep->taskp()) { // Earlier should have setup the links // Might be under a BEGIN we're not processing, so don't relink it } else { @@ -2404,53 +2433,56 @@ private: if (nodep->packagep()) { // Look only in specified package dotSymp = m_statep->getNodeSym(nodep->packagep()); } else { - if (nodep->inlinedDots()!="") { // Correct for current scope - dotSymp = m_modSymp; // Dotted lookup is always relative to module, as maybe variable name lower down with same scope name we want to ignore (t_math_divw) + if (nodep->inlinedDots() != "") { // Correct for current scope + // Dotted lookup is always relative to module, as maybe + // variable name lower down with same scope name we want + // to ignore (t_math_divw) + dotSymp = m_modSymp; string inl = AstNode::dedotName(nodep->inlinedDots()); - UINFO(8," Inlined "<findDotted(dotSymp, inl, baddot, okSymp); if (!dotSymp) { okSymp->cellErrorScopes(nodep); nodep->v3fatalSrc("Couldn't resolve inlined scope " - <inlinedDots()); + << AstNode::prettyNameQ(baddot) + << " in: " << nodep->inlinedDots()); } } - dotSymp = m_statep->findDotted(dotSymp, nodep->dotted(), - baddot, okSymp); // Maybe NULL + dotSymp = m_statep->findDotted(dotSymp, nodep->dotted(), baddot, + okSymp); // Maybe NULL } VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot); - AstNodeFTask* taskp = foundp ? VN_CAST(foundp->nodep(), NodeFTask) : NULL; // Maybe NULL + AstNodeFTask* taskp + = foundp ? VN_CAST(foundp->nodep(), NodeFTask) : NULL; // Maybe NULL if (taskp) { nodep->taskp(taskp); nodep->packagep(foundp->packagep()); - UINFO(7," Resolved "<v3error("Found definition of '" - <prettyName() - <<"'"<<" as a "<nodep()->typeName() - <<" but expected a task/function"); + << m_ds.m_dotText << (m_ds.m_dotText == "" ? "" : ".") + << nodep->prettyName() << "'" + << " as a " << foundp->nodep()->typeName() + << " but expected a task/function"); } else if (VN_IS(nodep, New) && m_statep->forPrearray()) { // Resolved in V3Width } else if (nodep->dotted() == "") { - string suggest = m_statep->suggestSymFallback( - dotSymp, nodep->name(), LinkNodeMatcherFTask()); + string suggest = m_statep->suggestSymFallback(dotSymp, nodep->name(), + LinkNodeMatcherFTask()); nodep->v3error("Can't find definition of task/function: " - <prettyNameQ()<warnMore()+suggest)); + << nodep->prettyNameQ() << endl + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); } else { - string suggest = m_statep->suggestSymFallback( - dotSymp, nodep->name(), LinkNodeMatcherFTask()); + string suggest = m_statep->suggestSymFallback(dotSymp, nodep->name(), + LinkNodeMatcherFTask()); nodep->v3error("Can't find definition of " - <dotted()+"."+nodep->prettyName()<<"'\n" - <<(suggest.empty() ? "" : nodep->warnMore()+suggest)); + << AstNode::prettyNameQ(baddot) << " in dotted task/function: '" + << nodep->dotted() + "." + nodep->prettyName() << "'\n" + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); okSymp->cellErrorScopes(nodep); } } @@ -2466,8 +2498,9 @@ private: virtual void visit(AstSelBit* nodep) VL_OVERRIDE { if (nodep->user3SetOnce()) return; iterateAndNextNull(nodep->lhsp()); - if (m_ds.m_dotPos == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart} - UINFO(9," deferring until after a V3Param pass: "<bitp()->unlinkFrBack(); AstCellArrayRef* newp = new AstCellArrayRef(nodep->fileline(), nodep->fromp()->name(), exprp); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } virtual void visit(AstNodePreSel* nodep) VL_OVERRIDE { // Excludes simple AstSelBit, see above if (nodep->user3SetOnce()) return; - if (m_ds.m_dotPos == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart} - nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference"); + if (m_ds.m_dotPos + == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart} + nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of " + "a dotted reference"); m_ds.m_dotErr = true; return; } @@ -2511,21 +2547,21 @@ private: iterateChildren(nodep); } virtual void visit(AstBegin* nodep) VL_OVERRIDE { - UINFO(5," "<name() != "") { m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); - UINFO(5," cur=se"<user3SetOnce()) return; if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { - UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), PackageRef), - m_ds.m_dotp->lhsp(), "Bad package link"); - UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep(), - m_ds.m_dotp->lhsp(), "Bad package link"); + UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), PackageRef), m_ds.m_dotp->lhsp(), + "Bad package link"); + UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep(), m_ds.m_dotp->lhsp(), + "Bad package link"); nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep()); m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = NULL; @@ -2599,20 +2635,17 @@ private: if (AstTypedef* defp = foundp ? VN_CAST(foundp->nodep(), Typedef) : NULL) { nodep->refDTypep(defp->subDTypep()); nodep->packagep(foundp->packagep()); - } - else if (AstParamTypeDType* defp = foundp ? VN_CAST(foundp->nodep(), ParamTypeDType) - : NULL) { + } else if (AstParamTypeDType* defp + = foundp ? VN_CAST(foundp->nodep(), ParamTypeDType) : NULL) { nodep->refDTypep(defp); nodep->packagep(foundp->packagep()); - } - else if (AstClass* defp = foundp ? VN_CAST(foundp->nodep(), Class) : NULL) { + } else if (AstClass* defp = foundp ? VN_CAST(foundp->nodep(), Class) : NULL) { AstClassRefDType* newp = new AstClassRefDType(nodep->fileline(), defp); newp->packagep(foundp->packagep()); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); return; - } - else { + } else { if (foundp) UINFO(1, "Found sym node: " << foundp->nodep() << endl); nodep->v3error("Can't find typedef: " << nodep->prettyNameQ()); } @@ -2625,14 +2658,15 @@ private: checkNoDot(nodep); VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name()); AstNodeFTask* taskp = foundp ? VN_CAST(foundp->nodep(), NodeFTask) : NULL; - if (!taskp) { nodep->v3error("Can't find definition of exported task/function: " - <prettyNameQ()); } - else if (taskp->dpiExport()) { + if (!taskp) { + nodep->v3error( + "Can't find definition of exported task/function: " << nodep->prettyNameQ()); + } else if (taskp->dpiExport()) { nodep->v3error("Function was already DPI Exported, duplicate not allowed: " - <prettyNameQ()); + << nodep->prettyNameQ()); } else { taskp->dpiExport(true); - if (nodep->cname()!="") taskp->cname(nodep->cname()); + if (nodep->cname() != "") taskp->cname(nodep->cname()); } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } @@ -2652,15 +2686,15 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } virtual void visit(AstCellRef* nodep) VL_OVERRIDE { - UINFO(5," AstCellRef: "<=5 || v3Global.opt.dumpTree()>=9) { + if (LinkDotState::debug() >= 5 || v3Global.opt.dumpTree() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree")); } - LinkDotState state (rootp, step); - LinkDotFindVisitor visitor(rootp,&state); - if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) { + LinkDotState state(rootp, step); + LinkDotFindVisitor visitor(rootp, &state); + if (LinkDotState::debug() >= 5 || v3Global.opt.dumpTree() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-find.tree")); } if (step == LDS_PRIMARY || step == LDS_PARAMED) { // Initial link stage, resolve parameters - LinkDotParamVisitor visitors(rootp,&state); - if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) { + LinkDotParamVisitor visitors(rootp, &state); + if (LinkDotState::debug() >= 5 || v3Global.opt.dumpTree() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree")); } - } - else if (step == LDS_ARRAYED) {} - else if (step == LDS_SCOPED) { + } else if (step == LDS_ARRAYED) { + } else if (step == LDS_SCOPED) { // Well after the initial link when we're ready to operate on the flat design, // process AstScope's. This needs to be separate pass after whole hierarchy graph created. - LinkDotScopeVisitor visitors(rootp,&state); - if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) { + LinkDotScopeVisitor visitors(rootp, &state); + if (LinkDotState::debug() >= 5 || v3Global.opt.dumpTree() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree")); } + } else { + v3fatalSrc("Bad case"); } - else v3fatalSrc("Bad case"); state.dump(); state.computeIfaceModSyms(); state.computeIfaceVarSyms(); state.computeScopeAliases(); state.dump(); - LinkDotResolveVisitor visitorb(rootp,&state); + LinkDotResolveVisitor visitorb(rootp, &state); } diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 50244c0b5..4cbb97210 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -41,35 +41,37 @@ private: typedef std::vector BeginStack; // STATE - AstNodeModule* m_modp; // Current module - AstNodeFTask* m_ftaskp; // Current function/task - AstWhile* m_loopp; // Current loop - bool m_loopInc; // In loop increment - int m_modRepeatNum; // Repeat counter - BeginStack m_beginStack; // All begin blocks above current node + AstNodeModule* m_modp; // Current module + AstNodeFTask* m_ftaskp; // Current function/task + AstWhile* m_loopp; // Current loop + bool m_loopInc; // In loop increment + int m_modRepeatNum; // Repeat counter + BeginStack m_beginStack; // All begin blocks above current node // METHODS VL_DEBUG_FUNC; // Declare debug() AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) { // Put label under given node, and if WHILE optionally at end of iteration - UINFO(4,"Create label for "<stmtsp(); - else if (VN_IS(nodep, NodeFTask)) underp = VN_CAST(nodep, NodeFTask)->stmtsp(); - else if (VN_IS(nodep, While)) { + bool under_and_next = true; + if (VN_IS(nodep, Begin)) { + underp = VN_CAST(nodep, Begin)->stmtsp(); + } else if (VN_IS(nodep, NodeFTask)) { + underp = VN_CAST(nodep, NodeFTask)->stmtsp(); + } else if (VN_IS(nodep, While)) { if (endOfIter) { // Note we jump to end of bodysp; a FOR loop has its // increment under incsp() which we don't skip underp = VN_CAST(nodep, While)->bodysp(); } else { - underp = nodep; under_and_next = false; // IE we skip the entire while + underp = nodep; + under_and_next = false; // IE we skip the entire while } - } - else { + } else { nodep->v3fatalSrc("Unknown jump point for break/disable/continue"); return NULL; } @@ -78,7 +80,7 @@ private: // see t_func_return test. while (underp && VN_IS(underp, Var)) underp = underp->nextp(); UASSERT_OBJ(underp, nodep, "Break/disable/continue not under expected statement"); - UINFO(5," Underpoint is "<fileline(), NULL); AstNRelinker repHandle; - if (under_and_next) underp->unlinkFrBackWithNext(&repHandle); - else underp->unlinkFrBack(&repHandle); + if (under_and_next) { + underp->unlinkFrBackWithNext(&repHandle); + } else { + underp->unlinkFrBack(&repHandle); + } repHandle.relink(labelp); labelp->addStmtsp(underp); // Keep any AstVars under the function not under the new JumpLabel - for (AstNode* nextp, *varp=underp; varp; varp = nextp) { + for (AstNode *nextp, *varp = underp; varp; varp = nextp) { nextp = varp->nextp(); - if (VN_IS(varp, Var)) { - labelp->addPrev(varp->unlinkFrBack()); - } + if (VN_IS(varp, Var)) labelp->addPrev(varp->unlinkFrBack()); } return labelp; } @@ -121,7 +124,7 @@ private: m_ftaskp = NULL; } virtual void visit(AstBegin* nodep) VL_OVERRIDE { - UINFO(8," "< loop=count,WHILE(loop>0) { body, loop-- } // Note var can be signed or unsigned based on original number. AstNode* countp = nodep->countp()->unlinkFrBackWithNext(); - string name = string("__Vrepeat")+cvtToStr(m_modRepeatNum++); + string name = string("__Vrepeat") + cvtToStr(m_modRepeatNum++); // Spec says value is integral, if negative is ignored AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name, nodep->findSigned32DType()); varp->usedLoopIdx(true); m_modp->addStmtp(varp); AstNode* initsp = new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), varp, true), - countp); - AstNode* decp = new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), varp, true), - new AstSub(nodep->fileline(), - new AstVarRef(nodep->fileline(), varp, false), - new AstConst(nodep->fileline(), 1))); + new AstVarRef(nodep->fileline(), varp, true), countp); + AstNode* decp = new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true), + new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), + new AstConst(nodep->fileline(), 1))); AstNode* zerosp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0); - AstNode* condp = new AstGtS(nodep->fileline(), - new AstVarRef(nodep->fileline(), varp, false), - zerosp); - AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext(); - AstNode* newp = new AstWhile(nodep->fileline(), - condp, - bodysp, - decp); + AstNode* condp + = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), zerosp); + AstNode* bodysp = nodep->bodysp(); + if (bodysp) bodysp->unlinkFrBackWithNext(); + AstNode* newp = new AstWhile(nodep->fileline(), condp, bodysp, decp); initsp = initsp->addNext(newp); newp = initsp; nodep->replaceWith(newp); @@ -178,67 +176,73 @@ private: AstFunc* funcp = VN_CAST(m_ftaskp, Func); if (!m_ftaskp) { nodep->v3error("Return isn't underneath a task or function"); - } else if (funcp && !nodep->lhsp()) { + } else if (funcp && !nodep->lhsp()) { nodep->v3error("Return underneath a function should have return value"); - } else if (!funcp && nodep->lhsp()) { + } else if (!funcp && nodep->lhsp()) { nodep->v3error("Return underneath a task shouldn't have return value"); } else { if (funcp && nodep->lhsp()) { // Set output variable to return value - nodep->addPrev(new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), - VN_CAST(funcp->fvarp(), Var), true), - nodep->lhsp()->unlinkFrBackWithNext())); + nodep->addPrev(new AstAssign( + nodep->fileline(), + new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), true), + nodep->lhsp()->unlinkFrBackWithNext())); } // Jump to the end of the function call AstJumpLabel* labelp = findAddLabel(m_ftaskp, false); nodep->addPrev(new AstJumpGo(nodep->fileline(), labelp)); } - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } virtual void visit(AstBreak* nodep) VL_OVERRIDE { iterateChildren(nodep); - if (!m_loopp) { nodep->v3error("break isn't underneath a loop"); } - else { + if (!m_loopp) { + nodep->v3error("break isn't underneath a loop"); + } else { // Jump to the end of the loop AstJumpLabel* labelp = findAddLabel(m_loopp, false); nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp)); } - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } virtual void visit(AstContinue* nodep) VL_OVERRIDE { iterateChildren(nodep); - if (!m_loopp) { nodep->v3error("continue isn't underneath a loop"); } - else { + if (!m_loopp) { + nodep->v3error("continue isn't underneath a loop"); + } else { // Jump to the end of this iteration // If a "for" loop then need to still do the post-loop increment AstJumpLabel* labelp = findAddLabel(m_loopp, true); nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp)); } - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } virtual void visit(AstDisable* nodep) VL_OVERRIDE { - UINFO(8," DISABLE "<name() == nodep->name()) { beginp = *it; break; } } - //if (debug()>=9) { UINFO(0,"\n"); beginp->dumpTree(cout, " labeli: "); } - if (!beginp) { nodep->v3error("disable isn't underneath a begin with name: " - <prettyNameQ()); } - else { + // if (debug() >= 9) { UINFO(0, "\n"); beginp->dumpTree(cout, " labeli: "); } + if (!beginp) { + nodep->v3error("disable isn't underneath a begin with name: " << nodep->prettyNameQ()); + } else { // Jump to the end of the named begin AstJumpLabel* labelp = findAddLabel(beginp, false); nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp)); } - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); - //if (debug()>=9) { UINFO(0,"\n"); beginp->dumpTree(cout, " labelo: "); } + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + // if (debug() >= 9) { UINFO(0, "\n"); beginp->dumpTree(cout, " labelo: "); } } virtual void visit(AstVarRef* nodep) VL_OVERRIDE { if (m_loopInc && nodep->varp()) nodep->varp()->usedLoopIdx(true); @@ -263,9 +267,7 @@ public: // Task class functions void V3LinkJump::linkJump(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 062cfa44b..7e6643543 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -35,7 +35,7 @@ // Levelizing class functions struct CmpLevel { - inline bool operator() (const AstNodeModule* lhsp, const AstNodeModule* rhsp) const { + inline bool operator()(const AstNodeModule* lhsp, const AstNodeModule* rhsp) const { return lhsp->level() < rhsp->level(); } }; @@ -43,7 +43,7 @@ struct CmpLevel { void V3LinkLevel::modSortByLevel() { // Sort modules by levels, root down to lowest children // Calculate levels again in case we added modules - UINFO(2,"modSortByLevel()\n"); + UINFO(2, "modSortByLevel()\n"); // level() was computed for us in V3LinkCells @@ -60,20 +60,21 @@ void V3LinkLevel::modSortByLevel() { AstNode* secp = tops[1]; // Complain about second one, as first often intended if (!secp->fileline()->warnIsOff(V3ErrorCode::MULTITOP)) { secp->v3warn(MULTITOP, "Multiple top level modules\n" - <warnMore() - <<"... Suggest see manual; fix the duplicates, or use --top-module to select top." - <warnMore() + << "... Suggest see manual; fix the duplicates, or use " + "--top-module to select top." + << V3Error::warnContextNone()); for (ModVec::const_iterator it = tops.begin(); it != tops.end(); ++it) { AstNode* alsop = *it; - std::cout<warnMore()<<"... Top module "<prettyNameQ()<warnContextSecondary(); + std::cout << secp->warnMore() << "... Top module " << alsop->prettyNameQ() << endl + << alsop->warnContextSecondary(); } } } // Reorder the netlist's modules to have modules in level sorted order stable_sort(mods.begin(), mods.end(), CmpLevel()); // Sort the vector - UINFO(9,"modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666 + UINFO(9, "modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666 for (ModVec::const_iterator it = mods.begin(); it != mods.end(); ++it) { AstNodeModule* nodep = *it; nodep->clearIter(); // Because we didn't iterate to find the node @@ -85,7 +86,7 @@ void V3LinkLevel::modSortByLevel() { AstNodeModule* nodep = *it; v3Global.rootp()->addModulep(nodep); } - UINFO(9,"modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666 + UINFO(9, "modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666 V3Global::dumpCheckGlobalTree("cells", false, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); } @@ -93,11 +94,11 @@ void V3LinkLevel::modSortByLevel() { // Wrapping void V3LinkLevel::wrapTop(AstNetlist* rootp) { - UINFO(2,__FUNCTION__<<": "<modulesp(); if (!oldmodp) { // Later V3LinkDot will warn - UINFO(1,"No module found to wrap\n"); + UINFO(1, "No module found to wrap\n"); return; } AstNodeModule* newmodp = new AstModule(oldmodp->fileline(), string("TOP")); @@ -115,15 +116,13 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) { // Instantiate all packages under the top wrapper // This way all later SCOPE based optimizations can ignore packages - for (AstNodeModule* modp = rootp->modulesp(); modp; modp=VN_CAST(modp->nextp(), NodeModule)) { + for (AstNodeModule* modp = rootp->modulesp(); modp; + modp = VN_CAST(modp->nextp(), NodeModule)) { if (VN_IS(modp, Package)) { - AstCell* cellp = new AstCell(modp->fileline(), - modp->fileline(), + AstCell* cellp = new AstCell(modp->fileline(), modp->fileline(), // Could add __03a__03a="::" to prevent conflict // with module names/"v" - modp->name(), - modp->name(), - NULL, NULL, NULL); + modp->name(), modp->name(), NULL, NULL, NULL); cellp->modp(modp); newmodp->addStmtp(cellp); } @@ -142,13 +141,12 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { NameSet dupNames; // For all modules, skipping over new top for (AstNodeModule* oldmodp = VN_CAST(rootp->modulesp()->nextp(), NodeModule); - oldmodp && oldmodp->level() <= 2; - oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) { + oldmodp && oldmodp->level() <= 2; oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) { for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) { if (AstVar* oldvarp = VN_CAST(subnodep, Var)) { if (oldvarp->isIO()) { if (ioNames.find(oldvarp->name()) != ioNames.end()) { - //UINFO(8, "Multitop dup I/O found: "<name()); } else { ioNames.insert(oldvarp->name()); @@ -160,29 +158,26 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { // For all modules, skipping over new top for (AstNodeModule* oldmodp = VN_CAST(rootp->modulesp()->nextp(), NodeModule); - oldmodp && oldmodp->level() <= 2; - oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) { + oldmodp && oldmodp->level() <= 2; oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) { if (VN_IS(oldmodp, Package)) continue; // Add instance - UINFO(5,"LOOP "<fileline(), - newmodp->fileline(), - (!v3Global.opt.l2Name().empty() - ? v3Global.opt.l2Name() : oldmodp->name()), - oldmodp->name(), - NULL, NULL, NULL); + UINFO(5, "LOOP " << oldmodp << endl); + AstCell* cellp = new AstCell( + newmodp->fileline(), newmodp->fileline(), + (!v3Global.opt.l2Name().empty() ? v3Global.opt.l2Name() : oldmodp->name()), + oldmodp->name(), NULL, NULL, NULL); cellp->modp(oldmodp); newmodp->addStmtp(cellp); // Add pins - for (AstNode* subnodep=oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) { + for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) { if (AstVar* oldvarp = VN_CAST(subnodep, Var)) { - UINFO(8,"VARWRAP "<isIO()) { string name = oldvarp->name(); if (dupNames.find(name) != dupNames.end()) { // __02E=. while __DOT__ looks nicer but will break V3LinkDot - name = oldmodp->name()+"__02E"+name; + name = oldmodp->name() + "__02E" + name; } AstVar* varp = oldvarp->cloneTree(false); @@ -196,7 +191,7 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { } if (varp->direction().isRefOrConstRef()) { varp->v3error("Unsupported: ref/const ref as primary input/output: " - <prettyNameQ()); + << varp->prettyNameQ()); } if (varp->isIO() && v3Global.opt.systemC()) { varp->sc(true); @@ -205,9 +200,9 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { varp->trace(false); } - AstPin* pinp = new AstPin(oldvarp->fileline(), 0, varp->name(), - new AstVarRef(varp->fileline(), - varp, oldvarp->isWritable())); + AstPin* pinp + = new AstPin(oldvarp->fileline(), 0, varp->name(), + new AstVarRef(varp->fileline(), varp, oldvarp->isWritable())); // Skip length and width comp; we know it's a direct assignment pinp->modVarp(oldvarp); cellp->addPinsp(pinp); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index d0e852695..c1ef8ebc5 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -41,24 +41,24 @@ private: // Cleared on netlist // AstNode::user1() -> bool. True if processed // AstNode::user2() -> bool. True if fileline recomputed - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; // TYPES - typedef std::map,AstTypedef*> ImplTypedefMap; + typedef std::map, AstTypedef*> ImplTypedefMap; typedef std::set FileLineSet; // STATE - AstVar* m_varp; // Variable we're under - ImplTypedefMap m_implTypedef; // Created typedefs for each - FileLineSet m_filelines; // Filelines that have been seen - bool m_inAlways; // Inside an always - bool m_inGenerate; // Inside a generate - bool m_needStart; // Need start marker on lower AstParse - AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module - AstNodeModule* m_modp; // Current module - AstNodeFTask* m_ftaskp; // Current task - AstNodeDType* m_dtypep; // Current data type + AstVar* m_varp; // Variable we're under + ImplTypedefMap m_implTypedef; // Created typedefs for each + FileLineSet m_filelines; // Filelines that have been seen + bool m_inAlways; // Inside an always + bool m_inGenerate; // Inside a generate + bool m_needStart; // Need start marker on lower AstParse + AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module + AstNodeModule* m_modp; // Current module + AstNodeFTask* m_ftaskp; // Current task + AstNodeDType* m_dtypep; // Current data type // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -84,8 +84,11 @@ private: // Create a name for the enum, to aid debug and tracing // This name is not guaranteed to be globally unique (due to later parameterization) string above; - if (m_modp && VN_IS(m_modp, Package)) above = m_modp->name()+"::"; - else if (m_modp) above = m_modp->name()+"."; + if (m_modp && VN_IS(m_modp, Package)) { + above = m_modp->name() + "::"; + } else if (m_modp) { + above = m_modp->name() + "."; + } return above + typedefp->name(); } return ""; @@ -115,16 +118,14 @@ private: virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { if (!nodep->user1SetOnce()) { // Process only once. cleanFileline(nodep); - UINFO(5," "<name() == "") { nodep->name(nameFromTypedef(nodep)); // Might still remain "" @@ -142,7 +143,7 @@ private: cleanFileline(nodep); iterateChildren(nodep); if (nodep->rangep()) { - if (!VN_IS(nodep->rangep()->msbp(), Const) + if (!VN_IS(nodep->rangep()->msbp(), Const) // || !VN_IS(nodep->rangep()->lsbp(), Const)) { nodep->v3error("Enum ranges must be integral, per spec"); } @@ -151,18 +152,19 @@ private: int increment = (msb > lsb) ? -1 : 1; int offset_from_init = 0; AstNode* addp = NULL; - for (int i=msb; i!=(lsb+increment); i+=increment, offset_from_init++) { + for (int i = msb; i != (lsb + increment); i += increment, offset_from_init++) { string name = nodep->name() + cvtToStr(i); AstNode* valuep = NULL; - if (nodep->valuep()) valuep = new AstAdd - (nodep->fileline(), - nodep->valuep()->cloneTree(true), - new AstConst(nodep->fileline(), - AstConst::Unsized32(), - offset_from_init)); + if (nodep->valuep()) + valuep = new AstAdd( + nodep->fileline(), nodep->valuep()->cloneTree(true), + new AstConst(nodep->fileline(), AstConst::Unsized32(), offset_from_init)); AstNode* newp = new AstEnumItem(nodep->fileline(), name, NULL, valuep); - if (addp) addp = addp->addNextNull(newp); - else addp = newp; + if (addp) { + addp = addp->addNextNull(newp); + } else { + addp = newp; + } } nodep->replaceWith(addp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -175,15 +177,15 @@ private: // It's a parameter type. Use a different node type for this. AstNodeDType* dtypep = VN_CAST(nodep->valuep(), NodeDType); if (!dtypep) { - nodep->v3error("Parameter type's initial value isn't a type: " - <prettyNameQ()); + nodep->v3error( + "Parameter type's initial value isn't a type: " << nodep->prettyNameQ()); nodep->unlinkFrBack(); } else { dtypep->unlinkFrBack(); - AstNode* newp = new AstParamTypeDType(nodep->fileline(), - nodep->varType(), nodep->name(), - VFlagChildDType(), dtypep); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + AstNode* newp = new AstParamTypeDType(nodep->fileline(), nodep->varType(), + nodep->name(), VFlagChildDType(), dtypep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } return; } @@ -195,18 +197,15 @@ private: switch (nodep->varType()) { case AstVarType::VAR: case AstVarType::PORT: - case AstVarType::WIRE: - nodep->sigUserRWPublic(true); - break; + case AstVarType::WIRE: nodep->sigUserRWPublic(true); break; default: break; } } // We used modTrace before leveling, and we may now // want to turn it off now that we know the levelizations - if (v3Global.opt.traceDepth() - && m_modp - && (m_modp->level()-1) > v3Global.opt.traceDepth()) { + if (v3Global.opt.traceDepth() && m_modp + && (m_modp->level() - 1) > v3Global.opt.traceDepth()) { m_modp->modTrace(false); nodep->trace(false); } @@ -237,15 +236,13 @@ private: // Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it FileLine* newfl = new FileLine(fl); newfl->warnOff(V3ErrorCode::PROCASSWIRE, true); - nodep->addNextHere - (new AstInitial - (newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true), - nodep->valuep()->unlinkFrBack()))); + nodep->addNextHere(new AstInitial( + newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true), + nodep->valuep()->unlinkFrBack()))); } // 3. Under blocks, it's an initial value to be under an assign else { - nodep->addNextHere - (new AstAssign(fl, new AstVarRef(fl, nodep->name(), true), - nodep->valuep()->unlinkFrBack())); + nodep->addNextHere(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true), + nodep->valuep()->unlinkFrBack())); } } if (nodep->isIfaceRef() && !nodep->isIfaceParent()) { @@ -253,7 +250,9 @@ private: // haven't made additional ones for interconnect yet, so assert is simple // What breaks later is we don't have a Scope/Cell representing // the interface to attach to - if (m_modp->level()<=2) nodep->v3error("Unsupported: Interfaced port on top level module"); + if (m_modp->level() <= 2) { + nodep->v3error("Unsupported: Interfaced port on top level module"); + } } } @@ -265,69 +264,61 @@ private: UASSERT_OBJ(typep, nodep, "Attribute not attached to typedef"); typep->attrPublic(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_CLOCK) { + } else if (nodep->attrType() == AstAttrType::VAR_CLOCK) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); nodep->v3warn(DEPRECATED, "sc_clock is deprecated and will be removed"); m_varp->attrScClocked(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_CLOCK_ENABLE) { + } else if (nodep->attrType() == AstAttrType::VAR_CLOCK_ENABLE) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); m_varp->attrClockEn(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) { + } else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); - m_varp->sigUserRWPublic(true); m_varp->sigModPublic(true); + m_varp->sigUserRWPublic(true); + m_varp->sigModPublic(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) { + } else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); m_varp->sigUserRWPublic(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RD) { + } else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RD) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); m_varp->sigUserRdPublic(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RW) { + } else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RW) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); m_varp->sigUserRWPublic(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) { + } else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); m_varp->attrIsolateAssign(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_SFORMAT) { + } else if (nodep->attrType() == AstAttrType::VAR_SFORMAT) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); m_varp->attrSFormat(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_SPLIT_VAR) { + } else if (nodep->attrType() == AstAttrType::VAR_SPLIT_VAR) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); if (!VN_IS(m_modp, Module)) { - m_varp->v3warn(SPLITVAR, m_varp->prettyNameQ() << " has split_var metacomment, " - "but will not be split because it is not declared in a module."); + m_varp->v3warn( + SPLITVAR, + m_varp->prettyNameQ() + << " has split_var metacomment, " + "but will not be split because it is not declared in a module."); } else { m_varp->attrSplitVar(true); } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_SC_BV) { + } else if (nodep->attrType() == AstAttrType::VAR_SC_BV) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); m_varp->attrScBv(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_CLOCKER) { + } else if (nodep->attrType() == AstAttrType::VAR_CLOCKER) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); m_varp->attrClocker(VVarAttrClocker::CLOCKER_YES); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else if (nodep->attrType() == AstAttrType::VAR_NO_CLOCKER) { + } else if (nodep->attrType() == AstAttrType::VAR_NO_CLOCKER) { UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); m_varp->attrClocker(VVarAttrClocker::CLOCKER_NO); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); @@ -351,36 +342,38 @@ private: virtual void visit(AstDefImplicitDType* nodep) VL_OVERRIDE { cleanFileline(nodep); - UINFO(8," DEFIMPLICIT "<containerp(), nodep->name())); + ImplTypedefMap::iterator it + = m_implTypedef.find(make_pair(nodep->containerp(), nodep->name())); if (it != m_implTypedef.end()) { defp = it->second; } else { // Definition must be inserted right after the variable (etc) that needed it // AstVar, AstTypedef, AstNodeFTask are common containers AstNode* backp = nodep->backp(); - for (; backp; backp=backp->backp()) { - if (VN_IS(backp, Var)) break; - else if (VN_IS(backp, Typedef)) break; - else if (VN_IS(backp, NodeFTask)) break; + for (; backp; backp = backp->backp()) { + if (VN_IS(backp, Var) || VN_IS(backp, Typedef) || VN_IS(backp, NodeFTask)) break; } UASSERT_OBJ(backp, nodep, "Implicit enum/struct type created under unexpected node type"); - AstNodeDType* dtypep = nodep->childDTypep(); dtypep->unlinkFrBack(); - if (VN_IS(backp, Typedef)) { // A typedef doesn't need us to make yet another level of typedefing + AstNodeDType* dtypep = nodep->childDTypep(); + dtypep->unlinkFrBack(); + if (VN_IS(backp, Typedef)) { + // A typedef doesn't need us to make yet another level of typedefing // For typedefs just remove the AstRefDType level of abstraction nodep->replaceWith(dtypep); VL_DO_DANGLING(nodep->deleteTree(), nodep); return; } else { - defp = new AstTypedef(nodep->fileline(), nodep->name(), NULL, - VFlagChildDType(), dtypep); - m_implTypedef.insert(make_pair(make_pair(nodep->containerp(), defp->name()), defp)); + defp = new AstTypedef(nodep->fileline(), nodep->name(), NULL, VFlagChildDType(), + dtypep); + m_implTypedef.insert( + make_pair(make_pair(nodep->containerp(), defp->name()), defp)); backp->addNextHere(defp); } } @@ -391,19 +384,22 @@ private: virtual void visit(AstForeach* nodep) VL_OVERRIDE { // FOREACH(array,loopvars,body) // -> BEGIN(declare vars, loopa=lowest; WHILE(loopa<=highest, ... body)) - //nodep->dumpTree(cout, "-foreach-old:"); + // nodep->dumpTree(cout, "-foreach-old:"); AstNode* newp = nodep->bodysp()->unlinkFrBackWithNext(); AstNode* arrayp = nodep->arrayp(); int dimension = 1; // Must do innermost (last) variable first AstNode* firstVarsp = nodep->varsp()->unlinkFrBackWithNext(); AstNode* lastVarsp = firstVarsp; - while (lastVarsp->nextp()) { lastVarsp = lastVarsp->nextp(); dimension++; } - for (AstNode* varsp = lastVarsp; varsp; varsp=varsp->backp()) { - UINFO(9,"foreachVar "<nextp()) { + lastVarsp = lastVarsp->nextp(); + dimension++; + } + for (AstNode* varsp = lastVarsp; varsp; varsp = varsp->backp()) { + UINFO(9, "foreachVar " << varsp << endl); FileLine* fl = varsp->fileline(); - AstNode* varp = new AstVar(fl, AstVarType::BLOCKTEMP, - varsp->name(), nodep->findSigned32DType()); + AstNode* varp + = new AstVar(fl, AstVarType::BLOCKTEMP, varsp->name(), nodep->findSigned32DType()); // These will be the left and right dimensions and size of the array: AstNode* leftp = new AstAttrOf(fl, AstAttrType::DIM_LEFT, new AstVarRef(fl, arrayp->name(), false), @@ -416,19 +412,16 @@ private: new AstConst(fl, dimension)); AstNode* stmtsp = varp; // Assign left-dimension into the loop var: - stmtsp->addNext(new AstAssign - (fl, new AstVarRef(fl, varp->name(), true), leftp)); + stmtsp->addNext(new AstAssign(fl, new AstVarRef(fl, varp->name(), true), leftp)); // This will turn into a constant bool for static arrays AstNode* notemptyp = new AstGt(fl, sizep, new AstConst(fl, 0)); // This will turn into a bool constant, indicating whether // we count the loop variable up or down: - AstNode* countupp = new AstLte(fl, leftp->cloneTree(true), - rightp->cloneTree(true)); + AstNode* countupp = new AstLte(fl, leftp->cloneTree(true), rightp->cloneTree(true)); AstNode* comparep = new AstCond( fl, countupp->cloneTree(true), // Left increments up to right - new AstLte(fl, new AstVarRef(fl, varp->name(), false), - rightp->cloneTree(true)), + new AstLte(fl, new AstVarRef(fl, varp->name(), false), rightp->cloneTree(true)), // Left decrements down to right new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp)); // This will reduce to comparep for static arrays @@ -436,16 +429,15 @@ private: AstNode* incp = new AstAssign( fl, new AstVarRef(fl, varp->name(), true), new AstAdd(fl, new AstVarRef(fl, varp->name(), false), - new AstCond(fl, countupp, - new AstConst(fl, 1), - new AstConst(fl, -1)))); + new AstCond(fl, countupp, new AstConst(fl, 1), new AstConst(fl, -1)))); stmtsp->addNext(new AstWhile(fl, condp, newp, incp)); newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true); dimension--; } - //newp->dumpTree(cout, "-foreach-new:"); + // newp->dumpTree(cout, "-foreach-new:"); VL_DO_DANGLING(firstVarsp->deleteTree(), firstVarsp); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { @@ -472,23 +464,15 @@ private: iterateChildren(nodep); m_valueModp = upperValueModp; } - virtual void visit(AstInitial* nodep) VL_OVERRIDE { - visitIterateNoValueMod(nodep); - } - virtual void visit(AstFinal* nodep) VL_OVERRIDE { - visitIterateNoValueMod(nodep); - } + virtual void visit(AstInitial* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); } + virtual void visit(AstFinal* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); } virtual void visit(AstAlways* nodep) VL_OVERRIDE { m_inAlways = true; visitIterateNoValueMod(nodep); m_inAlways = false; } - virtual void visit(AstCover* nodep) VL_OVERRIDE { - visitIterateNoValueMod(nodep); - } - virtual void visit(AstRestrict* nodep) VL_OVERRIDE { - visitIterateNoValueMod(nodep); - } + virtual void visit(AstCover* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); } + virtual void visit(AstRestrict* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); } virtual void visit(AstBegin* nodep) VL_OVERRIDE { V3Config::applyCoverageBlock(m_modp, nodep); @@ -502,10 +486,8 @@ private: // It's not FOR(BEGIN(...)) but we earlier changed it to BEGIN(FOR(...)) if (nodep->genforp() && nodep->name() == "") { nodep->name("genblk"); - } - else if (nodep->generate() && nodep->name() == "" - && (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf)) - && !nestedIf) { + } else if (nodep->generate() && nodep->name() == "" + && (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf)) && !nestedIf) { nodep->name("genblk"); } iterateChildren(nodep); @@ -542,9 +524,7 @@ public: // Link class functions void V3LinkParse::linkParse(AstNetlist* rootp) { - UINFO(4,__FUNCTION__<<": "<= 6); } diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 6bea4587c..904c4882e 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -64,7 +64,7 @@ private: // TODO: could move to V3LinkParse to get them out of the way of elaboration virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { // Module: Create sim table for entire module and iterate - UINFO(8,"MODULE "<dead()) return; AstNodeModule* origModp = m_modp; int origSenitemCvtNum = m_senitemCvtNum; @@ -110,9 +110,7 @@ private: virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE { // VarRef: Resolve its reference - if (nodep->varp()) { - nodep->varp()->usedParam(true); - } + if (nodep->varp()) { nodep->varp()->usedParam(true); } iterateChildren(nodep); } @@ -123,9 +121,7 @@ private: m_ftaskp = nodep; iterateChildren(nodep); m_ftaskp = NULL; - if (nodep->dpiExport()) { - nodep->scopeNamep(new AstScopeName(nodep->fileline())); - } + if (nodep->dpiExport()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); } } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { iterateChildren(nodep); @@ -142,34 +138,29 @@ private: // This is a bit unfortunate as we haven't done width resolution // and any width errors will look a bit odd, but it works. AstNode* sensp = nodep->sensp(); - if (sensp - && !VN_IS(sensp, NodeVarRef) - && !VN_IS(sensp, Const)) { + if (sensp && !VN_IS(sensp, NodeVarRef) && !VN_IS(sensp, Const)) { // Make a new temp wire - string newvarname = "__Vsenitemexpr"+cvtToStr(++m_senitemCvtNum); - AstVar* newvarp = new AstVar(sensp->fileline(), - AstVarType::MODULETEMP, newvarname, + string newvarname = "__Vsenitemexpr" + cvtToStr(++m_senitemCvtNum); + AstVar* newvarp = new AstVar(sensp->fileline(), AstVarType::MODULETEMP, newvarname, VFlagLogicPacked(), 1); // We can't just add under the module, because we may be // inside a generate, begin, etc. // We know a SenItem should be under a SenTree/Always etc, // we we'll just hunt upwards AstNode* addwherep = nodep; // Add to this element's next - while (VN_IS(addwherep, SenItem) - || VN_IS(addwherep, SenTree)) { + while (VN_IS(addwherep, SenItem) || VN_IS(addwherep, SenTree)) { addwherep = addwherep->backp(); } if (!VN_IS(addwherep, Always)) { // Assertion perhaps? - sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under some complicated block"); + sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under " + "some complicated block"); addwherep = m_modp; } addwherep->addNext(newvarp); sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, false)); - AstAssignW* assignp = new AstAssignW - (sensp->fileline(), - new AstVarRef(sensp->fileline(), newvarp, true), - sensp); + AstAssignW* assignp = new AstAssignW( + sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, true), sensp); addwherep->addNext(assignp); } } else { // Old V1995 sensitivity list; we'll probably mostly ignore @@ -178,18 +169,21 @@ private: did = 0; if (AstNodeSel* selp = VN_CAST(nodep->sensp(), NodeSel)) { AstNode* fromp = selp->fromp()->unlinkFrBack(); - selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp); + selp->replaceWith(fromp); + VL_DO_DANGLING(selp->deleteTree(), selp); did = 1; } // NodeSel doesn't include AstSel.... if (AstSel* selp = VN_CAST(nodep->sensp(), Sel)) { AstNode* fromp = selp->fromp()->unlinkFrBack(); - selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp); + selp->replaceWith(fromp); + VL_DO_DANGLING(selp->deleteTree(), selp); did = 1; } if (AstNodePreSel* selp = VN_CAST(nodep->sensp(), NodePreSel)) { AstNode* fromp = selp->lhsp()->unlinkFrBack(); - selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp); + selp->replaceWith(fromp); + VL_DO_DANGLING(selp->deleteTree(), selp); did = 1; } } @@ -213,10 +207,12 @@ private: // So we replicate it in another node // Note that V3Param knows not to replace AstVarRef's under AstAttrOf's AstNode* basefromp = AstArraySel::baseFromp(nodep); - if (AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) { // Maybe varxref - so need to clone + if (AstNodeVarRef* varrefp + = VN_CAST(basefromp, NodeVarRef)) { // Maybe varxref - so need to clone nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE, varrefp->cloneTree(false))); - } else if (AstUnlinkedRef* uvxrp = VN_CAST(basefromp, UnlinkedRef)) { // Maybe unlinked - so need to clone + } else if (AstUnlinkedRef* uvxrp + = VN_CAST(basefromp, UnlinkedRef)) { // Maybe unlinked - so need to clone nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE, uvxrp->cloneTree(false))); } else if (AstMemberSel* fromp = VN_CAST(basefromp, MemberSel)) { @@ -227,11 +223,11 @@ private: fromp->cloneTree(false))); } else if (VN_IS(basefromp, Replicate)) { // From {...}[...] syntax in IEEE 2017 - if (basefromp) { UINFO(1," Related node: "<v3error("Unsupported: Select of concatenation"); nodep = NULL; } else { - if (basefromp) { UINFO(1," Related node: "<v3fatalSrc("Illegal bit select; no signal/member being extracted from"); } } @@ -253,20 +249,21 @@ private: if (nodep->pragType() == AstPragmaType::PUBLIC_MODULE) { UASSERT_OBJ(m_modp, nodep, "PUBLIC_MODULE not under a module"); m_modp->modPublic(true); - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) { + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) { UASSERT_OBJ(m_ftaskp, nodep, "PUBLIC_TASK not under a task"); m_ftaskp->taskPublic(true); m_modp->modPublic(true); // Need to get to the task... - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) { - if (!v3Global.opt.coverageLine()) { // No need for block statements; may optimize better without - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) { + if (!v3Global.opt.coverageLine()) { // No need for block statements; may optimize + // better without + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } - } - else { + } else { iterateChildren(nodep); } } @@ -278,10 +275,10 @@ private: string fmt; for (string::const_iterator it = format.begin(); it != format.end(); ++it) { char ch = *it; - if (!inPct && ch=='%') { + if (!inPct && ch == '%') { inPct = true; fmt = ch; - } else if (inPct && (isdigit(ch) || ch=='.' || ch=='-')) { + } else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) { fmt += ch; } else if (inPct) { inPct = false; @@ -290,15 +287,21 @@ private: case '%': // %% - just output a % break; case 'm': // %m - auto insert "name" - if (isScan) { nodep->v3error("Unsupported: %m in $fscanf"); fmt = ""; } + if (isScan) { + nodep->v3error("Unsupported: %m in $fscanf"); + fmt = ""; + } break; case 'l': // %l - auto insert "library" - if (isScan) { nodep->v3error("Unsupported: %l in $fscanf"); fmt = ""; } + if (isScan) { + nodep->v3error("Unsupported: %l in $fscanf"); + fmt = ""; + } if (m_modp) fmt = VString::quotePercent(m_modp->prettyName()); break; default: // Most operators, just move to next argument if (!V3Number::displayedFmtLegal(ch)) { - nodep->v3error("Unknown $display-like format code: '%"<v3error("Unknown $display-like format code: '%" << ch << "'"); } else { if (!argp) { nodep->v3error("Missing arguments for $display-like format"); @@ -322,10 +325,10 @@ private: skipCount--; continue; } - AstConst *constp = VN_CAST(argp, Const); + AstConst* constp = VN_CAST(argp, Const); bool isFromString = (constp) ? constp->num().isFromString() : false; if (isFromString) { - int numchars = argp->dtypep()->width()/8; + int numchars = argp->dtypep()->width() / 8; string str(numchars, ' '); // now scan for % operators bool inpercent = false; @@ -338,23 +341,18 @@ private: } else if (inpercent) { inpercent = 0; switch (c) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '.': - inpercent = true; - break; - case '%': - break; + case '0' ... '9': + case '.': inpercent = true; break; + case '%': break; default: - if (V3Number::displayedFmtLegal(c)) { - skipCount++; - } + if (V3Number::displayedFmtLegal(c)) { skipCount++; } } } } newFormat.append(str); - AstNode *nextp = argp->nextp(); - argp->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(argp), argp); + AstNode* nextp = argp->nextp(); + argp->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(argp), argp); argp = nextp; } else { newFormat.append("%?"); // V3Width to figure it out @@ -366,7 +364,9 @@ private: } void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) { - if (!filep) nodep->v3error("Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable"); + if (!filep) { + nodep->v3error("Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable"); + } if (filep && filep->varp()) filep->varp()->attrFileDescr(true); } @@ -402,7 +402,8 @@ private: iterateChildren(nodep); // Cleanup old-school displays without format arguments if (!nodep->hasFormat()) { - UASSERT_OBJ(nodep->text()=="", nodep, "Non-format $sformatf should have \"\" format"); + UASSERT_OBJ(nodep->text() == "", nodep, + "Non-format $sformatf should have \"\" format"); if (VN_IS(nodep->exprsp(), Const) && VN_CAST(nodep->exprsp(), Const)->num().isFromString()) { AstConst* fmtp = VN_CAST(nodep->exprsp()->unlinkFrBack(), Const); @@ -421,14 +422,14 @@ private: } virtual void visit(AstUdpTable* nodep) VL_OVERRIDE { - UINFO(5,"UDPTABLE "<stmtsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* varp = VN_CAST(stmtp, Var)) { if (varp->isReadOnly()) { } else if (varp->isWritable()) { @@ -438,16 +439,15 @@ private: varoutp = varp; // Tie off m_modp->addStmtp(new AstAssignW( - varp->fileline(), - new AstVarRef(varp->fileline(), varp, true), - new AstConst(varp->fileline(), - AstConst::LogicFalse()))); + varp->fileline(), new AstVarRef(varp->fileline(), varp, true), + new AstConst(varp->fileline(), AstConst::LogicFalse()))); } else { varp->v3error("Only inputs and outputs are allowed in udp modules"); } } } - nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } } @@ -531,7 +531,7 @@ public: // Link class functions void V3LinkResolve::linkResolve(AstNetlist* rootp) { - UINFO(4,__FUNCTION__<<": "<v3errorEnd(nsstr); } else { @@ -79,13 +82,13 @@ V3Number::V3Number(VerilogStringLiteral, AstNode* nodep, const string& str) { // Create a number using a verilog string as the value, thus 8 bits per character. // cppcheck bug - doesn't see init() resets these // cppcheck: Member variable 'm_sized/m_width' is not initialized in the constructor - init(nodep, str.length()*8); + init(nodep, str.length() * 8); m_fromString = true; - for (unsigned pos=0; posopAdd(product, addend); if (product.bitsValue(width(), 4)) { // Overflowed static int warned = 0; - v3error("Too many digits for "< 1) { - v3error("Mixing X/Z/? with digits not legal in decimal constant: "< 1) { + v3error("Mixing X/Z/? with digits not legal in decimal constant: " << value_startp); } - } - else { + } else { // Convert bin/octal number to hex - for (const char* cp=value_startp+strlen(value_startp)-1; - cp >= value_startp; - cp--) { - if (*cp!='_' && *cp!='0' && obit>=width()) { - v3error("Too many digits for "<= value_startp; cp--) { + if (*cp != '_' && *cp != '0' && obit >= width()) { + v3error("Too many digits for " << width() << " bit number: " << sourcep); break; } - switch(tolower(base)) { + switch (tolower(base)) { case 'b': { - switch(tolower(*cp)) { + switch (tolower(*cp)) { case '0': setBit(obit++, 0); break; case '1': setBit(obit++, 1); break; - case 'z': case '?': setBit(obit++, 'z'); break; + case 'z': + case '?': setBit(obit++, 'z'); break; case 'x': setBit(obit++, 'x'); break; case '_': break; - default: - v3error("Illegal character in binary constant: "<<*cp); + default: v3error("Illegal character in binary constant: " << *cp); } - break; + break; } case 'o': case 'c': { - switch(tolower(*cp)) { + switch (tolower(*cp)) { + // clang-format off case '0': setBit(obit++, 0); setBit(obit++, 0); setBit(obit++, 0); break; case '1': setBit(obit++, 1); setBit(obit++, 0); setBit(obit++, 0); break; case '2': setBit(obit++, 0); setBit(obit++, 1); setBit(obit++, 0); break; @@ -260,19 +274,19 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) case '5': setBit(obit++, 1); setBit(obit++, 0); setBit(obit++, 1); break; case '6': setBit(obit++, 0); setBit(obit++, 1); setBit(obit++, 1); break; case '7': setBit(obit++, 1); setBit(obit++, 1); setBit(obit++, 1); break; - case 'z': case '?': - setBit(obit++, 'z'); setBit(obit++, 'z'); setBit(obit++, 'z'); break; - case 'x': - setBit(obit++, 'x'); setBit(obit++, 'x'); setBit(obit++, 'x'); break; + case 'z': + case '?': setBit(obit++, 'z'); setBit(obit++, 'z'); setBit(obit++, 'z'); break; + case 'x': setBit(obit++, 'x'); setBit(obit++, 'x'); setBit(obit++, 'x'); break; case '_': break; - default: - v3error("Illegal character in octal constant"); + // clang-format on + default: v3error("Illegal character in octal constant"); } break; } case 'h': { - switch(tolower(*cp)) { + switch (tolower(*cp)) { + // clang-format off case '0': setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); break; case '1': setBit(obit++,1); setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); break; case '2': setBit(obit++,0); setBit(obit++,1); setBit(obit++,0); setBit(obit++,0); break; @@ -289,31 +303,30 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) case 'd': setBit(obit++,1); setBit(obit++,0); setBit(obit++,1); setBit(obit++,1); break; case 'e': setBit(obit++,0); setBit(obit++,1); setBit(obit++,1); setBit(obit++,1); break; case 'f': setBit(obit++,1); setBit(obit++,1); setBit(obit++,1); setBit(obit++,1); break; - case 'z': case '?': - setBit(obit++,'z'); setBit(obit++,'z'); setBit(obit++,'z'); setBit(obit++,'z'); break; - case 'x': - setBit(obit++,'x'); setBit(obit++,'x'); setBit(obit++,'x'); setBit(obit++,'x'); break; - case '_': break; - default: - v3error("Illegal character in hex constant: "<<*cp); + case 'z': + case '?': setBit(obit++,'z'); setBit(obit++,'z'); setBit(obit++,'z'); setBit(obit++,'z'); break; + case 'x': setBit(obit++,'x'); setBit(obit++,'x'); setBit(obit++,'x'); setBit(obit++,'x'); break; + // clang-format on + case '_': break; + default: v3error("Illegal character in hex constant: " << *cp); } break; } - default: - v3error("Illegal base character: "<0; bit--) if (num & (VL_ULL(1)< 0; bit--) { + if (num & (VL_ULL(1) << bit)) return bit; + } return 0; } @@ -335,65 +350,78 @@ int V3Number::log2b(uint32_t num) { // Setters V3Number& V3Number::setZero() { - for (int i=0; i>VL_ULL(32)) & VL_ULL(0xffffffff); + m_value[1] = (value >> VL_ULL(32)) & VL_ULL(0xffffffff); opCleanThis(); return *this; } V3Number& V3Number::setLong(uint32_t value) { - for (int i=0; i=0; bit--) { - if (bitIs0(bit)) str+='0'; - else if (bitIs1(bit)) str+='1'; - else if (bitIsZ(bit)) str+='z'; - else str+='x'; + int bit = width() - 1; + if (fmtsize == "0") + while (bit && bitIs0(bit)) bit--; + for (; bit >= 0; bit--) { + if (bitIs0(bit)) { + str += '0'; + } else if (bitIs1(bit)) { + str += '1'; + } else if (bitIsZ(bit)) { + str += 'z'; + } else { + str += 'x'; + } } return str; } case 'o': { - int bit = width()-1; - if (fmtsize == "0") while (bit && bitIs0(bit)) bit--; - while ((bit%3)!=2) bit++; - for (; bit>0; bit -= 3) { - int v = bitsValue(bit-2, 3); + int bit = width() - 1; + if (fmtsize == "0") + while (bit && bitIs0(bit)) bit--; + while ((bit % 3) != 2) bit++; + for (; bit > 0; bit -= 3) { + int v = bitsValue(bit - 2, 3); str += static_cast('0' + v); } return str; } case 'h': case 'x': { - int bit = width()-1; - if (fmtsize == "0") while (bit && bitIs0(bit)) bit--; - while ((bit%4)!=3) bit++; - for (; bit>0; bit -= 4) { - int v = bitsValue(bit-3, 4); - if (v>=10) str += static_cast('a' + v - 10); - else str += static_cast('0' + v); + int bit = width() - 1; + if (fmtsize == "0") + while (bit && bitIs0(bit)) bit--; + while ((bit % 4) != 3) bit++; + for (; bit > 0; bit -= 4) { + int v = bitsValue(bit - 3, 4); + if (v >= 10) { + str += static_cast('a' + v - 10); + } else { + str += static_cast('0' + v); + } } return str; } case 'c': { - if (width()>8) fl->v3warn(WIDTH, "$display-like format of %c format of > 8 bit value"); + if (width() > 8) fl->v3warn(WIDTH, "$display-like format of %c format of > 8 bit value"); unsigned int v = bitsValue(0, 8); - char strc[2]; strc[0] = v&0xff; strc[1] = '\0'; + char strc[2]; + strc[0] = v & 0xff; + strc[1] = '\0'; str = strc; return str; } case 's': { // Spec says always drop leading zeros, this isn't quite right, we space pad. - int bit = this->width()-1; + int bit = this->width() - 1; bool start = true; - while ((bit%8)!=7) bit++; - for (; bit>=0; bit -= 8) { - int v = bitsValue(bit-7, 8); + while ((bit % 8) != 7) bit++; + for (; bit >= 0; bit -= 8) { + int v = bitsValue(bit - 7, 8); if (!start || v) { - str += static_cast((v==0) ? ' ' : v); + str += static_cast((v == 0) ? ' ' : v); start = false; // Drop leading 0s } else { if (fmtsize != "0") str += ' '; @@ -605,7 +659,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { str = cvtToStr(toUQuad()); } } - bool zeropad = fmtsize.length()>0 && fmtsize[0]=='0'; + bool zeropad = fmtsize.length() > 0 && fmtsize[0] == '0'; // fmtsize might have changed since we parsed the %fmtsize size_t fmtsizen = static_cast(atoi(fmtsize.c_str())); str = displayPad(fmtsizen, (zeropad ? '0' : ' '), left, str); @@ -622,7 +676,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { // 'l' // Library - converted to text by V3LinkResolve // 'p' // Packed - converted to another code by V3Width case 'u': { // Packed 2-state - for (int i=0; i((m_value[i] >> 0) & 0xff); str += static_cast((m_value[i] >> 8) & 0xff); str += static_cast((m_value[i] >> 16) & 0xff); @@ -631,7 +685,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { return str; } case 'z': { // Packed 4-state - for (int i=0; i((m_value[i] >> 0) & 0xff); str += static_cast((m_value[i] >> 8) & 0xff); str += static_cast((m_value[i] >> 16) & 0xff); @@ -644,12 +698,18 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { return str; } case 'v': { // Strength - int bit = width()-1; - for (; bit>=0; bit--) { - if (bitIs0(bit)) str += "St0 "; // Yes, always a space even for bit 0 - else if (bitIs1(bit)) str += "St1 "; - else if (bitIsZ(bit)) str += "StZ "; - else str += "StX"; + int bit = width() - 1; + for (; bit >= 0; bit--) { + if (bitIs0(bit)) { + str += "St0 "; + } // Yes, always a space even for bit 0 + else if (bitIs1(bit)) { + str += "St1 "; + } else if (bitIsZ(bit)) { + str += "StZ "; + } else { + str += "StX"; + } } return str; } @@ -659,7 +719,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { return str; } default: - fl->v3fatalSrc("Unknown $display-like format code for number: %"<v3fatalSrc("Unknown $display-like format code for number: %" << pos[0]); return "ERR"; } } @@ -675,16 +735,16 @@ string V3Number::toDecimalS() const { } string V3Number::toDecimalU() const { - int maxdecwidth = (width()+3)*4/3; + int maxdecwidth = (width() + 3) * 4 / 3; // Or (maxdecwidth+7)/8], but can't have more than 4 BCD bits per word - V3Number bcd (this, maxdecwidth+4); - V3Number tmp (this, maxdecwidth+4); - V3Number tmp2 (this, maxdecwidth+4); + V3Number bcd(this, maxdecwidth + 4); + V3Number tmp(this, maxdecwidth + 4); + V3Number tmp2(this, maxdecwidth + 4); - int from_bit = width()-1; + int from_bit = width() - 1; // Skip all leading zeros - for (; from_bit >= 0 && bitIs0(from_bit); --from_bit); + for (; from_bit >= 0 && bitIs0(from_bit); --from_bit) {} // Double-dabble algorithm for (; from_bit >= 0; --from_bit) { // Any digits >= 5 need an add 3 (via tmp) @@ -692,7 +752,7 @@ string V3Number::toDecimalU() const { if (bcd.bitsValue(nibble_bit, 4) >= 5) { tmp2.setAllBits0(); tmp2.setBit(nibble_bit, 1); // Add 3, decomposed as two bits - tmp2.setBit(nibble_bit+1, 1); + tmp2.setBit(nibble_bit + 1, 1); tmp.opAssign(bcd); bcd.opAdd(tmp, tmp2); } @@ -705,11 +765,11 @@ string V3Number::toDecimalU() const { } string output; - int lsb = (maxdecwidth-1) & ~3; - for (; lsb>0; lsb-=4) { // Skip leading zeros + int lsb = (maxdecwidth - 1) & ~3; + for (; lsb > 0; lsb -= 4) { // Skip leading zeros if (bcd.bitsValue(lsb, 4)) break; } - for (; lsb>=0; lsb-=4) { + for (; lsb >= 0; lsb -= 4) { output += ('0' + bcd.bitsValue(lsb, 4)); // 0..9 } return output; @@ -719,11 +779,11 @@ string V3Number::toDecimalU() const { // ACCESSORS - as numbers uint32_t V3Number::toUInt() const { - UASSERT(!isFourState(), "toUInt with 4-state "<<*this); + UASSERT(!isFourState(), "toUInt with 4-state " << *this); // We allow wide numbers that represent values <= 32 bits - for (int i=1; i(extended); } else { @@ -753,52 +817,50 @@ vlsint32_t V3Number::toSInt() const { } vluint64_t V3Number::toUQuad() const { - UASSERT(!isFourState(), "toUQuad with 4-state "<<*this); + UASSERT(!isFourState(), "toUQuad with 4-state " << *this); // We allow wide numbers that represent values <= 64 bits if (isDouble()) return static_cast(toDouble()); - for (int i=2; i(toUInt())); - return ((static_cast(m_value[1])<(toUInt())); + return ((static_cast(m_value[1]) << VL_ULL(32)) | (static_cast(m_value[0]))); } vlsint64_t V3Number::toSQuad() const { if (isDouble()) return static_cast(toDouble()); vluint64_t v = toUQuad(); - vluint64_t signExtend = (-(v & (VL_ULL(1)<<(width()-1)))); + vluint64_t signExtend = (-(v & (VL_ULL(1) << (width() - 1)))); vluint64_t extended = v | signExtend; return static_cast(extended); } string V3Number::toString() const { - UASSERT(!isFourState(), "toString with 4-state "<<*this); + UASSERT(!isFourState(), "toString with 4-state " << *this); // Spec says always drop leading zeros, this isn't quite right, we space pad. if (isString()) return m_stringVal; - int bit = this->width()-1; + int bit = this->width() - 1; bool start = true; - while ((bit%8)!=7) bit++; + while ((bit % 8) != 7) bit++; string str; - for (; bit>=0; bit -= 8) { - int v = bitsValue(bit-7, 8); + for (; bit >= 0; bit -= 8) { + int v = bitsValue(bit - 7, 8); if (!start || v) { - str += static_cast((v==0) ? ' ' : v); + str += static_cast((v == 0) ? ' ' : v); start = false; // Drop leading 0s } } return str; } -uint32_t V3Number::toHash() const { - return m_value[0]; -} +uint32_t V3Number::toHash() const { return m_value[0]; } uint32_t V3Number::edataWord(int eword) const { - UASSERT(!isFourState(), "edataWord with 4-state "<<*this); + UASSERT(!isFourState(), "edataWord with 4-state " << *this); return m_value[eword]; } @@ -807,53 +869,53 @@ uint8_t V3Number::dataByte(int byte) const { } bool V3Number::isEqZero() const { - for (int i=0; iwidth(), rhs.width()); bit++) { + for (int bit = 0; bit < std::max(this->width(), rhs.width()); bit++) { if (this->bitIs1(bit) && rhs.bitIs0(bit)) { return 1; } if (rhs.bitIs1(bit) && this->bitIs0(bit)) { return 0; } if (this->bitIsXZ(bit)) { return 0; } @@ -863,7 +925,7 @@ bool V3Number::isLt(const V3Number& rhs) const { } bool V3Number::isLtXZ(const V3Number& rhs) const { // Include X/Z in comparisons for sort ordering - for (int bit=0; bit < std::max(this->width(), rhs.width()); bit++) { + for (int bit = 0; bit < std::max(this->width(), rhs.width()); bit++) { if (this->bitIs1(bit) && rhs.bitIs0(bit)) { return 1; } if (rhs.bitIs1(bit) && this->bitIs0(bit)) { return 0; } if (this->bitIsXZ(bit)) { return 1; } @@ -873,23 +935,23 @@ bool V3Number::isLtXZ(const V3Number& rhs) const { } int V3Number::widthMin() const { - for (int bit=width()-1; bit>0; bit--) { - if (!bitIs0(bit)) return bit+1; + for (int bit = width() - 1; bit > 0; bit--) { + if (!bitIs0(bit)) return bit + 1; } return 1; // one bit even if number is == 0 } uint32_t V3Number::countOnes() const { int n = 0; - for (int bit=0; bitwidth(); bit++) { + for (int bit = 0; bit < this->width(); bit++) { if (bitIs1(bit)) n++; } return n; } uint32_t V3Number::mostSetBitP1() const { - for (int bit=this->width()-1; bit>=0; bit--) { - if (bitIs1(bit)) return bit+1; + for (int bit = this->width() - 1; bit >= 0; bit--) { + if (bitIs1(bit)) return bit + 1; } return 0; } @@ -900,8 +962,8 @@ V3Number& V3Number::opBitsNonX(const V3Number& lhs) { // 0/1->1, X/Z->0 NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); - for (int bit=0; bitwidth(); bit++) { - if (lhs.bitIs0(bit) || lhs.bitIs1(bit)) { setBit(bit, 1); } + for (int bit = 0; bit < this->width(); bit++) { + if (lhs.bitIs0(bit) || lhs.bitIs1(bit)) setBit(bit, 1); } return *this; } @@ -910,8 +972,8 @@ V3Number& V3Number::opBitsOne(const V3Number& lhs) { // 1->1, 0/X/Z->0 NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); - for (int bit=0; bitwidth(); bit++) { - if (lhs.bitIs1(bit)) { setBit(bit, 1); } + for (int bit = 0; bit < this->width(); bit++) { + if (lhs.bitIs1(bit)) setBit(bit, 1); } return *this; } @@ -920,8 +982,8 @@ V3Number& V3Number::opBitsXZ(const V3Number& lhs) { // 0/1->1, X/Z->0 NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); - for (int bit=0; bitwidth(); bit++) { - if (lhs.bitIsXZ(bit)) { setBit(bit, 1); } + for (int bit = 0; bit < this->width(); bit++) { + if (lhs.bitIsXZ(bit)) setBit(bit, 1); } return *this; } @@ -930,8 +992,8 @@ V3Number& V3Number::opBitsZ(const V3Number& lhs) { // 0/1->1, X/Z->0 NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); - for (int bit=0; bitwidth(); bit++) { - if (lhs.bitIsZ(bit)) { setBit(bit, 1); } + for (int bit = 0; bit < this->width(); bit++) { + if (lhs.bitIsZ(bit)) setBit(bit, 1); } return *this; } @@ -940,8 +1002,8 @@ V3Number& V3Number::opBitsNonZ(const V3Number& lhs) { // 0/1->1, X/Z->0 NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); - for (int bit=0; bitwidth(); bit++) { - if (!lhs.bitIsZ(bit)) { setBit(bit, 1); } + for (int bit = 0; bit < this->width(); bit++) { + if (!lhs.bitIsZ(bit)) setBit(bit, 1); } return *this; } @@ -954,10 +1016,13 @@ V3Number& V3Number::opRedOr(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); char outc = 0; - for (int bit=0; bit=0; bit--) { + int adjust = (lhs.countOnes() == 1) ? 0 : 1; + for (int bit = lhs.width() - 1; bit >= 0; bit--) { if (lhs.bitIs1(bit)) { - setLong(bit+adjust); + setLong(bit + adjust); return *this; } } @@ -1045,12 +1127,16 @@ V3Number& V3Number::opLogNot(const V3Number& lhs) { NUM_ASSERT_LOGIC_ARGS1(lhs); // op i, 1 bit return char outc = 1; - for (int bit=0; bitwidth(); bit++) { - if (lhs.bitIs0(bit)) { setBit(bit, 1); } - else if (lhs.bitIsXZ(bit)) { setBit(bit,'x'); } + for (int bit = 0; bit < this->width(); bit++) { + if (lhs.bitIs0(bit)) { + setBit(bit, 1); + } else if (lhs.bitIsXZ(bit)) { + setBit(bit, 'x'); + } } return *this; } @@ -1071,10 +1160,13 @@ V3Number& V3Number::opAnd(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); // i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend. setZero(); - for (int bit=0; bitwidth(); bit++) { - if (lhs.bitIs1(bit) && rhs.bitIs1(bit)) { setBit(bit, 1); } - else if (lhs.bitIs0(bit) || rhs.bitIs0(bit)) ; // 0 - else { setBit(bit,'x'); } + for (int bit = 0; bit < this->width(); bit++) { + if (lhs.bitIs1(bit) && rhs.bitIs1(bit)) { + setBit(bit, 1); + } else if (lhs.bitIs0(bit) || rhs.bitIs0(bit)) { // 0 + } else { + setBit(bit, 'x'); + } } return *this; } @@ -1084,10 +1176,14 @@ V3Number& V3Number::opOr(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); // i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend. setZero(); - for (int bit=0; bitwidth(); bit++) { - if (lhs.bitIs1(bit) || rhs.bitIs1(bit)) { setBit(bit, 1); } - else if (lhs.bitIs0(bit) && rhs.bitIs0(bit)) ; // 0 - else { setBit(bit,'x'); } + for (int bit = 0; bit < this->width(); bit++) { + if (lhs.bitIs1(bit) || rhs.bitIs1(bit)) { + setBit(bit, 1); + } else if (lhs.bitIs0(bit) && rhs.bitIs0(bit)) { + ; // 0 + } else { + setBit(bit, 'x'); + } } return *this; } @@ -1105,10 +1201,14 @@ V3Number& V3Number::opXor(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); setZero(); - for (int bit=0; bitwidth(); bit++) { - if (lhs.bitIs1(bit) && rhs.bitIs0(bit)) { setBit(bit, 1); } - else if (lhs.bitIs0(bit) && rhs.bitIs1(bit)) { setBit(bit, 1); } - else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) { setBit(bit,'x'); } + for (int bit = 0; bit < this->width(); bit++) { + if (lhs.bitIs1(bit) && rhs.bitIs0(bit)) { + setBit(bit, 1); + } else if (lhs.bitIs0(bit) && rhs.bitIs1(bit)) { + setBit(bit, 1); + } else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) { + setBit(bit, 'x'); + } // else zero } return *this; @@ -1119,10 +1219,14 @@ V3Number& V3Number::opXnor(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); setZero(); - for (int bit=0; bitwidth(); bit++) { - if (lhs.bitIs1(bit) && rhs.bitIs1(bit)) { setBit(bit, 1); } - else if (lhs.bitIs0(bit) && rhs.bitIs0(bit)) { setBit(bit, 1); } - else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) { setBit(bit,'x'); } + for (int bit = 0; bit < this->width(); bit++) { + if (lhs.bitIs1(bit) && rhs.bitIs1(bit)) { + setBit(bit, 1); + } else if (lhs.bitIs0(bit) && rhs.bitIs0(bit)) { + setBit(bit, 1); + } else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) { + setBit(bit, 'x'); + } // else zero } return *this; @@ -1137,11 +1241,11 @@ V3Number& V3Number::opConcat(const V3Number& lhs, const V3Number& rhs) { v3warn(WIDTHCONCAT, "Unsized numbers/parameters not allowed in concatenations."); } int obit = 0; - for (int bit=0; bit 8192) { - v3warn(WIDTHCONCAT, "More than a 8k bit replication is probably wrong: "<(lhs.width())); - for (int istart=0; istartwidth() != rhs.width()) return false; - for (int bit=0; bit < std::max(this->width(), rhs.width()); bit++) { + for (int bit = 0; bit < std::max(this->width(), rhs.width()); bit++) { if (this->bitIs(bit) != rhs.bitIs(bit)) { return false; } } return true; @@ -1375,17 +1508,23 @@ bool V3Number::isCaseEq(const V3Number& rhs) const { V3Number& V3Number::opCaseEq(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); - return setSingleBits(lhs.isCaseEq(rhs) ? 1:0); + return setSingleBits(lhs.isCaseEq(rhs) ? 1 : 0); } V3Number& V3Number::opCaseNeq(const V3Number& lhs, const V3Number& rhs) { // i op j, 1 bit return, max(L(lhs),L(rhs)) calculation, careful need to X/Z extend. NUM_ASSERT_OP_ARGS2(lhs, rhs); char outc = 0; - if (lhs.isString()) return opNeqN(lhs, rhs); - else if (lhs.isDouble()) return opNeqD(lhs, rhs); - for (int bit=0; bit < std::max(lhs.width(), rhs.width()); bit++) { - if (lhs.bitIs(bit) != rhs.bitIs(bit)) { outc=1; goto last; } + if (lhs.isString()) { + return opNeqN(lhs, rhs); + } else if (lhs.isDouble()) { + return opNeqD(lhs, rhs); + } + for (int bit = 0; bit < std::max(lhs.width(), rhs.width()); bit++) { + if (lhs.bitIs(bit) != rhs.bitIs(bit)) { + outc = 1; + goto last; + } } last: return setSingleBits(outc); @@ -1395,10 +1534,12 @@ V3Number& V3Number::opWildEq(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); char outc = 1; - for (int bit=0; bit < std::max(lhs.width(), rhs.width()); bit++) { - if (!rhs.bitIsXZ(bit) - && lhs.bitIs(bit) != rhs.bitIs(bit)) { outc = 0; goto last; } - if (lhs.bitIsXZ(bit)) outc='x'; + for (int bit = 0; bit < std::max(lhs.width(), rhs.width()); bit++) { + if (!rhs.bitIsXZ(bit) && lhs.bitIs(bit) != rhs.bitIs(bit)) { + outc = 0; + goto last; + } + if (lhs.bitIsXZ(bit)) outc = 'x'; } last: return setSingleBits(outc); @@ -1408,10 +1549,12 @@ V3Number& V3Number::opWildNeq(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); char outc = 0; - for (int bit=0; bit < std::max(lhs.width(), rhs.width()); bit++) { - if (!rhs.bitIsXZ(bit) - && lhs.bitIs(bit) != rhs.bitIs(bit)) { outc=1; goto last; } - if (lhs.bitIsXZ(bit)) outc='x'; + for (int bit = 0; bit < std::max(lhs.width(), rhs.width()); bit++) { + if (!rhs.bitIsXZ(bit) && lhs.bitIs(bit) != rhs.bitIs(bit)) { + outc = 1; + goto last; + } + if (lhs.bitIsXZ(bit)) outc = 'x'; } last: return setSingleBits(outc); @@ -1422,11 +1565,11 @@ V3Number& V3Number::opGt(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); char outc = 0; - for (int bit=0; bit < std::max(lhs.width(), rhs.width()); bit++) { - if (lhs.bitIs1(bit) && rhs.bitIs0(bit)) { outc=1; } - if (rhs.bitIs1(bit) && lhs.bitIs0(bit)) { outc = 0; } - if (lhs.bitIsXZ(bit)) { outc='x'; } - if (rhs.bitIsXZ(bit)) { outc='x'; } + for (int bit = 0; bit < std::max(lhs.width(), rhs.width()); bit++) { + if (lhs.bitIs1(bit) && rhs.bitIs0(bit)) outc = 1; + if (rhs.bitIs1(bit) && lhs.bitIs0(bit)) outc = 0; + if (lhs.bitIsXZ(bit)) outc = 'x'; + if (rhs.bitIsXZ(bit)) outc = 'x'; } return setSingleBits(outc); } @@ -1437,18 +1580,22 @@ V3Number& V3Number::opGtS(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); char outc = 0; { - int mbit = std::max(lhs.width()-1, rhs.width()-1); - if (lhs.bitIsXZ(mbit)) { outc='x'; } - else if (rhs.bitIsXZ(mbit)) { outc='x'; } - else if (lhs.bitIs0(mbit) && rhs.bitIs1Extend(mbit)) { outc = 1; } // + > - - else if (lhs.bitIs1Extend(mbit) && rhs.bitIs0(mbit)) { outc = 0; } // - !> + - else { + int mbit = std::max(lhs.width() - 1, rhs.width() - 1); + if (lhs.bitIsXZ(mbit)) { + outc = 'x'; + } else if (rhs.bitIsXZ(mbit)) { + outc = 'x'; + } else if (lhs.bitIs0(mbit) && rhs.bitIs1Extend(mbit)) { + outc = 1; // + > - + } else if (lhs.bitIs1Extend(mbit) && rhs.bitIs0(mbit)) { + outc = 0; // - !> + + } else { // both positive or negative, normal > - for (int bit=0; bit < std::max(lhs.width()-1, rhs.width()-1); bit++) { - if (lhs.bitIs1Extend(bit) && rhs.bitIs0(bit)) { outc = 1; } - if (rhs.bitIs1Extend(bit) && lhs.bitIs0(bit)) { outc = 0; } - if (lhs.bitIsXZ(bit)) { outc = 'x'; } - if (rhs.bitIsXZ(bit)) { outc = 'x'; } + for (int bit = 0; bit < std::max(lhs.width() - 1, rhs.width() - 1); bit++) { + if (lhs.bitIs1Extend(bit) && rhs.bitIs0(bit)) outc = 1; + if (rhs.bitIs1Extend(bit) && lhs.bitIs0(bit)) outc = 0; + if (lhs.bitIsXZ(bit)) outc = 'x'; + if (rhs.bitIsXZ(bit)) outc = 'x'; } } } @@ -1471,18 +1618,10 @@ V3Number& V3Number::opGteS(const V3Number& lhs, const V3Number& rhs) { return opGtS(lhs, rhs); } -V3Number& V3Number::opLt(const V3Number& lhs, const V3Number& rhs) { - return opGt(rhs, lhs); -} -V3Number& V3Number::opLte(const V3Number& lhs, const V3Number& rhs) { - return opGte(rhs, lhs); -} -V3Number& V3Number::opLtS(const V3Number& lhs, const V3Number& rhs) { - return opGtS(rhs, lhs); -} -V3Number& V3Number::opLteS(const V3Number& lhs, const V3Number& rhs) { - return opGteS(rhs, lhs); -} +V3Number& V3Number::opLt(const V3Number& lhs, const V3Number& rhs) { return opGt(rhs, lhs); } +V3Number& V3Number::opLte(const V3Number& lhs, const V3Number& rhs) { return opGte(rhs, lhs); } +V3Number& V3Number::opLtS(const V3Number& lhs, const V3Number& rhs) { return opGtS(rhs, lhs); } +V3Number& V3Number::opLteS(const V3Number& lhs, const V3Number& rhs) { return opGteS(rhs, lhs); } V3Number& V3Number::opRotR(const V3Number& lhs, const V3Number& rhs) { // L(lhs) bit return @@ -1491,7 +1630,7 @@ V3Number& V3Number::opRotR(const V3Number& lhs, const V3Number& rhs) { if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.toUInt(); - for (int bit=0; bitwidth(); bit++) { + for (int bit = 0; bit < this->width(); bit++) { setBit(bit, lhs.bitIs((bit + rhsval) % this->width())); } return *this; @@ -1504,7 +1643,7 @@ V3Number& V3Number::opRotL(const V3Number& lhs, const V3Number& rhs) { if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.toUInt(); - for (int bit=0; bitwidth(); bit++) { + for (int bit = 0; bit < this->width(); bit++) { if (bit >= static_cast(rhsval)) { setBit(bit, lhs.bitIs((bit - rhsval) % this->width())); } @@ -1518,14 +1657,12 @@ V3Number& V3Number::opShiftR(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); if (rhs.isFourState()) return setAllBitsX(); setZero(); - for (int bit=32; bit(lhs.width())) { - for (int bit=0; bitwidth(); bit++) { - setBit(bit, lhs.bitIs(bit + rhsval)); - } + for (int bit = 0; bit < this->width(); bit++) setBit(bit, lhs.bitIs(bit + rhsval)); } return *this; } @@ -1538,21 +1675,21 @@ V3Number& V3Number::opShiftRS(const V3Number& lhs, const V3Number& rhs, uint32_t NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); if (rhs.isFourState()) return setAllBitsX(); setZero(); - for (int bit=32; bitwidth(); sbit++) { setBit(sbit, lhs.bitIs(lbits - 1)); // 0/1/X/Z } - if (rhs.bitIs1(lbits-1)) setAllBits1(); // -1 else 0 + if (rhs.bitIs1(lbits - 1)) setAllBits1(); // -1 else 0 return *this; // shift of over 2^32 must be -1/0 } uint32_t rhsval = rhs.toUInt(); if (rhsval < static_cast(lhs.width())) { - for (int bit=0; bitwidth(); bit++) { + for (int bit = 0; bit < this->width(); bit++) { setBit(bit, lhs.bitIsExtend(bit + rhsval, lbits)); } } else { - for (int bit=0; bitwidth(); bit++) { - setBit(bit, lhs.bitIs(lbits-1)); // 0/1/X/Z + for (int bit = 0; bit < this->width(); bit++) { + setBit(bit, lhs.bitIs(lbits - 1)); // 0/1/X/Z } } return *this; @@ -1564,14 +1701,12 @@ V3Number& V3Number::opShiftL(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); if (rhs.isFourState()) return setAllBitsX(); setZero(); - for (int bit=32; bitwidth(); bit++) { - if (bit >= static_cast(rhsval)) { - setBit(bit, lhs.bitIs(bit - rhsval)); - } + for (int bit = 0; bit < this->width(); bit++) { + if (bit >= static_cast(rhsval)) setBit(bit, lhs.bitIs(bit - rhsval)); } return *this; } @@ -1594,9 +1729,9 @@ V3Number& V3Number::opNegate(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); if (lhs.isFourState()) return setAllBitsX(); - V3Number notlhs (&lhs, width()); + V3Number notlhs(&lhs, width()); notlhs.opNot(lhs); - V3Number one (&lhs, width(), 1); + V3Number one(&lhs, width(), 1); opAdd(notlhs, one); return *this; } @@ -1607,12 +1742,10 @@ V3Number& V3Number::opAdd(const V3Number& lhs, const V3Number& rhs) { if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); setZero(); // Addem - int carry=0; - for (int bit=0; bitwidth(); bit++) { - int sum = ((lhs.bitIs1(bit)?1:0) + (rhs.bitIs1(bit)?1:0) + carry); - if (sum & 1) { - setBit(bit, 1); - } + int carry = 0; + for (int bit = 0; bit < this->width(); bit++) { + int sum = ((lhs.bitIs1(bit) ? 1 : 0) + (rhs.bitIs1(bit) ? 1 : 0) + carry); + if (sum & 1) setBit(bit, 1); carry = (sum >= 2); } return *this; @@ -1622,7 +1755,7 @@ V3Number& V3Number::opSub(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); - V3Number negrhs (&rhs, rhs.width()); + V3Number negrhs(&rhs, rhs.width()); negrhs.opNegate(rhs); return opAdd(lhs, negrhs); } @@ -1636,11 +1769,11 @@ V3Number& V3Number::opMul(const V3Number& lhs, const V3Number& rhs) { setQuad(lhs.toUQuad() * rhs.toUQuad()); opCleanThis(); // Mult produces extra bits in result } else { - for (int lword=0; lword(lhs.m_value[lword]) - * static_cast(rhs.m_value[rword]); - for (int qword=lword+rword; qwordwords(); qword++) { + * static_cast(rhs.m_value[rword]); + for (int qword = lword + rword; qword < this->words(); qword++) { mul += static_cast(m_value[qword]); m_value[qword] = (mul & VL_ULL(0xffffffff)); mul = (mul >> VL_ULL(32)) & VL_ULL(0xffffffff); @@ -1656,11 +1789,12 @@ V3Number& V3Number::opMulS(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); - V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs); - V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs); + V3Number lhsNoSign = lhs; + if (lhs.isNegative()) lhsNoSign.opNegate(lhs); + V3Number rhsNoSign = rhs; + if (rhs.isNegative()) rhsNoSign.opNegate(rhs); V3Number qNoSign = opMul(lhsNoSign, rhsNoSign); - if ((lhs.isNegative() && !rhs.isNegative()) - || (!lhs.isNegative() && rhs.isNegative())) { + if ((lhs.isNegative() && !rhs.isNegative()) || (!lhs.isNegative() && rhs.isNegative())) { opNegate(qNoSign); } else { opAssign(qNoSign); @@ -1671,10 +1805,10 @@ V3Number& V3Number::opDiv(const V3Number& lhs, const V3Number& rhs) { // i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return NUM_ASSERT_OP_ARGS2(lhs, rhs); NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); - //UINFO(9, "opdiv "<>divs-start "<>divs-start "<divs-mid "<divs-mid "<> 32 won't mask the value - for (int i = vw-1; i>0; i--) { - vn[i] = (rhs.m_value[i] << s) | (shift_mask & (rhs.m_value[i-1] >> (32-s))); + for (int i = vw - 1; i > 0; i--) { + vn[i] = (rhs.m_value[i] << s) | (shift_mask & (rhs.m_value[i - 1] >> (32 - s))); } vn[0] = rhs.m_value[0] << s; // Copy and shift dividend by same amount; may set new upper word - if (s) un[uw] = lhs.m_value[uw-1] >> (32-s); - else un[uw] = 0; - for (int i=uw-1; i>0; i--) { - un[i] = (lhs.m_value[i] << s) | (shift_mask & (lhs.m_value[i-1] >> (32-s))); + if (s) { + un[uw] = lhs.m_value[uw - 1] >> (32 - s); + } else { + un[uw] = 0; + } + for (int i = uw - 1; i > 0; i--) { + un[i] = (lhs.m_value[i] << s) | (shift_mask & (lhs.m_value[i - 1] >> (32 - s))); } un[0] = lhs.m_value[0] << s; - //printf(" un="); for (int i=5; i>=0; i--) printf(" %08x",un[i]); printf("\n"); - //printf(" vn="); for (int i=5; i>=0; i--) printf(" %08x",vn[i]); printf("\n"); - //printf(" mv="); for (int i=5; i>=0; i--) printf(" %08x",m_value[i]); printf("\n"); + // printf(" un="); for (int i=5; i>=0; i--) printf(" %08x",un[i]); printf("\n"); + // printf(" vn="); for (int i=5; i>=0; i--) printf(" %08x",vn[i]); printf("\n"); + // printf(" mv="); for (int i=5; i>=0; i--) printf(" %08x",m_value[i]); printf("\n"); // Main loop for (int j = uw - vw; j >= 0; j--) { // Estimate - vluint64_t unw64 = (static_cast(un[j+vw])<(un[j+vw-1])); - vluint64_t qhat = unw64 / static_cast(vn[vw-1]); - vluint64_t rhat = unw64 - qhat*static_cast(vn[vw-1]); + vluint64_t unw64 = (static_cast(un[j + vw]) << VL_ULL(32) + | static_cast(un[j + vw - 1])); + vluint64_t qhat = unw64 / static_cast(vn[vw - 1]); + vluint64_t rhat = unw64 - qhat * static_cast(vn[vw - 1]); - again: + again: if (qhat >= VL_ULL(0x100000000) - || ((qhat*vn[vw-2]) > ((rhat< ((rhat << VL_ULL(32)) + un[j + vw - 2]))) { qhat = qhat - 1; - rhat = rhat + vn[vw-1]; + rhat = rhat + vn[vw - 1]; if (rhat < VL_ULL(0x100000000)) goto again; } vlsint64_t t = 0; // Must be signed vluint64_t k = 0; - for (int i=0; i> VL_ULL(32)) - (t >> VL_ULL(32)); } - t = un[j+vw] - k; - un[j+vw] = t; + t = un[j + vw] - k; + un[j + vw] = t; this->m_value[j] = qhat; // Save quotient digit if (t < 0) { // Over subtracted; correct by adding back this->m_value[j]--; k = 0; - for (int i=0; i(un[i+j]) + static_cast(vn[i]) + k; - un[i+j] = t; + for (int i = 0; i < vw; i++) { + t = static_cast(un[i + j]) + static_cast(vn[i]) + k; + un[i + j] = t; k = t >> VL_ULL(32); } - un[j+vw] = un[j+vw] + k; + un[j + vw] = un[j + vw] + k; } } - //printf(" un="); for (int i=5; i>=0; i--) printf(" %08x",un[i]); printf("\n"); - //printf(" vn="); for (int i=5; i>=0; i--) printf(" %08x",vn[i]); printf("\n"); - //printf(" mv="); for (int i=5; i>=0; i--) printf(" %08x",m_value[i]); printf("\n"); + // printf(" un="); for (int i=5; i>=0; i--) printf(" %08x",un[i]); printf("\n"); + // printf(" vn="); for (int i=5; i>=0; i--) printf(" %08x",vn[i]); printf("\n"); + // printf(" mv="); for (int i=5; i>=0; i--) printf(" %08x",m_value[i]); printf("\n"); if (is_modulus) { // modulus // Need to reverse normalization on copy to output - for (int i=0; i> s) | (shift_mask & (un[i+1] << (32-s))); + for (int i = 0; i < vw; i++) { + m_value[i] = (un[i] >> s) | (shift_mask & (un[i + 1] << (32 - s))); } - for (int i=vw; iwidth(); bit++) { - if (ibit>=0 && ibit(msbval)) { + for (int bit = 0; bit < this->width(); bit++) { + if (ibit >= 0 && ibit < lhs.width() && ibit <= static_cast(msbval)) { setBit(bit, lhs.bitIs(ibit)); } else { setBit(bit, 'x'); } ++ibit; } - //UINFO(0,"RANGE "<width(); bit++) { - if (if0s.bitIs1(bit) && if1s.bitIs1(bit)) { setBit(bit, 1); } - else if (if0s.bitIs0(bit) && if1s.bitIs0(bit)) { setBit(bit, 0); } - else setBit(bit,'x'); + for (int bit = 0; bit < this->width(); bit++) { + if (if0s.bitIs1(bit) && if1s.bitIs1(bit)) { + setBit(bit, 1); + } else if (if0s.bitIs0(bit) && if1s.bitIs0(bit)) { + setBit(bit, 0); + } else { + setBit(bit, 'x'); + } } } return *this; @@ -2063,8 +2218,12 @@ V3Number& V3Number::opRToIRoundS(const V3Number& lhs) { NUM_ASSERT_DOUBLE_ARGS1(lhs); double v = VL_ROUND(lhs.toDouble()); setZero(); - union { double d; vluint64_t q; } u; - u.d = v; if (u.d == 0.0) {} + union { + double d; + vluint64_t q; + } u; + u.d = v; + if (u.d == 0.0) {} int exp = static_cast((u.q >> VL_ULL(52)) & VL_MASK_Q(11)) - 1023; int lsb = exp - 52; @@ -2089,7 +2248,7 @@ V3Number& V3Number::opRealToBits(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_DOUBLE_ARGS1(lhs); // Conveniently our internal format is identical so we can copy bits... - if (lhs.width()!=64 || this->width()!=64) { + if (lhs.width() != 64 || this->width() != 64) { v3fatalSrc("Real operation on wrong sized number"); } opAssign(lhs); @@ -2099,7 +2258,7 @@ V3Number& V3Number::opRealToBits(const V3Number& lhs) { V3Number& V3Number::opBitsToRealD(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); // Conveniently our internal format is identical so we can copy bits... - if (lhs.width()!=64 || this->width()!=64) { + if (lhs.width() != 64 || this->width() != 64) { v3fatalSrc("Real operation on wrong sized number"); } opAssign(lhs); @@ -2109,7 +2268,7 @@ V3Number& V3Number::opBitsToRealD(const V3Number& lhs) { V3Number& V3Number::opNegateD(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_DOUBLE_ARGS1(lhs); - return setDouble(- lhs.toDouble()); + return setDouble(-lhs.toDouble()); } V3Number& V3Number::opAddD(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); @@ -2180,34 +2339,30 @@ V3Number& V3Number::opConcatN(const V3Number& lhs, const V3Number& rhs) { return setString(lhs.toString() + rhs.toString()); } V3Number& V3Number::opReplN(const V3Number& lhs, const V3Number& rhs) { - NUM_ASSERT_STRING_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(rhs); + NUM_ASSERT_STRING_ARGS1(lhs); + NUM_ASSERT_LOGIC_ARGS1(rhs); return opReplN(lhs, rhs.toUInt()); } V3Number& V3Number::opReplN(const V3Number& lhs, uint32_t rhsval) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_STRING_ARGS1(lhs); - string out; out.reserve(lhs.toString().length() * rhsval); - for (unsigned times=0; times m_value; // The Value, with bit 0 being in bit 0 of this vector (unless X/Z) + int m_width; // Width as specified/calculated. + bool m_sized : 1; // True if the user specified the width, else we track it. + bool m_signed : 1; // True if signed value + bool m_double : 1; // True if double real value + bool m_isString : 1; // True if string + bool m_fromString : 1; // True if from string literal + bool m_autoExtend : 1; // True if SystemVerilog extend-to-any-width + FileLine* m_fileline; + AstNode* m_nodep; // Parent node + std::vector m_value; // Value, with bit 0 in bit 0 of this vector (unless X/Z) std::vector m_valueX; // Each bit is true if it's X or Z, 10=z, 11=x - string m_stringVal; // If isString, the value of the string + string m_stringVal; // If isString, the value of the string // METHODS V3Number& setSingleBits(char value); - V3Number& setString(const string& str) { m_isString = true; m_stringVal = str; return *this; } + V3Number& setString(const string& str) { + m_isString = true; + m_stringVal = str; + return *this; + } void opCleanThis(bool warnOnTruncation = false); + public: void nodep(AstNode* nodep) { setNames(nodep); } FileLine* fileline() const { return m_fileline; } @@ -64,79 +69,87 @@ public: V3Number& setLongS(vlsint32_t value); V3Number& setDouble(double value); void setBit(int bit, char value) { // Note must be pre-zeroed! - if (bit>=m_width) return; - uint32_t mask = (1UL<<(bit&31)); - if (value=='0' || value==0) { - m_value [bit/32] &= ~mask; - m_valueX[bit/32] &= ~mask; - } else if (value=='1'|| value==1) { - m_value [bit/32] |= mask; - m_valueX[bit/32] &= ~mask; - } else if (value=='z'|| value==2) { - m_value [bit/32] &= ~mask; - m_valueX[bit/32] |= mask; + if (bit >= m_width) return; + uint32_t mask = (1UL << (bit & 31)); + if (value == '0' || value == 0) { + m_value[bit / 32] &= ~mask; + m_valueX[bit / 32] &= ~mask; + } else if (value == '1' || value == 1) { + m_value[bit / 32] |= mask; + m_valueX[bit / 32] &= ~mask; + } else if (value == 'z' || value == 2) { + m_value[bit / 32] &= ~mask; + m_valueX[bit / 32] |= mask; } else { // X - m_value [bit/32] |= mask; - m_valueX[bit/32] |= mask; + m_value[bit / 32] |= mask; + m_valueX[bit / 32] |= mask; } } + private: char bitIs(int bit) const { - if (bit>=m_width || bit<0) { + if (bit >= m_width || bit < 0) { // We never sign extend return '0'; } - return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0) - | ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); } + return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0) + | ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]); + } char bitIsExtend(int bit, int lbits) const { // lbits usually = width, but for C optimizations width=32_bits, lbits = 32_or_less - if (bit<0) return '0'; - UASSERT(lbits<=m_width, "Extend of wrong size"); - if (bit>=lbits) { - bit = lbits ? lbits-1 : 0; + if (bit < 0) return '0'; + UASSERT(lbits <= m_width, "Extend of wrong size"); + if (bit >= lbits) { + bit = lbits ? lbits - 1 : 0; // We do sign extend - return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0) - | ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); + return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0) + | ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]); } - return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0) - | ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); } + return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0) + | ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]); + } bool bitIs0(int bit) const { - if (bit<0) return false; - if (bit>=m_width) return !bitIsXZ(m_width-1); - return ( (m_value[bit/32] & (1UL<<(bit&31)))==0 - && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); } + if (bit < 0) return false; + if (bit >= m_width) return !bitIsXZ(m_width - 1); + return ((m_value[bit / 32] & (1UL << (bit & 31))) == 0 + && !(m_valueX[bit / 32] & (1UL << (bit & 31)))); + } bool bitIs1(int bit) const { - if (bit<0) return false; - if (bit>=m_width) return false; - return ( (m_value[bit/32] & (1UL<<(bit&31))) - && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); } + if (bit < 0) return false; + if (bit >= m_width) return false; + return ((m_value[bit / 32] & (1UL << (bit & 31))) + && !(m_valueX[bit / 32] & (1UL << (bit & 31)))); + } bool bitIs1Extend(int bit) const { - if (bit<0) return false; - if (bit>=m_width) return bitIs1Extend(m_width-1); - return ( (m_value[bit/32] & (1UL<<(bit&31))) - && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); } + if (bit < 0) return false; + if (bit >= m_width) return bitIs1Extend(m_width - 1); + return ((m_value[bit / 32] & (1UL << (bit & 31))) + && !(m_valueX[bit / 32] & (1UL << (bit & 31)))); + } bool bitIsX(int bit) const { - if (bit<0) return false; - if (bit>=m_width) return bitIsZ(m_width-1); - return ( (m_value[bit/32] & (1UL<<(bit&31))) - && (m_valueX[bit/32] & (1UL<<(bit&31))) ); } + if (bit < 0) return false; + if (bit >= m_width) return bitIsZ(m_width - 1); + return ((m_value[bit / 32] & (1UL << (bit & 31))) + && (m_valueX[bit / 32] & (1UL << (bit & 31)))); + } bool bitIsXZ(int bit) const { - if (bit<0) return false; - if (bit>=m_width) return bitIsXZ(m_width-1); - return ( (m_valueX[bit/32] & (1UL<<(bit&31)))); + if (bit < 0) return false; + if (bit >= m_width) return bitIsXZ(m_width - 1); + return ((m_valueX[bit / 32] & (1UL << (bit & 31)))); } bool bitIsZ(int bit) const { - if (bit<0) return false; - if (bit>=m_width) return bitIsZ(m_width-1); - return ( (~m_value[bit/32] & (1UL<<(bit&31))) - && (m_valueX[bit/32] & (1UL<<(bit&31))) ); } + if (bit < 0) return false; + if (bit >= m_width) return bitIsZ(m_width - 1); + return ((~m_value[bit / 32] & (1UL << (bit & 31))) + && (m_valueX[bit / 32] & (1UL << (bit & 31)))); + } uint32_t bitsValue(int lsb, int nbits) const { uint32_t v = 0; - for (int bitn=0; bitnfileline(); @@ -169,7 +187,7 @@ public: private: void V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl); - void init(AstNode* nodep, int swidth, bool sized=true) { + void init(AstNode* nodep, int swidth, bool sized = true) { setNames(nodep); m_signed = false; m_double = false; @@ -177,23 +195,27 @@ private: m_autoExtend = false; m_fromString = false; width(swidth, sized); - for (int i=0; i0b11, if 3->0b111 etc // ACCESSORS - string ascii(bool prefixed=true, bool cleanVerilog=false) const; + string ascii(bool prefixed = true, bool cleanVerilog = false) const; string displayed(AstNode* nodep, const string& vformat) const; static bool displayedFmtLegal(char format); // Is this a valid format letter? int width() const { return m_width; } @@ -214,26 +236,35 @@ public: bool sized() const { return m_sized; } bool autoExtend() const { return m_autoExtend; } bool isFromString() const { return m_fromString; } - bool isSigned() const { return m_signed; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned()) - bool isDouble() const { return m_double; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned()) - void isDouble(bool flag) { m_double = flag; } // Only if have 64 bit value loaded, and want to indicate it's real + // Only correct for parsing of numbers from strings, otherwise not used + // (use AstConst::isSigned()) + bool isSigned() const { return m_signed; } + // Only correct for parsing of numbers from strings, otherwise not used + // (use AstConst::isSigned()) + bool isDouble() const { return m_double; } + // Only if have 64 bit value loaded, and want to indicate it's real + void isDouble(bool flag) { m_double = flag; } bool isString() const { return m_isString; } - void isString(bool flag) { m_isString = flag; } - bool isNegative() const { return bitIs1(width()-1); } + void isString(bool flag) { m_isString = flag; } + bool isNegative() const { return bitIs1(width() - 1); } bool isFourState() const; bool hasZ() const { - for(int i=0;i1, X/Z->0 - V3Number& opBitsOne (const V3Number& lhs); // 1->1, 0/X/Z->0 - V3Number& opBitsXZ (const V3Number& lhs); // 0/1->0, X/Z->1 - V3Number& opBitsZ (const V3Number& lhs); // Z->1, 0/1/X->0 + V3Number& opBitsOne(const V3Number& lhs); // 1->1, 0/X/Z->0 + V3Number& opBitsXZ(const V3Number& lhs); // 0/1->0, X/Z->1 + V3Number& opBitsZ(const V3Number& lhs); // Z->1, 0/1/X->0 V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1 // - V3Number& opAssign (const V3Number& lhs); + V3Number& opAssign(const V3Number& lhs); V3Number& opAssignNonXZ(const V3Number& lhs, bool ignoreXZ = true); - V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension + V3Number& opExtendS(const V3Number& lhs, uint32_t lbits); // Sign extension V3Number& opExtendXZ(const V3Number& lhs, uint32_t lbits); // X/Z extension - V3Number& opRedOr (const V3Number& lhs); - V3Number& opRedAnd (const V3Number& lhs); - V3Number& opRedXor (const V3Number& lhs); - V3Number& opRedXnor (const V3Number& lhs); + V3Number& opRedOr(const V3Number& lhs); + V3Number& opRedAnd(const V3Number& lhs); + V3Number& opRedXor(const V3Number& lhs); + V3Number& opRedXnor(const V3Number& lhs); V3Number& opCountOnes(const V3Number& lhs); V3Number& opIsUnknown(const V3Number& lhs); - V3Number& opOneHot (const V3Number& lhs); - V3Number& opOneHot0 (const V3Number& lhs); - V3Number& opCLog2 (const V3Number& lhs); - V3Number& opClean (const V3Number& lhs, uint32_t bits); - V3Number& opConcat (const V3Number& lhs, const V3Number& rhs); - V3Number& opLenN (const V3Number& lhs); - V3Number& opRepl (const V3Number& lhs, const V3Number& rhs); - V3Number& opRepl (const V3Number& lhs, uint32_t rhsval); - V3Number& opStreamL (const V3Number& lhs, const V3Number& rhs); - V3Number& opSel (const V3Number& lhs, const V3Number& msb, const V3Number& lsb); - V3Number& opSel (const V3Number& lhs, uint32_t msbval, uint32_t lsbval); - V3Number& opSelInto (const V3Number& lhs, const V3Number& lsb, int width); - V3Number& opSelInto (const V3Number& lhs, int lsbval, int width); + V3Number& opOneHot(const V3Number& lhs); + V3Number& opOneHot0(const V3Number& lhs); + V3Number& opCLog2(const V3Number& lhs); + V3Number& opClean(const V3Number& lhs, uint32_t bits); + V3Number& opConcat(const V3Number& lhs, const V3Number& rhs); + V3Number& opLenN(const V3Number& lhs); + V3Number& opRepl(const V3Number& lhs, const V3Number& rhs); + V3Number& opRepl(const V3Number& lhs, uint32_t rhsval); + V3Number& opStreamL(const V3Number& lhs, const V3Number& rhs); + V3Number& opSel(const V3Number& lhs, const V3Number& msb, const V3Number& lsb); + V3Number& opSel(const V3Number& lhs, uint32_t msbval, uint32_t lsbval); + V3Number& opSelInto(const V3Number& lhs, const V3Number& lsb, int width); + V3Number& opSelInto(const V3Number& lhs, int lsbval, int width); V3Number& opToLowerN(const V3Number& lhs); V3Number& opToUpperN(const V3Number& lhs); - V3Number& opCond (const V3Number& lhs, const V3Number& if1s, const V3Number& if0s); - V3Number& opCaseEq (const V3Number& lhs, const V3Number& rhs); - V3Number& opCaseNeq (const V3Number& lhs, const V3Number& rhs); - V3Number& opWildEq (const V3Number& lhs, const V3Number& rhs); - V3Number& opWildNeq (const V3Number& lhs, const V3Number& rhs); - V3Number& opBufIf1 (const V3Number& ens, const V3Number& if1s); + V3Number& opCond(const V3Number& lhs, const V3Number& if1s, const V3Number& if0s); + V3Number& opCaseEq(const V3Number& lhs, const V3Number& rhs); + V3Number& opCaseNeq(const V3Number& lhs, const V3Number& rhs); + V3Number& opWildEq(const V3Number& lhs, const V3Number& rhs); + V3Number& opWildNeq(const V3Number& lhs, const V3Number& rhs); + V3Number& opBufIf1(const V3Number& ens, const V3Number& if1s); // "standard" math - V3Number& opNot (const V3Number& lhs); - V3Number& opLogNot (const V3Number& lhs); - V3Number& opLogAnd (const V3Number& lhs, const V3Number& rhs); - V3Number& opLogOr (const V3Number& lhs, const V3Number& rhs); - V3Number& opLogEq (const V3Number& lhs, const V3Number& rhs); - V3Number& opLogIf (const V3Number& lhs, const V3Number& rhs); - V3Number& opAbsS (const V3Number& lhs); - V3Number& opNegate (const V3Number& lhs); - V3Number& opAdd (const V3Number& lhs, const V3Number& rhs); - V3Number& opSub (const V3Number& lhs, const V3Number& rhs); - V3Number& opMul (const V3Number& lhs, const V3Number& rhs); - V3Number& opMulS (const V3Number& lhs, const V3Number& rhs); // Signed - V3Number& opDiv (const V3Number& lhs, const V3Number& rhs); - V3Number& opDivS (const V3Number& lhs, const V3Number& rhs); // Signed - V3Number& opModDiv (const V3Number& lhs, const V3Number& rhs); - V3Number& opModDivS (const V3Number& lhs, const V3Number& rhs); // Signed - V3Number& opPow (const V3Number& lhs, const V3Number& rhs, bool lsign=false, bool rsign=false); - V3Number& opPowSU (const V3Number& lhs, const V3Number& rhs); // Signed lhs, unsigned rhs - V3Number& opPowSS (const V3Number& lhs, const V3Number& rhs); // Signed lhs, signed rhs - V3Number& opPowUS (const V3Number& lhs, const V3Number& rhs); // Unsigned lhs, signed rhs - V3Number& opAnd (const V3Number& lhs, const V3Number& rhs); + V3Number& opNot(const V3Number& lhs); + V3Number& opLogNot(const V3Number& lhs); + V3Number& opLogAnd(const V3Number& lhs, const V3Number& rhs); + V3Number& opLogOr(const V3Number& lhs, const V3Number& rhs); + V3Number& opLogEq(const V3Number& lhs, const V3Number& rhs); + V3Number& opLogIf(const V3Number& lhs, const V3Number& rhs); + V3Number& opAbsS(const V3Number& lhs); + V3Number& opNegate(const V3Number& lhs); + V3Number& opAdd(const V3Number& lhs, const V3Number& rhs); + V3Number& opSub(const V3Number& lhs, const V3Number& rhs); + V3Number& opMul(const V3Number& lhs, const V3Number& rhs); + V3Number& opMulS(const V3Number& lhs, const V3Number& rhs); // Signed + V3Number& opDiv(const V3Number& lhs, const V3Number& rhs); + V3Number& opDivS(const V3Number& lhs, const V3Number& rhs); // Signed + V3Number& opModDiv(const V3Number& lhs, const V3Number& rhs); + V3Number& opModDivS(const V3Number& lhs, const V3Number& rhs); // Signed + V3Number& opPow(const V3Number& lhs, const V3Number& rhs, bool lsign = false, + bool rsign = false); + V3Number& opPowSU(const V3Number& lhs, const V3Number& rhs); // Signed lhs, unsigned rhs + V3Number& opPowSS(const V3Number& lhs, const V3Number& rhs); // Signed lhs, signed rhs + V3Number& opPowUS(const V3Number& lhs, const V3Number& rhs); // Unsigned lhs, signed rhs + V3Number& opAnd(const V3Number& lhs, const V3Number& rhs); V3Number& opChangeXor(const V3Number& lhs, const V3Number& rhs); - V3Number& opXor (const V3Number& lhs, const V3Number& rhs); - V3Number& opXnor (const V3Number& lhs, const V3Number& rhs); - V3Number& opOr (const V3Number& lhs, const V3Number& rhs); - V3Number& opRotR (const V3Number& lhs, const V3Number& rhs); - V3Number& opRotL (const V3Number& lhs, const V3Number& rhs); - V3Number& opShiftR (const V3Number& lhs, const V3Number& rhs); - V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_t lbits); // Arithmetic w/carry - V3Number& opShiftL (const V3Number& lhs, const V3Number& rhs); + V3Number& opXor(const V3Number& lhs, const V3Number& rhs); + V3Number& opXnor(const V3Number& lhs, const V3Number& rhs); + V3Number& opOr(const V3Number& lhs, const V3Number& rhs); + V3Number& opRotR(const V3Number& lhs, const V3Number& rhs); + V3Number& opRotL(const V3Number& lhs, const V3Number& rhs); + V3Number& opShiftR(const V3Number& lhs, const V3Number& rhs); + V3Number& opShiftRS(const V3Number& lhs, const V3Number& rhs, // Arithmetic w/carry + uint32_t lbits); + V3Number& opShiftL(const V3Number& lhs, const V3Number& rhs); // Comparisons - V3Number& opEq (const V3Number& lhs, const V3Number& rhs); - V3Number& opNeq (const V3Number& lhs, const V3Number& rhs); - V3Number& opGt (const V3Number& lhs, const V3Number& rhs); - V3Number& opGtS (const V3Number& lhs, const V3Number& rhs); // Signed - V3Number& opGte (const V3Number& lhs, const V3Number& rhs); - V3Number& opGteS (const V3Number& lhs, const V3Number& rhs); // Signed - V3Number& opLt (const V3Number& lhs, const V3Number& rhs); - V3Number& opLtS (const V3Number& lhs, const V3Number& rhs); // Signed - V3Number& opLte (const V3Number& lhs, const V3Number& rhs); - V3Number& opLteS (const V3Number& lhs, const V3Number& rhs); // Signed + V3Number& opEq(const V3Number& lhs, const V3Number& rhs); + V3Number& opNeq(const V3Number& lhs, const V3Number& rhs); + V3Number& opGt(const V3Number& lhs, const V3Number& rhs); + V3Number& opGtS(const V3Number& lhs, const V3Number& rhs); // Signed + V3Number& opGte(const V3Number& lhs, const V3Number& rhs); + V3Number& opGteS(const V3Number& lhs, const V3Number& rhs); // Signed + V3Number& opLt(const V3Number& lhs, const V3Number& rhs); + V3Number& opLtS(const V3Number& lhs, const V3Number& rhs); // Signed + V3Number& opLte(const V3Number& lhs, const V3Number& rhs); + V3Number& opLteS(const V3Number& lhs, const V3Number& rhs); // Signed // "D" - double (aka real) math - V3Number& opIToRD (const V3Number& lhs); - V3Number& opRToIS (const V3Number& lhs); + V3Number& opIToRD(const V3Number& lhs); + V3Number& opRToIS(const V3Number& lhs); V3Number& opRToIRoundS(const V3Number& lhs); V3Number& opRealToBits(const V3Number& lhs); V3Number& opBitsToRealD(const V3Number& lhs); - V3Number& opNegateD (const V3Number& lhs); - V3Number& opAddD (const V3Number& lhs, const V3Number& rhs); - V3Number& opSubD (const V3Number& lhs, const V3Number& rhs); - V3Number& opMulD (const V3Number& lhs, const V3Number& rhs); - V3Number& opDivD (const V3Number& lhs, const V3Number& rhs); - V3Number& opPowD (const V3Number& lhs, const V3Number& rhs); + V3Number& opNegateD(const V3Number& lhs); + V3Number& opAddD(const V3Number& lhs, const V3Number& rhs); + V3Number& opSubD(const V3Number& lhs, const V3Number& rhs); + V3Number& opMulD(const V3Number& lhs, const V3Number& rhs); + V3Number& opDivD(const V3Number& lhs, const V3Number& rhs); + V3Number& opPowD(const V3Number& lhs, const V3Number& rhs); // Comparisons - V3Number& opEqD (const V3Number& lhs, const V3Number& rhs); - V3Number& opNeqD (const V3Number& lhs, const V3Number& rhs); - V3Number& opGtD (const V3Number& lhs, const V3Number& rhs); - V3Number& opGteD (const V3Number& lhs, const V3Number& rhs); - V3Number& opLtD (const V3Number& lhs, const V3Number& rhs); - V3Number& opLteD (const V3Number& lhs, const V3Number& rhs); + V3Number& opEqD(const V3Number& lhs, const V3Number& rhs); + V3Number& opNeqD(const V3Number& lhs, const V3Number& rhs); + V3Number& opGtD(const V3Number& lhs, const V3Number& rhs); + V3Number& opGteD(const V3Number& lhs, const V3Number& rhs); + V3Number& opLtD(const V3Number& lhs, const V3Number& rhs); + V3Number& opLteD(const V3Number& lhs, const V3Number& rhs); // "N" - string operations - V3Number& opAtoN (const V3Number& lhs, int base); - V3Number& opPutcN (const V3Number& lhs, const V3Number& rhs, const V3Number& ths); - V3Number& opGetcN (const V3Number& lhs, const V3Number& rhs); - V3Number& opSubstrN (const V3Number& lhs, const V3Number& rhs, const V3Number& ths); - V3Number& opCompareNN(const V3Number& lhs,const V3Number& rhs, bool ignoreCase); - V3Number& opConcatN (const V3Number& lhs, const V3Number& rhs); - V3Number& opReplN (const V3Number& lhs, const V3Number& rhs); - V3Number& opReplN (const V3Number& lhs, uint32_t rhsval); - V3Number& opEqN (const V3Number& lhs, const V3Number& rhs); - V3Number& opNeqN (const V3Number& lhs, const V3Number& rhs); - V3Number& opGtN (const V3Number& lhs, const V3Number& rhs); - V3Number& opGteN (const V3Number& lhs, const V3Number& rhs); - V3Number& opLtN (const V3Number& lhs, const V3Number& rhs); - V3Number& opLteN (const V3Number& lhs, const V3Number& rhs); + V3Number& opAtoN(const V3Number& lhs, int base); + V3Number& opPutcN(const V3Number& lhs, const V3Number& rhs, const V3Number& ths); + V3Number& opGetcN(const V3Number& lhs, const V3Number& rhs); + V3Number& opSubstrN(const V3Number& lhs, const V3Number& rhs, const V3Number& ths); + V3Number& opCompareNN(const V3Number& lhs, const V3Number& rhs, bool ignoreCase); + V3Number& opConcatN(const V3Number& lhs, const V3Number& rhs); + V3Number& opReplN(const V3Number& lhs, const V3Number& rhs); + V3Number& opReplN(const V3Number& lhs, uint32_t rhsval); + V3Number& opEqN(const V3Number& lhs, const V3Number& rhs); + V3Number& opNeqN(const V3Number& lhs, const V3Number& rhs); + V3Number& opGtN(const V3Number& lhs, const V3Number& rhs); + V3Number& opGteN(const V3Number& lhs, const V3Number& rhs); + V3Number& opLtN(const V3Number& lhs, const V3Number& rhs); + V3Number& opLteN(const V3Number& lhs, const V3Number& rhs); }; -inline std::ostream& operator<<(std::ostream& os, const V3Number& rhs) { return os<(vertexp)) { - std::cerr<nodep()->fileline()->warnOther() - <<" Example path: " - <nodep()->typeName()<nodep()->fileline()->warnOther() + << " Example path: " << vvertexp->nodep()->typeName() << endl; } if (OrderVarVertex* vvertexp = dynamic_cast(vertexp)) { - std::cerr<varScp()->fileline()->warnOther() - <<" Example path: " - <varScp()->prettyName()<varScp()->fileline()->warnOther() + << " Example path: " << vvertexp->varScp()->prettyName() << endl; } } @@ -130,35 +128,38 @@ void OrderGraph::loopsVertexCb(V3GraphVertex* vertexp) { class OrderMoveDomScope { // Information stored for each unique loop, domain & scope trifecta public: - V3ListEnt m_readyDomScopeE;// List of next ready dom scope - V3List m_readyVertices; // Ready vertices with same domain & scope + V3ListEnt m_readyDomScopeE; // List of next ready dom scope + V3List m_readyVertices; // Ready vertices with same domain & scope private: - bool m_onReadyList; // True if DomScope is already on list of ready dom/scopes - const AstSenTree* m_domainp; // Domain all vertices belong to - const AstScope* m_scopep; // Scope all vertices belong to + bool m_onReadyList; // True if DomScope is already on list of ready dom/scopes + const AstSenTree* m_domainp; // Domain all vertices belong to + const AstScope* m_scopep; // Scope all vertices belong to typedef std::pair DomScopeKey; typedef std::map DomScopeMap; - static DomScopeMap s_dsMap; // Structure registered for each dom/scope pairing + static DomScopeMap s_dsMap; // Structure registered for each dom/scope pairing public: OrderMoveDomScope(const AstSenTree* domainp, const AstScope* scopep) - : m_onReadyList(false), m_domainp(domainp), m_scopep(scopep) {} + : m_onReadyList(false) + , m_domainp(domainp) + , m_scopep(scopep) {} OrderMoveDomScope* readyDomScopeNextp() const { return m_readyDomScopeE.nextp(); } const AstSenTree* domainp() const { return m_domainp; } const AstScope* scopep() const { return m_scopep; } void ready(OrderVisitor* ovp); // Check the domScope is on ready list, add if not - void movedVertex(OrderVisitor* ovp, OrderMoveVertex* vertexp); // Mark one vertex as finished, remove from ready list if done + void movedVertex( + OrderVisitor* ovp, + OrderMoveVertex* vertexp); // Mark one vertex as finished, remove from ready list if done // STATIC MEMBERS (for lookup) static void clear() { - for (DomScopeMap::iterator it=s_dsMap.begin(); it!=s_dsMap.end(); ++it) { + for (DomScopeMap::iterator it = s_dsMap.begin(); it != s_dsMap.end(); ++it) { delete it->second; } s_dsMap.clear(); } V3List& readyVertices() { return m_readyVertices; } - static OrderMoveDomScope* findCreate(const AstSenTree* domainp, - const AstScope* scopep) { + static OrderMoveDomScope* findCreate(const AstSenTree* domainp, const AstScope* scopep) { const DomScopeKey key = make_pair(domainp, scopep); DomScopeMap::iterator iter = s_dsMap.find(key); if (iter != s_dsMap.end()) { @@ -170,16 +171,14 @@ public: } } string name() const { - return (string("MDS:") - +" d="+cvtToHex(domainp()) - +" s="+cvtToHex(scopep())); + return (string("MDS:") + " d=" + cvtToHex(domainp()) + " s=" + cvtToHex(scopep())); } }; -OrderMoveDomScope::DomScopeMap OrderMoveDomScope::s_dsMap; +OrderMoveDomScope::DomScopeMap OrderMoveDomScope::s_dsMap; -inline std::ostream& operator<< (std::ostream& lhs, const OrderMoveDomScope& rhs) { - lhs<v3fatalSrc("Bad case"); } @@ -222,26 +220,24 @@ public: public: // CONSTRUCTORS OrderUser() { - for (int i=0; ivarScp()->varp()->width() - > vsv2p->varScp()->varp()->width(); + bool operator()(OrderVarStdVertex* vsv1p, OrderVarStdVertex* vsv2p) { + return vsv1p->varScp()->varp()->width() > vsv2p->varScp()->varp()->width(); } }; //! Comparator for fanout of vertex struct OrderVarFanoutCmp { - bool operator() (OrderVarStdVertex* vsv1p, OrderVarStdVertex* vsv2p) { + bool operator()(OrderVarStdVertex* vsv1p, OrderVarStdVertex* vsv2p) { return vsv1p->fanout() > vsv2p->fanout(); } }; @@ -261,12 +257,12 @@ struct OrderVarFanoutCmp { // class OrderClkMarkVisitor : public AstNVisitor { private: - bool m_hasClk; // flag indicating whether there is clock signal on rhs - bool m_inClocked; // Currently inside a sequential block - bool m_newClkMarked; // Flag for deciding whether a new run is needed - bool m_inAss; // Currently inside of a assignment - int m_childClkWidth; // If in hasClk, width of clock signal in child - int m_rightClkWidth; // Clk width on the RHS + bool m_hasClk; // flag indicating whether there is clock signal on rhs + bool m_inClocked; // Currently inside a sequential block + bool m_newClkMarked; // Flag for deciding whether a new run is needed + bool m_inAss; // Currently inside of a assignment + int m_childClkWidth; // If in hasClk, width of clock signal in child + int m_rightClkWidth; // Clk width on the RHS // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -278,11 +274,12 @@ private: m_rightClkWidth = varrefp->width(); if (varrefp->varp()->attrClocker() == VVarAttrClocker::CLOCKER_YES) { if (m_inClocked) { - varrefp->v3warn(CLKDATA, "Clock used as data (on rhs of assignment) in sequential block " - <prettyNameQ()<v3warn( + CLKDATA, "Clock used as data (on rhs of assignment) in sequential block " + << varrefp->prettyNameQ() << endl); } else { m_hasClk = true; - UINFO(5, "node is already marked as clocker "<lhsp()->width() > m_rightClkWidth) { - nodep->v3warn(CLKDATA, "Clock is assigned to part of data signal " - <lhsp()<lhsp()->width() <v3warn(CLKDATA, "Clock is assigned to part of data signal " << nodep->lhsp() + << endl); + UINFO(4, "CLKDATA: lhs with width " << nodep->lhsp()->width() << endl); + UINFO(4, " but rhs clock with width " << m_rightClkWidth << endl); return; // skip the marking } @@ -307,7 +304,7 @@ private: if (lhsp && (lhsp->varp()->attrClocker() == VVarAttrClocker::CLOCKER_UNKNOWN)) { lhsp->varp()->attrClocker(VVarAttrClocker::CLOCKER_YES); // mark as clocker m_newClkMarked = true; // enable a further run since new clocker is marked - UINFO(5, "node is newly marked as clocker by assignment "<v3warn(CLKDATA, "Clock used as data (on rhs of assignment) in sequential block " - <prettyNameQ()); + << nodep->prettyNameQ()); } else { m_hasClk = true; m_childClkWidth = nodep->width(); // Pass up - UINFO(5, "node is already marked as clocker "<lhsp(), VarRef)) { if (varrefp->varp()->attrClocker() == VVarAttrClocker::CLOCKER_YES) { m_clkAss = true; - UINFO(6, "node was marked as clocker "<rhsp()); @@ -419,8 +416,7 @@ public: //###################################################################### // ProcessMoveBuildGraph -template -class ProcessMoveBuildGraph { +template class ProcessMoveBuildGraph { // ProcessMoveBuildGraph takes as input the fine-grained graph of // OrderLogicVertex, OrderVarVertex, etc; this is 'm_graph' in // OrderVisitor. It produces a slightly coarsened graph to drive the @@ -449,29 +445,29 @@ public: // Clients of ProcessMoveBuildGraph must supply MoveVertexMaker // which creates new T_MoveVertex's. Each new vertex wraps lvertexp // (which may be NULL.) - virtual T_MoveVertex* makeVertexp(OrderLogicVertex* lvertexp, - const OrderEitherVertex* varVertexp, - const AstScope* scopep, - const AstSenTree* domainp) = 0; + virtual T_MoveVertex* makeVertexp( // + OrderLogicVertex* lvertexp, const OrderEitherVertex* varVertexp, + const AstScope* scopep, const AstSenTree* domainp) + = 0; virtual void freeVertexp(T_MoveVertex* freeMep) = 0; }; private: // MEMBERS - const V3Graph* m_graphp; // Input graph of OrderLogicVertex's etc - V3Graph* m_outGraphp; // Output graph of T_MoveVertex's - MoveVertexMaker* m_vxMakerp; // Factory class for T_MoveVertex's - Logic2Move m_logic2move; // Map Logic to Vertex - Var2Move m_var2move; // Map Vars to Vertex + const V3Graph* m_graphp; // Input graph of OrderLogicVertex's etc + V3Graph* m_outGraphp; // Output graph of T_MoveVertex's + MoveVertexMaker* m_vxMakerp; // Factory class for T_MoveVertex's + Logic2Move m_logic2move; // Map Logic to Vertex + Var2Move m_var2move; // Map Vars to Vertex public: // CONSTRUCTORS ProcessMoveBuildGraph(const V3Graph* logicGraphp, // Input graph of OrderLogicVertex etc. V3Graph* outGraphp, // Output graph of T_MoveVertex's MoveVertexMaker* vxMakerp) - : m_graphp(logicGraphp), - m_outGraphp(outGraphp), - m_vxMakerp(vxMakerp) {} + : m_graphp(logicGraphp) + , m_outGraphp(outGraphp) + , m_vxMakerp(vxMakerp) {} virtual ~ProcessMoveBuildGraph() {} // METHODS @@ -489,12 +485,10 @@ public: // done the forward search, so stop. // For each logic node, make a T_MoveVertex - for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; - itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; itp = itp->verticesNextp()) { if (OrderLogicVertex* lvertexp = dynamic_cast(itp)) { - T_MoveVertex* moveVxp = - m_vxMakerp->makeVertexp(lvertexp, NULL, lvertexp->scopep(), - lvertexp->domainp()); + T_MoveVertex* moveVxp = m_vxMakerp->makeVertexp(lvertexp, NULL, lvertexp->scopep(), + lvertexp->domainp()); if (moveVxp) { // Cross link so we can find it later m_logic2move[lvertexp] = moveVxp; @@ -502,31 +496,27 @@ public: } } // Build edges between logic vertices - for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; - itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; itp = itp->verticesNextp()) { if (OrderLogicVertex* lvertexp = dynamic_cast(itp)) { T_MoveVertex* moveVxp = m_logic2move[lvertexp]; - if (moveVxp) { - iterate(moveVxp, lvertexp, lvertexp->domainp()); - } + if (moveVxp) { iterate(moveVxp, lvertexp, lvertexp->domainp()); } } } } private: // Return true if moveVxp has downstream dependencies - bool iterate(T_MoveVertex* moveVxp, const V3GraphVertex* origVxp, - const AstSenTree* domainp) { + bool iterate(T_MoveVertex* moveVxp, const V3GraphVertex* origVxp, const AstSenTree* domainp) { bool madeDeps = false; // Search forward from given original vertex, making new edges from // moveVxp forward - for (V3GraphEdge* edgep = origVxp->outBeginp(); edgep; edgep=edgep->outNextp()) { - if (edgep->weight()==0) { // Was cut + for (V3GraphEdge* edgep = origVxp->outBeginp(); edgep; edgep = edgep->outNextp()) { + if (edgep->weight() == 0) { // Was cut continue; } int weight = edgep->weight(); - if (const OrderLogicVertex* toLVertexp = - dynamic_cast(edgep->top())) { + if (const OrderLogicVertex* toLVertexp + = dynamic_cast(edgep->top())) { // Do not construct dependencies across exclusive domains. if (domainsExclusive(domainp, toLVertexp->domainp())) continue; @@ -534,8 +524,7 @@ private: // Path from vertexp to a logic vertex; new edge. // Note we use the last edge's weight, not some function of // multiple edges - new OrderEdge(m_outGraphp, moveVxp, - m_logic2move[toLVertexp], weight); + new OrderEdge(m_outGraphp, moveVxp, m_logic2move[toLVertexp], weight); madeDeps = true; } else { // This is an OrderVarVertex or other vertex representing @@ -543,10 +532,10 @@ private: const V3GraphVertex* nonLogicVxp = edgep->top(); VxDomPair key(nonLogicVxp, domainp); if (!m_var2move[key]) { - const OrderEitherVertex* eithp = - dynamic_cast(nonLogicVxp); - T_MoveVertex* newMoveVxp = - m_vxMakerp->makeVertexp(NULL, eithp, eithp->scopep(), domainp); + const OrderEitherVertex* eithp + = dynamic_cast(nonLogicVxp); + T_MoveVertex* newMoveVxp + = m_vxMakerp->makeVertexp(NULL, eithp, eithp->scopep(), domainp); m_var2move[key] = newMoveVxp; // Find downstream logics that depend on (var, domain) @@ -573,24 +562,20 @@ private: //###################################################################### // OrderMoveVertexMaker and related -class OrderMoveVertexMaker - : public ProcessMoveBuildGraph::MoveVertexMaker { +class OrderMoveVertexMaker : public ProcessMoveBuildGraph::MoveVertexMaker { // MEMBERS V3Graph* m_pomGraphp; V3List* m_pomWaitingp; + public: // CONSTRUCTORS - OrderMoveVertexMaker(V3Graph* pomGraphp, - V3List* pomWaitingp) - : m_pomGraphp(pomGraphp), - m_pomWaitingp(pomWaitingp) {} + OrderMoveVertexMaker(V3Graph* pomGraphp, V3List* pomWaitingp) + : m_pomGraphp(pomGraphp) + , m_pomWaitingp(pomWaitingp) {} // METHODS - OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, - const OrderEitherVertex*, - const AstScope* scopep, - const AstSenTree* domainp) { - OrderMoveVertex* resultp = - new OrderMoveVertex(m_pomGraphp, lvertexp); + OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex*, + const AstScope* scopep, const AstSenTree* domainp) { + OrderMoveVertex* resultp = new OrderMoveVertex(m_pomGraphp, lvertexp); resultp->domScopep(OrderMoveDomScope::findCreate(domainp, scopep)); resultp->m_pomWaitingE.pushBack(*m_pomWaitingp, resultp); return resultp; @@ -599,39 +584,35 @@ public: freeMep->m_pomWaitingE.unlink(*m_pomWaitingp, freeMep); freeMep->unlinkDelete(m_pomGraphp); } + private: VL_UNCOPYABLE(OrderMoveVertexMaker); }; -class OrderMTaskMoveVertexMaker - : public ProcessMoveBuildGraph::MoveVertexMaker { +class OrderMTaskMoveVertexMaker : public ProcessMoveBuildGraph::MoveVertexMaker { V3Graph* m_pomGraphp; + public: explicit OrderMTaskMoveVertexMaker(V3Graph* pomGraphp) : m_pomGraphp(pomGraphp) {} - MTaskMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, - const OrderEitherVertex* varVertexp, - const AstScope* scopep, - const AstSenTree* domainp) { + MTaskMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex* varVertexp, + const AstScope* scopep, const AstSenTree* domainp) { // Exclude initial/settle logic from the mtasks graph. // We'll output time-zero logic separately. - if (domainp->hasInitial() || domainp->hasSettle()) { - return NULL; - } + if (domainp->hasInitial() || domainp->hasSettle()) return NULL; return new MTaskMoveVertex(m_pomGraphp, lvertexp, varVertexp, scopep, domainp); } - void freeVertexp(MTaskMoveVertex* freeMep) { - freeMep->unlinkDelete(m_pomGraphp); - } + void freeVertexp(MTaskMoveVertex* freeMep) { freeMep->unlinkDelete(m_pomGraphp); } + private: VL_UNCOPYABLE(OrderMTaskMoveVertexMaker); }; class OrderVerticesByDomainThenScope { PartPtrIdMap m_ids; + public: - virtual bool operator()(const V3GraphVertex* lhsp, - const V3GraphVertex* rhsp) const { + virtual bool operator()(const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { const MTaskMoveVertex* l_vxp = dynamic_cast(lhsp); const MTaskMoveVertex* r_vxp = dynamic_cast(rhsp); vluint64_t l_id = m_ids.findId(l_vxp->domainp()); @@ -651,12 +632,9 @@ public: // Sort vertex's, which must be AbstractMTask's, into a deterministic // order by comparing their serial IDs. - virtual bool operator()(const V3GraphVertex* lhsp, - const V3GraphVertex* rhsp) const { - const AbstractMTask* lmtaskp = - dynamic_cast(lhsp); - const AbstractMTask* rmtaskp = - dynamic_cast(rhsp); + virtual bool operator()(const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { + const AbstractMTask* lmtaskp = dynamic_cast(lhsp); + const AbstractMTask* rmtaskp = dynamic_cast(rhsp); return lmtaskp->id() < rmtaskp->id(); } }; @@ -678,61 +656,61 @@ private: // AstNodeModule::user3() -> Number of routines created // Each call to V3Const::constify // AstNode::user4() Used by V3Const::constify, called below - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser3InUse m_inuser3; - //AstUser4InUse m_inuser4; // Used only when building tree, so below + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; + AstUser3InUse m_inuser3; + // AstUser4InUse m_inuser4; // Used only when building tree, so below // STATE - OrderGraph m_graph; // Scoreboard of var usages/dependencies - SenTreeFinder m_finder; // Find global sentree's and add them - AstSenTree* m_comboDomainp; // Combo activation tree - AstSenTree* m_deleteDomainp;// Delete this from tree - AstSenTree* m_settleDomainp;// Initial activation tree - OrderInputsVertex* m_inputsVxp; // Top level vertex all inputs point from - OrderSettleVertex* m_settleVxp; // Top level vertex all settlement vertexes point from - OrderLogicVertex* m_logicVxp; // Current statement being tracked, NULL=ignored - AstTopScope* m_topScopep; // Current top scope being processed - AstScope* m_scopetopp; // Scope under TOPSCOPE - AstNodeModule* m_modp; // Current module - AstScope* m_scopep; // Current scope being processed - AstActive* m_activep; // Current activation block - bool m_inSenTree; // Underneath AstSenItem; any varrefs are clocks - bool m_inClocked; // Underneath clocked block - bool m_inClkAss; // Underneath AstAssign - bool m_inPre; // Underneath AstAssignPre - bool m_inPost; // Underneath AstAssignPost - OrderLogicVertex* m_activeSenVxp; // Sensitivity vertex - std::deque m_orderUserps; // All created OrderUser's for later deletion. + OrderGraph m_graph; // Scoreboard of var usages/dependencies + SenTreeFinder m_finder; // Find global sentree's and add them + AstSenTree* m_comboDomainp; // Combo activation tree + AstSenTree* m_deleteDomainp; // Delete this from tree + AstSenTree* m_settleDomainp; // Initial activation tree + OrderInputsVertex* m_inputsVxp; // Top level vertex all inputs point from + OrderSettleVertex* m_settleVxp; // Top level vertex all settlement vertexes point from + OrderLogicVertex* m_logicVxp; // Current statement being tracked, NULL=ignored + AstTopScope* m_topScopep; // Current top scope being processed + AstScope* m_scopetopp; // Scope under TOPSCOPE + AstNodeModule* m_modp; // Current module + AstScope* m_scopep; // Current scope being processed + AstActive* m_activep; // Current activation block + bool m_inSenTree; // Underneath AstSenItem; any varrefs are clocks + bool m_inClocked; // Underneath clocked block + bool m_inClkAss; // Underneath AstAssign + bool m_inPre; // Underneath AstAssignPre + bool m_inPost; // Underneath AstAssignPost + OrderLogicVertex* m_activeSenVxp; // Sensitivity vertex + std::deque m_orderUserps; // All created OrderUser's for later deletion. // STATE... for inside process - AstCFunc* m_pomNewFuncp; // Current function being created - int m_pomNewStmts; // Statements in function being created - V3Graph m_pomGraph; // Graph of logic elements to move - V3List m_pomWaiting; // List of nodes needing inputs to become ready + AstCFunc* m_pomNewFuncp; // Current function being created + int m_pomNewStmts; // Statements in function being created + V3Graph m_pomGraph; // Graph of logic elements to move + V3List m_pomWaiting; // List of nodes needing inputs to become ready protected: friend class OrderMoveDomScope; - V3List m_pomReadyDomScope; // List of ready domain/scope pairs, by loopId - std::vector m_unoptflatVars; // Vector of variables in UNOPTFLAT loop + V3List m_pomReadyDomScope; // List of ready domain/scope pairs, by loopId + std::vector m_unoptflatVars; // Vector of variables in UNOPTFLAT loop private: // STATS VDouble0 m_statCut[OrderVEdgeType::_ENUM_END]; // Count of each edge type cut // TYPES - enum VarUsage { VU_NONE=0, VU_CON=1, VU_GEN=2 }; + enum VarUsage { VU_NONE = 0, VU_CON = 1, VU_GEN = 2 }; // METHODS VL_DEBUG_FUNC; // Declare debug() void iterateNewStmt(AstNode* nodep) { if (m_scopep) { - UINFO(4," STMT "<sensesp(), nodep, "NULL"); // If inside combo logic, ignore the domain, we'll assign one based on interconnect AstSenTree* startDomainp = m_activep->sensesp(); - if (startDomainp->hasCombo()) startDomainp=NULL; + if (startDomainp->hasCombo()) startDomainp = NULL; m_logicVxp = new OrderLogicVertex(&m_graph, m_scopep, startDomainp, nodep); if (m_activeSenVxp) { // If in a clocked activation, add a link from the sensitivity to this block @@ -745,7 +723,8 @@ private: } } - OrderVarVertex* newVarUserVertex(AstVarScope* varscp, WhichVertex type, bool* createdp=NULL) { + OrderVarVertex* newVarUserVertex(AstVarScope* varscp, WhichVertex type, + bool* createdp = NULL) { if (!varscp->user1p()) { OrderUser* newup = new OrderUser(); m_orderUserps.push_back(newup); @@ -775,8 +754,8 @@ private: void processMoveReadyOne(OrderMoveVertex* vertexp); void processMoveDoneOne(OrderMoveVertex* vertexp); void processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* domScopep, int level); - AstActive* processMoveOneLogic(const OrderLogicVertex* lvertexp, - AstCFunc*& newFuncpr, int& newStmtsr); + AstActive* processMoveOneLogic(const OrderLogicVertex* lvertexp, AstCFunc*& newFuncpr, + int& newStmtsr); // processMTask* routines schedule threaded execution struct MTaskState { @@ -784,23 +763,28 @@ private: AstMTaskBody* m_mtaskBodyp; Logics m_logics; ExecMTask* m_execMTaskp; - MTaskState() : m_mtaskBodyp(NULL), m_execMTaskp(NULL) {} + MTaskState() + : m_mtaskBodyp(NULL) + , m_execMTaskp(NULL) {} }; void processMTasks(); - typedef enum {LOGIC_INITIAL, LOGIC_SETTLE} InitialLogicE; + typedef enum { LOGIC_INITIAL, LOGIC_SETTLE } InitialLogicE; void processMTasksInitial(InitialLogicE logic_type); - string cfuncName(AstNodeModule* modp, AstSenTree* domainp, - AstScope* scopep, AstNode* forWhatp) { + string cfuncName(AstNodeModule* modp, AstSenTree* domainp, AstScope* scopep, + AstNode* forWhatp) { modp->user3Inc(); int funcnum = modp->user3(); - string name = (domainp->hasCombo() ? "_combo" - : (domainp->hasInitial() ? "_initial" - : (domainp->hasSettle() ? "_settle" - : (domainp->isMulti() ? "_multiclk" : "_sequent")))); - name = name+"__"+scopep->nameDotless()+"__"+cvtToStr(funcnum); + string name = (domainp->hasCombo() + ? "_combo" + : (domainp->hasInitial() + ? "_initial" + : (domainp->hasSettle() + ? "_settle" + : (domainp->isMulti() ? "_multiclk" : "_sequent")))); + name = name + "__" + scopep->nameDotless() + "__" + cvtToStr(funcnum); if (v3Global.opt.profCFuncs()) { - name += "__PROF__"+forWhatp->fileline()->profileFuncname(); + name += "__PROF__" + forWhatp->fileline()->profileFuncname(); } return name; } @@ -819,46 +803,54 @@ private: // IEEE does not specify ordering between initial blocks, so we // can do whatever we want. We especially do not want to // evaluate multiple times, so do not mark the edge circular - } - else { + } else { nodep->circular(true); ++m_statCut[vertexp->type()]; if (edgep) ++m_statCut[edgep->type()]; // if (vertexp->isClock()) { // Seems obvious; no warning yet - //nodep->v3warn(GENCLK, "Signal unoptimizable: Generated clock: "<prettyNameQ()); + // nodep->v3warn(GENCLK, "Signal unoptimizable: Generated clock: + // "<prettyNameQ()); } else if (nodep->varp()->isSigPublic()) { - nodep->v3warn(UNOPT, "Signal unoptimizable: Feedback to public clock or circular logic: " - <prettyNameQ()); + nodep->v3warn(UNOPT, + "Signal unoptimizable: Feedback to public clock or circular logic: " + << nodep->prettyNameQ()); if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPT)) { - nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPT, true); // Complain just once + nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPT, + true); // Complain just once // Give the user an example. - bool tempWeight = (edgep && edgep->weight()==0); - if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop - m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb + bool tempWeight = (edgep && edgep->weight() == 0); + // Else the below loop detect can't see the loop + if (tempWeight) edgep->weight(1); + // Calls OrderGraph::loopsVertexCb + m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); if (tempWeight) edgep->weight(0); } } else { // We don't use UNOPT, as there are lots of V2 places where // it was needed, that aren't any more // First v3warn not inside warnIsOff so we can see the suppressions with --debug - nodep->v3warn(UNOPTFLAT, "Signal unoptimizable: Feedback to clock or circular logic: " - <prettyNameQ()); + nodep->v3warn(UNOPTFLAT, + "Signal unoptimizable: Feedback to clock or circular logic: " + << nodep->prettyNameQ()); if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPTFLAT)) { - nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true); // Complain just once + nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPTFLAT, + true); // Complain just once // Give the user an example. - bool tempWeight = (edgep && edgep->weight()==0); - if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop - m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb + bool tempWeight = (edgep && edgep->weight() == 0); + // Else the below loop detect can't see the loop + if (tempWeight) edgep->weight(1); + // Calls OrderGraph::loopsVertexCb + m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); if (tempWeight) edgep->weight(0); if (v3Global.opt.reportUnoptflat()) { // Report candidate variables for splitting reportLoopVars(vertexp); // Do a subgraph for the UNOPTFLAT loop OrderGraph loopGraph; - m_graph.subtreeLoops(&OrderEdge::followComboConnected, - vertexp, &loopGraph); + m_graph.subtreeLoops(&OrderEdge::followComboConnected, vertexp, + &loopGraph); loopGraph.dumpDotFilePrefixedAlways("unoptflat"); } } @@ -898,16 +890,14 @@ private: << varp->prettyName() << std::dec << ", width " << varp->width() << ", fanout " << vsvertexp->fanout(); if (canSplit) { - std::cerr <<", can split_var"; + std::cerr << ", can split_var"; canSplitList.insert(varp); } std::cerr << std::endl; } // Up to 10 of the most fanned out - std::cerr << V3Error::warnMore() - << "... Most fanned out candidate vars to split:" << endl; - std::stable_sort(m_unoptflatVars.begin(), m_unoptflatVars.end(), - OrderVarFanoutCmp()); + std::cerr << V3Error::warnMore() << "... Most fanned out candidate vars to split:" << endl; + std::stable_sort(m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarFanoutCmp()); lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10; for (int i = 0; i < lim; i++) { OrderVarStdVertex* vsvertexp = m_unoptflatVars[i]; @@ -920,7 +910,7 @@ private: std::cerr << ", can split_var"; canSplitList.insert(varp); } - std::cerr<varScp()->varp(); if (!varp->user3()) { string name = varp->prettyName(); - if ((varp->width() != 1) - && (name.find("__Vdly") == string::npos) + if ((varp->width() != 1) && (name.find("__Vdly") == string::npos) && (name.find("__Vcell") == string::npos)) { // Variable to report on and not yet done m_unoptflatVars.push_back(vsvertexp); @@ -949,33 +938,30 @@ private: } } // Iterate through all the to and from vertices of the same color - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; - edgep = edgep->outNextp()) { - if (edgep->top()->color() == color) { - reportLoopVarsIterate(edgep->top(), color); - } + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { + if (edgep->top()->color() == color) reportLoopVarsIterate(edgep->top(), color); } - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; - edgep = edgep->inNextp()) { - if (edgep->fromp()->color() == color) { - reportLoopVarsIterate(edgep->fromp(), color); - } + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { + if (edgep->fromp()->color() == color) reportLoopVarsIterate(edgep->fromp(), color); } } // VISITORS virtual void visit(AstNetlist* nodep) VL_OVERRIDE { { - AstUser4InUse m_inuser4; // Used only when building tree, so below + AstUser4InUse m_inuser4; // Used only when building tree, so below iterateChildren(nodep); } // We're finished, complete the topscopes - if (m_topScopep) { process(); m_topScopep=NULL; } + if (m_topScopep) { + process(); + m_topScopep = NULL; + } } virtual void visit(AstTopScope* nodep) VL_OVERRIDE { // Process the last thing we're finishing UASSERT_OBJ(!m_topScopep, nodep, "Only one topscope should ever be created"); - UINFO(2," Loading tree...\n"); - //VV***** We reset userp() + UINFO(2, " Loading tree...\n"); + // VV***** We reset userp() AstNode::user1ClearTree(); AstNode::user3ClearTree(); m_graph.clear(); @@ -986,20 +972,21 @@ private: m_finder.main(m_topScopep); // ProcessDomainsIterate will use these when it needs to move // something to a combodomain. This saves a ton of find() operations. - AstSenTree* combp = new AstSenTree(nodep->fileline(), // Gets cloned() so ok if goes out of scope - new AstSenItem(nodep->fileline(), AstSenItem::Combo())); + AstSenTree* combp + = new AstSenTree(nodep->fileline(), // Gets cloned() so ok if goes out of scope + new AstSenItem(nodep->fileline(), AstSenItem::Combo())); m_comboDomainp = m_finder.getSenTree(nodep->fileline(), combp); pushDeletep(combp); // Cleanup when done - AstSenTree* settlep = new AstSenTree(nodep->fileline(), // Gets cloned() so ok if goes out of scope - new AstSenItem(nodep->fileline(), - AstSenItem::Settle())); + AstSenTree* settlep + = new AstSenTree(nodep->fileline(), // Gets cloned() so ok if goes out of scope + new AstSenItem(nodep->fileline(), AstSenItem::Settle())); m_settleDomainp = m_finder.getSenTree(nodep->fileline(), settlep); pushDeletep(settlep); // Cleanup when done // Fake AstSenTree we set domainp to indicate needs deletion m_deleteDomainp = new AstSenTree(nodep->fileline(), new AstSenItem(nodep->fileline(), AstSenItem::Settle())); pushDeletep(m_deleteDomainp); // Cleanup when done - UINFO(5," DeleteDomain = "<hasClocked(); @@ -1089,19 +1076,17 @@ private: // clock_enable attribute: user's worrying about it for us con = false; } - if (m_inClkAss && (varscp->varp()->attrClocker() - != VVarAttrClocker::CLOCKER_YES)) { + if (m_inClkAss + && (varscp->varp()->attrClocker() != VVarAttrClocker::CLOCKER_YES)) { con = false; - UINFO(4, "nodep used as clock_enable "<nodep()<nodep() << endl); } } if (gen) varscp->user4(varscp->user4() | VU_GEN); if (con) varscp->user4(varscp->user4() | VU_CON); // Add edges - if (!m_inClocked - || m_inPost - ) { + if (!m_inClocked || m_inPost) { // Combo logic { // not settle and (combo or inPost) if (gen) { @@ -1113,8 +1098,8 @@ private: // internal clocks circular, which must only // happen if they are generated by delayed // assignment. - UINFO(5, " Found delayed assignment (post) " - << varVxp << endl); + UINFO(5, + " Found delayed assignment (post) " << varVxp << endl); varVxp->isDelayed(true); } else { // If the lhs is a clocker, avoid marking that as circular by @@ -1197,20 +1182,14 @@ private: m_inSenTree = false; } } - virtual void visit(AstAlways* nodep) VL_OVERRIDE { - iterateNewStmt(nodep); - } virtual void visit(AstAlwaysPost* nodep) VL_OVERRIDE { m_inPost = true; iterateNewStmt(nodep); m_inPost = false; } - virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { - iterateNewStmt(nodep); - } - virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { - iterateNewStmt(nodep); - } + virtual void visit(AstAlways* nodep) VL_OVERRIDE { iterateNewStmt(nodep); } + virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { iterateNewStmt(nodep); } + virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { iterateNewStmt(nodep); } virtual void visit(AstAssignW* nodep) VL_OVERRIDE { OrderClkAssVisitor visitor(nodep); m_inClkAss = visitor.isClkAss(); @@ -1233,9 +1212,7 @@ private: m_inPost = false; m_inClkAss = false; } - virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { - iterateNewStmt(nodep); - } + virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { iterateNewStmt(nodep); } virtual void visit(AstInitial* nodep) VL_OVERRIDE { // We use initials to setup parameters and static consts's which may be referenced // in user initial blocks. So use ordering to sort them all out. @@ -1275,22 +1252,20 @@ public: } virtual ~OrderVisitor() { // Stats - for (int type=0; type::iterator it=m_orderUserps.begin(); + for (std::deque::iterator it = m_orderUserps.begin(); it != m_orderUserps.end(); ++it) { delete *it; } m_graph.debug(V3Error::debugDefault()); } - void main(AstNode* nodep) { - iterate(nodep); - } + void main(AstNode* nodep) { iterate(nodep); } }; //###################################################################### @@ -1313,9 +1288,7 @@ static bool domainsExclusive(const AstSenTree* fromp, const AstSenTree* top) { bool toInitial = top->hasInitial() || top->hasSettle(); bool fromInitial = fromp->hasInitial() || fromp->hasSettle(); - if (toInitial != fromInitial) { - return true; - } + if (toInitial != fromInitial) return true; const AstSenItem* fromSenListp = VN_CAST(fromp->sensesp(), SenItem); const AstSenItem* toSenListp = VN_CAST(top->sensesp(), SenItem); @@ -1363,13 +1336,15 @@ inline void OrderMoveDomScope::movedVertex(OrderVisitor* ovp, OrderMoveVertex* v // OrderVisitor - Clock propagation void OrderVisitor::processInputs() { - m_graph.userClearVertices(); // Vertex::user() // 1 if input recursed, 2 if marked as input, 3 if out-edges recursed + m_graph.userClearVertices(); // Vertex::user() // 1 if input recursed, 2 if marked as input, + // 3 if out-edges recursed // Start at input vertex, process from input-to-output order VertexVec todoVec; // List of newly-input marked vectors we need to process todoVec.push_front(m_inputsVxp); m_inputsVxp->isFromInput(true); // By definition while (!todoVec.empty()) { - OrderEitherVertex* vertexp = todoVec.back(); todoVec.pop_back(); + OrderEitherVertex* vertexp = todoVec.back(); + todoVec.pop_back(); processInputsOutIterate(vertexp, todoVec); } } @@ -1377,8 +1352,8 @@ void OrderVisitor::processInputs() { void OrderVisitor::processInputsInIterate(OrderEitherVertex* vertexp, VertexVec& todoVec) { // Propagate PrimaryIn through simple assignments if (vertexp->user()) return; // Already processed - if (0 && debug()>=9) { - UINFO(9," InIIter "<= 9) { + UINFO(9, " InIIter " << vertexp << endl); if (OrderLogicVertex* vvertexp = dynamic_cast(vertexp)) { vvertexp->nodep()->dumpTree(cout, "- TT: "); } @@ -1387,22 +1362,23 @@ void OrderVisitor::processInputsInIterate(OrderEitherVertex* vertexp, VertexVec& // First handle all inputs to this vertex, in most cases they'll be already processed earlier // Also, determine if this vertex is an input int inonly = 1; // 0=no, 1=maybe, 2=yes until a no - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { OrderEitherVertex* frVertexp = static_cast(edgep->fromp()); processInputsInIterate(frVertexp, todoVec); if (frVertexp->isFromInput()) { - if (inonly==1) inonly = 2; + if (inonly == 1) inonly = 2; } else if (dynamic_cast(frVertexp)) { // Ignore post assignments, just for ordering } else { - //UINFO(9," InItStopDueTo "<user()<2) { // Set it. Note may have already been set earlier, too - UINFO(9," Input reassignment: "<user() < 2) { // Set it. Note may have already been set earlier, too + UINFO(9, " Input reassignment: " << vertexp << endl); vertexp->isFromInput(true); vertexp->user(2); // 2 means on list // Can't work on out-edges of a node we know is an input immediately, @@ -1410,12 +1386,12 @@ void OrderVisitor::processInputsInIterate(OrderEitherVertex* vertexp, VertexVec& // So push to list and work on it later when all in-edges known resolved todoVec.push_back(vertexp); } - //UINFO(9," InIdone "<user()==3) return; // Already out processed - //UINFO(9," InOIter "<user() == 3) return; // Already out processed + // UINFO(9, " InOIter " << vertexp << endl); // First make sure input path is fully recursed processInputsInIterate(vertexp, todoVec); // Propagate PrimaryIn through simple assignments @@ -1425,7 +1401,7 @@ void OrderVisitor::processInputsOutIterate(OrderEitherVertex* vertexp, VertexVec { // Propagate PrimaryIn through simple assignments, following target of vertex - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { OrderEitherVertex* toVertexp = static_cast(edgep->top()); if (OrderVarStdVertex* vvertexp = dynamic_cast(toVertexp)) { processInputsInIterate(vvertexp, todoVec); @@ -1445,7 +1421,7 @@ void OrderVisitor::processInputsOutIterate(OrderEitherVertex* vertexp, VertexVec void OrderVisitor::processCircular() { // Take broken edges and add circular flags // The change detect code will use this to force changedets - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (OrderVarStdVertex* vvertexp = dynamic_cast(itp)) { if (vvertexp->isClock() && !vvertexp->isFromInput()) { // If a clock is generated internally, we need to do another @@ -1457,31 +1433,29 @@ void OrderVisitor::processCircular() { // it is combinatorial, we do not (and indeed it will break // other tests such as t_gated_clk_1. if (!v3Global.opt.orderClockDly()) { - UINFO(5,"Circular Clock, no-order-clock-delay "<isDelayed()) { - UINFO(5,"Circular Clock, delayed "<isDelayed()) { + UINFO(5, "Circular Clock, delayed " << vvertexp << endl); nodeMarkCircular(vvertexp, NULL); - } - else { - UINFO(5,"Circular Clock, not delayed "<outBeginp(); edgep; edgep=edgep->outNextp()) { - if (edgep->weight()==0) { // was cut + for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { + if (edgep->weight() == 0) { // was cut OrderEdge* oedgep = dynamic_cast(edgep); UASSERT_OBJ(oedgep, vvertexp->varScp(), "Cutable edge not of proper type"); - UINFO(6," CutCircularO: "<name()<name() << endl); nodeMarkCircular(vvertexp, oedgep); } } for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - if (edgep->weight()==0) { // was cut + if (edgep->weight() == 0) { // was cut OrderEdge* oedgep = dynamic_cast(edgep); UASSERT_OBJ(oedgep, vvertexp->varScp(), "Cutable edge not of proper type"); - UINFO(6," CutCircularI: "<name()<name() << endl); nodeMarkCircular(vvertexp, oedgep); } } @@ -1492,15 +1466,16 @@ void OrderVisitor::processCircular() { void OrderVisitor::processSensitive() { // Sc sensitives are required on all inputs that go to a combo // block. (Not inputs that go only to clocked blocks.) - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (OrderVarStdVertex* vvertexp = dynamic_cast(itp)) { if (vvertexp->varScp()->varp()->isNonOutput()) { - //UINFO(0," scsen "<outBeginp(); edgep; edgep=edgep->outNextp()) { + // UINFO(0, " scsen " << vvertexp << endl); + for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; + edgep = edgep->outNextp()) { if (OrderEitherVertex* toVertexp = dynamic_cast(edgep->top())) { if (edgep->weight() && toVertexp->domainp()) { - //UINFO(0," "<domainp()<domainp() << endl); if (toVertexp->domainp()->hasCombo()) { vvertexp->varScp()->varp()->scSensitive(true); } @@ -1513,7 +1488,7 @@ void OrderVisitor::processSensitive() { } void OrderVisitor::processDomains() { - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { OrderEitherVertex* vertexp = dynamic_cast(itp); UASSERT(vertexp, "Null or vertex not derived from EitherVertex"); processDomainsIterate(vertexp); @@ -1528,49 +1503,39 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) { // else, if all inputs are from flops, it's end-of-sequential code // else, it's full combo code if (vertexp->domainp()) return; // Already processed, or sequential logic - UINFO(5," pdi: "<(vertexp); AstSenTree* domainp = NULL; UASSERT(m_comboDomainp, "not preset"); - if (vvertexp && vvertexp->varScp()->varp()->isNonOutput()) { - domainp = m_comboDomainp; - } - if (vvertexp && vvertexp->varScp()->isCircular()) { - domainp = m_comboDomainp; - } + if (vvertexp && vvertexp->varScp()->varp()->isNonOutput()) domainp = m_comboDomainp; + if (vvertexp && vvertexp->varScp()->isCircular()) domainp = m_comboDomainp; if (!domainp) { for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { OrderEitherVertex* fromVertexp = static_cast(edgep->fromp()); - if (edgep->weight() - && fromVertexp->domainMatters() - ) { - UINFO(9," from d="<domainp()) - <<" "<weight() && fromVertexp->domainMatters()) { + UINFO(9, " from d=" << cvtToHex(fromVertexp->domainp()) << " " << fromVertexp + << endl); if (!domainp // First input to this vertex || domainp->hasSettle() // or, we can ignore being in the settle domain || domainp->hasInitial()) { domainp = fromVertexp->domainp(); - } - else if (domainp->hasCombo()) { + } else if (domainp->hasCombo()) { // Once in combo, keep in combo; already as severe as we can get - } - else if (fromVertexp->domainp()->hasCombo()) { + } else if (fromVertexp->domainp()->hasCombo()) { // Any combo input means this vertex must remain combo domainp = m_comboDomainp; - } - else if (fromVertexp->domainp()->hasSettle() - || fromVertexp->domainp()->hasInitial()) { + } else if (fromVertexp->domainp()->hasSettle() + || fromVertexp->domainp()->hasInitial()) { // Ignore that we have a constant (initial) input - } - else if (domainp != fromVertexp->domainp()) { + } else if (domainp != fromVertexp->domainp()) { // Make a domain that merges the two domains - bool ddebug = debug()>=9; + bool ddebug = debug() >= 9; if (ddebug) { - cout<domainp()->isMulti()?" [MULT]":"") - <<" "<domainp()->isMulti() ? " [MULT]" : "") << " " + << vertexp << endl); } } @@ -1617,32 +1580,37 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) { void OrderVisitor::processEdgeReport() { // Make report of all signal names and what clock edges they have string filename = v3Global.debugFilename("order_edges.txt"); - const vl_unique_ptr logp (V3File::new_ofstream(filename)); - if (logp->fail()) v3fatal("Can't write "< logp(V3File::new_ofstream(filename)); + if (logp->fail()) v3fatal("Can't write " << filename); + // Testing emitter: V3EmitV::verilogForTree(v3Global.rootp(), *logp); std::deque report; - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (OrderVarVertex* vvertexp = dynamic_cast(itp)) { - string name (vvertexp->varScp()->prettyName()); - if (dynamic_cast(itp)) name += " {PRE}"; - else if (dynamic_cast(itp)) name += " {POST}"; - else if (dynamic_cast(itp)) name += " {PORD}"; - else if (dynamic_cast(itp)) name += " {STL}"; + string name(vvertexp->varScp()->prettyName()); + if (dynamic_cast(itp)) { + name += " {PRE}"; + } else if (dynamic_cast(itp)) { + name += " {POST}"; + } else if (dynamic_cast(itp)) { + name += " {PORD}"; + } else if (dynamic_cast(itp)) { + name += " {STL}"; + } std::ostringstream os; os.setf(std::ios::left); - os<<" "<varScp())<<" "<varScp()) << " " << std::setw(50) << name << " "; AstSenTree* sentreep = vvertexp->domainp(); if (sentreep) V3EmitV::verilogForTree(sentreep, os); report.push_back(os.str()); } } - *logp<<"Signals and their clock domains:"<::iterator it=report.begin(); it!=report.end(); ++it) { - *logp<<(*it)<::iterator it = report.begin(); it != report.end(); ++it) { + *logp << (*it) << endl; } } @@ -1655,13 +1623,14 @@ void OrderVisitor::processMoveClear() { void OrderVisitor::processMoveBuildGraph() { // Build graph of only vertices - UINFO(5," MoveBuildGraph\n"); + UINFO(5, " MoveBuildGraph\n"); processMoveClear(); - m_pomGraph.userClearVertices(); // Vertex::user() // OrderMoveVertex*, last edge added or NULL for none + m_pomGraph + .userClearVertices(); // Vertex::user->OrderMoveVertex*, last edge added or NULL=none OrderMoveVertexMaker createOrderMoveVertex(&m_pomGraph, &m_pomWaiting); - ProcessMoveBuildGraph serialPMBG( - &m_graph, &m_pomGraph, &createOrderMoveVertex); + ProcessMoveBuildGraph serialPMBG(&m_graph, &m_pomGraph, + &createOrderMoveVertex); serialPMBG.build(); } @@ -1684,7 +1653,7 @@ void OrderVisitor::processMove() { processMovePrepReady(); // New domain... another loop - UINFO(5," MoveIterate\n"); + UINFO(5, " MoveIterate\n"); while (!m_pomReadyDomScope.empty()) { // Start with top node on ready list's domain & scope OrderMoveDomScope* domScopep = m_pomReadyDomScope.begin(); @@ -1692,16 +1661,17 @@ void OrderVisitor::processMove() { UASSERT(topVertexp, "domScope on ready list without any nodes ready under it"); // Work on all scopes ready inside this domain while (domScopep) { - UINFO(6," MoveDomain l="<domainp()<pomWaitingNextp(); - if (vertexp->isWait() && vertexp->inEmpty()) { - processMoveReadyOne(vertexp); - } + if (vertexp->isWait() && vertexp->inEmpty()) { processMoveReadyOne(vertexp); } vertexp = nextp; } } @@ -1754,11 +1723,11 @@ void OrderVisitor::processMoveDoneOne(OrderMoveVertex* vertexp) { } // Don't need to add it to another list, as we're done with it // Mark our outputs as one closer to ready - for (V3GraphEdge* edgep = vertexp->outBeginp(), *nextp; edgep; edgep=nextp) { + for (V3GraphEdge *edgep = vertexp->outBeginp(), *nextp; edgep; edgep = nextp) { nextp = edgep->outNextp(); OrderMoveVertex* toVertexp = static_cast(edgep->top()); - UINFO(9," Clear to "<<(toVertexp->inEmpty()?"[EMP] ":" ") - <inEmpty() ? "[EMP] " : " ") << toVertexp + << endl); // Delete this edge VL_DO_DANGLING(edgep->unlinkDelete(), edgep); if (toVertexp->inEmpty()) { @@ -1770,22 +1739,21 @@ void OrderVisitor::processMoveDoneOne(OrderMoveVertex* vertexp) { } } -void OrderVisitor::processMoveOne(OrderMoveVertex* vertexp, - OrderMoveDomScope* domScopep, int level) { +void OrderVisitor::processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* domScopep, + int level) { UASSERT_OBJ(vertexp->domScopep() == domScopep, vertexp, "Domain mismatch; list misbuilt?"); const OrderLogicVertex* lvertexp = vertexp->logicp(); const AstScope* scopep = lvertexp->scopep(); - UINFO(5," POSmove l"<addActivep(newActivep); processMoveDoneOne(vertexp); } AstActive* OrderVisitor::processMoveOneLogic(const OrderLogicVertex* lvertexp, - AstCFunc*& newFuncpr, - int& newStmtsr) { + AstCFunc*& newFuncpr, int& newStmtsr) { AstActive* activep = NULL; AstScope* scopep = lvertexp->scopep(); AstSenTree* domainp = lvertexp->domainp(); @@ -1794,8 +1762,7 @@ AstActive* OrderVisitor::processMoveOneLogic(const OrderLogicVertex* lvertexp, UASSERT(modp, "NULL"); if (VN_IS(nodep, SenTree)) { // Just ignore sensitivities, we'll deal with them when we move statements that need them - } - else { // Normal logic + } else { // Normal logic // Make or borrow a CFunc to contain the new statements if (v3Global.opt.profCFuncs() || (v3Global.opt.outputSplitCFuncs() @@ -1817,13 +1784,13 @@ AstActive* OrderVisitor::processMoveOneLogic(const OrderLogicVertex* lvertexp, AstCCall* callp = new AstCCall(nodep->fileline(), newFuncpr); callp->argTypes("vlSymsp"); activep->addStmtsp(callp); - UINFO(6," New "<unlinkFrBack(); if (domainp == m_deleteDomainp) { - UINFO(4," Ordering deleting pre-settled "<addStmtsp(nodep); @@ -1844,20 +1811,18 @@ void OrderVisitor::processMTasksInitial(InitialLogicE logic_type) { int initStmts = 0; AstCFunc* initCFunc = NULL; AstScope* lastScopep = NULL; - for (V3GraphVertex* initVxp = m_graph.verticesBeginp(); - initVxp; initVxp = initVxp->verticesNextp()) { + for (V3GraphVertex* initVxp = m_graph.verticesBeginp(); initVxp; + initVxp = initVxp->verticesNextp()) { OrderLogicVertex* initp = dynamic_cast(initVxp); if (!initp) continue; - if ((logic_type == LOGIC_INITIAL) - && !initp->domainp()->hasInitial()) continue; - if ((logic_type == LOGIC_SETTLE) - && !initp->domainp()->hasSettle()) continue; + if ((logic_type == LOGIC_INITIAL) && !initp->domainp()->hasInitial()) continue; + if ((logic_type == LOGIC_SETTLE) && !initp->domainp()->hasSettle()) continue; if (initp->scopep() != lastScopep) { // Start new cfunc, don't let the cfunc cross scopes initCFunc = NULL; lastScopep = initp->scopep(); } - AstActive* newActivep = processMoveOneLogic(initp, initCFunc/*ref*/, initStmts/*ref*/); + AstActive* newActivep = processMoveOneLogic(initp, initCFunc /*ref*/, initStmts /*ref*/); if (newActivep) m_scopetopp->addActivep(newActivep); } } @@ -1877,8 +1842,7 @@ void OrderVisitor::processMTasks() { // This is quite similar to the 'm_pomGraph' of the serial code gen: V3Graph logicGraph; OrderMTaskMoveVertexMaker create_mtask_vertex(&logicGraph); - ProcessMoveBuildGraph mtask_pmbg( - &m_graph, &logicGraph, &create_mtask_vertex); + ProcessMoveBuildGraph mtask_pmbg(&m_graph, &logicGraph, &create_mtask_vertex); mtask_pmbg.build(); // Needed? We do this for m_pomGraph in serial mode, so do it here too: @@ -1901,11 +1865,9 @@ void OrderVisitor::processMTasks() { GraphStream emit_logic(&logicGraph); const V3GraphVertex* moveVxp; while ((moveVxp = emit_logic.nextp())) { - const MTaskMoveVertex* movep = - dynamic_cast(moveVxp); + const MTaskMoveVertex* movep = dynamic_cast(moveVxp); unsigned mtaskId = movep->color(); - UASSERT(mtaskId > 0, - "Every MTaskMoveVertex should have an mtask assignment >0"); + UASSERT(mtaskId > 0, "Every MTaskMoveVertex should have an mtask assignment >0"); if (movep->logicp()) { // Add this logic to the per-mtask order mtaskStates[mtaskId].m_logics.push_back(movep->logicp()); @@ -1915,18 +1877,17 @@ void OrderVisitor::processMTasks() { // of mtasks that consume it and produce it. We'll use this // information in V3EmitC when we lay out var's in memory. const OrderLogicVertex* logicp = movep->logicp(); - for (const V3GraphEdge* edgep = logicp->inBeginp(); - edgep; edgep = edgep->inNextp()) { - const OrderVarVertex* pre_varp = - dynamic_cast(edgep->fromp()); + for (const V3GraphEdge* edgep = logicp->inBeginp(); edgep; edgep = edgep->inNextp()) { + const OrderVarVertex* pre_varp + = dynamic_cast(edgep->fromp()); if (!pre_varp) continue; AstVar* varp = pre_varp->varScp()->varp(); // varp depends on logicp, so logicp produces varp, // and vice-versa below varp->addProducingMTaskId(mtaskId); } - for (const V3GraphEdge* edgep = logicp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (const V3GraphEdge* edgep = logicp->outBeginp(); edgep; + edgep = edgep->outNextp()) { const OrderVarVertex* post_varp = dynamic_cast(edgep->top()); if (!post_varp) continue; @@ -1949,8 +1910,7 @@ void OrderVisitor::processMTasks() { GraphStream emit_mtasks(&mtasks); const V3GraphVertex* mtaskVxp; while ((mtaskVxp = emit_mtasks.nextp())) { - const AbstractLogicMTask* mtaskp = - dynamic_cast(mtaskVxp); + const AbstractLogicMTask* mtaskp = dynamic_cast(mtaskVxp); // Create a body for this mtask AstMTaskBody* bodyp = new AstMTaskBody(rootFlp); @@ -1963,8 +1923,8 @@ void OrderVisitor::processMTasks() { const AstSenTree* last_domainp = NULL; AstCFunc* leafCFuncp = NULL; int leafStmts = 0; - for (MTaskState::Logics::iterator it = state.m_logics.begin(); - it != state.m_logics.end(); ++it) { + for (MTaskState::Logics::iterator it = state.m_logics.begin(); it != state.m_logics.end(); + ++it) { const OrderLogicVertex* logicp = *it; if (logicp->domainp() != last_domainp) { // Start a new leaf function. @@ -1972,8 +1932,8 @@ void OrderVisitor::processMTasks() { } last_domainp = logicp->domainp(); - AstActive* newActivep = processMoveOneLogic(logicp, leafCFuncp/*ref*/, - leafStmts/*ref*/); + AstActive* newActivep + = processMoveOneLogic(logicp, leafCFuncp /*ref*/, leafStmts /*ref*/); if (newActivep) bodyp->addStmtsp(newActivep); } @@ -1984,22 +1944,18 @@ void OrderVisitor::processMTasks() { // and OrderLogicVertex's which are ephemeral to V3Order. // - The ExecMTask graph and the AstMTaskBody's produced here // persist until code generation time. - state.m_execMTaskp = - new ExecMTask(execGraphp->mutableDepGraphp(), - bodyp, mtaskp->id()); + state.m_execMTaskp = new ExecMTask(execGraphp->mutableDepGraphp(), bodyp, mtaskp->id()); // Cross-link each ExecMTask and MTaskBody // Q: Why even have two objects? // A: One is an AstNode, the other is a GraphVertex, // to combine them would involve multiple inheritance... state.m_mtaskBodyp->execMTaskp(state.m_execMTaskp); - for (V3GraphEdge* inp = mtaskp->inBeginp(); - inp; inp = inp->inNextp()) { + for (V3GraphEdge* inp = mtaskp->inBeginp(); inp; inp = inp->inNextp()) { const V3GraphVertex* fromVxp = inp->fromp(); - const AbstractLogicMTask* fromp = - dynamic_cast(fromVxp); + const AbstractLogicMTask* fromp = dynamic_cast(fromVxp); MTaskState& fromState = mtaskStates[fromp->id()]; - new V3GraphEdge(execGraphp->mutableDepGraphp(), - fromState.m_execMTaskp, state.m_execMTaskp, 1); + new V3GraphEdge(execGraphp->mutableDepGraphp(), fromState.m_execMTaskp, + state.m_execMTaskp, 1); } execGraphp->addMTaskBody(bodyp); } @@ -2016,7 +1972,7 @@ void OrderVisitor::process() { // edges) will have its own color, and corresponds to a loop in the // original graph. However the new graph will be acyclic (the removed // edges are actually still there, just with weight 0). - UINFO(2," Acyclic & Order...\n"); + UINFO(2, " Acyclic & Order...\n"); m_graph.acyclic(&V3GraphEdge::followAlwaysTrue); m_graph.dumpDotFilePrefixed("orderg_acyc"); @@ -2028,43 +1984,45 @@ void OrderVisitor::process() { // This finds everything that can be traced from an input (which by // definition are the source clocks). After this any vertex which was // traced has isFromInput() true. - UINFO(2," Process Clocks...\n"); + UINFO(2, " Process Clocks...\n"); processInputs(); // must be before processCircular - UINFO(2," Process Circulars...\n"); + UINFO(2, " Process Circulars...\n"); processCircular(); // must be before processDomains // Assign logic vertices to new domains - UINFO(2," Domains...\n"); + UINFO(2, " Domains...\n"); processDomains(); m_graph.dumpDotFilePrefixed("orderg_domain"); if (debug() && v3Global.opt.dumpTree()) processEdgeReport(); if (!v3Global.opt.mtasks()) { - UINFO(2," Construct Move Graph...\n"); + UINFO(2, " Construct Move Graph...\n"); processMoveBuildGraph(); - if (debug()>=4) m_pomGraph.dumpDotFilePrefixed("ordermv_start"); // Different prefix (ordermv) as it's not the same graph + if (debug() >= 4) + m_pomGraph.dumpDotFilePrefixed( + "ordermv_start"); // Different prefix (ordermv) as it's not the same graph m_pomGraph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); - if (debug()>=4) m_pomGraph.dumpDotFilePrefixed("ordermv_simpl"); + if (debug() >= 4) m_pomGraph.dumpDotFilePrefixed("ordermv_simpl"); - UINFO(2," Move...\n"); + UINFO(2, " Move...\n"); processMove(); } else { - UINFO(2," Set up mtasks...\n"); + UINFO(2, " Set up mtasks...\n"); processMTasks(); } // Any SC inputs feeding a combo domain must be marked, so we can make them sc_sensitive - UINFO(2," Sensitive...\n"); + UINFO(2, " Sensitive...\n"); processSensitive(); // must be after processDomains // Dump data m_graph.dumpDotFilePrefixed("orderg_done"); if (0 && debug()) { - string dfilename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_INT_order"; - const vl_unique_ptr logp (V3File::new_ofstream(dfilename)); - if (logp->fail()) v3fatal("Can't write "< logp(V3File::new_ofstream(dfilename)); + if (logp->fail()) v3fatal("Can't write " << dfilename); m_graph.dump(*logp); } } @@ -2073,7 +2031,7 @@ void OrderVisitor::process() { // Order class functions void V3Order::orderAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "< > IfaceRefRefs; // Note may have duplicate entries + // Note may have duplicate entries + typedef std::deque > IfaceRefRefs; // STATE - typedef std::map CloneMap; + typedef std::map CloneMap; struct ModInfo { - AstNodeModule* m_modp; // Module with specified name - CloneMap m_cloneMap; // Map of old-varp -> new cloned varp + AstNodeModule* m_modp; // Module with specified name + CloneMap m_cloneMap; // Map of old-varp -> new cloned varp explicit ModInfo(AstNodeModule* modp) { m_modp = modp; } }; - typedef std::map ModNameMap; - ModNameMap m_modNameMap; // Hash of created module flavors by name + typedef std::map ModNameMap; + ModNameMap m_modNameMap; // Hash of created module flavors by name - typedef std::map LongMap; - LongMap m_longMap; // Hash of very long names to unique identity number - int m_longId; + typedef std::map LongMap; + LongMap m_longMap; // Hash of very long names to unique identity number + int m_longId; - typedef std::pair ValueMapValue; - typedef std::map ValueMap; - ValueMap m_valueMap; // Hash of node hash to (param value, name) - int m_nextValue; // Next value to use in m_valueMap + typedef std::pair ValueMapValue; + typedef std::map ValueMap; + ValueMap m_valueMap; // Hash of node hash to (param value, name) + int m_nextValue; // Next value to use in m_valueMap - typedef std::multimap LevelModMap; - LevelModMap m_todoModps; // Modules left to process + typedef std::multimap LevelModMap; + LevelModMap m_todoModps; // Modules left to process typedef std::deque CellList; - CellList m_cellps; // Cells left to process (in this module) + CellList m_cellps; // Cells left to process (in this module) AstNodeModule* m_modp; // Current module being processed - string m_unlinkedTxt; // Text for AstUnlinkedRef + string m_unlinkedTxt; // Text for AstUnlinkedRef UnrollStateful m_unroller; // Loop unroller @@ -118,32 +119,32 @@ private: VL_DEBUG_FUNC; // Declare debug() void makeSmallNames(AstNodeModule* modp) { - std::vector usedLetter; usedLetter.resize(256); + std::vector usedLetter; + usedLetter.resize(256); // Pass 1, assign first letter to each gparam's name - for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* varp = VN_CAST(stmtp, Var)) { - if (varp->isGParam()||varp->isIfaceRef()) { + if (varp->isGParam() || varp->isIfaceRef()) { char ch = varp->name()[0]; - ch = toupper(ch); if (ch<'A' || ch>'Z') ch='Z'; - varp->user4(usedLetter[static_cast(ch)]*256 + ch); + ch = toupper(ch); + if (ch < 'A' || ch > 'Z') ch = 'Z'; + varp->user4(usedLetter[static_cast(ch)] * 256 + ch); usedLetter[static_cast(ch)]++; } } else if (AstParamTypeDType* typep = VN_CAST(stmtp, ParamTypeDType)) { char ch = 'T'; - typep->user4(usedLetter[static_cast(ch)]*256 + ch); + typep->user4(usedLetter[static_cast(ch)] * 256 + ch); usedLetter[static_cast(ch)]++; } } } string paramSmallName(AstNodeModule* modp, AstNode* varp) { - if (varp->user4()<=1) { - makeSmallNames(modp); - } - int index = varp->user4()/256; - char ch = varp->user4()&255; + if (varp->user4() <= 1) makeSmallNames(modp); + int index = varp->user4() / 256; + char ch = varp->user4() & 255; string st = cvtToStr(ch); while (index) { - st += cvtToStr(char((index%25)+'A')); + st += cvtToStr(char((index % 25) + 'A')); index /= 26; } return st; @@ -155,19 +156,17 @@ private: key = ifrtp->cellp()->modp()->name(); } else if (ifrtp->ifacep()) { key = ifrtp->ifacep()->name(); - } else { + } else { nodep->v3fatalSrc("Can't parameterize interface without module name"); } } else if (AstBasicDType* bdtp = VN_CAST(nodep, BasicDType)) { if (bdtp->isRanged()) { - key += "["+cvtToStr(bdtp->left())+":"+cvtToStr(bdtp->right())+"]"; + key += "[" + cvtToStr(bdtp->left()) + ":" + cvtToStr(bdtp->right()) + "]"; } } V3Hash hash = V3Hashed::uncachedHash(nodep); // Force hash collisions -- for testing only - if (VL_UNLIKELY(v3Global.opt.debugCollision())) { - hash = V3Hash(); - } + if (VL_UNLIKELY(v3Global.opt.debugCollision())) hash = V3Hash(); int num; ValueMap::iterator it = m_valueMap.find(hash); if (it != m_valueMap.end() && it->second.second == key) { @@ -176,20 +175,20 @@ private: num = m_nextValue++; m_valueMap[hash] = make_pair(num, key); } - return string("z")+cvtToStr(num); + return string("z") + cvtToStr(num); } void collectPins(CloneMap* clonemapp, AstNodeModule* modp) { // Grab all I/O so we can remap our pins later - for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* varp = VN_CAST(stmtp, Var)) { if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) { // Cloning saved a pointer to the new node for us, so just follow that link. AstVar* oldvarp = varp->clonep(); - //UINFO(8,"Clone list 0x"< 0x"<<(uint32_t)varp< 0x"<<(uint32_t)varp<insert(make_pair(oldvarp, varp)); } - } - else if (AstParamTypeDType* ptp = VN_CAST(stmtp, ParamTypeDType)) { + } else if (AstParamTypeDType* ptp = VN_CAST(stmtp, ParamTypeDType)) { if (ptp->isGParam()) { AstParamTypeDType* oldptp = ptp->clonep(); clonemapp->insert(make_pair(oldptp, ptp)); @@ -198,22 +197,20 @@ private: } } void relinkPins(CloneMap* clonemapp, AstPin* startpinp) { - for (AstPin* pinp = startpinp; pinp; pinp=VN_CAST(pinp->nextp(), Pin)) { + for (AstPin* pinp = startpinp; pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { if (pinp->modVarp()) { // Find it in the clone structure - //UINFO(8,"Clone find 0x"<modVarp()<modVarp()<find(pinp->modVarp()); UASSERT_OBJ(cloneiter != clonemapp->end(), pinp, "Couldn't find pin in clone list"); pinp->modVarp(VN_CAST(cloneiter->second, Var)); - } - else if (pinp->modPTypep()) { + } else if (pinp->modPTypep()) { CloneMap::iterator cloneiter = clonemapp->find(pinp->modPTypep()); UASSERT_OBJ(cloneiter != clonemapp->end(), pinp, "Couldn't find pin in clone list"); pinp->modPTypep(VN_CAST(cloneiter->second, ParamTypeDType)); - } - else { + } else { pinp->v3fatalSrc("Not linked?"); } } @@ -227,30 +224,31 @@ private: LevelModMap::iterator itm = m_todoModps.begin(); AstNodeModule* nodep = itm->second; m_todoModps.erase(itm); - if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it again + if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it + // again m_modp = nodep; - UINFO(4," MOD "<hierName().empty()) m_modp->hierName(m_modp->origName()); iterateChildren(nodep); // Note above iterate may add to m_todoModps // // Process interface cells, then non-interface which may ref an interface cell - for (int nonIf=0; nonIf<2; ++nonIf) { - for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) { + for (int nonIf = 0; nonIf < 2; ++nonIf) { + for (CellList::iterator it = m_cellps.begin(); it != m_cellps.end(); ++it) { AstCell* cellp = *it; - if ((nonIf==0 && VN_IS(cellp->modp(), Iface)) - || (nonIf==1 && !VN_IS(cellp->modp(), Iface))) { - string fullName (m_modp->hierName()); - if (string* genHierNamep = (string *) cellp->user5p()) { + if ((nonIf == 0 && VN_IS(cellp->modp(), Iface)) + || (nonIf == 1 && !VN_IS(cellp->modp(), Iface))) { + string fullName(m_modp->hierName()); + if (string* genHierNamep = (string*)cellp->user5p()) { fullName += *genHierNamep; } visitCell(cellp, fullName); } } } - for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) { + for (CellList::iterator it = m_cellps.begin(); it != m_cellps.end(); ++it) { AstCell* cellp = *it; - if (string* genHierNamep = (string *) cellp->user5p()) { + if (string* genHierNamep = (string*)cellp->user5p()) { cellp->user5p(NULL); VL_DO_DANGLING(delete genHierNamep, genHierNamep); } @@ -268,9 +266,10 @@ private: } virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { if (nodep->dead()) { - UINFO(4," MOD-dead. "<recursiveClone()) { - UINFO(4," MOD-recursive-dead. "<dead(true); // So Dead checks won't count references to it } else if (nodep->level() <= 2 // Haven't added top yet, so level 2 is the top || VN_IS(nodep, Package)) { // Likewise haven't done wrapTopPackages yet @@ -279,9 +278,10 @@ private: m_generateHierName = ""; visitModules(); } else if (nodep->user5()) { - UINFO(4," MOD-done "<isParam()) { if (!nodep->valuep()) { nodep->v3error("Parameter without initial value is never given value" - <<" (IEEE 1800-2017 6.20.1): " - <prettyNameQ()); + << " (IEEE 1800-2017 6.20.1): " << nodep->prettyNameQ()); } else { V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init() if (!VN_IS(nodep->valuep(), Const)) { // Complex init, like an array // Make a new INITIAL to set the value. // This allows the normal array/struct handling code to properly // initialize the parameter. - nodep->addNext( - new AstInitial(nodep->fileline(), - new AstAssign( - nodep->fileline(), - new AstVarRef(nodep->fileline(), nodep, true), - nodep->valuep()->cloneTree(true)))); + nodep->addNext(new AstInitial( + nodep->fileline(), + new AstAssign(nodep->fileline(), + new AstVarRef(nodep->fileline(), nodep, true), + nodep->valuep()->cloneTree(true)))); } } } @@ -325,11 +323,11 @@ private: for (; candp; candp = candp->nextp()) { if (nodep->name() == candp->name()) { if (AstVar* varp = VN_CAST(candp, Var)) { - UINFO(9,"Found interface parameter: "<varp(varp); return true; } else if (AstPin* pinp = VN_CAST(candp, Pin)) { - UINFO(9,"Found interface parameter: "<exprp(), pinp, "Interface parameter pin missing expression"); VL_DO_DANGLING(nodep->replaceWith(pinp->exprp()->cloneTree(false)), nodep); return true; @@ -345,11 +343,10 @@ private: AstNode* backp = nodep; while ((backp = backp->backp())) { if (VN_IS(backp, NodeModule)) { - UINFO(9,"Hit module boundary, done looking for interface"<isIfaceRef() + if (VN_IS(backp, Var) && VN_CAST(backp, Var)->isIfaceRef() && VN_CAST(backp, Var)->childDTypep() && (VN_CAST(VN_CAST(backp, Var)->childDTypep(), IfaceRefDType) || (VN_CAST(VN_CAST(backp, Var)->childDTypep(), UnpackArrayDType) @@ -364,8 +361,8 @@ private: // Interfaces passed in on the port map have ifaces if (AstIface* ifacep = ifacerefp->ifacep()) { if (dotted == backp->name()) { - UINFO(9,"Iface matching scope: "<stmtsp())) { + UINFO(9, "Iface matching scope: " << ifacep << endl); + if (ifaceParamReplace(nodep, ifacep->stmtsp())) { // return; } } @@ -373,8 +370,8 @@ private: // Interfaces declared in this module have cells else if (AstCell* cellp = ifacerefp->cellp()) { if (dotted == cellp->name()) { - UINFO(9,"Iface matching scope: "<paramsp())) { + UINFO(9, "Iface matching scope: " << cellp << endl); + if (ifaceParamReplace(nodep, cellp->paramsp())) { // return; } } @@ -414,21 +411,21 @@ private: size_t pos = m_unlinkedTxt.find(replacestr); if (pos == string::npos) { nodep->v3error("Could not find array index in unlinked text: '" - <name()+"__BRA__"+index+"__KET__"); + nodep->name() + "__BRA__" + index + "__KET__"); } else { nodep->v3error("Could not expand constant selection inside dotted reference: " - <selp()->prettyNameQ()); + << nodep->selp()->prettyNameQ()); return; } } // Generate Statements virtual void visit(AstGenIf* nodep) VL_OVERRIDE { - UINFO(9," GENIF "<condp()); // We suppress errors when widthing params since short-circuiting in // the conditional evaluation may mean these error can never occur. We @@ -437,9 +434,7 @@ private: // NOT recurse the body. V3Const::constifyGenerateParamsEdit(nodep->condp()); // condp may change if (const AstConst* constp = VN_CAST(nodep->condp(), Const)) { - AstNode* keepp = (constp->isZero() - ? nodep->elsesp() - : nodep->ifsp()); + AstNode* keepp = (constp->isZero() ? nodep->elsesp() : nodep->ifsp()); if (keepp) { keepp->unlinkFrBackWithNext(); nodep->replaceWith(keepp); @@ -463,8 +458,8 @@ private: UASSERT_OBJ(forp, nodep, "Non-GENFOR under generate-for BEGIN"); // We should have a GENFOR under here. We will be replacing the begin, // so process here rather than at the generate to avoid iteration problems - UINFO(9," BEGIN "<v3fatalSrc("GENFOR should have been wrapped in BEGIN"); } virtual void visit(AstGenCase* nodep) VL_OVERRIDE { - UINFO(9," GENCASE "<exprp()); V3Case::caseLint(nodep); @@ -503,9 +498,9 @@ private: V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change AstConst* exprp = VN_CAST(nodep->exprp(), Const); // Constify - for (AstCaseItem* itemp = nodep->itemsp(); - itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) { - for (AstNode* ep = itemp->condsp(); ep; ) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { + for (AstNode* ep = itemp->condsp(); ep;) { AstNode* nextp = ep->nextp(); // May edit list iterateAndNextNull(ep); VL_DO_DANGLING(V3Const::constifyParamsEdit(ep), ep); // ep may change @@ -513,16 +508,14 @@ private: } } // Item match - for (AstCaseItem* itemp = nodep->itemsp(); - itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { if (!itemp->isDefault()) { - for (AstNode* ep = itemp->condsp(); ep; ep=ep->nextp()) { + for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) { if (const AstConst* ccondp = VN_CAST(ep, Const)) { - V3Number match (nodep, 1); + V3Number match(nodep, 1); match.opEq(ccondp->num(), exprp->num()); - if (!keepp && match.isNeqZero()) { - keepp = itemp->bodysp(); - } + if (!keepp && match.isNeqZero()) keepp = itemp->bodysp(); } else { itemp->v3error("Generate Case item does not evaluate to constant"); } @@ -530,8 +523,8 @@ private: } } // Else default match - for (AstCaseItem* itemp = nodep->itemsp(); - itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { if (itemp->isDefault()) { if (!keepp) keepp = itemp->bodysp(); } @@ -540,8 +533,9 @@ private: if (keepp) { keepp->unlinkFrBackWithNext(); nodep->replaceWith(keepp); + } else { + nodep->unlinkFrBack(); } - else nodep->unlinkFrBack(); VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -569,9 +563,9 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { // We always run this, even if no parameters, as need to look for interfaces, // and remove any recursive references { - UINFO(4,"De-parameterize: "<=10) nodep->dumpTree(cout, "-cell: "); + if (debug() >= 10) nodep->dumpTree(cout, "-cell: "); // Evaluate all module constants V3Const::constifyParamsEdit(nodep); AstNodeModule* srcModp = nodep->modp(); @@ -579,18 +573,19 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { // Make sure constification worked // Must be a separate loop, as constant conversion may have changed some pointers. - //if (debug()) nodep->dumpTree(cout, "-cel2: "); + // if (debug()) nodep->dumpTree(cout, "-cel2: "); string longname = srcModp->name(); bool any_overrides = false; - if (nodep->recursive()) any_overrides = true; // Must always clone __Vrcm (recursive modules) + // Must always clone __Vrcm (recursive modules) + if (nodep->recursive()) any_overrides = true; longname += "_"; - if (debug()>8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: "); - for (AstPin* pinp = nodep->paramsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) { + if (debug() > 8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: "); + for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { if (!pinp->exprp()) continue; // No-connect if (AstVar* modvarp = pinp->modVarp()) { if (!modvarp->isGParam()) { pinp->v3error("Attempted parameter setting of non-parameter: Param " - <prettyNameQ()<<" of "<prettyNameQ()); + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); } else if (VN_IS(pinp->exprp(), InitArray) && VN_IS(modvarp->subDTypep(), UnpackArrayDType)) { // Array assigned to array @@ -601,21 +596,19 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { AstConst* exprp = VN_CAST(pinp->exprp(), Const); AstConst* origp = VN_CAST(modvarp->valuep(), Const); if (!exprp) { - //if (debug()) pinp->dumpTree(cout, "error:"); + // if (debug()) pinp->dumpTree(cout, "error:"); pinp->v3error("Can't convert defparam value to constant: Param " - <prettyNameQ()<<" of "<prettyNameQ()); - pinp->exprp()->replaceWith( - new AstConst(pinp->fileline(), - AstConst::WidthedValue(), modvarp->width(), 0)); + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); + pinp->exprp()->replaceWith(new AstConst( + pinp->fileline(), AstConst::WidthedValue(), modvarp->width(), 0)); } else if (origp && exprp->sameTree(origp)) { // Setting parameter to its default value. Just ignore it. // This prevents making additional modules, and makes coverage more // obvious as it won't show up under a unique module page name. - } else if (exprp->num().isDouble() - || exprp->num().isString() - || exprp->num().isFourState()) { - longname += ("_" + paramSmallName(srcModp, modvarp) - + paramValueNumber(exprp)); + } else if (exprp->num().isDouble() || exprp->num().isString() + || exprp->num().isFourState()) { + longname + += ("_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp)); any_overrides = true; } else { longname += ("_" + paramSmallName(srcModp, modvarp) @@ -628,75 +621,92 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { AstNodeDType* origp = modvarp->subDTypep(); if (!exprp) { pinp->v3error("Parameter type pin value isn't a type: Param " - <prettyNameQ()<<" of "<prettyNameQ()); + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); } else if (!origp) { pinp->v3error("Parameter type variable isn't a type: Param " - <prettyNameQ()); + << modvarp->prettyNameQ()); } else { - UINFO(9,"Parameter type assignment expr="<sameTree(origp)) { // Setting parameter to its default value. Just ignore it. // This prevents making additional modules, and makes coverage more // obvious as it won't show up under a unique module page name. } else { V3Const::constifyParamsEdit(exprp); - longname += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp); + longname + += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp); any_overrides = true; } } } else { pinp->v3error("Parameter not found in sub-module: Param " - <prettyNameQ()<<" of "<prettyNameQ()); + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); } } IfaceRefRefs ifaceRefRefs; - for (AstPin* pinp = nodep->pinsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) { + for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { AstVar* modvarp = pinp->modVarp(); if (modvarp->isIfaceRef()) { AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType); if (!portIrefp && VN_IS(modvarp->subDTypep(), UnpackArrayDType)) { - portIrefp = VN_CAST(VN_CAST(modvarp->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType); + portIrefp + = VN_CAST(VN_CAST(modvarp->subDTypep(), UnpackArrayDType)->subDTypep(), + IfaceRefDType); } AstIfaceRefDType* pinIrefp = NULL; AstNode* exprp = pinp->exprp(); - if (exprp - && VN_IS(exprp, VarRef) - && VN_CAST(exprp, VarRef)->varp() + if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp() && VN_CAST(exprp, VarRef)->varp()->subDTypep() && VN_IS(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType)) { pinIrefp = VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType); - } else if (exprp - && exprp->op1p() - && VN_IS(exprp->op1p(), VarRef) + } else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef) && VN_CAST(exprp->op1p(), VarRef)->varp() && VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep() - && VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType) - && VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep() - && VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) { - pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType); - } else if (exprp - && VN_IS(exprp, VarRef) - && VN_CAST(exprp, VarRef)->varp() + && VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), + UnpackArrayDType) + && VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), + UnpackArrayDType) + ->subDTypep() + && VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), + UnpackArrayDType) + ->subDTypep(), + IfaceRefDType)) { + pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), + UnpackArrayDType) + ->subDTypep(), + IfaceRefDType); + } else if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp() && VN_CAST(exprp, VarRef)->varp()->subDTypep() - && VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType) - && VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep() - && VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) { - pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType); + && VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), + UnpackArrayDType) + && VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), + UnpackArrayDType) + ->subDTypep() + && VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), + UnpackArrayDType) + ->subDTypep(), + IfaceRefDType)) { + pinIrefp = VN_CAST( + VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType) + ->subDTypep(), + IfaceRefDType); } - UINFO(9," portIfaceRef "<v3error("Interface port "<prettyNameQ() - <<" is not an interface " << modvarp); + pinp->v3error("Interface port " << modvarp->prettyNameQ() + << " is not an interface " << modvarp); } else if (!pinIrefp) { - pinp->v3error("Interface port "<prettyNameQ() - <<" is not connected to interface/modport pin expression"); + pinp->v3error("Interface port " + << modvarp->prettyNameQ() + << " is not connected to interface/modport pin expression"); } else { - UINFO(9," pinIfaceRef "<ifaceViaCellp() != pinIrefp->ifaceViaCellp()) { - UINFO(9," IfaceRefDType needs reconnect "<modVarp()) + paramValueNumber(pinIrefp)); any_overrides = true; @@ -704,11 +714,11 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { if (portIrefp->ifacep() != pinIrefp->ifacep() // Might be different only due to param cloning, so check names too && portIrefp->ifaceName() != pinIrefp->ifaceName()) { - pinp->v3error("Port "<prettyNameQ()<<" expects " - <ifaceName()) - <<" interface but pin connects " - <ifaceName()) - <<" interface"); + pinp->v3error("Port " << pinp->prettyNameQ() << " expects " + << AstNode::prettyNameQ(portIrefp->ifaceName()) + << " interface but pin connects " + << AstNode::prettyNameQ(pinIrefp->ifaceName()) + << " interface"); } } } @@ -716,23 +726,24 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { } if (!any_overrides) { - UINFO(8,"Cell parameters all match original values, skipping expansion.\n"); + UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); } else { // If the name is very long, we don't want to overwhelm the filename limit // We don't do this always, as it aids debugability to have intuitive naming. // TODO can use new V3Name hash replacement instead of this string newname = longname; - if (longname.length()>30) { + if (longname.length() > 30) { LongMap::iterator iter = m_longMap.find(longname); if (iter != m_longMap.end()) { newname = iter->second; } else { newname = srcModp->name(); - newname += "__pi"+cvtToStr(++m_longId); // We use all upper case above, so lower here can't conflict + // We use all upper case above, so lower here can't conflict + newname += "__pi" + cvtToStr(++m_longId); m_longMap.insert(make_pair(longname, newname)); } } - UINFO(4,"Name: "<name()<<"->"<"<name() << "->" << longname << "->" << newname << endl); // // Already made this flavor? @@ -750,11 +761,11 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { cellmodp->recursiveClone(false); nodep->recursive(false); // Recursion may need level cleanups - if (cellmodp->level() <= m_modp->level()) cellmodp->level(m_modp->level()+1); + if (cellmodp->level() <= m_modp->level()) cellmodp->level(m_modp->level() + 1); if ((cellmodp->level() - srcModp->level()) >= (v3Global.opt.moduleRecursionDepth() - 2)) { nodep->v3error("Exceeded maximum --module-recursion-depth of " - <name(), ModInfo(cellmodp))); iter = m_modNameMap.find(newname); CloneMap* clonemapp = &(iter->second.m_cloneMap); - UINFO(4," De-parameterize to new: "<paramsp()); // Fix any interface references - for (IfaceRefRefs::iterator it=ifaceRefRefs.begin(); - it!=ifaceRefRefs.end(); ++it) { + for (IfaceRefRefs::iterator it = ifaceRefRefs.begin(); it != ifaceRefRefs.end(); + ++it) { AstIfaceRefDType* portIrefp = it->first; AstIfaceRefDType* pinIrefp = it->second; AstIfaceRefDType* cloneIrefp = portIrefp->clonep(); - UINFO(8," IfaceOld "<ifacep(pinIrefp->ifaceViaCellp()); - UINFO(8," IfaceNew "<paramsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) { + for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { if (pinp->exprp()) { if (AstVar* modvarp = pinp->modVarp()) { AstNode* newp = pinp->exprp(); // Const or InitArray @@ -801,8 +812,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree(); // Set this parameter to value requested by cell modvarp->valuep(newp->cloneTree(false)); - } - else if (AstParamTypeDType* modptp = pinp->modPTypep()) { + } else if (AstParamTypeDType* modptp = pinp->modPTypep()) { AstNodeDType* dtypep = VN_CAST(pinp->exprp(), NodeDType); UASSERT_OBJ(dtypep, pinp, "unlinked param dtype"); if (modptp->childDTypep()) { @@ -817,7 +827,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { } } else { - UINFO(4," De-parameterize to old: "<second.m_cloneMap); relinkPins(clonemapp, nodep->pinsp()); - UINFO(8," Done with "<recursive(false); // Delete the parameters from the cell; they're not relevant any longer. if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree(); - UINFO(8," Done with "<=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree")); + UINFO(8, " Done with " << nodep << endl); + // if (debug() >= 10) + // v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree")); } // Now remember to process the child module at the end of the module @@ -846,9 +857,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { // Param class functions void V3Param::param(AstNetlist* rootp) { - UINFO(2,__FUNCTION__<<": "<= 6); } diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index a0426103a..805b10974 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -14,7 +14,6 @@ // //************************************************************************* - #include "V3Ast.h" // This must be before V3ParseBison.cpp, as we don't want #defines to conflict //====================================================================== @@ -27,7 +26,7 @@ int V3ParseImp::bisonParse() { // Use --debugi-bison 9 to enable this - if (PARSEP->debugBison()>=9) yydebug = 1; + if (PARSEP->debugBison() >= 9) yydebug = 1; return yyparse(); } @@ -36,8 +35,8 @@ const char* V3ParseImp::tokenName(int token) { static const char** nameTablep = NULL; if (!nameTablep) { int size; - for (size = 0; yytname[size]; ++size) ; - nameTablep = new const char* [size]; + for (size = 0; yytname[size]; ++size) {} + nameTablep = new const char*[size]; // Workaround bug in bison's which have '!' in yytname but not token values int iout = 0; for (int i = 0; yytname[i]; ++i) { @@ -46,9 +45,11 @@ const char* V3ParseImp::tokenName(int token) { } } if (token >= 255) { - return nameTablep[token-255]; + return nameTablep[token - 255]; } else { - static char ch[2]; ch[0] = token; ch[1] = '\0'; + static char ch[2]; + ch[0] = token; + ch[1] = '\0'; return ch; } #else @@ -76,18 +77,20 @@ void V3ParseGrammar::argWrapList(AstNodeFTaskRef* nodep) { } AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) { - return new AstAssignW(fileline, new AstVarRef(fileline, name, true), - new AstConst(fileline, AstConst::StringToParse(), - (value ? "'1" : "'0"))); + return new AstAssignW( + fileline, new AstVarRef(fileline, name, true), + new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0"))); } AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) { // Remove any UnsizedRange's from list - for (AstNodeRange* nodep = nrangep, *nextp; nodep; nodep = nextp) { + for (AstNodeRange *nodep = nrangep, *nextp; nodep; nodep = nextp) { nextp = VN_CAST(nodep->nextp(), NodeRange); if (!VN_IS(nodep, Range)) { - nodep->v3error("Unsupported or syntax error: Unsized range in cell or other declaration"); - nodep->unlinkFrBack(); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->v3error( + "Unsupported or syntax error: Unsized range in cell or other declaration"); + nodep->unlinkFrBack(); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } } if (nrangep && nrangep->nextp()) { @@ -98,8 +101,8 @@ AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) { return VN_CAST(nrangep, Range); } -AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, - AstNodeRange* nrangep, bool isPacked) { +AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nrangep, + bool isPacked) { // Split RANGE0-RANGE1-RANGE2 // into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3), RANGE), RANGE) AstNodeDType* arrayp = basep; @@ -110,26 +113,26 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, if (prevp) nrangep->unlinkFrBack(); AstRange* rangep = VN_CAST(nrangep, Range); if (rangep && isPacked) { - arrayp = new AstPackArrayDType - (rangep->fileline(), VFlagChildDType(), arrayp, rangep); + arrayp + = new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep); } else if (VN_IS(nrangep, QueueRange)) { - arrayp = new AstQueueDType - (nrangep->fileline(), VFlagChildDType(), arrayp, NULL); - } else if (rangep && (VN_IS(rangep->leftp(), Unbounded) - || VN_IS(rangep->rightp(), Unbounded))) { + arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp, NULL); + } else if (rangep + && (VN_IS(rangep->leftp(), Unbounded) + || VN_IS(rangep->rightp(), Unbounded))) { arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp, rangep->rightp()->cloneTree(true)); } else if (rangep) { - arrayp = new AstUnpackArrayDType - (rangep->fileline(), VFlagChildDType(), arrayp, rangep); + arrayp = new AstUnpackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, + rangep); } else if (VN_IS(nrangep, UnsizedRange)) { - arrayp = new AstUnsizedArrayDType - (nrangep->fileline(), VFlagChildDType(), arrayp); + arrayp = new AstUnsizedArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp); } else if (VN_IS(nrangep, AssocRange)) { AstAssocRange* arangep = VN_CAST(nrangep, AssocRange); - AstNodeDType* keyp = arangep->keyDTypep(); keyp->unlinkFrBack(); - arrayp = new AstAssocArrayDType - (nrangep->fileline(), VFlagChildDType(), arrayp, keyp); + AstNodeDType* keyp = arangep->keyDTypep(); + keyp->unlinkFrBack(); + arrayp + = new AstAssocArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp, keyp); } else { UASSERT_OBJ(0, nrangep, "Expected range or unsized range"); } @@ -142,10 +145,9 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp, AstNode* attrsp) { AstNodeDType* dtypep = GRAMMARP->m_varDTypep; - UINFO(5," creVar "<m_varIO == VDirection::NONE - && GRAMMARP->m_varDecl == AstVarType::PORT) { + UINFO(5, " creVar " << name << " decl=" << GRAMMARP->m_varDecl << " io=" + << GRAMMARP->m_varIO << " dt=" << (dtypep ? "set" : "") << endl); + if (GRAMMARP->m_varIO == VDirection::NONE && GRAMMARP->m_varDecl == AstVarType::PORT) { // Just a port list with variable name (not v2k format); AstPort already created if (dtypep) fileline->v3error("Unsupported: Ranges ignored in port-lists"); return NULL; @@ -159,7 +161,8 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, } else { // May make new variables with same type, so clone dtypep = dtypep->cloneTree(false); } - //UINFO(0,"CREVAR "<ascii()<<" decl="<m_varDecl.ascii()<<" io="<m_varIO.ascii()<ascii()<<" decl="<m_varDecl.ascii()<<" + // io="<m_varIO.ascii()<m_varDecl; if (type == AstVarType::UNKNOWN) { if (GRAMMARP->m_varIO.isAny()) { @@ -169,7 +172,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, } } if (type == AstVarType::GENVAR) { - if (arrayp) fileline->v3error("Genvars may not be arrayed: "<v3error("Genvars may not be arrayed: " << name); } // Split RANGE0-RANGE1-RANGE2 into @@ -202,9 +205,13 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, // We need to autosize parameters and integers separately // // Propagate from current module tracing state - if (nodep->isGenVar()) nodep->trace(false); - else if (nodep->isParam() && !v3Global.opt.traceParams()) nodep->trace(false); - else nodep->trace(allTracingOn(nodep->fileline())); + if (nodep->isGenVar()) { + nodep->trace(false); + } else if (nodep->isParam() && !v3Global.opt.traceParams()) { + nodep->trace(false); + } else { + nodep->trace(allTracingOn(nodep->fileline())); + } // Remember the last variable created, so we can attach attributes to it in later parsing GRAMMARP->m_varAttrp = nodep; @@ -222,7 +229,7 @@ string V3ParseGrammar::deQuote(FileLine* fileline, string text) { for (string::const_iterator cp = text.begin(); cp != text.end(); ++cp) { if (quoted) { if (isdigit(*cp)) { - octal_val = octal_val*8 + (*cp-'0'); + octal_val = octal_val * 8 + (*cp - '0'); if (++octal_digits == 3) { octal_digits = 0; quoted = false; @@ -238,29 +245,33 @@ string V3ParseGrammar::deQuote(FileLine* fileline, string text) { continue; } quoted = false; - if (*cp == 'n') newtext += '\n'; - else if (*cp == 'a') newtext += '\a'; // SystemVerilog 3.1 - else if (*cp == 'f') newtext += '\f'; // SystemVerilog 3.1 - else if (*cp == 'r') newtext += '\r'; - else if (*cp == 't') newtext += '\t'; - else if (*cp == 'v') newtext += '\v'; // SystemVerilog 3.1 - else if (*cp == 'x' && isxdigit(cp[1]) && isxdigit(cp[2])) { // SystemVerilog 3.1 -#define vl_decodexdigit(c) ((isdigit(c)?((c)-'0'):(tolower((c))-'a'+10))) - newtext += (char)(16*vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2])); + if (*cp == 'n') { + newtext += '\n'; + } else if (*cp == 'a') { + newtext += '\a'; // SystemVerilog 3.1 + } else if (*cp == 'f') { + newtext += '\f'; // SystemVerilog 3.1 + } else if (*cp == 'r') { + newtext += '\r'; + } else if (*cp == 't') { + newtext += '\t'; + } else if (*cp == 'v') { + newtext += '\v'; // SystemVerilog 3.1 + } else if (*cp == 'x' && isxdigit(cp[1]) + && isxdigit(cp[2])) { // SystemVerilog 3.1 +#define vl_decodexdigit(c) ((isdigit(c) ? ((c) - '0') : (tolower((c)) - 'a' + 10))) + newtext += (char)(16 * vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2])); cp += 2; - } - else if (isalnum(*cp)) { - fileline->v3error("Unknown escape sequence: \\"<<*cp); + } else if (isalnum(*cp)) { + fileline->v3error("Unknown escape sequence: \\" << *cp); break; - } - else newtext += *cp; + } else + newtext += *cp; } - } - else if (*cp == '\\') { + } else if (*cp == '\\') { quoted = true; octal_digits = 0; - } - else if (*cp != '"') { + } else if (*cp != '"') { newtext += *cp; } } diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index ca502f9b3..2294d08f4 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -41,9 +41,9 @@ //====================================================================== // Globals -V3ParseImp* V3ParseImp::s_parsep = NULL; +V3ParseImp* V3ParseImp::s_parsep = NULL; -int V3ParseSym::s_anonNum = 0; +int V3ParseSym::s_anonNum = 0; extern void yyerror(const char*); extern void yyerrorf(const char* format, ...); @@ -63,7 +63,10 @@ V3ParseImp::~V3ParseImp() { lexDestroy(); parserClear(); - if (debug()>=9) { UINFO(0,"~V3ParseImp\n"); symp()->dump(cout, "-vpi: "); } + if (debug() >= 9) { + UINFO(0, "~V3ParseImp\n"); + symp()->dump(cout, "-vpi: "); + } } //###################################################################### @@ -73,7 +76,7 @@ void V3ParseImp::ppline(const char* textp) { // Handle `line directive FileLine* prevFl = copyOrSameFileLine(); int enterExit; - fileline()->lineDirective(textp, enterExit/*ref*/); + fileline()->lineDirective(textp, enterExit /*ref*/); if (enterExit == 1) { // Enter fileline()->parent(prevFl); } else if (enterExit == 2) { // Exit @@ -83,9 +86,7 @@ void V3ParseImp::ppline(const char* textp) { } } -void V3ParseImp::verilatorCmtLintSave() { - m_lintState.push_back(*parsep()->fileline()); -} +void V3ParseImp::verilatorCmtLintSave() { m_lintState.push_back(*parsep()->fileline()); } void V3ParseImp::verilatorCmtLintRestore() { if (m_lintState.empty()) { @@ -117,16 +118,10 @@ void V3ParseImp::verilatorCmtBad(const char* textp) { if (cmtparse.substr(0, strlen("/*verilator")) == "/*verilator") { cmtparse.replace(0, strlen("/*verilator"), ""); } - while (isspace(cmtparse[0])) { - cmtparse.replace(0, 1, ""); - } + while (isspace(cmtparse[0])) cmtparse.replace(0, 1, ""); string cmtname; - for (int i = 0; isalnum(cmtparse[i]); i++) { - cmtname += cmtparse[i]; - } - if (!parsep()->optFuture(cmtname)) { - yyerrorf("Unknown verilator comment: %s", textp); - } + for (int i = 0; isalnum(cmtparse[i]); i++) { cmtname += cmtparse[i]; } + if (!parsep()->optFuture(cmtname)) yyerrorf("Unknown verilator comment: %s", textp); } void V3ParseImp::errorPreprocDirective(const char* textp) { @@ -140,8 +135,9 @@ void V3ParseImp::errorPreprocDirective(const char* textp) { } V3PreShell::candidateDefines(&speller); string suggest = speller.bestCandidateMsg(textp); - fileline()->v3error("Define or directive not defined: '"<warnMore()+suggest)); + fileline()->v3error("Define or directive not defined: '" + << textp << "'\n" + << (suggest.empty() ? "" : fileline()->warnMore() + suggest)); } void V3ParseImp::tag(const char* text) { @@ -154,19 +150,22 @@ void V3ParseImp::tag(const char* text) { } double V3ParseImp::parseDouble(const char* textp, size_t length, bool* successp) { - char* strgp = new char[length+1]; + char* strgp = new char[length + 1]; char* dp = strgp; if (successp) *successp = true; - for (const char* sp = textp; sp < (textp+length); ++sp) { + for (const char* sp = textp; sp < (textp + length); ++sp) { if (*sp != '_') *dp++ = *sp; } *dp++ = '\0'; char* endp = strgp; double d = strtod(strgp, &endp); - size_t parsed_len = endp-strgp; + size_t parsed_len = endp - strgp; if (parsed_len != strlen(strgp)) { - if (successp) *successp = false; - else yyerrorf("Syntax error parsing real: %s", strgp); + if (successp) { + *successp = false; + } else { + yyerrorf("Syntax error parsing real: %s", strgp); + } } VL_DO_DANGLING(delete[] strgp, strgp); return d; @@ -179,20 +178,21 @@ size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) { size_t got = 0; while (got < max_size // Haven't got enough && !m_ppBuffers.empty()) { // And something buffered - string front = m_ppBuffers.front(); m_ppBuffers.pop_front(); + string front = m_ppBuffers.front(); + m_ppBuffers.pop_front(); size_t len = front.length(); - if (len > (max_size-got)) { // Front string too big - string remainder = front.substr(max_size-got); - front = front.substr(0, max_size-got); + if (len > (max_size - got)) { // Front string too big + string remainder = front.substr(max_size - got); + front = front.substr(0, max_size - got); m_ppBuffers.push_front(remainder); // Put back remainder for next time - len = (max_size-got); + len = (max_size - got); } - memcpy(buf+got, front.c_str(), len); + memcpy(buf + got, front.c_str(), len); got += len; } - if (debug()>=9) { + if (debug() >= 9) { string out = string(buf, got); - cout<<" inputToLex got="<::iterator it = m_ppBuffers.begin(); it!=m_ppBuffers.end(); ++it) { + for (std::deque::iterator it = m_ppBuffers.begin(); it != m_ppBuffers.end(); + ++it) { if (noblanks) { bool blank = true; for (string::iterator its = it->begin(); its != it->end(); ++its) { - if (!isspace(*its) && *its!='\n') { blank = false; break; } + if (!isspace(*its) && *its != '\n') { + blank = false; + break; + } } if (blank) continue; } @@ -220,7 +224,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i const string& errmsg) { // "" for no error, make fake node string modname = V3Os::filenameNonExt(modfilename); - UINFO(2,__FUNCTION__<<": "<newContent(); m_inLibrary = inLibrary; @@ -237,7 +241,8 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i if (v3Global.opt.preprocOnly() || v3Global.opt.keepTempFiles()) { // Create output file with all the preprocessor output we buffered up - string vppfilename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_"+modname+".vpp"; + string vppfilename + = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "_" + modname + ".vpp"; std::ofstream* ofp = NULL; std::ostream* osp; if (v3Global.opt.preprocOnly()) { @@ -246,7 +251,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i osp = ofp = V3File::new_ofstream(vppfilename); } if (osp->fail()) { - fileline->v3error("Cannot write preprocessor output: "+vppfilename); + fileline->v3error("Cannot write preprocessor output: " + vppfilename); return; } else { preprocDumps(*osp); @@ -267,7 +272,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i void V3ParseImp::lexFile(const string& modname) { // Prepare for lexing - UINFO(3,"Lexing "<warnResetDefault(); // Reenable warnings on each file lexDestroy(); // Restart from clean slate. @@ -283,7 +288,7 @@ void V3ParseImp::lexFile(const string& modname) { V3Parse::V3Parse(AstNetlist* rootp, VInFilter* filterp, V3ParseSym* symp) { m_impp = new V3ParseImp(rootp, filterp, symp); } -V3Parse::~V3Parse() { +V3Parse::~V3Parse() { // VL_DO_CLEAR(delete m_impp, m_impp = NULL); } void V3Parse::parseFile(FileLine* fileline, const string& modname, bool inLibrary, diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 7c2076f4e..cc75b3ca8 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -45,49 +45,49 @@ typedef enum { iprop_NONE, iprop_CONTEXT, iprop_PURE } V3ImportProperty; // We can't use bison's %union as we want to pass the fileline with all tokens struct V3ParseBisonYYSType { - FileLine* fl; - AstNode* scp; // Symbol table scope for future lookups - int token; // Read token, aka tok + FileLine* fl; + AstNode* scp; // Symbol table scope for future lookups + int token; // Read token, aka tok union { - V3Number* nump; - string* strp; - int cint; - double cdouble; - bool cbool; - V3UniqState uniqstate; - VSignedState signstate; + V3Number* nump; + string* strp; + int cint; + double cdouble; + bool cbool; + V3UniqState uniqstate; + VSignedState signstate; V3ImportProperty iprop; V3ErrorCode::en errcodeen; AstAttrType::en attrtypeen; - AstNode* nodep; + AstNode* nodep; - AstBasicDType* bdtypep; - AstBegin* beginp; - AstCase* casep; - AstCaseItem* caseitemp; - AstCell* cellp; - AstClass* classp; - AstConst* constp; + AstBasicDType* bdtypep; + AstBegin* beginp; + AstCase* casep; + AstCaseItem* caseitemp; + AstCell* cellp; + AstClass* classp; + AstConst* constp; AstMemberDType* memberp; - AstNodeModule* modulep; + AstNodeModule* modulep; AstNodeUOrStructDType* uorstructp; - AstNodeDType* dtypep; - AstNodeFTask* ftaskp; + AstNodeDType* dtypep; + AstNodeFTask* ftaskp; AstNodeFTaskRef* ftaskrefp; - AstNodeRange* rangep; + AstNodeRange* rangep; AstNodeSenItem* senitemp; - AstNodeVarRef* varnodep; - AstPackage* packagep; - AstPackageRef* packagerefp; - AstParseRef* parserefp; - AstPatMember* patmemberp; - AstPattern* patternp; - AstPin* pinp; - AstRefDType* refdtypep; - AstSenTree* sentreep; - AstVar* varp; - AstVarRef* varrefp; + AstNodeVarRef* varnodep; + AstPackage* packagep; + AstPackageRef* packagerefp; + AstParseRef* parserefp; + AstPatMember* patmemberp; + AstPattern* patternp; + AstPin* pinp; + AstRefDType* refdtypep; + AstSenTree* sentreep; + AstVar* varp; + AstVarRef* varrefp; }; }; @@ -97,33 +97,33 @@ struct V3ParseBisonYYSType { class V3ParseImp { // MEMBERS - AstNetlist* m_rootp; // Root of the design - VInFilter* m_filterp; // Reading filter - V3ParseSym* m_symp; // Symbol table + AstNetlist* m_rootp; // Root of the design + VInFilter* m_filterp; // Reading filter + V3ParseSym* m_symp; // Symbol table - V3Lexer* m_lexerp; // Current FlexLexer - static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based - FileLine* m_fileline; // Filename/linenumber currently active + V3Lexer* m_lexerp; // Current FlexLexer + static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based + FileLine* m_fileline; // Filename/linenumber currently active - bool m_inCellDefine; // Inside a `celldefine - bool m_inLibrary; // Currently reading a library vs. regular file - int m_inBeginKwd; // Inside a `begin_keywords - int m_lastVerilogState; // Last LEX state in `begin_keywords + bool m_inCellDefine; // Inside a `celldefine + bool m_inLibrary; // Currently reading a library vs. regular file + int m_inBeginKwd; // Inside a `begin_keywords + int m_lastVerilogState; // Last LEX state in `begin_keywords VOptionBool m_unconnectedDrive; // Last unconnected drive - int m_prevLexToken; // previous parsed token (for lexer) - bool m_ahead; // aheadval is valid - V3ParseBisonYYSType m_aheadVal; // ahead token value + int m_prevLexToken; // previous parsed token (for lexer) + bool m_ahead; // aheadval is valid + V3ParseBisonYYSType m_aheadVal; // ahead token value V3ParseBisonYYSType m_curBisonVal; // current token for error reporting - V3ParseBisonYYSType m_prevBisonVal; // previous token for error reporting + V3ParseBisonYYSType m_prevBisonVal; // previous token for error reporting - std::deque m_stringps; // Created strings for later cleanup - std::deque m_numberps; // Created numbers for later cleanup - std::deque m_lintState; // Current lint state for save/restore - std::deque m_ppBuffers; // Preprocessor->lex buffer of characters to process + std::deque m_stringps; // Created strings for later cleanup + std::deque m_numberps; // Created numbers for later cleanup + std::deque m_lintState; // Current lint state for save/restore + std::deque m_ppBuffers; // Preprocessor->lex buffer of characters to process - string m_tag; // Contents (if any) of current verilator tag - AstNode* m_tagNodep; // Points to the node to set to m_tag or NULL to not set. + string m_tag; // Contents (if any) of current verilator tag + AstNode* m_tagNodep; // Points to the node to set to m_tag or NULL to not set. public: // Note these are an exception to using the filename as the debug type static int debugBison() { @@ -151,12 +151,21 @@ public: void errorPreprocDirective(const char* textp); void tag(const char* text); void tagNodep(AstNode* nodep) { m_tagNodep = nodep; } - AstNode* tagNodep() const { return m_tagNodep;} + AstNode* tagNodep() const { return m_tagNodep; } static double parseDouble(const char* text, size_t length, bool* successp = NULL); - void pushBeginKeywords(int state) { m_inBeginKwd++; m_lastVerilogState = state; } + void pushBeginKeywords(int state) { + m_inBeginKwd++; + m_lastVerilogState = state; + } bool popBeginKeywords() { - if (m_inBeginKwd) { m_inBeginKwd--; return true; } else return false; } + if (m_inBeginKwd) { + m_inBeginKwd--; + return true; + } else { + return false; + } + } int lastVerilogState() const { return m_lastVerilogState; } static const char* tokenName(int tok); @@ -204,7 +213,7 @@ public: void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } // Interactions with parser - int bisonParse(); + int bisonParse(); // Interactions with lexer void lexNew(); @@ -222,7 +231,9 @@ public: public: // CONSTRUCTORS V3ParseImp(AstNetlist* rootp, VInFilter* filterp, V3ParseSym* parserSymp) - : m_rootp(rootp), m_filterp(filterp), m_symp(parserSymp) { + : m_rootp(rootp) + , m_filterp(filterp) + , m_symp(parserSymp) { m_fileline = NULL; m_lexerp = NULL; m_inCellDefine = false; diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 04a063f31..fda0bf411 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -54,7 +54,6 @@ class MergeCandidate; // handle huge nodes gracefully. Maybe not! But it still can, given // appropriate tuning. - // PART_SIBLING_EDGE_LIMIT (integer) // // Arbitrarily limit the number of edges on a single vertex that will be @@ -76,7 +75,6 @@ class MergeCandidate; // vertices, leave this as is. #define PART_SIBLING_EDGE_LIMIT 25 - // PART_STEPPED_COST (boolean) // // When computing critical path costs, use a step function on the actual @@ -109,7 +107,6 @@ class MergeCandidate; // behavior. #define PART_STEPPED_COST true - // PART_STEPPED_RESCORE_LIMIT (boolean) // // If false, we always try to merge the absolute lowest (best) scoring @@ -132,7 +129,6 @@ class MergeCandidate; // is fixed) leave it set false for the most aggressive partition. #define PART_STEPPED_RESCORE_LIMIT false - // Don't produce more than a certain maximum number of MTasks. This helps // the TSP variable sort not to blow up (a concern for some of the tests) // and we probably don't want a huge number of mtasks in practice anyway @@ -158,8 +154,7 @@ static void partCheckCachedScoreVsActual(uint32_t cached, uint32_t actual) { // won't propagate that new CP to children as it hasn't grown. So, // children may continue to think that the CP coming through this path // is a little higher than it really is; permit that. - UASSERT((((cached * 10) <= (actual * 11)) - && (cached * 11) >= (actual * 10)), + UASSERT((((cached * 10) <= (actual * 11)) && (cached * 11) >= (actual * 10)), "Calculation error in scoring (approximate, may need tweak)"); #else UASSERT(cached == actual, "Calculation error in scoring"); @@ -199,8 +194,7 @@ private: public: // CONSTRUCTORS - PartPropagateCp(V3Graph* graphp, GraphWay way, T_CostAccessor* accessp, - bool slowAsserts, + PartPropagateCp(V3Graph* graphp, GraphWay way, T_CostAccessor* accessp, bool slowAsserts, V3EdgeFuncP edgeFuncp = &V3GraphEdge::followAlwaysTrue) : GraphAlg<>(graphp, edgeFuncp) , m_way(way) @@ -213,8 +207,7 @@ public: // For *vxp, whose CP-inclusive has just increased to // newInclusiveCp, iterate to all wayward nodes, update the edges // of each, and add each to m_pending if its overall CP has grown. - for (V3GraphEdge* edgep = vxp->beginp(m_way); - edgep; edgep = edgep->nextp(m_way)) { + for (V3GraphEdge* edgep = vxp->beginp(m_way); edgep; edgep = edgep->nextp(m_way)) { if (!m_edgeFuncp(edgep)) continue; V3GraphVertex* relativep = edgep->furtherp(m_way); m_accessp->notifyEdgeCp(relativep, m_way, vxp, newInclusiveCp); @@ -222,8 +215,8 @@ public: if (m_accessp->critPathCost(relativep, m_way) < newInclusiveCp) { // relativep's critPathCost() is out of step with its // longest !wayward edge. Schedule that to be resolved. - uint32_t newPendingVal = - newInclusiveCp - m_accessp->critPathCost(relativep, m_way); + uint32_t newPendingVal + = newInclusiveCp - m_accessp->critPathCost(relativep, m_way); if (m_pending.has(relativep)) { if (newPendingVal > m_pending.at(relativep)) { m_pending.set(relativep, newPendingVal); @@ -262,9 +255,7 @@ public: // to its edges, update the critPathCost. uint32_t startCp = m_accessp->critPathCost(updateMep, m_way); uint32_t newCp = startCp + cpGrowBy; - if (m_slowAsserts) { - m_accessp->checkNewCpVersusEdges(updateMep, m_way, newCp); - } + if (m_slowAsserts) m_accessp->checkNewCpVersusEdges(updateMep, m_way, newCp); m_accessp->setCritPathCost(updateMep, m_way, newCp); cpHasIncreased(updateMep, newCp + m_accessp->cost(updateMep)); @@ -292,19 +283,18 @@ private: // METHODS protected: friend class PartPropagateCp; - void notifyEdgeCp(V3GraphVertex* vxp, GraphWay way, - V3GraphVertex* throughp, uint32_t cp) const { + void notifyEdgeCp(V3GraphVertex* vxp, GraphWay way, V3GraphVertex* throughp, + uint32_t cp) const { uint32_t throughCost = critPathCost(throughp, way); UASSERT_SELFTEST(uint32_t, cp, (1 + throughCost)); } + private: - void checkNewCpVersusEdges(V3GraphVertex* vxp, - GraphWay way, uint32_t cp) const { + void checkNewCpVersusEdges(V3GraphVertex* vxp, GraphWay way, uint32_t cp) const { // Don't need to check this in the self test; it supports an assert // that runs in production code. } - void setCritPathCost(V3GraphVertex* vxp, - GraphWay way, uint32_t cost) { + void setCritPathCost(V3GraphVertex* vxp, GraphWay way, uint32_t cost) { m_cp[vxp] = cost; // Confirm that we only set each node's CP once. That's an // important property of PartPropagateCp which allows it to be far @@ -327,15 +317,12 @@ private: while (const V3GraphVertex* cvxp = order.nextp()) { V3GraphVertex* vxp = const_cast(cvxp); uint32_t cpCost = 0; - for (V3GraphEdge* edgep = vxp->inBeginp(); - edgep; edgep = edgep->inNextp()) { + for (V3GraphEdge* edgep = vxp->inBeginp(); edgep; edgep = edgep->inNextp()) { V3GraphVertex* parentp = edgep->fromp(); - cpCost = std::max(cpCost, - critPathCost(parentp, GraphWay::FORWARD) + 1); + cpCost = std::max(cpCost, critPathCost(parentp, GraphWay::FORWARD) + 1); } if (checkOnly) { - UASSERT_SELFTEST(uint32_t, cpCost, - critPathCost(vxp, GraphWay::FORWARD)); + UASSERT_SELFTEST(uint32_t, cpCost, critPathCost(vxp, GraphWay::FORWARD)); } else { setCritPathCost(vxp, GraphWay::FORWARD, cpCost); } @@ -345,9 +332,7 @@ private: // Generate a pseudo-random graph vluint64_t rngState[2] = {VL_ULL(0x12345678), VL_ULL(0x9abcdef0)}; // Create 50 vertices - for (unsigned i = 0; i < 50; ++i) { - m_vx[i] = new V3GraphVertex(&m_graph); - } + for (unsigned i = 0; i < 50; ++i) m_vx[i] = new V3GraphVertex(&m_graph); // Create 250 edges at random. Edges must go from // lower-to-higher index vertices, so we get a DAG. for (unsigned i = 0; i < 250; ++i) { @@ -363,8 +348,7 @@ private: partInitCriticalPaths(false); // This SelfTest class is also the T_CostAccessor - PartPropagateCp - prop(&m_graph, GraphWay::FORWARD, this, true); + PartPropagateCp prop(&m_graph, GraphWay::FORWARD, this, true); // Seed the propagator with every input node; // This should result in the complete graph getting all CP's assigned. @@ -384,10 +368,9 @@ private: // Finally, confirm that the entire graph appears to have correct CPs. partInitCriticalPaths(true); } + public: - static void selfTest() { - PartPropagateCpSelfTest().go(); - } + static void selfTest() { PartPropagateCpSelfTest().go(); } }; //###################################################################### @@ -399,7 +382,7 @@ public: typedef std::list VxList; struct CmpLogicMTask { - bool operator() (const LogicMTask* ap, const LogicMTask* bp) const { + bool operator()(const LogicMTask* ap, const LogicMTask* bp) const { return ap->id() < bp->id(); } }; @@ -424,16 +407,15 @@ public: return mtaskp->critPathCost(way); } // Store a new CP to this node - void setCritPathCost(V3GraphVertex* vxp, - GraphWay way, uint32_t cost) const { + void setCritPathCost(V3GraphVertex* vxp, GraphWay way, uint32_t cost) const { LogicMTask* mtaskp = dynamic_cast(vxp); mtaskp->setCritPathCost(way, cost); } // Notify vxp that the wayward CP at the throughp-->vxp edge // has increased to 'cp'. (vxp is wayward from throughp.) // This is our cue to update vxp's m_edges[!way][throughp]. - void notifyEdgeCp(V3GraphVertex* vxp, GraphWay way, - V3GraphVertex* throuvhVxp, uint32_t cp) const { + void notifyEdgeCp(V3GraphVertex* vxp, GraphWay way, V3GraphVertex* throuvhVxp, + uint32_t cp) const { LogicMTask* updateVxp = dynamic_cast(vxp); LogicMTask* lthrouvhVxp = dynamic_cast(throuvhVxp); EdgeSet& edges = updateVxp->m_edges[way.invert()]; @@ -441,8 +423,7 @@ public: if (cp > edgeCp) edges.set(lthrouvhVxp, cp); } // Check that CP matches that of the longest edge wayward of vxp. - void checkNewCpVersusEdges(V3GraphVertex* vxp, - GraphWay way, uint32_t cp) const { + void checkNewCpVersusEdges(V3GraphVertex* vxp, GraphWay way, uint32_t cp) const { LogicMTask* mtaskp = dynamic_cast(vxp); EdgeSet& edges = mtaskp->m_edges[way.invert()]; // This is mtaskp's relative with longest !wayward inclusive CP: @@ -450,6 +431,7 @@ public: uint32_t edgeCp = (*edgeIt).value(); UASSERT_OBJ(edgeCp == cp, vxp, "CP doesn't match longest wayward edge"); } + private: VL_UNCOPYABLE(CpCostAccessor); }; @@ -495,7 +477,7 @@ public: : AbstractLogicMTask(graphp) , m_cost(0) , m_generation(0) { - for (int i=0; ilogicp()) { @@ -514,9 +496,7 @@ public: m_vertices.splice(m_vertices.end(), otherp->m_vertices); m_cost += otherp->m_cost; } - virtual const VxList* vertexListp() const { - return &m_vertices; - } + virtual const VxList* vertexListp() const { return &m_vertices; } static vluint64_t incGeneration() { static vluint64_t s_generation = 0; ++s_generation; @@ -560,9 +540,7 @@ public: EdgeSet& edges = m_edges[way]; UASSERT(!edges.has(relativep), "Adding existing edge"); // value is !way cp to this edge - edges.set(relativep, - relativep->stepCost() - + relativep->critPathCost(way.invert())); + edges.set(relativep, relativep->stepCost() + relativep->critPathCost(way.invert())); } void removeRelative(GraphWay way, LogicMTask* relativep) { EdgeSet& edges = m_edges[way]; @@ -574,13 +552,11 @@ public: } void checkRelativesCp(GraphWay way) const { const EdgeSet& edges = m_edges[way]; - for (EdgeSet::const_reverse_iterator it = edges.rbegin(); - it != edges.rend(); ++it) { + for (EdgeSet::const_reverse_iterator it = edges.rbegin(); it != edges.rend(); ++it) { LogicMTask* relativep = (*it).key(); uint32_t cachedCp = (*it).value(); - partCheckCachedScoreVsActual - (cachedCp, - relativep->critPathCost(way.invert()) + relativep->stepCost()); + partCheckCachedScoreVsActual(cachedCp, relativep->critPathCost(way.invert()) + + relativep->stepCost()); } } @@ -588,29 +564,24 @@ public: // Display forward and reverse critical path costs. This gives a quick // read on whether graph partitioning looks reasonable or bad. std::ostringstream out; - out <<"mt"<furtherp(way), - "In critPathCostWithout(), edge 'withoutp' must " - "further to 'this'"); + UASSERT(this == withoutp->furtherp(way), "In critPathCostWithout(), edge 'withoutp' must " + "further to 'this'"); // Iterate through edges until we get a relative other than // wayEdgeEndp(way, withoutp). This should take 2 iterations max. const EdgeSet& edges = m_edges[way.invert()]; uint32_t result = 0; - for (EdgeSet::const_reverse_iterator it = edges.rbegin(); - it != edges.rend(); ++it) { + for (EdgeSet::const_reverse_iterator it = edges.rbegin(); it != edges.rend(); ++it) { if ((*it).key() != withoutp->furtherp(way.invert())) { // Use the cached cost. It could be a small overestimate // due to stepping. This is consistent with critPathCost() @@ -623,10 +594,8 @@ public: } private: - static bool pathExistsFromInternal(LogicMTask* fromp, - LogicMTask* top, - const V3GraphEdge* excludedEdgep, - vluint64_t generation) { + static bool pathExistsFromInternal(LogicMTask* fromp, LogicMTask* top, + const V3GraphEdge* excludedEdgep, vluint64_t generation) { // Q) Why does this take LogicMTask instead of generic V3GraphVertex? // A) We'll use the critical paths known to LogicMTask to prune the // recursion for speed. Also store 'generation' in @@ -647,17 +616,20 @@ private: // Base case: fromp is too late, cannot possibly be a prereq for top. if (fromp->critPathCost(GraphWay::REVERSE) - < (top->critPathCost(GraphWay::REVERSE) + top->stepCost())) return false; + < (top->critPathCost(GraphWay::REVERSE) + top->stepCost())) { + return false; + } if ((fromp->critPathCost(GraphWay::FORWARD) + fromp->stepCost()) - > top->critPathCost(GraphWay::FORWARD)) return false; + > top->critPathCost(GraphWay::FORWARD)) { + return false; + } // Recursively look for a path - for (const V3GraphEdge* followp = fromp->outBeginp(); - followp; followp = followp->outNextp()) { + for (const V3GraphEdge* followp = fromp->outBeginp(); followp; + followp = followp->outNextp()) { if (followp == excludedEdgep) continue; LogicMTask* nextp = dynamic_cast(followp->top()); - if (pathExistsFromInternal(nextp, top, NULL, generation)) - return true; + if (pathExistsFromInternal(nextp, top, NULL, generation)) return true; } return false; } @@ -671,25 +643,22 @@ private: // TODO: consider changing this API to the 'isTransitiveEdge' API // used by GraphPathChecker public: - static bool pathExistsFrom(LogicMTask* fromp, - LogicMTask* top, + static bool pathExistsFrom(LogicMTask* fromp, LogicMTask* top, const V3GraphEdge* excludedEdgep) { - return pathExistsFromInternal(fromp, top, excludedEdgep, - incGeneration()); + return pathExistsFromInternal(fromp, top, excludedEdgep, incGeneration()); } - static void dumpCpFilePrefixed(const V3Graph* graphp, - const string& nameComment) { - string filename = v3Global.debugFilename(nameComment)+".txt"; - UINFO(1,"Writing "< ofp(V3File::new_ofstream(filename)); std::ostream* osp = &(*ofp); // &* needed to deref unique_ptr - if (osp->fail()) v3fatalStatic("Can't write "<fail()) v3fatalStatic("Can't write " << filename); // Find start vertex with longest CP const LogicMTask* startp = NULL; - for (const V3GraphVertex* vxp = graphp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (const V3GraphVertex* vxp = graphp->verticesBeginp(); vxp; + vxp = vxp->verticesNextp()) { const LogicMTask* mtaskp = dynamic_cast(vxp); if (!startp) { startp = mtaskp; @@ -710,25 +679,28 @@ public: const EdgeSet& children = nextp->m_edges[GraphWay::FORWARD]; EdgeSet::const_reverse_iterator it = children.rbegin(); - if (it == children.rend()) nextp = NULL; - else nextp = (*it).key(); + if (it == children.rend()) { + nextp = NULL; + } else { + nextp = (*it).key(); + } } - *osp<<"totalCost = "<::iterator it = path.begin(); - it != path.end(); ++it) { + for (std::vector::iterator it = path.begin(); it != path.end(); ++it) { const LogicMTask* mtaskp = *it; - *osp<<"begin mtask with cost "<cost()<cost() << endl; for (VxList::const_iterator lit = mtaskp->vertexListp()->begin(); lit != mtaskp->vertexListp()->end(); ++lit) { const OrderLogicVertex* logicp = (*lit)->logicp(); if (!logicp) continue; if (false) { // Show nodes only - *osp<<"> "; logicp->nodep()->dumpTree(*osp); + *osp << "> "; + logicp->nodep()->dumpTree(*osp); } else { // Show nodes with hierarchical costs V3InstrCount::count(logicp->nodep(), false, osp); @@ -751,8 +723,7 @@ class MTaskIdLessThan { public: MTaskIdLessThan() {} virtual ~MTaskIdLessThan() {} - virtual bool operator() (const AbstractMTask* lhsp, - const AbstractMTask* rhsp) const { + virtual bool operator()(const AbstractMTask* lhsp, const AbstractMTask* rhsp) const { return lhsp->id() < rhsp->id(); } }; @@ -764,7 +735,8 @@ private: vluint64_t m_id; // Serial number for ordering public: // CONSTRUCTORS - MergeCandidate() : m_removedFromSb(false) { + MergeCandidate() + : m_removedFromSb(false) { static vluint64_t serial = 0; ++serial; m_id = serial; @@ -773,9 +745,7 @@ public: // METHODS bool removedFromSb() const { return m_removedFromSb; } void removedFromSb(bool removed) { m_removedFromSb = removed; } - bool operator<(const MergeCandidate& other) const { - return m_id < other.m_id; - } + bool operator<(const MergeCandidate& other) const { return m_id < other.m_id; } }; // A pair of associated LogicMTask's that are merge candidates for sibling @@ -786,6 +756,7 @@ private: LogicMTask* m_bp; // CONSTRUCTORS SiblingMC() VL_EQ_DELETE; + public: SiblingMC(LogicMTask* ap, LogicMTask* bp) { // Assign 'ap' and 'bp' in a canonical order, so we can more easily @@ -830,12 +801,8 @@ public: LogicMTask* furtherMTaskp(GraphWay way) const { return dynamic_cast(this->furtherp(way)); } - LogicMTask* fromMTaskp() const { - return dynamic_cast(fromp()); - } - LogicMTask* toMTaskp() const { - return dynamic_cast(top()); - } + LogicMTask* fromMTaskp() const { return dynamic_cast(fromp()); } + LogicMTask* toMTaskp() const { return dynamic_cast(top()); } virtual bool mergeWouldCreateCycle() const { return LogicMTask::pathExistsFrom(fromMTaskp(), toMTaskp(), this); } @@ -856,6 +823,7 @@ public: fromp->addRelative(GraphWay::FORWARD, top); top->addRelative(GraphWay::REVERSE, fromp); } + private: VL_UNCOPYABLE(MTaskEdge); }; @@ -865,9 +833,9 @@ private: class OrderByPtrId { PartPtrIdMap m_ids; + public: - virtual bool operator() (const OrderVarStdVertex* lhsp, - const OrderVarStdVertex* rhsp) const { + virtual bool operator()(const OrderVarStdVertex* lhsp, const OrderVarStdVertex* rhsp) const { vluint64_t l_id = m_ids.findId(lhsp); vluint64_t r_id = m_ids.findId(rhsp); return l_id < r_id; @@ -897,11 +865,11 @@ class PartParallelismEst { public: // CONSTRUCTORS explicit PartParallelismEst(const V3Graph* graphp) - : m_graphp(graphp), - m_totalGraphCost(0), - m_longestCpCost(0), - m_vertexCount(0), - m_edgeCount(0) {} + : m_graphp(graphp) + , m_totalGraphCost(0) + , m_longestCpCost(0) + , m_vertexCount(0) + , m_edgeCount(0) {} // METHODS uint32_t totalGraphCost() const { return m_totalGraphCost; } @@ -916,12 +884,10 @@ public: // of the graph through the end of the node. vl_unordered_map critPaths; GraphStreamUnordered serialize(m_graphp); - for (const V3GraphVertex* vertexp; - (vertexp = serialize.nextp());) { + for (const V3GraphVertex* vertexp; (vertexp = serialize.nextp());) { m_vertexCount++; uint32_t cpCostToHere = 0; - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; - edgep = edgep->inNextp()) { + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { ++m_edgeCount; // For each upstream item, add its critical path cost to // the cost of this edge, to form a new candidate critical @@ -940,23 +906,18 @@ public: } } void statsReport(const string& stage) { - V3Stats::addStat("MTask graph, "+stage+", critical path cost", - m_longestCpCost); - V3Stats::addStat("MTask graph, "+stage+", total graph cost", - m_totalGraphCost); - V3Stats::addStat("MTask graph, "+stage+", mtask count", - m_vertexCount); - V3Stats::addStat("MTask graph, "+stage+", edge count", - m_edgeCount); - V3Stats::addStat("MTask graph, "+stage+", parallelism factor", - parallelismFactor()); + V3Stats::addStat("MTask graph, " + stage + ", critical path cost", m_longestCpCost); + V3Stats::addStat("MTask graph, " + stage + ", total graph cost", m_totalGraphCost); + V3Stats::addStat("MTask graph, " + stage + ", mtask count", m_vertexCount); + V3Stats::addStat("MTask graph, " + stage + ", edge count", m_edgeCount); + V3Stats::addStat("MTask graph, " + stage + ", parallelism factor", parallelismFactor()); } void debugReport() { - UINFO(0, " Critical path cost = "<weight() != 0, mtaskp, "Should be no cut edges in mtasks graph"); UASSERT_OBJ(relatives.find(edgep->furtherp(rev)) == relatives.end(), mtaskp, "Should be no redundant edges in mtasks graph"); relatives.insert(edgep->furtherp(rev)); - LogicMTask* relativep - = dynamic_cast(edgep->furtherp(rev)); - cpCost = std::max(cpCost, - (relativep->critPathCost(way) - + static_cast(relativep->stepCost()))); + LogicMTask* relativep = dynamic_cast(edgep->furtherp(rev)); + cpCost = std::max(cpCost, (relativep->critPathCost(way) + + static_cast(relativep->stepCost()))); } if (checkOnly) { partCheckCachedScoreVsActual(mtaskp->critPathCost(way), cpCost); @@ -1011,10 +967,8 @@ static void partInitCriticalPaths(V3Graph* mtasksp) { // Reset all MTaskEdges so that 'm_edges' will show correct CP numbers. // They would have been all zeroes on initial creation of the MTaskEdges. - for (V3GraphVertex* vxp = mtasksp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { - for (V3GraphEdge* edgep = vxp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphVertex* vxp = mtasksp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { + for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { MTaskEdge* mtedgep = dynamic_cast(edgep); mtedgep->resetCriticalPaths(); } @@ -1026,8 +980,7 @@ static void partInitCriticalPaths(V3Graph* mtasksp) { static void partCheckCriticalPaths(V3Graph* mtasksp) { partInitHalfCriticalPaths(GraphWay::FORWARD, mtasksp, true); partInitHalfCriticalPaths(GraphWay::REVERSE, mtasksp, true); - for (V3GraphVertex* vxp = mtasksp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (V3GraphVertex* vxp = mtasksp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { LogicMTask* mtaskp = dynamic_cast(vxp); mtaskp->checkRelativesCp(GraphWay::FORWARD); mtaskp->checkRelativesCp(GraphWay::REVERSE); @@ -1074,22 +1027,18 @@ static V3GraphEdge* partBlastEdgep(GraphWay way, V3GraphEdge* edgep) { // // Another way of stating this: this code ensures that scores of // non-transitive edges only ever increase. -static void partMergeEdgesFrom(V3Graph* mtasksp, LogicMTask* recipientp, - LogicMTask* donorp, +static void partMergeEdgesFrom(V3Graph* mtasksp, LogicMTask* recipientp, LogicMTask* donorp, V3Scoreboard* sbp) { for (unsigned wi = 0; wi < 2; ++wi) { GraphWay way = wi ? GraphWay::REVERSE : GraphWay::FORWARD; - for (V3GraphEdge* edgep = donorp->beginp(way); - edgep; edgep = partBlastEdgep(way, edgep)) { + for (V3GraphEdge* edgep = donorp->beginp(way); edgep; edgep = partBlastEdgep(way, edgep)) { MTaskEdge* tedgep = MTaskEdge::cast(edgep); - if (sbp && !tedgep->removedFromSb()) - sbp->removeElem(tedgep); + if (sbp && !tedgep->removedFromSb()) sbp->removeElem(tedgep); // Existing edge; mark it in need of a rescore if (recipientp->hasRelative(way, tedgep->furtherMTaskp(way))) { if (sbp) { - MTaskEdge* existMTaskEdgep = - MTaskEdge::cast(recipientp->findConnectingEdgep - (way, tedgep->furtherMTaskp(way))); + MTaskEdge* existMTaskEdgep = MTaskEdge::cast( + recipientp->findConnectingEdgep(way, tedgep->furtherMTaskp(way))); UASSERT(existMTaskEdgep, "findConnectingEdge didn't find edge"); if (!existMTaskEdgep->removedFromSb()) { sbp->hintScoreChanged(existMTaskEdgep); @@ -1099,11 +1048,9 @@ static void partMergeEdgesFrom(V3Graph* mtasksp, LogicMTask* recipientp, // No existing edge into *this, make one. MTaskEdge* newEdgep; if (way == GraphWay::REVERSE) { - newEdgep = new MTaskEdge(mtasksp, tedgep->fromMTaskp(), - recipientp, 1); + newEdgep = new MTaskEdge(mtasksp, tedgep->fromMTaskp(), recipientp, 1); } else { - newEdgep = new MTaskEdge(mtasksp, recipientp, - tedgep->toMTaskp(), 1); + newEdgep = new MTaskEdge(mtasksp, recipientp, tedgep->toMTaskp(), 1); } if (sbp) sbp->addElem(newEdgep); } @@ -1151,15 +1098,14 @@ public: , m_scoreLimitBeforeRescore(0xffffffff) , m_mergesSinceRescore(0) , m_slowAsserts(slowAsserts) - , m_sb(&mergeCandidateScore, slowAsserts) { } + , m_sb(&mergeCandidateScore, slowAsserts) {} // METHODS void go() { unsigned maxMTasks = v3Global.opt.threadsMaxMTasks(); if (maxMTasks == 0) { // Unspecified so estimate if (v3Global.opt.threads() > 1) { - maxMTasks = (PART_DEFAULT_MAX_MTASKS_PER_THREAD - * v3Global.opt.threads()); + maxMTasks = (PART_DEFAULT_MAX_MTASKS_PER_THREAD * v3Global.opt.threads()); } else { // Running PartContraction with --threads <= 1 means self-test maxMTasks = 500; @@ -1175,11 +1121,9 @@ public: // - Merge the best pair. // - Incrementally recompute critical paths near the merged mtask. - for (V3GraphVertex* itp = m_mtasksp->verticesBeginp(); itp; - itp = itp->verticesNextp()) { + for (V3GraphVertex* itp = m_mtasksp->verticesBeginp(); itp; itp = itp->verticesNextp()) { vl_unordered_set neighbors; - for (V3GraphEdge* edgep = itp->outBeginp(); edgep; - edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = itp->outBeginp(); edgep; edgep = edgep->outNextp()) { m_sb.addElem(MTaskEdge::cast(edgep)); UASSERT_OBJ(neighbors.find(edgep->top()) == neighbors.end(), itp, "Redundant edge found in input to PartContraction()"); @@ -1234,17 +1178,18 @@ public: // Except, if we have too many mtasks, raise the score // limit and keep going... unsigned mtaskCount = 0; - for (V3GraphVertex* vxp = m_mtasksp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (V3GraphVertex* vxp = m_mtasksp->verticesBeginp(); vxp; + vxp = vxp->verticesNextp()) { ++mtaskCount; } if (mtaskCount > maxMTasks) { uint32_t oldLimit = m_scoreLimit; m_scoreLimit = (m_scoreLimit * 120) / 100; v3Global.rootp()->fileline()->v3warn( - UNOPTTHREADS, "Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads."); - UINFO(1,"Critical path limit was="<critPathCost(way), mtaskp->critPathCost(way)); } - uint32_t origRelativesCp - = mtaskp->critPathCost(way) + mtaskp->stepCost(); - uint32_t newRelativesCp - = newCp + LogicMTask::stepCost(mtaskp->cost() + otherp->cost()); + uint32_t origRelativesCp = mtaskp->critPathCost(way) + mtaskp->stepCost(); + uint32_t newRelativesCp = newCp + LogicMTask::stepCost(mtaskp->cost() + otherp->cost()); NewCp result; result.cp = newCp; @@ -1336,14 +1277,11 @@ private: } void removeSiblingMCsWith(LogicMTask* mtaskp) { - for (SibpSet::iterator it = m_mtask2sibs[mtaskp].begin(); - it != m_mtask2sibs[mtaskp].end(); ++it) { + for (SibpSet::iterator it = m_mtask2sibs[mtaskp].begin(); it != m_mtask2sibs[mtaskp].end(); + ++it) { const SiblingMC* pairp = *it; - if (!pairp->removedFromSb()) { - m_sb.removeElem(pairp); - } - LogicMTask* otherp = (pairp->bp() == mtaskp) ? - pairp->ap() : pairp->bp(); + if (!pairp->removedFromSb()) { m_sb.removeElem(pairp); } + LogicMTask* otherp = (pairp->bp() == mtaskp) ? pairp->ap() : pairp->bp(); size_t erased = m_mtask2sibs[otherp].erase(pairp); UASSERT_OBJ(erased > 0, otherp, "Expected existing mtask"); erased = m_pairs.erase(*pairp); @@ -1354,8 +1292,8 @@ private: } void contract(MergeCandidate* mergeCanp) { - LogicMTask *top = NULL; - LogicMTask *fromp = NULL; + LogicMTask* top = NULL; + LogicMTask* fromp = NULL; MTaskEdge* mergeEdgep = dynamic_cast(mergeCanp); SiblingMC* mergeSibsp = NULL; if (mergeEdgep) { @@ -1363,8 +1301,7 @@ private: fromp = dynamic_cast(mergeEdgep->fromp()); } else { mergeSibsp = dynamic_cast(mergeCanp); - UASSERT(mergeSibsp, - "Failed to cast mergeCanp to either MTaskEdge or SiblingMC"); + UASSERT(mergeSibsp, "Failed to cast mergeCanp to either MTaskEdge or SiblingMC"); top = mergeSibsp->ap(); fromp = mergeSibsp->bp(); } @@ -1384,7 +1321,8 @@ private: donorp = fromp; recipientp = top; } - VL_DANGLING(fromp); VL_DANGLING(top); // Use donorp and recipientp now instead + VL_DANGLING(fromp); + VL_DANGLING(top); // Use donorp and recipientp now instead // Recursively update forward and reverse CP numbers. // @@ -1394,51 +1332,41 @@ private: // // These 'NewCp' objects carry a bit indicating whether we must // propagate CP for each of the four cases: - NewCp recipientNewCpFwd - = newCp(GraphWay::FORWARD, recipientp, donorp, mergeEdgep); - NewCp donorNewCpFwd - = newCp(GraphWay::FORWARD, donorp, recipientp, mergeEdgep); - NewCp recipientNewCpRev - = newCp(GraphWay::REVERSE, recipientp, donorp, mergeEdgep); - NewCp donorNewCpRev - = newCp(GraphWay::REVERSE, donorp, recipientp, mergeEdgep); + NewCp recipientNewCpFwd = newCp(GraphWay::FORWARD, recipientp, donorp, mergeEdgep); + NewCp donorNewCpFwd = newCp(GraphWay::FORWARD, donorp, recipientp, mergeEdgep); + NewCp recipientNewCpRev = newCp(GraphWay::REVERSE, recipientp, donorp, mergeEdgep); + NewCp donorNewCpRev = newCp(GraphWay::REVERSE, donorp, recipientp, mergeEdgep); if (mergeEdgep) { // Remove and free the connecting edge. Must do this before // propagating CP's below. m_sb.removeElem(mergeCanp); - VL_DO_CLEAR(mergeEdgep->unlinkDelete(), mergeEdgep=NULL); + VL_DO_CLEAR(mergeEdgep->unlinkDelete(), mergeEdgep = NULL); } // This also updates cost and stepCost on recipientp recipientp->moveAllVerticesFrom(donorp); - UINFO(9, "recipient = "<id() - << ", donor = "<id() - << ", mergeEdgep = "< - forwardPropagator(m_mtasksp, GraphWay::FORWARD, &cpAccess, m_slowAsserts); - PartPropagateCp - reversePropagator(m_mtasksp, GraphWay::REVERSE, &cpAccess, m_slowAsserts); + PartPropagateCp forwardPropagator(m_mtasksp, GraphWay::FORWARD, + &cpAccess, m_slowAsserts); + PartPropagateCp reversePropagator(m_mtasksp, GraphWay::REVERSE, + &cpAccess, m_slowAsserts); - recipientp->setCritPathCost(GraphWay::FORWARD, - recipientNewCpFwd.cp); + recipientp->setCritPathCost(GraphWay::FORWARD, recipientNewCpFwd.cp); if (recipientNewCpFwd.propagate) { forwardPropagator.cpHasIncreased(recipientp, recipientNewCpFwd.propagateCp); } - recipientp->setCritPathCost(GraphWay::REVERSE, - recipientNewCpRev.cp); + recipientp->setCritPathCost(GraphWay::REVERSE, recipientNewCpRev.cp); if (recipientNewCpRev.propagate) { reversePropagator.cpHasIncreased(recipientp, recipientNewCpRev.propagateCp); } @@ -1479,16 +1407,14 @@ private: siblingPairFromRelatives(GraphWay::REVERSE, recipientp, true); siblingPairFromRelatives(GraphWay::FORWARD, recipientp, true); unsigned edges = 0; - for (V3GraphEdge* edgep = recipientp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = recipientp->outBeginp(); edgep; edgep = edgep->outNextp()) { LogicMTask* postreqp = dynamic_cast(edgep->top()); siblingPairFromRelatives(GraphWay::REVERSE, postreqp, false); edges++; if (edges > PART_SIBLING_EDGE_LIMIT) break; } edges = 0; - for (V3GraphEdge* edgep = recipientp->inBeginp(); - edgep; edgep = edgep->inNextp()) { + for (V3GraphEdge* edgep = recipientp->inBeginp(); edgep; edgep = edgep->inNextp()) { LogicMTask* prereqp = dynamic_cast(edgep->fromp()); siblingPairFromRelatives(GraphWay::FORWARD, prereqp, false); edges++; @@ -1503,8 +1429,7 @@ private: // behave identically without the caching (just slower) m_sb.rescore(); - UINFO(6, "Did rescore. Merges since previous = " - << m_mergesSinceRescore << endl); + UINFO(6, "Did rescore. Merges since previous = " << m_mergesSinceRescore << endl); m_mergesSinceRescore = 0; m_scoreLimitBeforeRescore = 0xffffffff; @@ -1519,9 +1444,7 @@ private: return 1 + edgeScore(edgep); } const SiblingMC* sibsp = dynamic_cast(pairp); - if (sibsp) { - return siblingScore(sibsp); - } + if (sibsp) { return siblingScore(sibsp); } v3fatalSrc("Failed to cast pairp to either MTaskEdge or SiblingMC in mergeCandidateScore"); return 0; } @@ -1529,12 +1452,11 @@ private: static uint32_t siblingScore(const SiblingMC* sibsp) { LogicMTask* ap = sibsp->ap(); LogicMTask* bp = sibsp->bp(); - uint32_t mergedCpCostFwd = std::max(ap->critPathCost(GraphWay::FORWARD), - bp->critPathCost(GraphWay::FORWARD)); - uint32_t mergedCpCostRev = std::max(ap->critPathCost(GraphWay::REVERSE), - bp->critPathCost(GraphWay::REVERSE)); - return mergedCpCostRev + mergedCpCostFwd - + LogicMTask::stepCost(ap->cost() + bp->cost()); + uint32_t mergedCpCostFwd + = std::max(ap->critPathCost(GraphWay::FORWARD), bp->critPathCost(GraphWay::FORWARD)); + uint32_t mergedCpCostRev + = std::max(ap->critPathCost(GraphWay::REVERSE), bp->critPathCost(GraphWay::REVERSE)); + return mergedCpCostRev + mergedCpCostFwd + LogicMTask::stepCost(ap->cost() + bp->cost()); } static uint32_t edgeScore(const V3GraphEdge* edgep) { @@ -1543,17 +1465,15 @@ private: // critical path running through the merged node.) LogicMTask* top = dynamic_cast(edgep->top()); LogicMTask* fromp = dynamic_cast(edgep->fromp()); - uint32_t mergedCpCostFwd = std::max - (fromp->critPathCost(GraphWay::FORWARD), - top->critPathCostWithout(GraphWay::FORWARD, edgep)); - uint32_t mergedCpCostRev = std::max - (fromp->critPathCostWithout(GraphWay::REVERSE, edgep), - top->critPathCost(GraphWay::REVERSE)); + uint32_t mergedCpCostFwd = std::max(fromp->critPathCost(GraphWay::FORWARD), + top->critPathCostWithout(GraphWay::FORWARD, edgep)); + uint32_t mergedCpCostRev = std::max(fromp->critPathCostWithout(GraphWay::REVERSE, edgep), + top->critPathCost(GraphWay::REVERSE)); return mergedCpCostRev + mergedCpCostFwd - + LogicMTask::stepCost(fromp->cost() + top->cost()); + + LogicMTask::stepCost(fromp->cost() + top->cost()); } - void makeSiblingMC(LogicMTask* ap, LogicMTask *bp) { + void makeSiblingMC(LogicMTask* ap, LogicMTask* bp) { SiblingMC newSibs(ap, bp); std::pair insertResult = m_pairs.insert(newSibs); if (insertResult.second) { @@ -1564,17 +1484,15 @@ private: } else if (m_slowAsserts) { // It's fine if we already have this SiblingMC, we may have // created it earlier. Just confirm that we have associated data. - UASSERT_OBJ(m_mtask2sibs.find(ap) != m_mtask2sibs.end(), ap, - "Sibling not found"); - UASSERT_OBJ(m_mtask2sibs.find(bp) != m_mtask2sibs.end(), bp, - "Sibling not found"); + UASSERT_OBJ(m_mtask2sibs.find(ap) != m_mtask2sibs.end(), ap, "Sibling not found"); + UASSERT_OBJ(m_mtask2sibs.find(bp) != m_mtask2sibs.end(), bp, "Sibling not found"); bool found = false; - for (SibpSet::iterator it = m_mtask2sibs[ap].begin(); - it != m_mtask2sibs[ap].end(); ++it) { + for (SibpSet::iterator it = m_mtask2sibs[ap].begin(); it != m_mtask2sibs[ap].end(); + ++it) { const SiblingMC* sibsp = *it; UASSERT_OBJ(!(!sibsp->removedFromSb() && !m_sb.contains(sibsp)), ap, "One sibling must be the one we collided with"); - if ( (sibsp->ap() == ap && sibsp->bp() == bp) + if ((sibsp->ap() == ap && sibsp->bp() == bp) || (sibsp->bp() == ap && sibsp->ap() == bp)) found = true; } @@ -1585,8 +1503,8 @@ private: static const GraphWay* s_shortestWaywardCpInclusiveWay; static int shortestWaywardCpInclusive(const void* vap, const void* vbp) { const GraphWay* wp = s_shortestWaywardCpInclusiveWay; - const LogicMTask* ap = *reinterpret_cast(vap); - const LogicMTask* bp = *reinterpret_cast(vbp); + const LogicMTask* ap = *reinterpret_cast(vap); + const LogicMTask* bp = *reinterpret_cast(vbp); uint32_t aCp = ap->critPathCost(*wp) + ap->stepCost(); uint32_t bCp = bp->critPathCost(*wp) + bp->stepCost(); if (aCp < bCp) { return -1; } @@ -1596,12 +1514,10 @@ private: return 0; } - void siblingPairFromRelatives(GraphWay way, V3GraphVertex* mtaskp, - bool exhaustive) { + void siblingPairFromRelatives(GraphWay way, V3GraphVertex* mtaskp, bool exhaustive) { std::vector shortestPrereqs; - for (V3GraphEdge* edgep = mtaskp->beginp(way); - edgep; edgep = edgep->nextp(way)) { + for (V3GraphEdge* edgep = mtaskp->beginp(way); edgep; edgep = edgep->nextp(way)) { LogicMTask* prereqp = dynamic_cast(edgep->furtherp(way)); shortestPrereqs.push_back(prereqp); // Prevent nodes with huge numbers of edges from massively @@ -1613,8 +1529,8 @@ private: // qsort_r would be nice here, but it isn't portable s_shortestWaywardCpInclusiveWay = &way; - qsort(&shortestPrereqs[0], shortestPrereqs.size(), - sizeof(LogicMTask*), &shortestWaywardCpInclusive); + qsort(&shortestPrereqs[0], shortestPrereqs.size(), sizeof(LogicMTask*), + &shortestWaywardCpInclusive); // Don't make all NxN/2 possible pairs of prereqs, that's a lot // to cart around. Just make a few pairs. @@ -1642,7 +1558,7 @@ private: // or worse which would suggest N^2 scaling or worse. UASSERT(usecsLarge < (usecsSmall * 1500), "selfTestChain() took longer than expected. Small input runtime = " - <setCost(1); unsigned i; - for (i=0; i<50; ++i) { + for (i = 0; i < 50; ++i) { LogicMTask* mtp = new LogicMTask(&mtasks, NULL); mtp->setCost(1); // Edge from every input -> center new MTaskEdge(&mtasks, mtp, center, 1); } - for (i=0; i<50; ++i) { + for (i = 0; i < 50; ++i) { LogicMTask* mtp = new LogicMTask(&mtasks, NULL); mtp->setCost(1); // Edge from center -> every output @@ -1728,7 +1641,7 @@ private: // Checking exact values here is maybe overly precise. What we're // mostly looking for is a healthy reduction in the number of // mtasks. - if (debug()>=5) { + if (debug() >= 5) { UINFO(0, "X self test stats:\n"); check.debugReport(); } @@ -1737,6 +1650,7 @@ private: UASSERT_SELFTEST(uint32_t, check.vertexCount(), 14); UASSERT_SELFTEST(uint32_t, check.edgeCount(), 13); } + public: static void selfTest() { selfTestX(); @@ -1767,7 +1681,7 @@ private: m_tracingCall = false; if (nodep->dpiImportWrapper()) { if (nodep->pure() ? !v3Global.opt.threadsDpiPure() - : !v3Global.opt.threadsDpiUnpure()) { + : !v3Global.opt.threadsDpiUnpure()) { m_hasDpiHazard = true; } } @@ -1883,7 +1797,7 @@ class PartFixDataHazards { private: // TYPES typedef std::set LogicMTaskSet; - typedef std::map TasksByRank; + typedef std::map TasksByRank; typedef std::set OvvSet; typedef vl_unordered_map Olv2MTaskMap; @@ -1894,46 +1808,41 @@ private: public: // CONSTRUCTORs explicit PartFixDataHazards(V3Graph* mtasksp) - : m_mtasksp(mtasksp), m_mergesDone(0) {} + : m_mtasksp(mtasksp) + , m_mergesDone(0) {} // METHODS private: void findAdjacentTasks(OvvSet::iterator ovvIt, TasksByRank* tasksByRankp) { // Find all writer tasks for this variable, group by rank. - for (V3GraphEdge* edgep = (*ovvIt)->inBeginp(); - edgep; edgep = edgep->inNextp()) { + for (V3GraphEdge* edgep = (*ovvIt)->inBeginp(); edgep; edgep = edgep->inNextp()) { OrderLogicVertex* logicp = dynamic_cast(edgep->fromp()); if (!logicp) continue; - if (logicp->domainp()->hasInitial() - || logicp->domainp()->hasSettle()) continue; + if (logicp->domainp()->hasInitial() || logicp->domainp()->hasSettle()) continue; LogicMTask* writerMtaskp = m_olv2mtask.at(logicp); (*tasksByRankp)[writerMtaskp->rank()].insert(writerMtaskp); } // Find all reader tasks for this variable, group by rank. - for (V3GraphEdge* edgep = (*ovvIt)->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = (*ovvIt)->outBeginp(); edgep; edgep = edgep->outNextp()) { OrderLogicVertex* logicp = dynamic_cast(edgep->fromp()); if (!logicp) continue; - if (logicp->domainp()->hasInitial() - || logicp->domainp()->hasSettle()) continue; + if (logicp->domainp()->hasInitial() || logicp->domainp()->hasSettle()) continue; LogicMTask* readerMtaskp = m_olv2mtask.at(logicp); (*tasksByRankp)[readerMtaskp->rank()].insert(readerMtaskp); } } void mergeSameRankTasks(TasksByRank* tasksByRankp) { LogicMTask* lastMergedp = NULL; - for (TasksByRank::iterator rankIt = tasksByRankp->begin(); - rankIt != tasksByRankp->end(); ++rankIt) { + for (TasksByRank::iterator rankIt = tasksByRankp->begin(); rankIt != tasksByRankp->end(); + ++rankIt) { // Find the largest node at this rank, merge into it. (If we // happen to find a huge node, this saves time in // partMergeEdgesFrom() versus merging into an arbitrary node.) LogicMTask* mergedp = NULL; - for (LogicMTaskSet::iterator it = rankIt->second.begin(); - it != rankIt->second.end(); ++it) { + for (LogicMTaskSet::iterator it = rankIt->second.begin(); it != rankIt->second.end(); + ++it) { LogicMTask* mtaskp = *it; if (mergedp) { - if (mergedp->cost() < mtaskp->cost()) { - mergedp = mtaskp; - } + if (mergedp->cost() < mtaskp->cost()) { mergedp = mtaskp; } } else { mergedp = mtaskp; } @@ -1947,8 +1856,7 @@ private: rankIt->second.erase(begin); // Merge donorp into mergedp. // Fix up the map, so donor's OLVs map to mergedp - for (LogicMTask::VxList::const_iterator tmvit = - donorp->vertexListp()->begin(); + for (LogicMTask::VxList::const_iterator tmvit = donorp->vertexListp()->begin(); tmvit != donorp->vertexListp()->end(); ++tmvit) { MTaskMoveVertex* tmvp = *tmvit; OrderLogicVertex* logicp = tmvp->logicp(); @@ -1986,12 +1894,13 @@ private: // Find all calls to DPI-imported functions, we can put those // into a serial order at least. That should solve the most // likely DPI-related data hazards. - if (DpiImportCallVisitor(nodep).hasDpiHazard()) { + if (DpiImportCallVisitor(nodep).hasDpiHazard()) { // return true; } } return false; } + public: void go() { vluint64_t startUsecs = 0; @@ -2003,24 +1912,21 @@ public: // OVV's which wrap systemC vars will be handled slightly specially OvvSet ovvSetSystemC(ovvOrder); - for (V3GraphVertex* vxp = m_mtasksp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (V3GraphVertex* vxp = m_mtasksp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { LogicMTask* mtaskp = dynamic_cast(vxp); // Should be only one MTaskMoveVertex in each mtask at this // stage, but whatever, write it as a loop: - for (LogicMTask::VxList::const_iterator it - = mtaskp->vertexListp()->begin(); + for (LogicMTask::VxList::const_iterator it = mtaskp->vertexListp()->begin(); it != mtaskp->vertexListp()->end(); ++it) { MTaskMoveVertex* tmvp = *it; if (OrderLogicVertex* logicp = tmvp->logicp()) { m_olv2mtask[logicp] = mtaskp; // Look at downstream vars. - for (V3GraphEdge *edgep = logicp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = logicp->outBeginp(); edgep; + edgep = edgep->outNextp()) { // Only consider OrderVarStdVertex which reflects // an actual lvalue assignment; the others do not. - OrderVarStdVertex* ovvp - = dynamic_cast(edgep->top()); + OrderVarStdVertex* ovvp = dynamic_cast(edgep->top()); if (!ovvp) continue; if (ovvp->varScp()->varp()->isSc()) { ovvSetSystemC.insert(ovvp); @@ -2042,8 +1948,7 @@ public: const V3GraphVertex* vertexp; while ((vertexp = serialize.nextp())) { uint32_t rank = 0; - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; - edgep = edgep->inNextp()) { + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { rank = std::max(edgep->fromp()->rank() + 1, rank); } const_cast(vertexp)->rank(rank); @@ -2063,8 +1968,7 @@ public: // NOTE: we don't update the CP's stored in the LogicMTasks to // reflect the changes we make to the graph. That's OK, as we // haven't yet initialized CPs when we call this routine. - for (OvvSet::iterator ovvit = ovvSet.begin(); - ovvit != ovvSet.end(); ++ovvit) { + for (OvvSet::iterator ovvit = ovvSet.begin(); ovvit != ovvSet.end(); ++ovvit) { // Build a set of mtasks, per rank, which access this var. // Within a rank, sort by MTaskID to avoid nondeterminism. TasksByRank tasksByRank; @@ -2104,8 +2008,8 @@ public: // Hopefully we only have a few SC vars -- top level ports, probably. { TasksByRank tasksByRank; - for (OvvSet::iterator ovvit = ovvSetSystemC.begin(); - ovvit != ovvSetSystemC.end(); ++ovvit) { + for (OvvSet::iterator ovvit = ovvSetSystemC.begin(); ovvit != ovvSetSystemC.end(); + ++ovvit) { findAdjacentTasks(ovvit, &tasksByRank); } mergeSameRankTasks(&tasksByRank); @@ -2116,19 +2020,17 @@ public: // Same basic strategy as above to serialize access to SC vars. if (!v3Global.opt.threadsDpiPure() || !v3Global.opt.threadsDpiUnpure()) { TasksByRank tasksByRank; - for (V3GraphVertex* vxp = m_mtasksp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (V3GraphVertex* vxp = m_mtasksp->verticesBeginp(); vxp; + vxp = vxp->verticesNextp()) { LogicMTask* mtaskp = dynamic_cast(vxp); - if (hasDpiHazard(mtaskp)) { - tasksByRank[vxp->rank()].insert(mtaskp); - } + if (hasDpiHazard(mtaskp)) { tasksByRank[vxp->rank()].insert(mtaskp); } } mergeSameRankTasks(&tasksByRank); } - UINFO(4, "PartFixDataHazards() merged "<id() < bp->id(); - } + bool operator()(const ExecMTask* ap, ExecMTask* bp) const { return ap->id() < bp->id(); } }; // MEMBERS @@ -2187,10 +2086,8 @@ private: public: // CONSTRUCTORS - explicit PartPackMTasks(V3Graph* mtasksp, - uint32_t nThreads = v3Global.opt.threads(), - unsigned sandbagNumerator = 30, - unsigned sandbagDenom = 100) + explicit PartPackMTasks(V3Graph* mtasksp, uint32_t nThreads = v3Global.opt.threads(), + unsigned sandbagNumerator = 30, unsigned sandbagDenom = 100) : m_mtasksp(mtasksp) , m_nThreads(nThreads) , m_sandbagNumerator(sandbagNumerator) @@ -2209,24 +2106,22 @@ public: // Add some padding to the estimated runtime when looking from // another thread - uint32_t sandbaggedEndTime = state.completionTime - + (m_sandbagNumerator * mtaskp->cost()) / m_sandbagDenom; + uint32_t sandbaggedEndTime + = state.completionTime + (m_sandbagNumerator * mtaskp->cost()) / m_sandbagDenom; // If task B is packed after task A on thread 0, don't let thread 1 // think that A finishes later than thread 0 thinks that B // finishes, otherwise we get priority inversions and fail the self // test. if (mtaskp->packNextp()) { - uint32_t successorEndTime - = completionTime(mtaskp->packNextp(), mtaskp->thread()); - if ((sandbaggedEndTime >= successorEndTime) - && (successorEndTime > 1)) { + uint32_t successorEndTime = completionTime(mtaskp->packNextp(), mtaskp->thread()); + if ((sandbaggedEndTime >= successorEndTime) && (successorEndTime > 1)) { sandbaggedEndTime = successorEndTime - 1; } } - UINFO(6, "Sandbagged end time for "<name() - <<" on th "<name() << " on th " << thread << " = " + << sandbaggedEndTime << endl); return sandbaggedEndTime; } @@ -2237,8 +2132,7 @@ public: void go() { // Build initial ready list - for (V3GraphVertex* vxp = m_mtasksp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (V3GraphVertex* vxp = m_mtasksp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { ExecMTask* mtaskp = dynamic_cast(vxp); if (vxp->inEmpty()) m_ready.insert(mtaskp); } @@ -2255,28 +2149,23 @@ public: uint32_t bestTh = 0; ExecMTask* bestMtaskp = NULL; for (uint32_t th = 0; th < m_nThreads; ++th) { - for (ReadyMTasks::iterator taskIt = m_ready.begin(); - taskIt != m_ready.end(); ++taskIt) { + for (ReadyMTasks::iterator taskIt = m_ready.begin(); taskIt != m_ready.end(); + ++taskIt) { uint32_t timeBegin = m_busyUntil[th]; if (timeBegin > bestTime) { - UINFO(6, "th "<inBeginp(); - edgep; edgep = edgep->inNextp()) { - ExecMTask* priorp - = dynamic_cast(edgep->fromp()); + for (V3GraphEdge* edgep = taskp->inBeginp(); edgep; edgep = edgep->inNextp()) { + ExecMTask* priorp = dynamic_cast(edgep->fromp()); uint32_t priorEndTime = completionTime(priorp, th); - if (priorEndTime > timeBegin) { - timeBegin = priorEndTime; - } + if (priorEndTime > timeBegin) timeBegin = priorEndTime; } - UINFO(6, "Task "<name() - <<" start at "<name() << " start at " << timeBegin << " on thread " + << th << endl); if ((timeBegin < bestTime) || ((timeBegin == bestTime) && bestMtaskp // Redundant, but appeases static analysis tools @@ -2289,16 +2178,15 @@ public: } if (!bestMtaskp) v3fatalSrc("Should have found some task"); - UINFO(6, "Will schedule "<name() - <<" onto thread "<name() << " onto thread " << bestTh << endl); uint32_t bestEndTime = bestTime + bestMtaskp->cost(); setCompletionTime(bestMtaskp, bestEndTime); // Update the ready list size_t erased = m_ready.erase(bestMtaskp); UASSERT_OBJ(erased > 0, bestMtaskp, "Should have erased something?"); - for (V3GraphEdge* edgeOutp = bestMtaskp->outBeginp(); - edgeOutp; edgeOutp = edgeOutp->outNextp()) { + for (V3GraphEdge* edgeOutp = bestMtaskp->outBeginp(); edgeOutp; + edgeOutp = edgeOutp->outNextp()) { ExecMTask* nextp = dynamic_cast(edgeOutp->top()); UASSERT(nextp->thread() == 0xffffffff, @@ -2308,8 +2196,8 @@ public: UASSERT_OBJ(m_ready.find(nextp) == m_ready.end(), nextp, "Tasks after one being assigned should not be ready"); bool isReady = true; - for (V3GraphEdge* edgeInp = nextp->inBeginp(); - edgeInp; edgeInp = edgeInp->inNextp()) { + for (V3GraphEdge* edgeInp = nextp->inBeginp(); edgeInp; + edgeInp = edgeInp->inNextp()) { ExecMTask* priorp = dynamic_cast(edgeInp->fromp()); if (priorp == bestMtaskp) continue; if (priorp->thread() == 0xffffffff) { @@ -2319,17 +2207,17 @@ public: } if (isReady) { m_ready.insert(nextp); - UINFO(6, "Inserted "<name()<<" into ready\n"); + UINFO(6, "Inserted " << nextp->name() << " into ready\n"); } } // Update the ExecMTask itself if (m_prevMTask[bestTh]) { m_prevMTask[bestTh]->packNextp(bestMtaskp); - UINFO(6, "Packing "<name() - <<" after "<name()<name() << " after " + << m_prevMTask[bestTh]->name() << endl); } else { - UINFO(6, "Marking "<name()<<" as thread root\n"); + UINFO(6, "Marking " << bestMtaskp->name() << " as thread root\n"); bestMtaskp->threadRoot(true); } bestMtaskp->thread(bestTh); @@ -2402,10 +2290,11 @@ void V3Partition::debugMTaskGraphStats(const V3Graph* graphp, const string& stag if (!debug()) return; UINFO(4, "\n"); - UINFO(4, " Stats for "<verticesBeginp(); mtaskp; mtaskp = mtaskp->verticesNextp()) { @@ -2418,19 +2307,17 @@ void V3Partition::debugMTaskGraphStats(const V3Graph* graphp, const string& stag UASSERT(log2Cost < 32, "log2Cost overflow in debugMTaskGraphStats"); ++mtaskCostHist[log2Cost]; } - UINFO(4, " Total mtask cost = "< 0) ? cvtToStr(totalCost / mtaskCount) : "INF!") << "\n"); UINFO(4, " Histogram of mtask costs:\n"); for (unsigned i = 0; i < 32; ++i) { if (mtaskCostHist[i]) { - UINFO(4, " 2^"<=4) { + if (debug() >= 4) { UINFO(0, "\n"); UINFO(0, " Parallelism estimate for based on mtask costs:\n"); vertexParEst.debugReport(); @@ -2462,27 +2349,22 @@ void V3Partition::hashGraphDebug(const V3Graph* graphp, const char* debugName) { vl_unordered_map vx2Id; unsigned id = 0; - for (const V3GraphVertex* vxp = graphp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (const V3GraphVertex* vxp = graphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { vx2Id[vxp] = id++; } unsigned hash = 0; - for (const V3GraphVertex* vxp = graphp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { - for (const V3GraphEdge* edgep = vxp->outBeginp(); - edgep; edgep= edgep->outNextp()) { + for (const V3GraphVertex* vxp = graphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { + for (const V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { const V3GraphVertex* top = edgep->top(); hash = vx2Id[top] + 31u * hash; // The K&R hash function } } - UINFO(0, "Hash of shape (not contents) of "<(outp->top()); + const MTaskMoveVertex* top = dynamic_cast(outp->top()); UASSERT(top, "MoveVertex not associated to mtask"); Vx2MTaskMap::const_iterator it = vx2mtaskp->find(top); UASSERT(it != vx2mtaskp->end(), "MTask map can't find id"); @@ -2503,7 +2383,7 @@ void V3Partition::setupMTaskDeps(V3Graph* mtasksp, const Vx2MTaskMap* vx2mtaskp) UASSERT_OBJ(otherMTaskp != mtaskp, mtaskp, "Would create a cycle edge"); // Don't create redundant edges. - if (mtaskp->hasRelative(GraphWay::FORWARD, otherMTaskp)) { + if (mtaskp->hasRelative(GraphWay::FORWARD, otherMTaskp)) { // continue; } new MTaskEdge(mtasksp, mtaskp, otherMTaskp, 1); @@ -2526,8 +2406,8 @@ void V3Partition::go(V3Graph* mtasksp) { // node, to assert that we never count any node twice. AstUser5InUse inUser5; Vx2MTaskMap vx2mtask; - for (V3GraphVertex* vxp = m_fineDepsGraphp->verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (V3GraphVertex* vxp = m_fineDepsGraphp->verticesBeginp(); vxp; + vxp = vxp->verticesNextp()) { MTaskMoveVertex* mtmvVxp = dynamic_cast(vxp); UASSERT_OBJ(mtmvVxp, vxp, "Every vertex here should be an MTaskMoveVertex"); @@ -2575,9 +2455,7 @@ void V3Partition::go(V3Graph* mtasksp) { mtasksp->orderPreRanked(); int targetParFactor = v3Global.opt.threads(); - if (targetParFactor < 2) { - v3fatalSrc("We should not reach V3Partition when --threads <= 1"); - } + if (targetParFactor < 2) { v3fatalSrc("We should not reach V3Partition when --threads <= 1"); } // Set cpLimit to roughly totalGraphCost / nThreads // @@ -2586,9 +2464,8 @@ void V3Partition::go(V3Graph* mtasksp) { // when scheduling them. unsigned fudgeNumerator = 3; unsigned fudgeDenominator = 5; - uint32_t cpLimit = ((totalGraphCost * fudgeNumerator) - / (targetParFactor * fudgeDenominator)); - UINFO(4, "V3Partition set cpLimit = "< SortedMTaskSet; SortedMTaskSet sorted; - for (V3GraphVertex* itp = mtasksp->verticesBeginp(); itp; - itp = itp->verticesNextp()) { + for (V3GraphVertex* itp = mtasksp->verticesBeginp(); itp; itp = itp->verticesNextp()) { LogicMTask* mtaskp = dynamic_cast(itp); sorted.insert(mtaskp); } uint32_t nextId = 1; - for (SortedMTaskSet::iterator it = sorted.begin(); - it != sorted.end(); ++it) { + for (SortedMTaskSet::iterator it = sorted.begin(); it != sorted.end(); ++it) { // We shouldn't perturb the sort order of the set, despite // changing the IDs, they should all just remain in the same // relative order. Confirm that: UASSERT(nextId <= (*it)->id(), "Should only shrink MTaskIDs here"); - UINFO(4, "Reassigning MTask id " << (*it)->id() - << " to id " << nextId << "\n"); + UINFO(4, "Reassigning MTask id " << (*it)->id() << " to id " << nextId << "\n"); (*it)->id(nextId); nextId++; } } // Set color to indicate an mtaskId on every underlying MTaskMoveVertex. - for (V3GraphVertex* itp = mtasksp->verticesBeginp(); itp; - itp = itp->verticesNextp()) { + for (V3GraphVertex* itp = mtasksp->verticesBeginp(); itp; itp = itp->verticesNextp()) { LogicMTask* mtaskp = dynamic_cast(itp); - for (LogicMTask::VxList::const_iterator it - = mtaskp->vertexListp()->begin(); + for (LogicMTask::VxList::const_iterator it = mtaskp->vertexListp()->begin(); it != mtaskp->vertexListp()->end(); ++it) { MTaskMoveVertex* mvertexp = *it; mvertexp->color(mtaskp->id()); @@ -2661,8 +2534,7 @@ void V3Partition::finalizeCosts(V3Graph* execMTaskGraphp) { // choice among several ready mtasks, we'll want to start the // highest priority one first, so we're always working on the "long // pole" - for (V3GraphEdge* edgep = mtp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = mtp->outBeginp(); edgep; edgep = edgep->outNextp()) { ExecMTask* followp = dynamic_cast(edgep->top()); if ((followp->priority() + mtp->cost()) > mtp->priority()) { mtp->priority(followp->priority() + mtp->cost()); @@ -2673,7 +2545,7 @@ void V3Partition::finalizeCosts(V3Graph* execMTaskGraphp) { // Some MTasks may now have zero cost, eliminate those. // (It's common for tasks to shrink to nothing when V3LifePost // removes dly assignments.) - for (V3GraphVertex* vxp = execMTaskGraphp->verticesBeginp(); vxp; ) { + for (V3GraphVertex* vxp = execMTaskGraphp->verticesBeginp(); vxp;) { ExecMTask* mtp = dynamic_cast(vxp); vxp = vxp->verticesNextp(); // Advance before delete @@ -2682,13 +2554,10 @@ void V3Partition::finalizeCosts(V3Graph* execMTaskGraphp) { // the MTaskBody to see if it's empty. That's the source of truth. AstMTaskBody* bodyp = mtp->bodyp(); if (!bodyp->stmtsp()) { // Kill this empty mtask - UINFO(6, "Removing zero-cost "<name()<inBeginp(); - inp; inp = inp->inNextp()) { - for (V3GraphEdge* outp = mtp->outBeginp(); - outp; outp = outp->outNextp()) { - new V3GraphEdge(execMTaskGraphp, inp->fromp(), - outp->top(), 1); + UINFO(6, "Removing zero-cost " << mtp->name() << endl); + for (V3GraphEdge* inp = mtp->inBeginp(); inp; inp = inp->inNextp()) { + for (V3GraphEdge* outp = mtp->outBeginp(); outp; outp = outp->outNextp()) { + new V3GraphEdge(execMTaskGraphp, inp->fromp(), outp->top(), 1); } } VL_DO_DANGLING(mtp->unlinkDelete(execMTaskGraphp), mtp); @@ -2703,8 +2572,7 @@ void V3Partition::finalizeCosts(V3Graph* execMTaskGraphp) { // tasks, which could be transitive. Prune out all transitive edges. { execMTaskGraphp->removeTransitiveEdges(); - V3Partition::debugMTaskGraphStats(execMTaskGraphp, - "transitive2"); + V3Partition::debugMTaskGraphStats(execMTaskGraphp, "transitive2"); } // Record summary stats for final m_tasks graph. @@ -2713,7 +2581,7 @@ void V3Partition::finalizeCosts(V3Graph* execMTaskGraphp) { parEst.traverse(); parEst.statsReport("final"); if (debug() >= 3) { - UINFO(0," Final mtask parallelism report:\n"); + UINFO(0, " Final mtask parallelism report:\n"); parEst.debugReport(); } } diff --git a/src/V3PreLex.l b/src/V3PreLex.l index c75bf8844..443a199f7 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -353,7 +353,7 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) { // become a stale invalid pointer. // VPreStream* streamp = curStreamp(); - if (debug()>=10) { + if (debug() >= 10) { cout<<"- pp:inputToLex ITL s="<= 10) { cout<<"- pp::inputToLex got="< m_args; // List of define arguments public: @@ -78,7 +81,9 @@ public: void parenLevel(int value) { m_parenLevel = value; } std::vector& args() { return m_args; } VDefineRef(const string& name, const string& params) - : m_name(name), m_params(params), m_parenLevel(0) {} + : m_name(name) + , m_params(params) + , m_parenLevel(0) {} ~VDefineRef() {} }; @@ -87,13 +92,14 @@ public: class VPreIfEntry { // One for each pending ifdef/ifndef - bool m_on; // Current parse for this ifdef level is "on" - bool m_everOn; // Some if term in elsif tree has been on + bool m_on; // Current parse for this ifdef level is "on" + bool m_everOn; // Some if term in elsif tree has been on public: bool on() const { return m_on; } bool everOn() const { return m_everOn; } VPreIfEntry(bool on, bool everOn) - : m_on(on), m_everOn(everOn || on) {} // Note everOn includes new state + : m_on(on) + , m_everOn(everOn || on) {} // Note everOn includes new state ~VPreIfEntry() {} }; @@ -103,7 +109,7 @@ public: class V3PreProcImp : public V3PreProc { public: // TYPES - typedef std::map DefinesMap; + typedef std::map DefinesMap; typedef VInFilter::StrList StrList; // debug() -> see V3PreShellImp::debug; use --debugi-V3PreShell @@ -118,58 +124,67 @@ public: int m_lastLineno; // Last line number (stall detection) int m_tokensOnLine; // Number of tokens on line (stall detection) - enum ProcState { ps_TOP, - ps_DEFNAME_UNDEF, ps_DEFNAME_DEFINE, - ps_DEFNAME_IFDEF, ps_DEFNAME_IFNDEF, ps_DEFNAME_ELSIF, - ps_DEFFORM, ps_DEFVALUE, ps_DEFPAREN, ps_DEFARG, - ps_INCNAME, ps_ERRORNAME, ps_JOIN, ps_STRIFY }; + enum ProcState { + ps_TOP, + ps_DEFNAME_UNDEF, + ps_DEFNAME_DEFINE, + ps_DEFNAME_IFDEF, + ps_DEFNAME_IFNDEF, + ps_DEFNAME_ELSIF, + ps_DEFFORM, + ps_DEFVALUE, + ps_DEFPAREN, + ps_DEFARG, + ps_INCNAME, + ps_ERRORNAME, + ps_JOIN, + ps_STRIFY + }; static const char* procStateName(ProcState s) { static const char* states[] - = {"ps_TOP", - "ps_DEFNAME_UNDEF", "ps_DEFNAME_DEFINE", + = {"ps_TOP", "ps_DEFNAME_UNDEF", "ps_DEFNAME_DEFINE", "ps_DEFNAME_IFDEF", "ps_DEFNAME_IFNDEF", "ps_DEFNAME_ELSIF", - "ps_DEFFORM", "ps_DEFVALUE", "ps_DEFPAREN", "ps_DEFARG", - "ps_INCNAME", "ps_ERRORNAME", "ps_JOIN", "ps_STRIFY"}; + "ps_DEFFORM", "ps_DEFVALUE", "ps_DEFPAREN", + "ps_DEFARG", "ps_INCNAME", "ps_ERRORNAME", + "ps_JOIN", "ps_STRIFY"}; return states[s]; } std::stack m_states; ///< Current state of parser - int m_off; ///< If non-zero, ifdef level is turned off, don't dump text - bool m_incError; ///< Include error found - string m_lastSym; ///< Last symbol name found. - string m_formals; ///< Last formals found + int m_off; ///< If non-zero, ifdef level is turned off, don't dump text + bool m_incError; ///< Include error found + string m_lastSym; ///< Last symbol name found. + string m_formals; ///< Last formals found // For getRawToken/ `line insertion - string m_lineCmt; ///< Line comment(s) to be returned - bool m_lineCmtNl; ///< Newline needed before inserting lineCmt - int m_lineAdd; ///< Empty lines to return to maintain line count - bool m_rawAtBol; ///< Last rawToken left us at beginning of line + string m_lineCmt; ///< Line comment(s) to be returned + bool m_lineCmtNl; ///< Newline needed before inserting lineCmt + int m_lineAdd; ///< Empty lines to return to maintain line count + bool m_rawAtBol; ///< Last rawToken left us at beginning of line // For getFinalToken - bool m_finAhead; ///< Have read a token ahead - int m_finToken; ///< Last token read - string m_finBuf; ///< Last yytext read - bool m_finAtBol; ///< Last getFinalToken left us at beginning of line - FileLine* m_finFilelinep; ///< Location of last returned token (internal only) + bool m_finAhead; ///< Have read a token ahead + int m_finToken; ///< Last token read + string m_finBuf; ///< Last yytext read + bool m_finAtBol; ///< Last getFinalToken left us at beginning of line + FileLine* m_finFilelinep; ///< Location of last returned token (internal only) // For stringification - string m_strify; ///< Text to be stringified + string m_strify; ///< Text to be stringified // For defines std::stack m_defRefs; ///< Pending define substitution - std::stack m_ifdefStack; ///< Stack of true/false emitting evaluations - unsigned m_defDepth; ///< How many `defines deep - bool m_defPutJoin; ///< Insert `` after substitution + std::stack m_ifdefStack; ///< Stack of true/false emitting evaluations + unsigned m_defDepth; ///< How many `defines deep + bool m_defPutJoin; ///< Insert `` after substitution // For `` join std::stack m_joinStack; ///< Text on lhs of join // For getline() - string m_lineChars; ///< Characters left for next line + string m_lineChars; ///< Characters left for next line - void v3errorEnd(std::ostringstream& str) { - fileline()->v3errorEnd(str); - } + void v3errorEnd(std::ostringstream& str) { fileline()->v3errorEnd(str); } static const char* tokenName(int tok); void debugToken(int tok, const char* cmtp); @@ -194,7 +209,7 @@ private: void parsingOn() { m_off--; - if (m_off<0) fatalSrc("Underflow of parsing cmds"); + if (m_off < 0) fatalSrc("Underflow of parsing cmds"); // addLineComment no longer needed; getFinalToken will correct. } void parsingOff() { m_off++; } @@ -205,15 +220,11 @@ private: ProcState state() const { return m_states.top(); } bool stateIsDefname() const { - return state()==ps_DEFNAME_UNDEF - || state()==ps_DEFNAME_DEFINE - || state()==ps_DEFNAME_IFDEF - || state()==ps_DEFNAME_IFNDEF - || state()==ps_DEFNAME_ELSIF; - } - void statePush(ProcState state) { - m_states.push(state); + return state() == ps_DEFNAME_UNDEF || state() == ps_DEFNAME_DEFINE + || state() == ps_DEFNAME_IFDEF || state() == ps_DEFNAME_IFNDEF + || state() == ps_DEFNAME_ELSIF; } + void statePush(ProcState state) { m_states.push(state); } void statePop() { m_states.pop(); if (VL_UNCOVERABLE(m_states.empty())) { @@ -222,7 +233,8 @@ private: } } void stateChange(ProcState state) { - statePop(); statePush(state); + statePop(); + statePush(state); } public: @@ -278,7 +290,7 @@ public: m_lexp->m_keepComments = m_preprocp->keepComments(); m_lexp->m_keepWhitespace = m_preprocp->keepWhitespace(); m_lexp->m_pedantic = m_preprocp->pedantic(); - m_lexp->debug(debug()>=5 ? debug() : 0); // See also V3PreProc::debug() method + m_lexp->debug(debug() >= 5 ? debug() : 0); // See also V3PreProc::debug() method } ~V3PreProcImp() { if (m_lexp) VL_DO_CLEAR(delete m_lexp, m_lexp = NULL); @@ -297,12 +309,11 @@ V3PreProc* V3PreProc::createPreProc(FileLine* fl) { //************************************************************************* // Defines -void V3PreProcImp::undef(const string& name) { - m_defines.erase(name); -} +void V3PreProcImp::undef(const string& name) { m_defines.erase(name); } void V3PreProcImp::undefineall() { - for (DefinesMap::iterator nextit, it = m_defines.begin(); it != m_defines.end(); it=nextit) { - nextit = it; ++nextit; + for (DefinesMap::iterator nextit, it = m_defines.begin(); it != m_defines.end(); it = nextit) { + nextit = it; + ++nextit; if (!it->second.cmdline()) m_defines.erase(it); } } @@ -313,7 +324,7 @@ bool V3PreProcImp::defExists(const string& name) { string V3PreProcImp::defValue(const string& name) { DefinesMap::iterator iter = m_defines.find(name); if (iter == m_defines.end()) { - fileline()->v3error("Define or directive not defined: `"+name); + fileline()->v3error("Define or directive not defined: `" + name); return ""; } return iter->second.value(); @@ -321,7 +332,7 @@ string V3PreProcImp::defValue(const string& name) { string V3PreProcImp::defParams(const string& name) { DefinesMap::iterator iter = m_defines.find(name); if (iter == m_defines.end()) { - fileline()->v3error("Define or directive not defined: `"+name); + fileline()->v3error("Define or directive not defined: `" + name); return ""; } return iter->second.params(); @@ -333,20 +344,21 @@ FileLine* V3PreProcImp::defFileline(const string& name) { } void V3PreProcImp::define(FileLine* fl, const string& name, const string& value, const string& params, bool cmdline) { - UINFO(4,"DEFINE '"<v3error("Attempting to define built-in directive: '`" - << name << "' (IEEE 1800-2017 22.5.1)"); + fl->v3error("Attempting to define built-in directive: '`" << name + << "' (IEEE 1800-2017 22.5.1)"); } else { if (defExists(name)) { if (!(defValue(name) == value && defParams(name) == params)) { // Duplicate defs are OK - fl->v3warn(REDEFMACRO, "Redefining existing define: '"<v3warn(REDEFMACRO, "Redefining existing define: '" + << name << "', with different value: " << value + << (params == "" ? "" : " ") << params); defFileline(name)->v3warn(REDEFMACRO, "Previous definition is here, with value: " - << defValue(name) - << (defParams(name).empty() ? "" : " ") - << defParams(name)); + << defValue(name) + << (defParams(name).empty() ? "" : " ") + << defParams(name)); } undef(name); } @@ -357,14 +369,19 @@ void V3PreProcImp::define(FileLine* fl, const string& name, const string& value, string V3PreProcImp::removeDefines(const string& text) { string val; string rtnsym = text; - for (int loopprevent=0; loopprevent<100; loopprevent++) { + for (int loopprevent = 0; loopprevent < 100; loopprevent++) { string xsym = rtnsym; - if (xsym.substr(0, 1)=="`") xsym.replace(0, 1, ""); + if (xsym.substr(0, 1) == "`") xsym.replace(0, 1, ""); if (defExists(xsym)) { val = defValue(xsym); - if (val != rtnsym) rtnsym = val; // Prevent infinite loop if have `define X X - else break; - } else break; + if (val != rtnsym) { + rtnsym = val; // Prevent infinite loop if have `define X X + } else { + break; + } + } else { + break; + } } return rtnsym; // NA } @@ -387,14 +404,13 @@ string V3PreProcImp::commentCleanup(const string& text) { while ((pos = cmd.find('\"')) != string::npos) cmd.replace(pos, 1, " "); while ((pos = cmd.find('\t')) != string::npos) cmd.replace(pos, 1, " "); while ((pos = cmd.find(" ")) != string::npos) cmd.replace(pos, 2, " "); - while (!cmd.empty() && isspace(cmd[cmd.size()-1])) cmd.erase(cmd.size()-1); + while (!cmd.empty() && isspace(cmd[cmd.size() - 1])) cmd.erase(cmd.size() - 1); return cmd; } bool V3PreProcImp::commentTokenMatch(string& cmdr, const char* strg) { int len = strlen(strg); - if (0==strncmp(cmdr.c_str(), strg, len) - && (cmdr[len]=='\0' || isspace(cmdr[len]))) { + if (0 == strncmp(cmdr.c_str(), strg, len) && (cmdr[len] == '\0' || isspace(cmdr[len]))) { if (isspace(cmdr[len])) len++; cmdr = cmdr.substr(len); return true; @@ -412,32 +428,35 @@ void V3PreProcImp::comment(const string& text) { } const char* cp = text.c_str(); - if (cp[0]=='/' && (cp[1]=='/' || cp[1]=='*')) { + if (cp[0] == '/' && (cp[1] == '/' || cp[1] == '*')) { cp += 2; - } else return; + } else { + return; + } while (isspace(*cp)) cp++; bool synth = false; bool vlcomment = false; - if ((cp[0]=='v' || cp[0]=='V') - && 0==(strncmp(cp+1, "erilator", 8))) { + if ((cp[0] == 'v' || cp[0] == 'V') && 0 == (strncmp(cp + 1, "erilator", 8))) { cp += strlen("verilator"); - if (*cp == '_') fileline()->v3error("Extra underscore in meta-comment;" - " use /*verilator {...}*/ not /*verilator_{...}*/"); + if (*cp == '_') + fileline()->v3error("Extra underscore in meta-comment;" + " use /*verilator {...}*/ not /*verilator_{...}*/"); vlcomment = true; - } else if (0==(strncmp(cp, "synopsys", strlen("synopsys")))) { + } else if (0 == (strncmp(cp, "synopsys", strlen("synopsys")))) { cp += strlen("synopsys"); synth = true; - if (*cp == '_') fileline()->v3error("Extra underscore in meta-comment;" - " use /*synopsys {...}*/ not /*synopsys_{...}*/"); - } else if (0==(strncmp(cp, "cadence", strlen("cadence")))) { + if (*cp == '_') + fileline()->v3error("Extra underscore in meta-comment;" + " use /*synopsys {...}*/ not /*synopsys_{...}*/"); + } else if (0 == (strncmp(cp, "cadence", strlen("cadence")))) { cp += strlen("cadence"); synth = true; - } else if (0==(strncmp(cp, "pragma", strlen("pragma")))) { + } else if (0 == (strncmp(cp, "pragma", strlen("pragma")))) { cp += strlen("pragma"); synth = true; - } else if (0==(strncmp(cp, "ambit synthesis", strlen("ambit synthesis")))) { + } else if (0 == (strncmp(cp, "ambit synthesis", strlen("ambit synthesis")))) { cp += strlen("ambit synthesis"); synth = true; } else { @@ -453,16 +472,16 @@ void V3PreProcImp::comment(const string& text) { if (synth) { if (v3Global.opt.assertOn()) { // one_hot, one_cold, (full_case, parallel_case) - if (commentTokenMatch(cmd/*ref*/, "full_case")) { + if (commentTokenMatch(cmd /*ref*/, "full_case")) { if (!printed) insertUnreadback("/*verilator full_case*/"); } - if (commentTokenMatch(cmd/*ref*/, "parallel_case")) { + if (commentTokenMatch(cmd /*ref*/, "parallel_case")) { if (!printed) insertUnreadback("/*verilator parallel_case*/"); } - //if (commentTokenMatch(cmd/*ref*/, "one_hot")) { + // if (commentTokenMatch(cmd/*ref*/, "one_hot")) { // insertUnreadback ("/*verilator one_hot*/ "+cmd+";"); //} - //if (commentTokenMatch(cmd/*ref*/, "one_cold")) { + // if (commentTokenMatch(cmd/*ref*/, "one_cold")) { // insertUnreadback ("/*verilator one_cold*/ "+cmd+";"); //} // else ignore the comment we don't recognize @@ -471,11 +490,11 @@ void V3PreProcImp::comment(const string& text) { string::size_type pos; if ((pos = cmd.find("public_flat_rw")) != string::npos) { // "/*verilator public_flat_rw @(foo) */" -> "/*verilator public_flat_rw*/ @(foo)" - cmd = cmd.substr(pos+strlen("public_flat_rw")); + cmd = cmd.substr(pos + strlen("public_flat_rw")); while (isspace(cmd[0])) cmd = cmd.substr(1); - if (!printed) insertUnreadback("/*verilator public_flat_rw*/ "+cmd+" /**/"); + if (!printed) insertUnreadback("/*verilator public_flat_rw*/ " + cmd + " /**/"); } else { - if (!printed) insertUnreadback("/*verilator "+cmd+"*/"); + if (!printed) insertUnreadback("/*verilator " + cmd + "*/"); } } } @@ -493,34 +512,34 @@ FileLine* V3PreProc::fileline() { const char* V3PreProcImp::tokenName(int tok) { switch (tok) { - case VP_BACKQUOTE : return("BACKQUOTE"); - case VP_COMMENT : return("COMMENT"); - case VP_DEFARG : return("DEFARG"); - case VP_DEFFORM : return("DEFFORM"); - case VP_DEFINE : return("DEFINE"); - case VP_DEFREF : return("DEFREF"); - case VP_DEFREF_JOIN : return("DEFREF_JOIN"); - case VP_DEFVALUE : return("DEFVALUE"); - case VP_ELSE : return("ELSE"); - case VP_ELSIF : return("ELSIF"); - case VP_ENDIF : return("ENDIF"); - case VP_EOF : return("EOF"); - case VP_EOF_ERROR : return("EOF_ERROR"); - case VP_ERROR : return("ERROR"); - case VP_IFDEF : return("IFDEF"); - case VP_IFNDEF : return("IFNDEF"); - case VP_JOIN : return("JOIN"); - case VP_INCLUDE : return("INCLUDE"); - case VP_LINE : return("LINE"); - case VP_STRIFY : return("STRIFY"); - case VP_STRING : return("STRING"); - case VP_SYMBOL : return("SYMBOL"); - case VP_SYMBOL_JOIN : return("SYMBOL_JOIN"); - case VP_TEXT : return("TEXT"); - case VP_UNDEF : return("UNDEF"); - case VP_UNDEFINEALL : return("UNDEFINEALL"); - case VP_WHITE : return("WHITE"); - default: return("?"); + case VP_BACKQUOTE: return ("BACKQUOTE"); + case VP_COMMENT: return ("COMMENT"); + case VP_DEFARG: return ("DEFARG"); + case VP_DEFFORM: return ("DEFFORM"); + case VP_DEFINE: return ("DEFINE"); + case VP_DEFREF: return ("DEFREF"); + case VP_DEFREF_JOIN: return ("DEFREF_JOIN"); + case VP_DEFVALUE: return ("DEFVALUE"); + case VP_ELSE: return ("ELSE"); + case VP_ELSIF: return ("ELSIF"); + case VP_ENDIF: return ("ENDIF"); + case VP_EOF: return ("EOF"); + case VP_EOF_ERROR: return ("EOF_ERROR"); + case VP_ERROR: return ("ERROR"); + case VP_IFDEF: return ("IFDEF"); + case VP_IFNDEF: return ("IFNDEF"); + case VP_JOIN: return ("JOIN"); + case VP_INCLUDE: return ("INCLUDE"); + case VP_LINE: return ("LINE"); + case VP_STRIFY: return ("STRIFY"); + case VP_STRING: return ("STRING"); + case VP_SYMBOL: return ("SYMBOL"); + case VP_SYMBOL_JOIN: return ("SYMBOL_JOIN"); + case VP_TEXT: return ("TEXT"); + case VP_UNDEF: return ("UNDEF"); + case VP_UNDEFINEALL: return ("UNDEFINEALL"); + case VP_WHITE: return ("WHITE"); + default: return ("?"); } } @@ -530,7 +549,7 @@ void V3PreProcImp::unputString(const string& strg) { // However this can lead to "flex scanner push-back overflow" // so instead we scan from a temporary buffer, then on EOF return. // This is also faster than the old scheme, amazingly. - if (m_lexp->m_bufferState!=m_lexp->currentBuffer()) { + if (m_lexp->m_bufferState != m_lexp->currentBuffer()) { fatalSrc("bufferStack missing current buffer; will return incorrectly"); // Hard to debug lost text as won't know till much later } @@ -539,31 +558,31 @@ void V3PreProcImp::unputString(const string& strg) { void V3PreProcImp::unputDefrefString(const string& strg) { int multiline = 0; - for (size_t i=0; icurStreamp()->m_ignNewlines += multiline; // Must be after unput - applies to new stream + // Must be after unput - applies to new stream + m_lexp->curStreamp()->m_ignNewlines += multiline; } string V3PreProcImp::trimWhitespace(const string& strg, bool trailing) { // Remove leading whitespace string out = strg; string::size_type leadspace = 0; - while (out.length() > leadspace - && isspace(out[leadspace])) leadspace++; + while (out.length() > leadspace && isspace(out[leadspace])) leadspace++; if (leadspace) out.erase(0, leadspace); // Remove trailing whitespace if (trailing) { string::size_type trailspace = 0; - while (out.length() > trailspace - && isspace(out[out.length()-1-trailspace])) trailspace++; + while (out.length() > trailspace && isspace(out[out.length() - 1 - trailspace])) + trailspace++; // Don't remove \{space_or_newline} - if (trailspace && out.length() > trailspace && out[out.length()-1-trailspace]=='\\') + if (trailspace && out.length() > trailspace && out[out.length() - 1 - trailspace] == '\\') trailspace--; - if (trailspace) out.erase(out.length()-trailspace, trailspace); + if (trailspace) out.erase(out.length() - trailspace, trailspace); } return out; } @@ -577,16 +596,16 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { // Note we parse the definition parameters and value here. If a // parameterized define is used many, many times, we could cache the // parsed result. - UINFO(4,"defineSubstIn `"<name()<<" "<params()<args().size(); i++) { - UINFO(4,"defineArg["<args()[i]<<"'"<name() << " " << refp->params() << endl); + for (unsigned i = 0; i < refp->args().size(); i++) { + UINFO(4, "defineArg[" << i << "] = '" << refp->args()[i] << "'" << endl); } // Grab value string value = defValue(refp->name()); - UINFO(4,"defineValue '"< argValueByName; - { // Parse argument list into map + std::map argValueByName; + { // Parse argument list into map unsigned numArgs = 0; string argName; int paren = 1; // (), {} and [] can use same counter, as must be matched pair per spec @@ -598,16 +617,21 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { const char* cp = params.c_str(); if (*cp == '(') cp++; for (; *cp; cp++) { - //UINFO(4," Parse Paren="<args().size() > numArgs) { // A call `def( a ) must be equivalent to `def(a ), so trimWhitespace // At one point we didn't trim trailing @@ -615,8 +639,9 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { string arg = trimWhitespace(refp->args()[numArgs], true); if (arg != "") valueDef = arg; } else if (!haveDefault) { - error("Define missing argument '"+argName+"' for: "+refp->name()+"\n"); - return " `"+refp->name()+" "; + error("Define missing argument '" + argName + "' for: " + refp->name() + + "\n"); + return " `" + refp->name() + " "; } numArgs++; } @@ -626,64 +651,69 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { token = ""; haveDefault = false; continue; - } - else if (*cp=='=') { + } else if (*cp == '=') { haveDefault = true; argName = token; token = ""; continue; } } - if (cp[0]=='\\' && cp[1]) { + if (cp[0] == '\\' && cp[1]) { token += cp[0]; // \{any} Put out literal next character token += cp[1]; cp++; continue; } if (!quote) { - if (*cp=='(' || *cp=='{' || *cp=='[') paren++; - else if (*cp==')' || *cp=='}' || *cp==']') paren--; + if (*cp == '(' || *cp == '{' || *cp == '[') { + paren++; + } else if (*cp == ')' || *cp == '}' || *cp == ']') { + paren--; + } } - if (*cp=='"') quote=!quote; + if (*cp == '"') quote = !quote; if (*cp) token += *cp; } if (refp->args().size() > numArgs // `define X() is ok to call with nothing - && !(refp->args().size()==1 && numArgs==0 - && trimWhitespace(refp->args()[0], false)=="")) { - error("Define passed too many arguments: "+refp->name()+"\n"); - return " `"+refp->name()+" "; + && !(refp->args().size() == 1 && numArgs == 0 + && trimWhitespace(refp->args()[0], false) == "")) { + error("Define passed too many arguments: " + refp->name() + "\n"); + return " `" + refp->name() + " "; } } string out; - { // Parse substitution define using arguments + { // Parse substitution define using arguments string argName; bool quote = false; bool backslashesc = false; // In \.....{space} block // Note we go through the loop once more at the NULL end-of-string - for (const char* cp=value.c_str(); (*cp) || argName!=""; cp=(*cp?cp+1:cp)) { - //UINFO(4, "CH "<<*cp<<" an "<::iterator iter = argValueByName.find(argName); + std::map::iterator iter = argValueByName.find(argName); if (iter != argValueByName.end()) { // Substitute string subst = iter->second; if (subst == "") { // Normally `` is removed later, but with no token after, we're otherwise // stuck, so remove proceeding `` - if (out.size()>=2 && out.substr(out.size()-2) == "``") { - out = out.substr(0, out.size()-2); + if (out.size() >= 2 && out.substr(out.size() - 2) == "``") { + out = out.substr(0, out.size() - 2); } } else { out += subst; @@ -695,36 +725,33 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { } if (!quote) { // Check for `` only after we've detected end-of-argname - if (cp[0]=='`' && cp[1]=='`') { + if (cp[0] == '`' && cp[1] == '`') { if (backslashesc) { // Don't put out the ``, we're forming an escape // which will not expand further later } else { - out += "``"; // `` must get removed later, as `FOO```BAR must pre-expand FOO and BAR + out += "``"; // `` must get removed later, as `FOO```BAR must pre-expand + // FOO and BAR // See also removal in empty substitutes above } cp++; continue; - } - else if (cp[0]=='`' && cp[1]=='"') { + } else if (cp[0] == '`' && cp[1] == '"') { out += "`\""; // `" means to put out a " without enabling quote mode (sort of) // however we must expand any macro calls inside it first. // So keep it `", so we don't enter quote mode. cp++; continue; - } - else if (cp[0]=='`' && cp[1]=='\\' && cp[2]=='`' && cp[3]=='"') { - out += "`\\`\""; // `\`" means to put out a backslash quote + } else if (cp[0] == '`' && cp[1] == '\\' && cp[2] == '`' && cp[3] == '"') { + out += "`\\`\""; // `\`" means to put out a backslash quote // Leave it literal until we parse the VP_STRIFY string cp += 3; continue; - } - else if (cp[0]=='`' && cp[1]=='\\') { + } else if (cp[0] == '`' && cp[1] == '\\') { out += '\\'; // `\ means to put out a backslash cp++; continue; - } - else if (cp[0]=='\\' && cp[1]=='\n') { + } else if (cp[0] == '\\' && cp[1] == '\n') { // We kept the \\n when we lexed because we don't want whitespace // trimming to mis-drop the final \\n // At replacement time we need the standard newline. @@ -733,24 +760,23 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { continue; } } - if (cp[0]=='\\' && cp[1]=='\"') { + if (cp[0] == '\\' && cp[1] == '\"') { out += cp[0]; // \{any} Put out literal next character out += cp[1]; cp++; continue; - } - else if (cp[0]=='\\') { + } else if (cp[0] == '\\') { // Normally \{any} would put out literal next character // Instead we allow "`define A(nm) \nm" to expand, per proposed mantis1537 out += cp[0]; continue; } - if (*cp=='"') quote=!quote; + if (*cp == '"') quote = !quote; if (*cp) out += *cp; } } - UINFO(4,"defineSubstOut '"< with the whole file. StrList wholefile; - bool ok = filterp->readWholefile(filename, wholefile/*ref*/); + bool ok = filterp->readWholefile(filename, wholefile /*ref*/); if (!ok) { - error("File not found: "+filename+"\n"); + error("File not found: " + filename + "\n"); return; } @@ -774,7 +800,7 @@ void V3PreProcImp::openFile(FileLine* fl, VInFilter* filterp, const string& file // We allow the same include file twice, because occasionally it pops // up, with guards preventing a real recursion. if (m_lexp->m_streampStack.size() > V3PreProc::INCLUDE_DEPTH_MAX) { - error("Recursive inclusion of file: "+filename); + error("Recursive inclusion of file: " + filename); // Include might be a tree of includes that is O(n^2) or worse. // Once hit this error then, ignore all further includes so can unwind. m_incError = true; @@ -788,7 +814,7 @@ void V3PreProcImp::openFile(FileLine* fl, VInFilter* filterp, const string& file FileLine* flsp = new FileLine(filename); flsp->lineno(1); flsp->newContent(); - for (StrList::iterator it=wholefile.begin(); it!=wholefile.end(); ++it) { + for (StrList::iterator it = wholefile.begin(); it != wholefile.end(); ++it) { flsp->contentp()->pushText(*it); } @@ -799,23 +825,23 @@ void V3PreProcImp::openFile(FileLine* fl, VInFilter* filterp, const string& file // Filter all DOS CR's en-mass. This avoids bugs with lexing CRs in the wrong places. // This will also strip them from strings, but strings aren't supposed // to be multi-line without a "\" - for (StrList::iterator it=wholefile.begin(); it!=wholefile.end(); ++it) { + for (StrList::iterator it = wholefile.begin(); it != wholefile.end(); ++it) { // We don't end-loop at \0 as we allow and strip mid-string '\0's (for now). bool strip = false; const char* sp = it->data(); const char* ep = sp + it->length(); // Only process if needed, as saves extra string allocations - for (const char* cp=sp; cplength()); - for (const char* cp=sp; cplength()); + for (const char* cp = sp; cp < ep; cp++) { + if (!(*cp == '\r' || *cp == '\0')) out += *cp; } *it = out; } @@ -830,8 +856,9 @@ void V3PreProcImp::openFile(FileLine* fl, VInFilter* filterp, const string& file void V3PreProcImp::insertUnreadbackAtBol(const string& text) { // Insert insuring we're at the beginning of line, for `line // We don't always add a leading newline, as it may result in extra unreadback(newlines). - if (m_lineCmt == "") { m_lineCmtNl = true; } - else if (m_lineCmt[m_lineCmt.length()-1]!='\n') { + if (m_lineCmt == "") { + m_lineCmtNl = true; + } else if (m_lineCmt[m_lineCmt.length() - 1] != '\n') { insertUnreadback("\n"); } insertUnreadback(text); @@ -845,11 +872,11 @@ void V3PreProcImp::addLineComment(int enterExit) { void V3PreProcImp::dumpDefines(std::ostream& os) { for (DefinesMap::const_iterator it = m_defines.begin(); it != m_defines.end(); ++it) { - os<<"`define "<first; + os << "`define " << it->first; // No need to print "()" below as already part of params() - if (!it->second.params().empty()) os<second.params(); - if (!it->second.value().empty()) os<<" "<second.value(); - os<second.params().empty()) os << it->second.params(); + if (!it->second.value().empty()) os << " " << it->second.value(); + os << endl; } } @@ -862,15 +889,15 @@ void V3PreProcImp::candidateDefines(VSpellCheck* spellerp) { int V3PreProcImp::getRawToken() { // Get a token from the file, whatever it may be. while (true) { - next_tok: + next_tok: if (m_lineAdd) { m_lineAdd--; m_rawAtBol = true; yyourtext("\n", 1); - if (debug()>=5) debugToken(VP_WHITE, "LNA"); + if (debug() >= 5) debugToken(VP_WHITE, "LNA"); return VP_WHITE; } - if (m_lineCmt!="") { + if (m_lineCmt != "") { // We have some `line directive or other processed data to return to the user. static string rtncmt; // Keep the c string till next call rtncmt = m_lineCmt; @@ -880,12 +907,12 @@ int V3PreProcImp::getRawToken() { } yyourtext(rtncmt.c_str(), rtncmt.length()); m_lineCmt = ""; - if (yyourleng()) m_rawAtBol = (yyourtext()[yyourleng()-1]=='\n'); - if (state()==ps_DEFVALUE) { + if (yyourleng()) m_rawAtBol = (yyourtext()[yyourleng() - 1] == '\n'); + if (state() == ps_DEFVALUE) { V3PreLex::s_currentLexp->appendDefValue(yyourtext(), yyourleng()); goto next_tok; } else { - if (debug()>=5) debugToken(VP_TEXT, "LCM"); + if (debug() >= 5) debugToken(VP_TEXT, "LCM"); return VP_TEXT; } } @@ -894,25 +921,25 @@ int V3PreProcImp::getRawToken() { // Snarf next token from the file m_lexp->curFilelinep()->startToken(); int tok = m_lexp->lex(); - if (debug()>=5) debugToken(tok, "RAW"); + if (debug() >= 5) debugToken(tok, "RAW"); if (m_lastLineno != m_lexp->m_tokFilelinep->lineno()) { m_lastLineno = m_lexp->m_tokFilelinep->lineno(); m_tokensOnLine = 0; } else if (++m_tokensOnLine > LINE_TOKEN_MAX) { - error("Too many preprocessor tokens on a line (>"+cvtToStr(LINE_TOKEN_MAX) - +"); perhaps recursive `define"); + error("Too many preprocessor tokens on a line (>" + cvtToStr(LINE_TOKEN_MAX) + + "); perhaps recursive `define"); tok = VP_EOF_ERROR; } - if (tok==VP_EOF || tok==VP_EOF_ERROR) { + if (tok == VP_EOF || tok == VP_EOF_ERROR) { // An error might be in an unexpected point, so stop parsing - if (tok==VP_EOF_ERROR) forceEof(); + if (tok == VP_EOF_ERROR) forceEof(); // A EOF on an include, stream will find the EOF, after adding needed `lines goto next_tok; } - if (yyourleng()) m_rawAtBol = (yyourtext()[yyourleng()-1]=='\n'); + if (yyourleng()) m_rawAtBol = (yyourtext()[yyourleng() - 1] == '\n'); return tok; } } @@ -925,14 +952,12 @@ void V3PreProcImp::debugToken(int tok, const char* cmtp) { while ((pos = buf.find('\n')) != string::npos) { buf.replace(pos, 1, "\\n"); } while ((pos = buf.find('\r')) != string::npos) { buf.replace(pos, 1, "\\r"); } string flcol = m_lexp->m_tokFilelinep->asciiLineCol(); - fprintf(stderr, "%s: %s %s %s(%d) dr%d: <%d>%-10s: %s\n", - flcol.c_str(), - cmtp, (m_off ? "of" : "on"), - procStateName(state()), static_cast(m_states.size()), - static_cast(m_defRefs.size()), - m_lexp->currentStartState(), tokenName(tok), buf.c_str()); + fprintf(stderr, "%s: %s %s %s(%d) dr%d: <%d>%-10s: %s\n", flcol.c_str(), cmtp, + (m_off ? "of" : "on"), procStateName(state()), static_cast(m_states.size()), + static_cast(m_defRefs.size()), m_lexp->currentStartState(), tokenName(tok), + buf.c_str()); if (s_debugFileline >= 9) { - std::cerr<m_tokFilelinep->warnContextSecondary()<m_tokFilelinep->warnContextSecondary() << endl; } } } @@ -943,17 +968,18 @@ void V3PreProcImp::debugToken(int tok, const char* cmtp) { int V3PreProcImp::getStateToken() { // Return the next state-determined token while (true) { - next_tok: + next_tok: if (isEof()) return VP_EOF; int tok = getRawToken(); // Most states emit white space and comments between tokens. (Unless collecting a string) - if (tok==VP_WHITE && state() !=ps_STRIFY) return tok; - if (tok==VP_BACKQUOTE && state() !=ps_STRIFY) { tok = VP_TEXT; } - if (tok==VP_COMMENT) { + if (tok == VP_WHITE && state() != ps_STRIFY) return tok; + if (tok == VP_BACKQUOTE && state() != ps_STRIFY) { tok = VP_TEXT; } + if (tok == VP_COMMENT) { if (!m_off) { if (m_lexp->m_keepComments == KEEPCMT_SUB) { - string rtn; rtn.assign(yyourtext(), yyourleng()); + string rtn; + rtn.assign(yyourtext(), yyourleng()); comment(rtn); // Need to ensure "foo/**/bar" becomes two tokens insertUnreadback(" "); @@ -967,17 +993,17 @@ int V3PreProcImp::getStateToken() { // We're off or processed the comment specially. If there are newlines // in it, we also return the newlines as TEXT so that the linenumber // count is maintained for downstream tools - for (size_t len=0; len(yyourleng()); len++) { - if (yyourtext()[len]=='\n') m_lineAdd++; + for (size_t len = 0; len < static_cast(yyourleng()); len++) { + if (yyourtext()[len] == '\n') m_lineAdd++; } goto next_tok; } - if (tok==VP_LINE) { + if (tok == VP_LINE) { addLineComment(m_lexp->m_enterExit); goto next_tok; } - if (tok==VP_DEFREF_JOIN) { + if (tok == VP_DEFREF_JOIN) { // Here's something fun and unspecified as yet: // The existence of non-existance of a base define changes `` expansion // `define QA_b zzz @@ -989,23 +1015,24 @@ int V3PreProcImp::getStateToken() { // `define Q1 `QA()``_b // -> a_b // This may be a side effect of how `UNDEFINED remains as `UNDEFINED, // but it screws up our method here. So hardcode it. - string name (yyourtext()+1, yyourleng()-1); + string name(yyourtext() + 1, yyourleng() - 1); if (defExists(name)) { // JOIN(DEFREF) // Put back the `` and process the defref - UINFO(5,"```: define "< string doesn't include the ``, so can just grab next and continue - string out (yyourtext(), yyourleng()); - UINFO(5,"`` LHS:"<pushStateDefForm(); goto next_tok; + } else { + fatalSrc("Bad case\n"); } - else fatalSrc("Bad case\n"); goto next_tok; - } - else if (tok==VP_TEXT) { + } else if (tok == VP_TEXT) { // IE, something like comment between define and symbol - if (!m_off) return tok; - else goto next_tok; - } - else if (tok==VP_DEFREF) { + if (!m_off) { + return tok; + } else { + goto next_tok; + } + } else if (tok == VP_DEFREF) { // IE, `ifdef `MACRO(x): Substitute and come back here when state pops. break; - } - else { - error(string("Expecting define name. Found: ")+tokenName(tok)+"\n"); + } else { + error(string("Expecting define name. Found: ") + tokenName(tok) + "\n"); goto next_tok; } } case ps_DEFFORM: { - if (tok==VP_DEFFORM) { + if (tok == VP_DEFFORM) { m_formals = m_lexp->m_defValue; - if (debug()>=5) cout<<"DefFormals='"<= 5) { + cout << "DefFormals='" << V3PreLex::cleanDbgStrg(m_formals) << "'\n"; + } stateChange(ps_DEFVALUE); m_lexp->pushStateDefValue(); goto next_tok; - } else if (tok==VP_TEXT) { + } else if (tok == VP_TEXT) { // IE, something like comment in formals - if (!m_off) return tok; - else goto next_tok; + if (!m_off) { + return tok; + } else { + goto next_tok; + } } else { - error(string("Expecting define formal arguments. Found: ")+tokenName(tok)+"\n"); + error(string("Expecting define formal arguments. Found: ") + tokenName(tok) + + "\n"); goto next_tok; } } @@ -1101,8 +1132,10 @@ int V3PreProcImp::getStateToken() { static string newlines; newlines = "\n"; // Always start with trailing return if (tok == VP_DEFVALUE) { - if (debug()>=5) cout<<"DefValue='"<m_defValue) - <<"' formals='"<= 5) { + cout << "DefValue='" << V3PreLex::cleanDbgStrg(m_lexp->m_defValue) + << "' formals='" << V3PreLex::cleanDbgStrg(m_formals) << "'\n"; + } // Add any formals string formals = m_formals; string value = m_lexp->m_defValue; @@ -1112,42 +1145,39 @@ int V3PreProcImp::getStateToken() { // 2. Substituting in " .... " with embedded returns requires \ escape. // This is very difficult in the presence of `", so we // keep the \ before the newline. - for (size_t i=0; iname()+"\n"); + error(string("Expecting ( to begin argument list for define reference `") + + refp->name() + "\n"); statePop(); goto next_tok; } @@ -1155,128 +1185,130 @@ int V3PreProcImp::getStateToken() { case ps_DEFARG: { if (m_defRefs.empty()) fatalSrc("Shouldn't be in DEFARG w/o active defref"); VDefineRef* refp = &(m_defRefs.top()); - refp->nextarg(refp->nextarg()+m_lexp->m_defValue); m_lexp->m_defValue = ""; - UINFO(4,"defarg++ "<nextarg()<nextarg(refp->nextarg() + m_lexp->m_defValue); + m_lexp->m_defValue = ""; + UINFO(4, "defarg++ " << refp->nextarg() << endl); + if (tok == VP_DEFARG && yyourleng() == 1 && yyourtext()[0] == ',') { refp->args().push_back(refp->nextarg()); stateChange(ps_DEFARG); m_lexp->pushStateDefArg(1); refp->nextarg(""); goto next_tok; - } else if (tok==VP_DEFARG && yyourleng()==1 && yyourtext()[0]==')') { + } else if (tok == VP_DEFARG && yyourleng() == 1 && yyourtext()[0] == ')') { // Substitute in and prepare for next action // Similar code in non-parenthesized define (Search for END_OF_DEFARG) refp->args().push_back(refp->nextarg()); string out; if (!m_off) { out = defineSubst(refp); - //NOP: out = m_preprocp->defSubstitute(out); + // NOP: out = m_preprocp->defSubstitute(out); } VL_DO_DANGLING(m_defRefs.pop(), refp); if (m_defRefs.empty()) { statePop(); - if (state() == ps_JOIN) { // Handle {left}```FOO(ARG) where `FOO(ARG) might be empty + if (state() + == ps_JOIN) { // Handle {left}```FOO(ARG) where `FOO(ARG) might be empty if (m_joinStack.empty()) fatalSrc("`` join stack empty, but in a ``"); - string lhs = m_joinStack.top(); m_joinStack.pop(); + string lhs = m_joinStack.top(); + m_joinStack.pop(); out.insert(0, lhs); - UINFO(5,"``-end-defarg Out:"<m_parenLevel = 0; - } - else { // Finished a defref inside a upper defref + } else { // Finished a defref inside a upper defref // Can't subst now, or // `define a(ign) x,y // foo(`a(ign),`b) would break because a contains comma refp = &(m_defRefs.top()); // We popped, so new top - refp->nextarg(refp->nextarg()+m_lexp->m_defValue+out); m_lexp->m_defValue = ""; + refp->nextarg(refp->nextarg() + m_lexp->m_defValue + out); + m_lexp->m_defValue = ""; m_lexp->m_parenLevel = refp->parenLevel(); statePop(); // Will go to ps_DEFARG, as we're under another define } goto next_tok; - } else if (tok==VP_DEFREF) { + } else if (tok == VP_DEFREF) { // Expand it, then state will come back here // Value of building argument is data before the lower defref // we'll append it when we push the argument. break; - } else if (tok==VP_SYMBOL || tok==VP_STRING || tok==VP_TEXT || tok==VP_WHITE) { - string rtn; rtn.assign(yyourtext(), yyourleng()); - refp->nextarg(refp->nextarg()+rtn); + } else if (tok == VP_SYMBOL || tok == VP_STRING || tok == VP_TEXT || tok == VP_WHITE) { + string rtn; + rtn.assign(yyourtext(), yyourleng()); + refp->nextarg(refp->nextarg() + rtn); goto next_tok; - } else if (tok==VP_STRIFY) { + } else if (tok == VP_STRIFY) { // We must expand stringinfication, when done will return to this state statePush(ps_STRIFY); goto next_tok; } else { error(string("Expecting ) or , to end argument list for define reference. Found: ") - +tokenName(tok)); + + tokenName(tok)); statePop(); goto next_tok; } } case ps_INCNAME: { - if (tok==VP_STRING) { + if (tok == VP_STRING) { statePop(); m_lastSym.assign(yyourtext(), yyourleng()); - UINFO(4,"Include "< stateChange(ps_INCNAME); // Still m_lexp->pushStateIncFilename(); goto next_tok; - } - else if (tok==VP_DEFREF - || tok==VP_STRIFY) { + } else if (tok == VP_DEFREF || tok == VP_STRIFY) { // Expand it, then state will come back here break; - } - else { + } else { statePop(); - error(string("Expecting include filename. Found: ")+tokenName(tok)+"\n"); + error(string("Expecting include filename. Found: ") + tokenName(tok) + "\n"); goto next_tok; } } case ps_ERRORNAME: { - if (tok==VP_STRING) { + if (tok == VP_STRING) { if (!m_off) { m_lastSym.assign(yyourtext(), yyourleng()); error(m_lastSym); } statePop(); goto next_tok; - } - else { - error(string("Expecting `error string. Found: ")+tokenName(tok)+"\n"); + } else { + error(string("Expecting `error string. Found: ") + tokenName(tok) + "\n"); statePop(); goto next_tok; } } case ps_JOIN: { - if (tok==VP_SYMBOL || tok==VP_TEXT) { + if (tok == VP_SYMBOL || tok == VP_TEXT) { if (m_joinStack.empty()) fatalSrc("`` join stack empty, but in a ``"); - string lhs = m_joinStack.top(); m_joinStack.pop(); - UINFO(5,"`` LHS:"< V3PreProc::DEFINE_RECURSION_LEVEL_MAX) { - error("Recursive `define substitution: `"+name); + error("Recursive `define substitution: `" + name); goto next_tok; } // Substitute if (!defExists(name)) { // Not found, return original string as-is m_defDepth = 0; - UINFO(4,"Defref `"< not_defined"< not_defined" << endl); if (m_off) { goto next_tok; } else { return VP_TEXT; } - } - else { + } else { string params = defParams(name); - if (params=="0" || params=="") { // Found, as simple substitution + if (params == "0" || params == "") { // Found, as simple substitution string out; if (!m_off) { VDefineRef tempref(name, ""); out = defineSubst(&tempref); } // Similar code in parenthesized define (Search for END_OF_DEFARG) - //NOP: out = m_preprocp->defSubstitute(out); + // NOP: out = m_preprocp->defSubstitute(out); if (m_defRefs.empty()) { // Just output the substitution if (state() == ps_JOIN) { // Handle {left}```FOO where `FOO might be empty if (m_joinStack.empty()) fatalSrc("`` join stack empty, but in a ``"); - string lhs = m_joinStack.top(); m_joinStack.pop(); + string lhs = m_joinStack.top(); + m_joinStack.pop(); out.insert(0, lhs); - UINFO(5,"``-end-defref Out:"<nextarg(refp->nextarg()+m_lexp->m_defValue+out); + refp->nextarg(refp->nextarg() + m_lexp->m_defValue + out); m_lexp->m_defValue = ""; } goto next_tok; - } - else { // Found, with parameters - UINFO(4,"Defref `"< parameterized"< parameterized" << endl); // The CURRENT macro needs the paren saved, it's not a // property of the child macro if (!m_defRefs.empty()) m_defRefs.top().parenLevel(m_lexp->m_parenLevel); @@ -1443,13 +1466,11 @@ int V3PreProcImp::getStateToken() { goto next_tok; } case VP_EOF: - if (!m_ifdefStack.empty()) { - error("`ifdef not terminated at EOF\n"); - } + if (!m_ifdefStack.empty()) error("`ifdef not terminated at EOF\n"); return tok; case VP_UNDEFINEALL: if (!m_off) { - UINFO(4,"Undefineall "<=5) { + if (0 && debug() >= 5) { string bufcln = V3PreLex::cleanDbgStrg(buf); string flcol = m_lexp->m_tokFilelinep->asciiLineCol(); - fprintf(stderr, "%s: FIN: %-10s: %s\n", - flcol.c_str(), - tokenName(tok), bufcln.c_str()); + fprintf(stderr, "%s: FIN: %-10s: %s\n", flcol.c_str(), tokenName(tok), + bufcln.c_str()); } // Track `line const char* bufp = buf.c_str(); while (*bufp == '\n') bufp++; - if ((tok == VP_TEXT || tok == VP_LINE) && 0==strncmp(bufp, "`line ", 6)) { + if ((tok == VP_TEXT || tok == VP_LINE) && 0 == strncmp(bufp, "`line ", 6)) { int enter; - m_finFilelinep->lineDirective(bufp, enter/*ref*/); - } - else { - if (m_finAtBol && !(tok==VP_TEXT && buf=="\n") - && m_preprocp->lineDirectives()) { - if (int outBehind = (m_lexp->m_tokFilelinep->lastLineno() - - m_finFilelinep->lastLineno())) { - if (debug()>=5) { + m_finFilelinep->lineDirective(bufp, enter /*ref*/); + } else { + if (m_finAtBol && !(tok == VP_TEXT && buf == "\n") && m_preprocp->lineDirectives()) { + if (int outBehind + = (m_lexp->m_tokFilelinep->lastLineno() - m_finFilelinep->lastLineno())) { + if (debug() >= 5) { string flcol = m_lexp->m_tokFilelinep->asciiLineCol(); - fprintf(stderr, "%s: FIN: readjust, fin at %d request at %d\n", - flcol.c_str(), - m_finFilelinep->lastLineno(), - m_lexp->m_tokFilelinep->lastLineno()); + fprintf(stderr, "%s: FIN: readjust, fin at %d request at %d\n", flcol.c_str(), + m_finFilelinep->lastLineno(), m_lexp->m_tokFilelinep->lastLineno()); } m_finFilelinep->filename(m_lexp->m_tokFilelinep->filename()); m_finFilelinep->lineno(m_lexp->m_tokFilelinep->lastLineno()); @@ -1521,7 +1540,7 @@ int V3PreProcImp::getFinalToken(string& buf) { // Output stream is behind, send newlines to get back in sync // (Most likely because we're completing a disabled `endif) if (m_preprocp->keepWhitespace()) { - buf = string(outBehind,'\n'); + buf = string(outBehind, '\n'); return VP_TEXT; } } else { @@ -1532,7 +1551,7 @@ int V3PreProcImp::getFinalToken(string& buf) { } } // Track newlines in prep for next token - for (string::iterator cp=buf.begin(); cp!=buf.end(); ++cp) { + for (string::iterator cp = buf.begin(); cp != buf.end(); ++cp) { if (*cp == '\n') { m_finAtBol = true; m_finFilelinep->linenoInc(); @@ -1552,36 +1571,32 @@ string V3PreProcImp::getline() { bool gotEof = false; while (NULL == (rtnp = strchr(m_lineChars.c_str(), '\n')) && !gotEof) { string buf; - int tok = getFinalToken(buf/*ref*/); - if (debug()>=5) { + int tok = getFinalToken(buf /*ref*/); + if (debug() >= 5) { string bufcln = V3PreLex::cleanDbgStrg(buf); string flcol = m_lexp->m_tokFilelinep->asciiLineCol(); - fprintf(stderr, "%s: GETFETC: %-10s: %s\n", - flcol.c_str(), - tokenName(tok), bufcln.c_str()); + fprintf(stderr, "%s: GETFETC: %-10s: %s\n", flcol.c_str(), tokenName(tok), + bufcln.c_str()); } - if (tok==VP_EOF) { + if (tok == VP_EOF) { // Add a final newline, if the user forgot the final \n. - if (m_lineChars != "" && m_lineChars[m_lineChars.length()-1] != '\n') { + if (m_lineChars != "" && m_lineChars[m_lineChars.length() - 1] != '\n') { m_lineChars.append("\n"); } gotEof = true; - } - else { + } else { m_lineChars.append(buf); } } // Make new string with data up to the newline. - int len = rtnp-m_lineChars.c_str()+1; + int len = rtnp - m_lineChars.c_str() + 1; string theLine(m_lineChars, 0, len); m_lineChars = m_lineChars.erase(0, len); // Remove returned characters - if (debug()>=4) { + if (debug() >= 4) { string lncln = V3PreLex::cleanDbgStrg(theLine); string flcol = m_lexp->m_tokFilelinep->asciiLineCol(); - fprintf(stderr, "%s: GETLINE: %s\n", - flcol.c_str(), - lncln.c_str()); + fprintf(stderr, "%s: GETLINE: %s\n", flcol.c_str(), lncln.c_str()); } return theLine; } diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index ec613e954..e4271defa 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -42,17 +42,17 @@ class PremitAssignVisitor : public AstNVisitor { private: // NODE STATE // AstVar::user4() // bool; occurs on LHS of current assignment - AstUser4InUse m_inuser4; + AstUser4InUse m_inuser4; // STATE - bool m_noopt; // Disable optimization of variables in this block + bool m_noopt; // Disable optimization of variables in this block // METHODS VL_DEBUG_FUNC; // Declare debug() // VISITORS virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { - //AstNode::user4ClearTree(); // Implied by AstUser4InUse + // AstNode::user4ClearTree(); // Implied by AstUser4InUse // LHS first as fewer varrefs iterateAndNextNull(nodep->lhsp()); // Now find vars marked as lhs @@ -64,7 +64,7 @@ private: nodep->varp()->user4(true); } else { if (nodep->varp()->user4()) { - if (!m_noopt) UINFO(4, "Block has LHS+RHS var: "< bool. True if converted to conditional // AstShiftR::user2() -> bool. True if converted to conditional // *::user4() -> See PremitAssignVisitor - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; // STATE - AstNodeModule* m_modp; // Current module - AstCFunc* m_funcp; // Current block - AstNode* m_stmtp; // Current statement - AstWhile* m_inWhilep; // Inside while loop, special statement additions - AstTraceInc* m_inTracep; // Inside while loop, special statement additions - bool m_assignLhs; // Inside assignment lhs, don't breakup extracts + AstNodeModule* m_modp; // Current module + AstCFunc* m_funcp; // Current block + AstNode* m_stmtp; // Current statement + AstWhile* m_inWhilep; // Inside while loop, special statement additions + AstTraceInc* m_inTracep; // Inside while loop, special statement additions + bool m_assignLhs; // Inside assignment lhs, don't breakup extracts // METHODS VL_DEBUG_FUNC; // Declare debug() bool assignNoTemp(AstNodeAssign* nodep) { - return (VN_IS(nodep->lhsp(), VarRef) - && !AstVar::scVarRecurse(nodep->lhsp()) + return (VN_IS(nodep->lhsp(), VarRef) && !AstVar::scVarRecurse(nodep->lhsp()) && VN_IS(nodep->rhsp(), Const)); } void checkNode(AstNode* nodep) { @@ -119,24 +118,22 @@ private: // ARRAYSEL(*here*, ...) (No wides can be in any argument but first, // so we don't check which arg is wide) // ASSIGN(x, SEL*HERE*(ARRAYSEL()...) (m_assignLhs==true handles this.) - //UINFO(9, " Check: "<user1()) { // Not already done + // UINFO(9, " Check: " << nodep << endl); + // UINFO(9, " Detail stmtp=" << (m_stmtp?"Y":"N") << " U=" << (nodep->user1()?"Y":"N") + // << " IW=" << (nodep->isWide()?"Y":"N") << endl); + if (m_stmtp && !nodep->user1()) { // Not already done if (nodep->isWide()) { if (m_assignLhs) { - } else if (nodep->firstAbovep() - && VN_IS(nodep->firstAbovep(), NodeAssign) + } else if (nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), NodeAssign) && assignNoTemp(VN_CAST(nodep->firstAbovep(), NodeAssign))) { // Not much point if it's just a direct assignment to a constant } else if (VN_IS(nodep->backp(), Sel) && VN_CAST(nodep->backp(), Sel)->widthp() == nodep) { // AstSel::width must remain a constant - } else if (nodep->firstAbovep() - && VN_IS(nodep->firstAbovep(), ArraySel)) { + } else if (nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel)) { // ArraySel's are pointer refs, ignore } else { - UINFO(4,"Cre Temp: "<varNumGetInc())); - AstVar* varp = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, - nodep->dtypep()); + string newvarname = (string("__Vtemp") + cvtToStr(m_modp->varNumGetInc())); + AstVar* varp + = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep()); m_funcp->addInitsp(varp); return varp; } @@ -171,7 +168,7 @@ private: } void createDeepTemp(AstNode* nodep, bool noSubst) { - if (debug()>8) nodep->dumpTree(cout, "deepin:"); + if (debug() > 8) nodep->dumpTree(cout, "deepin:"); AstNRelinker linker; nodep->unlinkFrBack(&linker); @@ -183,16 +180,15 @@ private: linker.relink(newp); // Put assignment before the referencing statement AstAssign* assp = new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), varp, true), - nodep); + new AstVarRef(nodep->fileline(), varp, true), nodep); insertBeforeStmt(assp); - if (debug()>8) assp->dumpTree(cout, "deepou:"); + if (debug() > 8) assp->dumpTree(cout, "deepou:"); nodep->user1(true); // Don't add another assignment } // VISITORS virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { - UINFO(4," MOD "<precondsp()); startStatement(nodep); @@ -229,7 +225,7 @@ private: bool noopt = PremitAssignVisitor(nodep).noOpt(); if (noopt && !nodep->user1()) { // Need to do this even if not wide, as e.g. a select may be on a wide operator - UINFO(4,"Deep temp for LHS/RHS\n"); + UINFO(4, "Deep temp for LHS/RHS\n"); createDeepTemp(nodep->rhsp(), false); } } @@ -244,7 +240,7 @@ private: iterateChildren(nodep); return; } - UINFO(4," STMT "< 32/64 bits in C++ will wrap-around and generate non-0s if (!nodep->user2SetOnce()) { - UINFO(4," ShiftFix "<rhsp(), Const); if (shiftp && shiftp->num().mostSetBitP1() > 32) { - shiftp->v3error("Unsupported: Shifting of by over 32-bit number isn't supported." - <<" (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n"); + shiftp->v3error( + "Unsupported: Shifting of by over 32-bit number isn't supported." + << " (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n"); } if (nodep->widthMin() <= 64 // Else we'll use large operators which work right - // C operator's width must be < maximum shift which is based on Verilog width - && nodep->width() < (1LL<rhsp()->widthMin())) { + // C operator's width must be < maximum shift which is + // based on Verilog width + && nodep->width() < (1LL << nodep->rhsp()->widthMin())) { AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); AstNode* constzerop; - int m1value = nodep->widthMin()-1; // Constant of width-1; not changing dtype width + int m1value + = nodep->widthMin() - 1; // Constant of width-1; not changing dtype width if (nodep->signedFlavor()) { // Then over shifting gives the sign bit, not all zeros // Note *NOT* clean output -- just like normal shift! // Create equivalent of VL_SIGNONES_(node_width) - constzerop = new AstNegate(nodep->fileline(), - new AstShiftR(nodep->fileline(), - nodep->lhsp()->cloneTree(false), - new AstConst(nodep->fileline(), - m1value), - nodep->width())); + constzerop = new AstNegate( + nodep->fileline(), + new AstShiftR(nodep->fileline(), nodep->lhsp()->cloneTree(false), + new AstConst(nodep->fileline(), m1value), nodep->width())); } else { constzerop = new AstConst(nodep->fileline(), AstConst::WidthedValue(), nodep->width(), 0); @@ -291,43 +288,39 @@ private: AstNode* constwidthp = new AstConst(nodep->fileline(), AstConst::WidthedValue(), nodep->rhsp()->widthMin(), m1value); constwidthp->dtypeFrom(nodep->rhsp()); // unsigned - AstCond* newp = - new AstCond(nodep->fileline(), - new AstGte(nodep->fileline(), - constwidthp, - nodep->rhsp()->cloneTree(false)), - nodep, - constzerop); + AstCond* newp = new AstCond( + nodep->fileline(), + new AstGte(nodep->fileline(), constwidthp, nodep->rhsp()->cloneTree(false)), + nodep, constzerop); replaceHandle.relink(newp); } } - iterateChildren(nodep); checkNode(nodep); - } - virtual void visit(AstShiftL* nodep) VL_OVERRIDE { - visitShift(nodep); - } - virtual void visit(AstShiftR* nodep) VL_OVERRIDE { - visitShift(nodep); - } - virtual void visit(AstShiftRS* nodep) VL_OVERRIDE { - visitShift(nodep); + iterateChildren(nodep); + checkNode(nodep); } + virtual void visit(AstShiftL* nodep) VL_OVERRIDE { visitShift(nodep); } + virtual void visit(AstShiftR* nodep) VL_OVERRIDE { visitShift(nodep); } + virtual void visit(AstShiftRS* nodep) VL_OVERRIDE { visitShift(nodep); } // Operators virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE { - iterateChildren(nodep); checkNode(nodep); + iterateChildren(nodep); + checkNode(nodep); } virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE { - iterateChildren(nodep); checkNode(nodep); + iterateChildren(nodep); + checkNode(nodep); } virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE { - iterateChildren(nodep); checkNode(nodep); + iterateChildren(nodep); + checkNode(nodep); } virtual void visit(AstUCFunc* nodep) VL_OVERRIDE { - iterateChildren(nodep); checkNode(nodep); + iterateChildren(nodep); + checkNode(nodep); } virtual void visit(AstSel* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->fromp()); - { // Only the 'from' is part of the assignment LHS + { // Only the 'from' is part of the assignment LHS bool prevAssign = m_assignLhs; m_assignLhs = false; iterateAndNextNull(nodep->lsbp()); @@ -338,7 +331,7 @@ private: } virtual void visit(AstArraySel* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->fromp()); - { // Only the 'from' is part of the assignment LHS + { // Only the 'from' is part of the assignment LHS bool prevAssign = m_assignLhs; m_assignLhs = false; iterateAndNextNull(nodep->bitp()); @@ -348,7 +341,7 @@ private: } virtual void visit(AstAssocSel* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->fromp()); - { // Only the 'from' is part of the assignment LHS + { // Only the 'from' is part of the assignment LHS bool prevAssign = m_assignLhs; m_assignLhs = false; iterateAndNextNull(nodep->bitp()); @@ -362,8 +355,7 @@ private: } virtual void visit(AstNodeCond* nodep) VL_OVERRIDE { iterateChildren(nodep); - if (nodep->expr1p()->isWide() - && !VN_IS(nodep->condp(), Const) + if (nodep->expr1p()->isWide() && !VN_IS(nodep->condp(), Const) && !VN_IS(nodep->condp(), VarRef)) { // We're going to need the expression several times in the expanded code, // so might as well make it a common expression @@ -380,12 +372,11 @@ private: if (v3Global.opt.autoflush()) { AstNode* searchp = nodep->nextp(); while (searchp && VN_IS(searchp, Comment)) searchp = searchp->nextp(); - if (searchp - && VN_IS(searchp, Display) + if (searchp && VN_IS(searchp, Display) && nodep->filep()->sameGateTree(VN_CAST(searchp, Display)->filep())) { // There's another display next; we can just wait to flush } else { - UINFO(4,"Autoflush "<addNextHere(new AstFFlush(nodep->fileline(), AstNode::cloneTreeNull(nodep->filep(), true))); } @@ -395,9 +386,8 @@ private: iterateChildren(nodep); // Any strings sent to a display must be var of string data type, // to avoid passing a pointer to a temporary. - for (AstNode* expp=nodep->exprsp(); expp; expp = expp->nextp()) { - if (expp->dtypep()->basicp() - && expp->dtypep()->basicp()->isString() + for (AstNode* expp = nodep->exprsp(); expp; expp = expp->nextp()) { + if (expp->dtypep()->basicp() && expp->dtypep()->basicp()->isString() && !VN_IS(expp, VarRef)) { createDeepTemp(expp, true); } @@ -430,9 +420,7 @@ public: // Premit class functions void V3Premit::premitAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index 018a1d4f1..49b78d76f 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -26,50 +26,49 @@ #include - //###################################################################### // ProtectLib top-level visitor class ProtectVisitor : public AstNVisitor { - private: - AstVFile* m_vfilep; // DPI-enabled Verilog wrapper - AstCFile* m_cfilep; // C implementation of DPI functions +private: + AstVFile* m_vfilep; // DPI-enabled Verilog wrapper + AstCFile* m_cfilep; // C implementation of DPI functions // Verilog text blocks - AstTextBlock* m_modPortsp; // Module port list - AstTextBlock* m_comboPortsp; // Combo function port list - AstTextBlock* m_seqPortsp; // Sequential function port list + AstTextBlock* m_modPortsp; // Module port list + AstTextBlock* m_comboPortsp; // Combo function port list + AstTextBlock* m_seqPortsp; // Sequential function port list AstTextBlock* m_comboIgnorePortsp; // Combo ignore function port list - AstTextBlock* m_comboDeclsp; // Combo signal declaration list - AstTextBlock* m_seqDeclsp; // Sequential signal declaration list - AstTextBlock* m_tmpDeclsp; // Temporary signal declaration list - AstTextBlock* m_hashValuep; // CPP hash value - AstTextBlock* m_comboParamsp; // Combo function parameter list - AstTextBlock* m_clkSensp; // Clock sensitivity list - AstTextBlock* m_comboIgnoreParamsp; // Combo ignore parameter list - AstTextBlock* m_seqParamsp; // Sequential parameter list - AstTextBlock* m_nbAssignsp; // Non-blocking assignment list - AstTextBlock* m_seqAssignsp; // Sequential assignment list - AstTextBlock* m_comboAssignsp; // Combo assignment list + AstTextBlock* m_comboDeclsp; // Combo signal declaration list + AstTextBlock* m_seqDeclsp; // Sequential signal declaration list + AstTextBlock* m_tmpDeclsp; // Temporary signal declaration list + AstTextBlock* m_hashValuep; // CPP hash value + AstTextBlock* m_comboParamsp; // Combo function parameter list + AstTextBlock* m_clkSensp; // Clock sensitivity list + AstTextBlock* m_comboIgnoreParamsp; // Combo ignore parameter list + AstTextBlock* m_seqParamsp; // Sequential parameter list + AstTextBlock* m_nbAssignsp; // Non-blocking assignment list + AstTextBlock* m_seqAssignsp; // Sequential assignment list + AstTextBlock* m_comboAssignsp; // Combo assignment list // C text blocks - AstTextBlock* m_cHashValuep; // CPP hash value - AstTextBlock* m_cComboParamsp; // Combo function parameter list - AstTextBlock* m_cComboInsp; // Combo input copy list - AstTextBlock* m_cComboOutsp; // Combo output copy list - AstTextBlock* m_cSeqParamsp; // Sequential parameter list - AstTextBlock* m_cSeqClksp; // Sequential clock copy list - AstTextBlock* m_cSeqOutsp; // Sequential output copy list - AstTextBlock* m_cIgnoreParamsp; // Combo ignore parameter list + AstTextBlock* m_cHashValuep; // CPP hash value + AstTextBlock* m_cComboParamsp; // Combo function parameter list + AstTextBlock* m_cComboInsp; // Combo input copy list + AstTextBlock* m_cComboOutsp; // Combo output copy list + AstTextBlock* m_cSeqParamsp; // Sequential parameter list + AstTextBlock* m_cSeqClksp; // Sequential clock copy list + AstTextBlock* m_cSeqOutsp; // Sequential output copy list + AstTextBlock* m_cIgnoreParamsp; // Combo ignore parameter list string m_libName; string m_topName; - bool m_foundTop; // Have seen the top module + bool m_foundTop; // Have seen the top module // VISITORS virtual void visit(AstNetlist* nodep) VL_OVERRIDE { - m_vfilep = new AstVFile(nodep->fileline(), - v3Global.opt.makeDir()+"/"+m_libName+".sv"); + m_vfilep + = new AstVFile(nodep->fileline(), v3Global.opt.makeDir() + "/" + m_libName + ".sv"); nodep->addFilesp(m_vfilep); - m_cfilep = new AstCFile(nodep->fileline(), - v3Global.opt.makeDir()+"/"+m_libName+".cpp"); + m_cfilep + = new AstCFile(nodep->fileline(), v3Global.opt.makeDir() + "/" + m_libName + ".cpp"); nodep->addFilesp(m_cfilep); iterateChildren(nodep); } @@ -87,8 +86,8 @@ class ProtectVisitor : public AstNVisitor { iterateChildren(nodep); V3Hash hash = V3Hashed::uncachedHash(m_cfilep); - m_hashValuep->addText(fl, cvtToStr(hash.fullValue())+";\n"); - m_cHashValuep->addText(fl, cvtToStr(hash.fullValue())+"U;\n"); + m_hashValuep->addText(fl, cvtToStr(hash.fullValue()) + ";\n"); + m_cHashValuep->addText(fl, cvtToStr(hash.fullValue()) + "U;\n"); m_foundTop = true; } @@ -127,47 +126,55 @@ class ProtectVisitor : public AstNVisitor { // Comments AstTextBlock* txtp = new AstTextBlock(fl); addComment(txtp, fl, "Wrapper module for DPI protected library"); - addComment(txtp, fl, "This module requires lib"+m_libName+ - ".a or lib"+m_libName+".so to work"); - addComment(txtp, fl, "See instructions in your simulator for how" + addComment(txtp, fl, + "This module requires lib" + m_libName + ".a or lib" + m_libName + + ".so to work"); + addComment(txtp, fl, + "See instructions in your simulator for how" " to use DPI libraries\n"); // Module declaration - m_modPortsp = new AstTextBlock(fl, "module "+m_libName+" (\n", false, true); + m_modPortsp = new AstTextBlock(fl, "module " + m_libName + " (\n", false, true); txtp->addNodep(m_modPortsp); txtp->addText(fl, ");\n\n"); // DPI declarations hashComment(txtp, fl); - txtp->addText(fl, "import \"DPI-C\" function void "+ - m_libName+"_protectlib_check_hash(int protectlib_hash__V);\n\n"); + txtp->addText(fl, "import \"DPI-C\" function void " + m_libName + + "_protectlib_check_hash(int protectlib_hash__V);\n\n"); initialComment(txtp, fl); - txtp->addText(fl, "import \"DPI-C\" function chandle "+ - m_libName+"_protectlib_create(string scope__V);\n\n"); + txtp->addText(fl, "import \"DPI-C\" function chandle " + m_libName + + "_protectlib_create(string scope__V);\n\n"); comboComment(txtp, fl); - m_comboPortsp = new AstTextBlock(fl, "import \"DPI-C\" function longint "+ - m_libName+"_protectlib_combo_update " - "(\n", false, true); + m_comboPortsp = new AstTextBlock(fl, + "import \"DPI-C\" function longint " + m_libName + + "_protectlib_combo_update " + "(\n", + false, true); m_comboPortsp->addText(fl, "chandle handle__V\n"); txtp->addNodep(m_comboPortsp); txtp->addText(fl, ");\n\n"); seqComment(txtp, fl); - m_seqPortsp = new AstTextBlock(fl, "import \"DPI-C\" function longint "+ - m_libName+"_protectlib_seq_update" - "(\n", false, true); + m_seqPortsp = new AstTextBlock(fl, + "import \"DPI-C\" function longint " + m_libName + + "_protectlib_seq_update" + "(\n", + false, true); m_seqPortsp->addText(fl, "chandle handle__V\n"); txtp->addNodep(m_seqPortsp); txtp->addText(fl, ");\n\n"); comboIgnoreComment(txtp, fl); - m_comboIgnorePortsp = new AstTextBlock(fl, "import \"DPI-C\" function void "+ - m_libName+"_protectlib_combo_ignore" - "(\n", false, true); + m_comboIgnorePortsp = new AstTextBlock(fl, + "import \"DPI-C\" function void " + m_libName + + "_protectlib_combo_ignore" + "(\n", + false, true); m_comboIgnorePortsp->addText(fl, "chandle handle__V\n"); txtp->addNodep(m_comboIgnorePortsp); txtp->addText(fl, ");\n\n"); finalComment(txtp, fl); - txtp->addText(fl, "import \"DPI-C\" function void "+ - m_libName+"_protectlib_final(chandle handle__V);\n\n"); + txtp->addText(fl, "import \"DPI-C\" function void " + m_libName + + "_protectlib_final(chandle handle__V);\n\n"); // Local variables txtp->addText(fl, "chandle handle__V;\n\n"); @@ -189,16 +196,18 @@ class ProtectVisitor : public AstNVisitor { // Initial txtp->addText(fl, "initial begin\n"); - txtp->addText(fl, m_libName+"_protectlib_check_hash(protectlib_hash__V);\n"); - txtp->addText(fl, "handle__V = "+m_libName+"_protectlib_create" - "($sformatf(\"%m\"));\n"); + txtp->addText(fl, m_libName + "_protectlib_check_hash(protectlib_hash__V);\n"); + txtp->addText(fl, "handle__V = " + m_libName + + "_protectlib_create" + "($sformatf(\"%m\"));\n"); txtp->addText(fl, "end\n\n"); // Combinatorial process addComment(txtp, fl, "Combinatorialy evaluate changes to inputs"); - m_comboParamsp = new AstTextBlock(fl, "always @(*) begin\n" - "last_combo_seqnum__V = "+ - m_libName+"_protectlib_combo_update(\n", + m_comboParamsp = new AstTextBlock(fl, + "always @(*) begin\n" + "last_combo_seqnum__V = " + + m_libName + "_protectlib_combo_update(\n", false, true); m_comboParamsp->addText(fl, "handle__V\n"); txtp->addNodep(m_comboParamsp); @@ -210,14 +219,13 @@ class ProtectVisitor : public AstNVisitor { m_clkSensp = new AstTextBlock(fl, "always @(", false, true); txtp->addNodep(m_clkSensp); txtp->addText(fl, ") begin\n"); - m_comboIgnoreParamsp = new AstTextBlock(fl, m_libName+"_protectlib_combo_ignore(\n", - false, true); + m_comboIgnoreParamsp + = new AstTextBlock(fl, m_libName + "_protectlib_combo_ignore(\n", false, true); m_comboIgnoreParamsp->addText(fl, "handle__V\n"); txtp->addNodep(m_comboIgnoreParamsp); txtp->addText(fl, ");\n"); - m_seqParamsp = new AstTextBlock(fl, "last_seq_seqnum__V <= "+m_libName+ - "_protectlib_seq_update(\n", - false, true); + m_seqParamsp = new AstTextBlock( + fl, "last_seq_seqnum__V <= " + m_libName + "_protectlib_seq_update(\n", false, true); m_seqParamsp->addText(fl, "handle__V\n"); txtp->addNodep(m_seqParamsp); txtp->addText(fl, ");\n"); @@ -229,7 +237,7 @@ class ProtectVisitor : public AstNVisitor { addComment(txtp, fl, "Select between combinatorial and sequential results"); txtp->addText(fl, "always @(*) begin\n"); m_seqAssignsp = new AstTextBlock(fl, "if (last_seq_seqnum__V > " - "last_combo_seqnum__V) begin\n"); + "last_combo_seqnum__V) begin\n"); txtp->addNodep(m_seqAssignsp); m_comboAssignsp = new AstTextBlock(fl, "end else begin\n"); txtp->addNodep(m_comboAssignsp); @@ -237,15 +245,17 @@ class ProtectVisitor : public AstNVisitor { txtp->addText(fl, "end\n\n"); // Final - txtp->addText(fl, "final "+m_libName+"_protectlib_final(handle__V);\n\n"); + txtp->addText(fl, "final " + m_libName + "_protectlib_final(handle__V);\n\n"); txtp->addText(fl, "endmodule\n"); m_vfilep->tblockp(txtp); } void castPtr(FileLine* fl, AstTextBlock* txtp) { - txtp->addText(fl, m_topName+"_container* handlep__V = " - "static_cast<"+m_topName+"_container*>(vhandlep__V);\n"); + txtp->addText(fl, m_topName + + "_container* handlep__V = " + "static_cast<" + + m_topName + "_container*>(vhandlep__V);\n"); } void createCppFile(FileLine* fl) { @@ -254,18 +264,18 @@ class ProtectVisitor : public AstNVisitor { addComment(txtp, fl, "Wrapper functions for DPI protected library\n"); // Includes - txtp->addText(fl, "#include \""+m_topName+".h\"\n"); + txtp->addText(fl, "#include \"" + m_topName + ".h\"\n"); txtp->addText(fl, "#include \"verilated_dpi.h\"\n\n"); txtp->addText(fl, "#include \n"); txtp->addText(fl, "#include \n\n"); // Verilated module plus sequence number addComment(txtp, fl, "Container class to house verilated object and sequence number"); - txtp->addText(fl, "class "+m_topName+"_container: public "+m_topName+" {\n"); + txtp->addText(fl, "class " + m_topName + "_container: public " + m_topName + " {\n"); txtp->addText(fl, "public:\n"); txtp->addText(fl, "long long m_seqnum;\n"); - txtp->addText(fl, m_topName+"_container(const char* scopep__V):\n"); - txtp->addText(fl, m_topName+"(scopep__V) {}\n"); + txtp->addText(fl, m_topName + "_container(const char* scopep__V):\n"); + txtp->addText(fl, m_topName + "(scopep__V) {}\n"); txtp->addText(fl, "};\n\n"); // Extern C @@ -273,31 +283,32 @@ class ProtectVisitor : public AstNVisitor { // Hash check hashComment(txtp, fl); - txtp->addText(fl, "void "+m_libName+"_protectlib_check_hash" - "(int protectlib_hash__V) {\n"); + txtp->addText(fl, "void " + m_libName + + "_protectlib_check_hash" + "(int protectlib_hash__V) {\n"); m_cHashValuep = new AstTextBlock(fl, "int expected_hash__V = "); txtp->addNodep(m_cHashValuep); txtp->addText(fl, "if (protectlib_hash__V != expected_hash__V) {\n"); - txtp->addText(fl, "fprintf(stderr, \"%%Error: cannot use "+m_libName+" library, " - "Verliog (%u) and library (%u) hash values do not " - "agree\\n\", protectlib_hash__V, expected_hash__V);\n"); + txtp->addText(fl, "fprintf(stderr, \"%%Error: cannot use " + m_libName + + " library, " + "Verliog (%u) and library (%u) hash values do not " + "agree\\n\", protectlib_hash__V, expected_hash__V);\n"); txtp->addText(fl, "exit(EXIT_FAILURE);\n"); txtp->addText(fl, "}\n"); txtp->addText(fl, "}\n\n"); // Initial initialComment(txtp, fl); - txtp->addText(fl, "void* "+m_libName+"_protectlib_create" - " (const char* scopep__V) {\n"); - txtp->addText(fl, m_topName+"_container* handlep__V = " - "new "+m_topName+"_container(scopep__V);\n"); + txtp->addText(fl, "void* " + m_libName + "_protectlib_create(const char* scopep__V) {\n"); + txtp->addText(fl, m_topName + "_container* handlep__V = new " + m_topName + + "_container(scopep__V);\n"); txtp->addText(fl, "return handlep__V;\n"); txtp->addText(fl, "}\n\n"); // Updates comboComment(txtp, fl); - m_cComboParamsp = new AstTextBlock(fl, "long long "+m_libName+"_protectlib_combo_update(\n", - false, true); + m_cComboParamsp = new AstTextBlock( + fl, "long long " + m_libName + "_protectlib_combo_update(\n", false, true); m_cComboParamsp->addText(fl, "void* vhandlep__V\n"); txtp->addNodep(m_cComboParamsp); txtp->addText(fl, ")\n"); @@ -310,8 +321,8 @@ class ProtectVisitor : public AstNVisitor { txtp->addText(fl, "}\n\n"); seqComment(txtp, fl); - m_cSeqParamsp = new AstTextBlock(fl, "long long "+m_libName+"_protectlib_seq_update(\n", - false, true); + m_cSeqParamsp = new AstTextBlock( + fl, "long long " + m_libName + "_protectlib_seq_update(\n", false, true); m_cSeqParamsp->addText(fl, "void* vhandlep__V\n"); txtp->addNodep(m_cSeqParamsp); txtp->addText(fl, ")\n"); @@ -324,8 +335,8 @@ class ProtectVisitor : public AstNVisitor { txtp->addText(fl, "}\n\n"); comboIgnoreComment(txtp, fl); - m_cIgnoreParamsp = new AstTextBlock(fl, "void "+m_libName+"_protectlib_combo_ignore(\n", - false, true); + m_cIgnoreParamsp = new AstTextBlock( + fl, "void " + m_libName + "_protectlib_combo_ignore(\n", false, true); m_cIgnoreParamsp->addText(fl, "void* vhandlep__V\n"); txtp->addNodep(m_cIgnoreParamsp); txtp->addText(fl, ")\n"); @@ -333,7 +344,7 @@ class ProtectVisitor : public AstNVisitor { // Final finalComment(txtp, fl); - txtp->addText(fl, "void "+m_libName+"_protectlib_final(void* vhandlep__V) {\n"); + txtp->addText(fl, "void " + m_libName + "_protectlib_final(void* vhandlep__V) {\n"); castPtr(fl, txtp); txtp->addText(fl, "handlep__V->final();\n"); txtp->addText(fl, "delete handlep__V;\n"); @@ -346,11 +357,11 @@ class ProtectVisitor : public AstNVisitor { virtual void visit(AstVar* nodep) VL_OVERRIDE { if (!nodep->isIO()) return; if (VN_IS(nodep->dtypep(), UnpackArrayDType)) { - nodep->v3error("Unsupported: unpacked arrays with protect-lib on "<prettyNameQ()); + nodep->v3error("Unsupported: unpacked arrays with protect-lib on " + << nodep->prettyNameQ()); } if (nodep->direction() == VDirection::INPUT) { - if (nodep->isUsedClock() - || nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) { + if (nodep->isUsedClock() || nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) { handleClock(nodep); } else { handleDataInput(nodep); @@ -358,8 +369,8 @@ class ProtectVisitor : public AstNVisitor { } else if (nodep->direction() == VDirection::OUTPUT) { handleOutput(nodep); } else { - nodep->v3error("Unsupported: protect-lib port direction: "<< - nodep->direction().ascii()); + nodep->v3error( + "Unsupported: protect-lib port direction: " << nodep->direction().ascii()); } } @@ -369,18 +380,18 @@ class ProtectVisitor : public AstNVisitor { string frstmt; bool useSetWSvlv = V3Task::dpiToInternalFrStmt(varp, varp->name(), frstmt); if (useSetWSvlv) { - return frstmt+" handlep__V->"+varp->name()+", "+varp->name()+");\n"; + return frstmt + " handlep__V->" + varp->name() + ", " + varp->name() + ");\n"; } - return "handlep__V->"+varp->name()+" = "+frstmt+";\n"; + return "handlep__V->" + varp->name() + " = " + frstmt + ";\n"; } void handleClock(AstVar* varp) { FileLine* fl = varp->fileline(); handleInput(varp); m_seqPortsp->addNodep(varp->cloneTree(false)); - m_seqParamsp->addText(fl, varp->name()+"\n"); - m_clkSensp->addText(fl, "edge("+varp->name()+")"); - m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false)+"\n"); + m_seqParamsp->addText(fl, varp->name() + "\n"); + m_clkSensp->addText(fl, "edge(" + varp->name() + ")"); + m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); m_cSeqClksp->addText(fl, cInputConnection(varp)); } @@ -388,61 +399,76 @@ class ProtectVisitor : public AstNVisitor { FileLine* fl = varp->fileline(); handleInput(varp); m_comboPortsp->addNodep(varp->cloneTree(false)); - m_comboParamsp->addText(fl, varp->name()+"\n"); + m_comboParamsp->addText(fl, varp->name() + "\n"); m_comboIgnorePortsp->addNodep(varp->cloneTree(false)); - m_comboIgnoreParamsp->addText(fl, varp->name()+"\n"); - m_cComboParamsp->addText(fl, varp->dpiArgType(true, false)+"\n"); + m_comboIgnoreParamsp->addText(fl, varp->name() + "\n"); + m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); m_cComboInsp->addText(fl, cInputConnection(varp)); - m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false)+"\n"); + m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); } - void handleInput(AstVar* varp) { - m_modPortsp->addNodep(varp->cloneTree(false)); - } + void handleInput(AstVar* varp) { m_modPortsp->addNodep(varp->cloneTree(false)); } void handleOutput(AstVar* varp) { FileLine* fl = varp->fileline(); m_modPortsp->addNodep(varp->cloneTree(false)); m_comboPortsp->addNodep(varp->cloneTree(false)); - m_comboParamsp->addText(fl, varp->name()+"_combo__V\n"); + m_comboParamsp->addText(fl, varp->name() + "_combo__V\n"); m_seqPortsp->addNodep(varp->cloneTree(false)); - m_seqParamsp->addText(fl, varp->name()+"_tmp__V\n"); + m_seqParamsp->addText(fl, varp->name() + "_tmp__V\n"); AstNodeDType* comboDtypep = varp->dtypep()->cloneTree(false); m_comboDeclsp->addNodep(comboDtypep); - m_comboDeclsp->addText(fl, " "+varp->name()+"_combo__V;\n"); + m_comboDeclsp->addText(fl, " " + varp->name() + "_combo__V;\n"); AstNodeDType* seqDtypep = varp->dtypep()->cloneTree(false); m_seqDeclsp->addNodep(seqDtypep); - m_seqDeclsp->addText(fl, " "+varp->name()+"_seq__V;\n"); + m_seqDeclsp->addText(fl, " " + varp->name() + "_seq__V;\n"); AstNodeDType* tmpDtypep = varp->dtypep()->cloneTree(false); m_tmpDeclsp->addNodep(tmpDtypep); - m_tmpDeclsp->addText(fl, " "+varp->name()+"_tmp__V;\n"); + m_tmpDeclsp->addText(fl, " " + varp->name() + "_tmp__V;\n"); - m_nbAssignsp->addText(fl, varp->name()+"_seq__V <= "+varp->name()+"_tmp__V;\n"); - m_seqAssignsp->addText(fl, varp->name()+" = "+varp->name()+"_seq__V;\n"); - m_comboAssignsp->addText(fl, varp->name()+" = "+varp->name()+"_combo__V;\n"); - m_cComboParamsp->addText(fl, varp->dpiArgType(true, false)+"\n"); + m_nbAssignsp->addText(fl, varp->name() + "_seq__V <= " + varp->name() + "_tmp__V;\n"); + m_seqAssignsp->addText(fl, varp->name() + " = " + varp->name() + "_seq__V;\n"); + m_comboAssignsp->addText(fl, varp->name() + " = " + varp->name() + "_combo__V;\n"); + m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); m_cComboOutsp->addText(fl, V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->")); - m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false)+"\n"); + m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); m_cSeqOutsp->addText(fl, V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->")); } - public: - explicit ProtectVisitor(AstNode* nodep): - m_vfilep(NULL), m_cfilep(NULL), m_modPortsp(NULL), - m_comboPortsp(NULL), m_seqPortsp(NULL), m_comboIgnorePortsp(NULL), m_comboDeclsp(NULL), - m_seqDeclsp(NULL), m_tmpDeclsp(NULL), m_hashValuep(NULL), - m_comboParamsp(NULL), - m_clkSensp(NULL), - m_comboIgnoreParamsp(NULL), m_seqParamsp(NULL), m_nbAssignsp(NULL), m_seqAssignsp(NULL), - m_comboAssignsp(NULL), m_cHashValuep(NULL), m_cComboParamsp(NULL), m_cComboInsp(NULL), - m_cComboOutsp(NULL), m_cSeqParamsp(NULL), m_cSeqClksp(NULL), m_cSeqOutsp(NULL), - m_cIgnoreParamsp(NULL), m_libName(v3Global.opt.protectLib()), - m_topName(v3Global.opt.prefix()), m_foundTop(false) - { +public: + explicit ProtectVisitor(AstNode* nodep) + : m_vfilep(NULL) + , m_cfilep(NULL) + , m_modPortsp(NULL) + , m_comboPortsp(NULL) + , m_seqPortsp(NULL) + , m_comboIgnorePortsp(NULL) + , m_comboDeclsp(NULL) + , m_seqDeclsp(NULL) + , m_tmpDeclsp(NULL) + , m_hashValuep(NULL) + , m_comboParamsp(NULL) + , m_clkSensp(NULL) + , m_comboIgnoreParamsp(NULL) + , m_seqParamsp(NULL) + , m_nbAssignsp(NULL) + , m_seqAssignsp(NULL) + , m_comboAssignsp(NULL) + , m_cHashValuep(NULL) + , m_cComboParamsp(NULL) + , m_cComboInsp(NULL) + , m_cComboOutsp(NULL) + , m_cSeqParamsp(NULL) + , m_cSeqClksp(NULL) + , m_cSeqOutsp(NULL) + , m_cIgnoreParamsp(NULL) + , m_libName(v3Global.opt.protectLib()) + , m_topName(v3Global.opt.prefix()) + , m_foundTop(false) { iterate(nodep); } }; diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index 1243ceb1a..4ce1a1485 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -43,8 +43,8 @@ private: // NODE STATE // AstVar::user1p -> AstVarScope replacement for this variable // AstTask::user2p -> AstTask*. Replacement task - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; // TYPES typedef vl_unordered_map PackageScopeMap; @@ -53,26 +53,25 @@ private: typedef std::set > VarRefScopeSet; // STATE, inside processing a single module - AstNodeModule* m_modp; // Current module - AstScope* m_scopep; // Current scope we are building + AstNodeModule* m_modp; // Current module + AstScope* m_scopep; // Current scope we are building // STATE, for passing down one level of hierarchy (may need save/restore) - AstCell* m_aboveCellp; // Cell that instantiates this module - AstScope* m_aboveScopep; // Scope that instantiates this scope + AstCell* m_aboveCellp; // Cell that instantiates this module + AstScope* m_aboveScopep; // Scope that instantiates this scope - PackageScopeMap m_packageScopes; // Scopes for each package - VarScopeMap m_varScopes; // Varscopes created for each scope and var - VarRefScopeSet m_varRefScopes; // Varrefs-in-scopes needing fixup when done + PackageScopeMap m_packageScopes; // Scopes for each package + VarScopeMap m_varScopes; // Varscopes created for each scope and var + VarRefScopeSet m_varRefScopes; // Varrefs-in-scopes needing fixup when done // METHODS VL_DEBUG_FUNC; // Declare debug() void cleanupVarRefs() { - for (VarRefScopeSet::iterator it = m_varRefScopes.begin(); - it!=m_varRefScopes.end(); ++it) { + for (VarRefScopeSet::iterator it = m_varRefScopes.begin(); it != m_varRefScopes.end(); + ++it) { AstVarRef* nodep = it->first; AstScope* scopep = it->second; - if (nodep->packagep() - && !nodep->varp()->isClassMember()) { + if (nodep->packagep() && !nodep->varp()->isClassMember()) { PackageScopeMap::iterator it2 = m_packageScopes.find(nodep->packagep()); UASSERT_OBJ(it2 != m_packageScopes.end(), nodep, "Can't locate package scope"); scopep = it2->second; @@ -87,7 +86,10 @@ private: // VISITORS virtual void visit(AstNetlist* nodep) VL_OVERRIDE { AstNodeModule* modp = nodep->topModulep(); - if (!modp) { nodep->v3error("No top level module found"); return; } + if (!modp) { + nodep->v3error("No top level module found"); + return; + } // Operate starting at the top of the hierarchy m_aboveCellp = NULL; m_aboveScopep = NULL; @@ -97,22 +99,25 @@ private: virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { // Create required blocks and add to module string scopename; - if (!m_aboveScopep) scopename = "TOP"; - else scopename = m_aboveScopep->name()+"."+m_aboveCellp->name(); + if (!m_aboveScopep) { + scopename = "TOP"; + } else { + scopename = m_aboveScopep->name() + "." + m_aboveCellp->name(); + } - UINFO(4," MOD AT "<(m_aboveCellp) - : static_cast(nodep)) - ->fileline(), - nodep, scopename, m_aboveScopep, m_aboveCellp); + m_scopep = new AstScope( + (m_aboveCellp ? static_cast(m_aboveCellp) : static_cast(nodep)) + ->fileline(), + nodep, scopename, m_aboveScopep, m_aboveCellp); if (VN_IS(nodep, Package)) { m_packageScopes.insert(make_pair(VN_CAST(nodep, Package), m_scopep)); } // Now for each child cell, iterate the module this cell points to - for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp=cellnextp->nextp()) { + for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp = cellnextp->nextp()) { if (AstCell* cellp = VN_CAST(cellnextp, Cell)) { AstScope* oldScopep = m_scopep; AstCell* oldAbCellp = m_aboveCellp; @@ -132,7 +137,7 @@ private: } // Create scope for the current usage of this module - UINFO(4," back AT "<isTop()) { @@ -168,8 +173,8 @@ private: AstNode* abovep = (m_aboveCellp ? static_cast(m_aboveCellp) : static_cast(nodep)); - m_scopep = new AstScope(abovep->fileline(), - m_modp, scopename, m_aboveScopep, m_aboveCellp); + m_scopep + = new AstScope(abovep->fileline(), m_modp, scopename, m_aboveScopep, m_aboveCellp); // Create scope for the current usage of this cell AstNode::user1ClearTree(); nodep->addMembersp(m_scopep); @@ -181,7 +186,7 @@ private: m_aboveCellp = oldAbCellp; m_aboveScopep = oldAbScopep; } - virtual void visit(AstCellInline* nodep) VL_OVERRIDE { + virtual void visit(AstCellInline* nodep) VL_OVERRIDE { // nodep->scopep(m_scopep); } virtual void visit(AstActive* nodep) VL_OVERRIDE { @@ -189,7 +194,7 @@ private: } virtual void visit(AstInitial* nodep) VL_OVERRIDE { // Add to list of blocks under this scope - UINFO(4," Move "<cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); @@ -197,7 +202,7 @@ private: } virtual void visit(AstFinal* nodep) VL_OVERRIDE { // Add to list of blocks under this scope - UINFO(4," Move "<cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); @@ -205,7 +210,7 @@ private: } virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // Add to list of blocks under this scope - UINFO(4," Move "<cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); @@ -213,7 +218,7 @@ private: } virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE { // Copy under the scope but don't recurse - UINFO(4," Move "<cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); @@ -221,7 +226,7 @@ private: } virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // Add to list of blocks under this scope - UINFO(4," Move "<cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); @@ -229,7 +234,7 @@ private: } virtual void visit(AstAlways* nodep) VL_OVERRIDE { // Add to list of blocks under this scope - UINFO(4," Move "<cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); @@ -237,7 +242,7 @@ private: } virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // Add to list of blocks under this scope - UINFO(4," Move "<cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); @@ -245,7 +250,7 @@ private: } virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { // Add to list of blocks under this scope - UINFO(4," Move "<cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); @@ -253,7 +258,7 @@ private: } virtual void visit(AstCFunc* nodep) VL_OVERRIDE { // Add to list of blocks under this scope - UINFO(4," CFUNC "<cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); @@ -263,7 +268,7 @@ private: } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { // Add to list of blocks under this scope - UINFO(4," FTASK "<classMethod()) { // Only one scope will be created, so avoid pointless cloning @@ -281,7 +286,7 @@ private: // Make new scope variable if (!nodep->user1p()) { AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep); - UINFO(6," New scope "<isTrace()) varscp->trace(false); nodep->user1p(varscp); if (v3Global.opt.isClocker(varscp->prettyName())) { @@ -307,10 +312,10 @@ private: // So push to a list and post-correct m_varRefScopes.insert(make_pair(nodep, m_scopep)); } - } + } virtual void visit(AstScopeName* nodep) VL_OVERRIDE { // If there's a %m in the display text, we add a special node that will contain the name() - string prefix = string("__DOT__")+m_scopep->name(); + string prefix = string("__DOT__") + m_scopep->name(); // TOP and above will be the user's name(). // Note 'TOP.' is stripped by scopePrettyName // To keep correct visual order, must add before other Text's @@ -375,36 +380,16 @@ private: } } - virtual void visit(AstInitial* nodep) VL_OVERRIDE { - movedDeleteOrIterate(nodep); - } - virtual void visit(AstFinal* nodep) VL_OVERRIDE { - movedDeleteOrIterate(nodep); - } - virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { - movedDeleteOrIterate(nodep); - } - virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE { - movedDeleteOrIterate(nodep); - } - virtual void visit(AstAssignW* nodep) VL_OVERRIDE { - movedDeleteOrIterate(nodep); - } - virtual void visit(AstAlways* nodep) VL_OVERRIDE { - movedDeleteOrIterate(nodep); - } - virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { - movedDeleteOrIterate(nodep); - } - virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { - movedDeleteOrIterate(nodep); - } - virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { - movedDeleteOrIterate(nodep); - } - virtual void visit(AstCFunc* nodep) VL_OVERRIDE { - movedDeleteOrIterate(nodep); - } + virtual void visit(AstInitial* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); } + virtual void visit(AstFinal* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); } + virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); } + virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); } + virtual void visit(AstAssignW* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); } + virtual void visit(AstAlways* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); } + virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); } + virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); } + virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); } + virtual void visit(AstCFunc* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); } virtual void visit(AstVarXRef* nodep) VL_OVERRIDE { // The crossrefs are dealt with in V3LinkDot @@ -412,17 +397,17 @@ private: } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { // The crossrefs are dealt with in V3LinkDot - UINFO(9," Old pkg-taskref "<packagep()) { // Point to the clone UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked"); AstNodeFTask* newp = VN_CAST(nodep->taskp()->user2p(), NodeFTask); UASSERT_OBJ(newp, nodep, "No clone for package function"); nodep->taskp(newp); - UINFO(9," New pkg-taskref "<taskp(NULL); - UINFO(9," New pkg-taskref "<= 3); } diff --git a/src/V3SenTree.h b/src/V3SenTree.h index a40b495ec..50002f7d4 100644 --- a/src/V3SenTree.h +++ b/src/V3SenTree.h @@ -116,8 +116,9 @@ private: // Don't grab SenTrees under Actives, only those that are global (under Scope directly) iterateChildren(nodep); } - virtual void visit(AstSenTree* nodep) VL_OVERRIDE { m_trees.add(nodep); } - + virtual void visit(AstSenTree* nodep) VL_OVERRIDE { // + m_trees.add(nodep); + } virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } diff --git a/src/V3Simulate.h b/src/V3Simulate.h index c48ee7907..ac14e601f 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -89,21 +89,21 @@ private: // STATE // Major mode - bool m_checkOnly; ///< Checking only (no simulation) mode - bool m_scoped; ///< Running with AstVarScopes instead of AstVars - bool m_params; ///< Doing parameter propagation + bool m_checkOnly; ///< Checking only (no simulation) mode + bool m_scoped; ///< Running with AstVarScopes instead of AstVars + bool m_params; ///< Doing parameter propagation // Checking: - string m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize - AstNode* m_whyNotNodep; ///< First node not optimizable - bool m_anyAssignDly; ///< True if found a delayed assignment - bool m_anyAssignComb; ///< True if found a non-delayed assignment - bool m_inDlyAssign; ///< Under delayed assignment - int m_instrCount; ///< Number of nodes - int m_dataCount; ///< Bytes of data - AstJumpGo* m_jumpp; ///< Jump label we're branching from + string m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize + AstNode* m_whyNotNodep; ///< First node not optimizable + bool m_anyAssignDly; ///< True if found a delayed assignment + bool m_anyAssignComb; ///< True if found a non-delayed assignment + bool m_inDlyAssign; ///< Under delayed assignment + int m_instrCount; ///< Number of nodes + int m_dataCount; ///< Bytes of data + AstJumpGo* m_jumpp; ///< Jump label we're branching from // Simulating: - ConstPile m_constFreeps; ///< List of all AstConst* free and not in use - ConstPile m_constAllps; ///< List of all AstConst* free and in use + ConstPile m_constFreeps; ///< List of all AstConst* free and not in use + ConstPile m_constAllps; ///< List of all AstConst* free and in use std::deque m_callStack; ///< Call stack for verbose error messages // Cleanup @@ -116,35 +116,35 @@ private: // Potentially very slow, intended for debugging string prettyNumber(const V3Number* nump, AstNodeDType* dtypep) { - if (AstRefDType* refdtypep = VN_CAST(dtypep, RefDType)) { + if (AstRefDType* refdtypep = VN_CAST(dtypep, RefDType)) { // dtypep = refdtypep->skipRefp(); } if (AstStructDType* stp = VN_CAST(dtypep, StructDType)) { if (stp->packed()) { std::ostringstream out; - out<<"'{"; - for (AstMemberDType* itemp = stp->membersp(); - itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) { + out << "'{"; + for (AstMemberDType* itemp = stp->membersp(); itemp; + itemp = VN_CAST(itemp->nextp(), MemberDType)) { int width = itemp->width(); int lsb = itemp->lsb(); int msb = lsb + width - 1; V3Number fieldNum(nump, width); fieldNum.opSel(*nump, msb, lsb); - out<name()<<": "; + out << itemp->name() << ": "; if (AstNodeDType* childTypep = itemp->subDTypep()) { - out<nextp()) out<<", "; + if (itemp->nextp()) out << ", "; } - out<<"}"; + out << "}"; return out.str(); } } else if (AstPackArrayDType* arrayp = VN_CAST(dtypep, PackArrayDType)) { if (AstNodeDType* childTypep = arrayp->subDTypep()) { std::ostringstream out; - out<<"["; + out << "["; int arrayElements = arrayp->elementsConst(); for (int element = 0; element < arrayElements; ++element) { int width = childTypep->width(); @@ -153,10 +153,10 @@ private: V3Number fieldNum(nump, width); fieldNum.opSel(*nump, msb, lsb); int arrayElem = arrayp->lsb() + element; - out<= 5) { - UINFO(0, "Clear optimizable: "<::iterator it = m_callStack.begin(); it != m_callStack.end(); ++it) { AstFuncRef* funcp = (*it)->m_funcp; - stack<<"\n "<fileline() - <<"... Called from " - <prettyName()<<"() with parameters:"; + stack << "\n " << funcp->fileline() << "... Called from " + << funcp->prettyName() << "() with parameters:"; V3TaskConnects* tconnects = (*it)->m_tconnects; for (V3TaskConnects::iterator conIt = tconnects->begin(); conIt != tconnects->end(); ++conIt) { AstVar* portp = conIt->first; AstNode* pinp = conIt->second->exprp(); AstNodeDType* dtypep = pinp->dtypep(); - stack<<"\n "<prettyName( - )<<" = "<num(), dtypep); + stack << "\n " << portp->prettyName() << " = " + << prettyNumber(&fetchConst(pinp)->num(), dtypep); } } m_whyNotOptimizable += stack.str(); @@ -216,11 +215,12 @@ private: AstConst* constp; AstNodeDType* dtypep = nodep->dtypep(); if (!m_constFreeps[dtypep].empty()) { - //UINFO(7, "Num Reuse "<width()<width() << endl); + constp = m_constFreeps[dtypep].back(); + m_constFreeps[dtypep].pop_back(); constp->num().nodep(nodep); } else { - //UINFO(7, "Num New "<width()<width() << endl); constp = new AstConst(nodep->fileline(), AstConst::DtypedValue(), nodep->dtypep(), 0); m_constAllps[constp->dtypep()].push_back(constp); } @@ -228,6 +228,7 @@ private: constp->num().isString(nodep->isString()); return constp; } + public: void newValue(AstNode* nodep, const AstNode* valuep) { if (const AstConst* constp = VN_CAST_CONST(valuep, Const)) { @@ -245,6 +246,7 @@ public: setOutValue(nodep, newTrackedClone(const_cast(valuep))); } } + private: AstNode* newTrackedClone(AstNode* nodep) { AstNode* newp = nodep->cloneTree(false); @@ -271,30 +273,26 @@ private: return fetchOutConst(nodep); } } + public: - AstNode* fetchValueNull(AstNode* nodep) { - return nodep->user3p(); - } + AstNode* fetchValueNull(AstNode* nodep) { return nodep->user3p(); } + private: - AstNode* fetchOutValueNull(AstNode* nodep) { - return nodep->user2p(); - } - AstConst* fetchConstNull(AstNode* nodep) { - return VN_CAST(fetchValueNull(nodep), Const); - } + AstNode* fetchOutValueNull(AstNode* nodep) { return nodep->user2p(); } + AstConst* fetchConstNull(AstNode* nodep) { return VN_CAST(fetchValueNull(nodep), Const); } AstConst* fetchOutConstNull(AstNode* nodep) { return VN_CAST(fetchOutValueNull(nodep), Const); } AstNode* fetchValue(AstNode* nodep) { AstNode* valuep = fetchValueNull(nodep); UASSERT_OBJ(valuep, nodep, "No value found for node."); - //UINFO(9, " fetch val "<<*valuep<<" on "<num(); return NULL; } + private: void setValue(AstNode* nodep, const AstNode* valuep) { UASSERT_OBJ(valuep, nodep, "Simulate setting null value"); - UINFO(9, " set val "<name()<<" on "<name() << " on " << nodep << endl); nodep->user3p((void*)valuep); } void setOutValue(AstNode* nodep, const AstNode* valuep) { UASSERT_OBJ(valuep, nodep, "Simulate setting null value"); - UINFO(9, " set oval "<name()<<" on "<name() << " on " << nodep << endl); nodep->user2p((void*)valuep); } @@ -331,7 +331,7 @@ private: m_dataCount += nodep->width(); } if (!nodep->isPredictOptimizable()) { - //UINFO(9, " !predictopt "<prettyTypeName()<prettyTypeName() << endl); #endif } } AstNode* varOrScope(AstVarRef* nodep) { AstNode* vscp; - if (m_scoped) vscp = nodep->varScopep(); - else vscp = nodep->varp(); + if (m_scoped) { + vscp = nodep->varScopep(); + } else { + vscp = nodep->varp(); + } UASSERT_OBJ(vscp, nodep, "Not linked"); return vscp; } @@ -420,10 +424,9 @@ private: vscp->user1(vscp->user1() | VU_RV); bool isConst = nodep->varp()->isParam() && nodep->varp()->valuep(); AstNode* valuep = isConst ? fetchValueNull(nodep->varp()->valuep()) : NULL; - if (isConst && valuep) { // Propagate PARAM constants for constant function analysis - if (!m_checkOnly && optimizable()) { - newValue(vscp, valuep); - } + if (isConst + && valuep) { // Propagate PARAM constants for constant function analysis + if (!m_checkOnly && optimizable()) newValue(vscp, valuep); } else { if (m_checkOnly) varRefCb(nodep); } @@ -437,9 +440,11 @@ private: AstNode* valuep = fetchValueNull(vscp); if (!valuep) { if (m_params) { - clearOptimizable(nodep, "Language violation: reference to non-function-local variable"); + clearOptimizable( + nodep, "Language violation: reference to non-function-local variable"); } else { - nodep->v3fatalSrc("Variable value should have been set before any visitor called."); + nodep->v3fatalSrc( + "Variable value should have been set before any visitor called."); } valuep = allocConst(nodep); // Any value; just so recover from error } @@ -449,12 +454,20 @@ private: } virtual void visit(AstVarXRef* nodep) VL_OVERRIDE { if (jumpingOver(nodep)) return; - if (m_scoped) { badNodeType(nodep); return; } - else { clearOptimizable(nodep, "Language violation: Dotted hierarchical references not allowed in constant functions"); } + if (m_scoped) { + badNodeType(nodep); + return; + } else { + clearOptimizable(nodep, "Language violation: Dotted hierarchical references not " + "allowed in constant functions"); + } } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { if (jumpingOver(nodep)) return; - if (!m_params) { badNodeType(nodep); return; } + if (!m_params) { + badNodeType(nodep); + return; + } if (nodep->dpiImport()) { clearOptimizable(nodep, "DPI import functions aren't simulatable"); } @@ -463,7 +476,7 @@ private: } virtual void visit(AstNodeIf* nodep) VL_OVERRIDE { if (jumpingOver(nodep)) return; - UINFO(5, " IF "<itemp()->valuep(); if (valuep) { iterateAndNextNull(valuep); - if (optimizable()) { - newValue(nodep, fetchValue(valuep)); - } + if (optimizable()) newValue(nodep, fetchValue(valuep)); } else { clearOptimizable(nodep, "No value found for enum item"); } @@ -510,8 +517,7 @@ private: checkNodeInfo(nodep); iterateChildren(nodep); if (!m_checkOnly && optimizable()) { - nodep->numberOperate(newConst(nodep)->num(), - fetchConst(nodep->lhsp())->num()); + nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num()); } } virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE { @@ -519,8 +525,7 @@ private: checkNodeInfo(nodep); iterateChildren(nodep); if (!m_checkOnly && optimizable()) { - nodep->numberOperate(newConst(nodep)->num(), - fetchConst(nodep->lhsp())->num(), + nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(), fetchConst(nodep->rhsp())->num()); } } @@ -529,8 +534,7 @@ private: checkNodeInfo(nodep); iterateChildren(nodep); if (!m_checkOnly && optimizable()) { - nodep->numberOperate(newConst(nodep)->num(), - fetchConst(nodep->lhsp())->num(), + nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(), fetchConst(nodep->rhsp())->num(), fetchConst(nodep->thsp())->num()); } @@ -652,7 +656,7 @@ private: } uint32_t index = fetchConst(selp->bitp())->toUInt(); AstNode* valuep = newTrackedClone(fetchValue(nodep->rhsp())); - UINFO(9, " set val["<addIndexValuep(index, valuep); @@ -664,7 +668,7 @@ private: AstVarRef* varrefp = NULL; V3Number lsb(nodep); iterateAndNextNull(nodep->rhsp()); // Value to assign - handleAssignSelRecurse(nodep, selp, varrefp/*ref*/, lsb/*ref*/, 0); + handleAssignSelRecurse(nodep, selp, varrefp /*ref*/, lsb /*ref*/, 0); if (!m_checkOnly && optimizable()) { UASSERT_OBJ(varrefp, nodep, "Indicated optimizable, but no variable found on RHS of select"); @@ -683,15 +687,12 @@ private: outconstp->num().setAllBitsX(); } } - outconstp->num().opSelInto(fetchConst(nodep->rhsp())->num(), - lsb, - selp->widthConst()); + outconstp->num().opSelInto(fetchConst(nodep->rhsp())->num(), lsb, selp->widthConst()); assignOutValue(nodep, vscp, outconstp); } } - void handleAssignSelRecurse(AstNodeAssign* nodep, AstSel* selp, - AstVarRef*& outVarrefpRef, V3Number& lsbRef, - int depth) { + void handleAssignSelRecurse(AstNodeAssign* nodep, AstSel* selp, AstVarRef*& outVarrefpRef, + V3Number& lsbRef, int depth) { // Recurse down to find final variable being set (outVarrefp), with // lsb to be eventually set on lsbRef checkNodeInfo(selp); @@ -702,7 +703,7 @@ private: return; // And presumably still optimizable() } else if (AstSel* subselp = VN_CAST(selp->lhsp(), Sel)) { V3Number sublsb(nodep); - handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb/*ref*/, depth+1); + handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb /*ref*/, depth + 1); if (optimizable()) { lsbRef = sublsb; lsbRef.opAdd(sublsb, fetchConst(selp->lsbp())->num()); @@ -725,20 +726,22 @@ private: } if (AstSel* selp = VN_CAST(nodep->lhsp(), Sel)) { - if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; } + if (!m_params) { + clearOptimizable(nodep, "LHS has select"); + return; + } handleAssignSel(nodep, selp); - } - else if (AstArraySel* selp = VN_CAST(nodep->lhsp(), ArraySel)) { - if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; } + } else if (AstArraySel* selp = VN_CAST(nodep->lhsp(), ArraySel)) { + if (!m_params) { + clearOptimizable(nodep, "LHS has select"); + return; + } handleAssignArray(nodep, selp); - } - else if (!VN_IS(nodep->lhsp(), VarRef)) { + } else if (!VN_IS(nodep->lhsp(), VarRef)) { clearOptimizable(nodep, "LHS isn't simple variable"); - } - else if (m_checkOnly) { + } else if (m_checkOnly) { iterateChildren(nodep); - } - else if (optimizable()) { + } else if (optimizable()) { iterateAndNextNull(nodep->rhsp()); if (optimizable()) { AstNode* vscp = varOrScope(VN_CAST(nodep->lhsp(), VarRef)); @@ -756,7 +759,7 @@ private: AstNode* itemp = initp->getIndexDefaultedValuep(offset); if (!itemp) { clearOptimizable(nodep, "Array initialization has too few elements, need element " - +cvtToStr(offset)); + + cvtToStr(offset)); } else { setValue(nodep, itemp); } @@ -770,15 +773,15 @@ private: } virtual void visit(AstNodeCase* nodep) VL_OVERRIDE { if (jumpingOver(nodep)) return; - UINFO(5, " CASE "<exprp()); bool hit = false; - for (AstCaseItem* itemp = nodep->itemsp(); - itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { if (!itemp->isDefault()) { for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) { if (hit) break; @@ -795,8 +798,8 @@ private: } } // Else default match - for (AstCaseItem* itemp = nodep->itemsp(); - itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { if (hit) break; if (!hit && itemp->isDefault()) { iterateAndNextNull(itemp->bodysp()); @@ -819,7 +822,7 @@ private: if (jumpingOver(nodep)) return; checkNodeInfo(nodep); if (!m_checkOnly) { - UINFO(5, " JUMP GO "<labelp() == nodep) { - UINFO(5, " JUMP DONE "<initsp()); while (true) { - UINFO(5, " FOR-ITER "<condp()); if (!optimizable()) break; - if (!fetchConst(nodep->condp())->num().isNeqZero()) { + if (!fetchConst(nodep->condp())->num().isNeqZero()) { // break; } iterateAndNextNull(nodep->bodysp()); iterateAndNextNull(nodep->incsp()); - if (loops++ > unrollCount()*16) { + if (loops++ > unrollCount() * 16) { clearOptimizable(nodep, "Loop unrolling took too long; probably this is an" - "infinite loop, or set --unroll-count above " - + cvtToStr(unrollCount())); + "infinite loop, or set --unroll-count above " + + cvtToStr(unrollCount())); break; } } @@ -873,21 +881,24 @@ private: virtual void visit(AstWhile* nodep) VL_OVERRIDE { // Doing lots of Whiles is slow, so only for parameters if (jumpingOver(nodep)) return; - UINFO(5, " WHILE "<precondsp()); if (jumpingOver(nodep)) break; iterateAndNextNull(nodep->condp()); if (jumpingOver(nodep)) break; if (!optimizable()) break; - if (!fetchConst(nodep->condp())->num().isNeqZero()) { + if (!fetchConst(nodep->condp())->num().isNeqZero()) { // break; } iterateAndNextNull(nodep->bodysp()); @@ -896,9 +907,11 @@ private: if (jumpingOver(nodep)) break; // Prep for next loop - if (loops++ > unrollCount()*16) { - clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite" - " loop, or set --unroll-count above "+cvtToStr(unrollCount())); + if (loops++ > unrollCount() * 16) { + clearOptimizable(nodep, + "Loop unrolling took too long; probably this is an infinite" + " loop, or set --unroll-count above " + + cvtToStr(unrollCount())); break; } } @@ -908,12 +921,17 @@ private: virtual void visit(AstFuncRef* nodep) VL_OVERRIDE { if (jumpingOver(nodep)) return; if (!optimizable()) return; // Accelerate - UINFO(5, " FUNCREF "<taskp(), NodeFTask); UASSERT_OBJ(funcp, nodep, "Not linked"); - if (m_params) { V3Width::widthParamsEdit(funcp); } VL_DANGLING(funcp); // Make sure we've sized the function - funcp = VN_CAST(nodep->taskp(), NodeFTask); UASSERT_OBJ(funcp, nodep, "Not linked"); + if (m_params) V3Width::widthParamsEdit(funcp); + VL_DANGLING(funcp); // Make sure we've sized the function + funcp = VN_CAST(nodep->taskp(), NodeFTask); + UASSERT_OBJ(funcp, nodep, "Not linked"); // Apply function call values to function V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); // Must do this in two steps, eval all params, then apply them @@ -923,7 +941,9 @@ private: AstNode* pinp = it->second->exprp(); if (pinp) { // Else too few arguments in function call - ignore it if (portp->isWritable()) { - clearOptimizable(portp, "Language violation: Outputs/refs not allowed in constant functions"); + clearOptimizable( + portp, + "Language violation: Outputs/refs not allowed in constant functions"); return; } // Evaluate pin value @@ -935,9 +955,7 @@ private: AstNode* pinp = it->second->exprp(); if (pinp) { // Else too few arguments in function call - ignore it // Apply value to the function - if (!m_checkOnly && optimizable()) { - newValue(portp, fetchValue(pinp)); - } + if (!m_checkOnly && optimizable()) newValue(portp, fetchValue(pinp)); } } SimStackNode stackNode(nodep, &tconnects); @@ -954,7 +972,10 @@ private: virtual void visit(AstVar* nodep) VL_OVERRIDE { if (jumpingOver(nodep)) return; - if (!m_params) { badNodeType(nodep); return; } + if (!m_params) { + badNodeType(nodep); + return; + } } virtual void visit(AstScopeName* nodep) VL_OVERRIDE { @@ -986,7 +1007,8 @@ private: nextArgp = nextArgp->nextp(); AstConst* constp = fetchConstNull(argp); if (!constp) { - clearOptimizable(nodep, "Argument for $display like statement is not constant"); + clearOptimizable( + nodep, "Argument for $display like statement is not constant"); break; } string pformat = string("%") + pos[0]; @@ -1051,6 +1073,7 @@ private: iterate(nodep); UASSERT_OBJ(!m_jumpp, m_jumpp, "JumpGo branched to label that wasn't found"); } + public: // CONSTRUCTORS SimulateVisitor() { @@ -1076,26 +1099,24 @@ public: m_constFreeps = m_constAllps; } void mainTableCheck(AstNode* nodep) { - setMode(true/*scoped*/, true/*checking*/, false/*params*/); + setMode(true /*scoped*/, true /*checking*/, false /*params*/); mainGuts(nodep); } void mainTableEmulate(AstNode* nodep) { - setMode(true/*scoped*/, false/*checking*/, false/*params*/); + setMode(true /*scoped*/, false /*checking*/, false /*params*/); mainGuts(nodep); } void mainCheckTree(AstNode* nodep) { - setMode(false/*scoped*/, true/*checking*/, false/*params*/); + setMode(false /*scoped*/, true /*checking*/, false /*params*/); mainGuts(nodep); } void mainParamEmulate(AstNode* nodep) { - setMode(false/*scoped*/, false/*checking*/, true/*params*/); + setMode(false /*scoped*/, false /*checking*/, true /*params*/); mainGuts(nodep); } virtual ~SimulateVisitor() { - for (ConstPile::iterator it = m_constAllps.begin(); - it != m_constAllps.end(); ++it) { - for (ConstDeque::iterator it2 = it->second.begin(); - it2 != it->second.end(); ++it2) { + for (ConstPile::iterator it = m_constAllps.begin(); it != m_constAllps.end(); ++it) { + for (ConstDeque::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) { delete (*it2); } } diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 87fab6817..c77a28bef 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -52,11 +52,11 @@ class SliceVisitor : public AstNVisitor { // AstNodeAssign::user1() -> bool. True if find is complete // AstNodeUniop::user1() -> bool. True if find is complete // AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE - AstNode* m_assignp; // Assignment we are under - bool m_assignError; // True if the current assign already has an error + AstNode* m_assignp; // Assignment we are under + bool m_assignError; // True if the current assign already has an error // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -66,54 +66,59 @@ class SliceVisitor : public AstNVisitor { AstUnpackArrayDType* arrayp = VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType); if (!arrayp) { // V3Width should have complained, but... if (!m_assignError) { - nodep->v3error(nodep->prettyTypeName() - <<" is not an unpacked array, but is in an unpacked array context"); + nodep->v3error( + nodep->prettyTypeName() + << " is not an unpacked array, but is in an unpacked array context"); } m_assignError = true; return nodep->cloneTree(false); // Likely will cause downstream errors } if (arrayp->rangep()->elementsConst() != elements) { - if (!m_assignError) nodep->v3error("Slices of arrays in assignments have different unpacked dimensions, " - <rangep()->elementsConst()); + if (!m_assignError) { + nodep->v3error( + "Slices of arrays in assignments have different unpacked dimensions, " + << elements << " versus " << arrayp->rangep()->elementsConst()); + } m_assignError = true; - elements = 1; offset = 0; + elements = 1; + offset = 0; } AstNode* newp; if (AstInitArray* initp = VN_CAST(nodep, InitArray)) { - UINFO(9," cloneInitArray("<rangep()->littleEndian() - ? arrayp->rangep()->elementsConst()-1-offset : offset; + ? arrayp->rangep()->elementsConst() - 1 - offset + : offset; AstNode* itemp = initp->getIndexDefaultedValuep(leOffset); if (!itemp) { - nodep->v3error("Array initialization has too few elements, need element "<v3error("Array initialization has too few elements, need element " + << offset); itemp = initp->initsp(); } newp = itemp->cloneTree(false); - } - else if (AstNodeCond* snodep = VN_CAST(nodep, NodeCond)) { - UINFO(9," cloneCond("<cloneType(snodep->condp()->cloneTree(false), cloneAndSel(snodep->expr1p(), elements, offset), cloneAndSel(snodep->expr2p(), elements, offset)); - } - else if (AstSliceSel* snodep = VN_CAST(nodep, SliceSel)) { - UINFO(9," cloneSliceSel("<declRange().lo() + (!snodep->declRange().littleEndian() - ? snodep->declRange().elements()-1-offset : offset)); + ? snodep->declRange().elements() - 1 - offset + : offset)); newp = new AstArraySel(nodep->fileline(), snodep->fromp()->cloneTree(false), leOffset); - } - else if (VN_IS(nodep, ArraySel) - || VN_IS(nodep, NodeVarRef) - || VN_IS(nodep, NodeSel)) { - UINFO(9," cloneSel("<rangep()->littleEndian() - ? arrayp->rangep()->elementsConst()-1-offset : offset; + ? arrayp->rangep()->elementsConst() - 1 - offset + : offset; newp = new AstArraySel(nodep->fileline(), nodep->cloneTree(false), leOffset); - } - else { - if (!m_assignError) nodep->v3error(nodep->prettyTypeName()<<" unexpected in assignment to unpacked array"); + } else { + if (!m_assignError) { + nodep->v3error(nodep->prettyTypeName() + << " unexpected in assignment to unpacked array"); + } m_assignError = true; newp = nodep->cloneTree(false); // Likely will cause downstream errors } @@ -122,11 +127,13 @@ class SliceVisitor : public AstNVisitor { virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { // Called recursively on newly created assignments - if (!nodep->user1() - && !VN_IS(nodep, AssignAlias)) { + if (!nodep->user1() && !VN_IS(nodep, AssignAlias)) { nodep->user1(true); m_assignError = false; - if (debug()>=9) { cout<dumpTree(cout, " Deslice-In: "); } + if (debug() >= 9) { + cout << endl; + nodep->dumpTree(cout, " Deslice-In: "); + } AstNodeDType* dtp = nodep->lhsp()->dtypep()->skipRefp(); if (AstUnpackArrayDType* arrayp = VN_CAST(dtp, UnpackArrayDType)) { // Left and right could have different msb/lsbs/endianness, but #elements is common @@ -136,13 +143,17 @@ class SliceVisitor : public AstNVisitor { int elements = arrayp->rangep()->elementsConst(); for (int offset = 0; offset < elements; ++offset) { AstNode* newp = nodep->cloneType // AstNodeAssign - (cloneAndSel(nodep->lhsp(), elements, offset), - cloneAndSel(nodep->rhsp(), elements, offset)); - if (debug()>=9) { newp->dumpTree(cout, "-new "); } + (cloneAndSel(nodep->lhsp(), elements, offset), + cloneAndSel(nodep->rhsp(), elements, offset)); + if (debug() >= 9) { newp->dumpTree(cout, "-new "); } newlistp = AstNode::addNextNull(newlistp, newp); } - if (debug()>=9) { cout<dumpTree(cout, " Deslice-Dn: "); } - nodep->replaceWith(newlistp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + if (debug() >= 9) { + cout << endl; + nodep->dumpTree(cout, " Deslice-Dn: "); + } + nodep->replaceWith(newlistp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); // Normal edit iterator will now iterate on all of the expansion assignments // This will potentially call this function again to resolve next level of slicing return; @@ -154,8 +165,7 @@ class SliceVisitor : public AstNVisitor { } virtual void visit(AstInitArray* nodep) VL_OVERRIDE { - UASSERT_OBJ(!m_assignp, nodep, - "Array initialization should have been removed earlier"); + UASSERT_OBJ(!m_assignp, nodep, "Array initialization should have been removed earlier"); } void expandBiOp(AstNodeBiop* nodep) { @@ -163,30 +173,31 @@ class SliceVisitor : public AstNVisitor { nodep->user1(true); // If it's an unpacked array, blow it up into comparing each element AstNodeDType* fromDtp = nodep->lhsp()->dtypep()->skipRefp(); - UINFO(9, " Bi-Eq/Neq expansion "<lhsp()->dtypep()->skipRefp(), NodeArrayDType)) { - nodep->lhsp()->v3error("Slice operator "<lhsp()->prettyTypeName() - <<" on non-slicable (e.g. non-vector) left-hand-side operand"); - } - else if (!VN_IS(nodep->rhsp()->dtypep()->skipRefp(), NodeArrayDType)) { - nodep->rhsp()->v3error("Slice operator "<rhsp()->prettyTypeName() - <<" on non-slicable (e.g. non-vector) right-hand-side operand"); - } - else { + nodep->lhsp()->v3error( + "Slice operator " + << nodep->lhsp()->prettyTypeName() + << " on non-slicable (e.g. non-vector) left-hand-side operand"); + } else if (!VN_IS(nodep->rhsp()->dtypep()->skipRefp(), NodeArrayDType)) { + nodep->rhsp()->v3error( + "Slice operator " + << nodep->rhsp()->prettyTypeName() + << " on non-slicable (e.g. non-vector) right-hand-side operand"); + } else { for (int index = 0; index < adtypep->rangep()->elementsConst(); ++index) { // EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1]) AstNodeBiop* clonep - = VN_CAST(nodep->cloneType - (new AstArraySel(nodep->fileline(), - nodep->lhsp()->cloneTree(false), - index), - new AstArraySel(nodep->fileline(), - nodep->rhsp()->cloneTree(false), - index)), + = VN_CAST(nodep->cloneType( + new AstArraySel(nodep->fileline(), + nodep->lhsp()->cloneTree(false), index), + new AstArraySel(nodep->fileline(), + nodep->rhsp()->cloneTree(false), index)), NodeBiop); - if (!logp) logp = clonep; + if (!logp) + logp = clonep; else { switch (nodep->type()) { case AstType::atEq: // FALLTHRU @@ -212,18 +223,10 @@ class SliceVisitor : public AstNVisitor { iterateChildren(nodep); } } - virtual void visit(AstEq* nodep) VL_OVERRIDE { - expandBiOp(nodep); - } - virtual void visit(AstNeq* nodep) VL_OVERRIDE { - expandBiOp(nodep); - } - virtual void visit(AstEqCase* nodep) VL_OVERRIDE { - expandBiOp(nodep); - } - virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { - expandBiOp(nodep); - } + virtual void visit(AstEq* nodep) VL_OVERRIDE { expandBiOp(nodep); } + virtual void visit(AstNeq* nodep) VL_OVERRIDE { expandBiOp(nodep); } + virtual void visit(AstEqCase* nodep) VL_OVERRIDE { expandBiOp(nodep); } + virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { expandBiOp(nodep); } virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } @@ -241,9 +244,7 @@ public: // Link class functions void V3Slice::sliceAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Split.cpp b/src/V3Split.cpp index cbfba4dee..6e69257d3 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -97,18 +97,19 @@ // Support classes class SplitNodeVertex : public V3GraphVertex { - AstNode* m_nodep; + AstNode* m_nodep; + protected: SplitNodeVertex(V3Graph* graphp, AstNode* nodep) - : V3GraphVertex(graphp), m_nodep(nodep) {} + : V3GraphVertex(graphp) + , m_nodep(nodep) {} virtual ~SplitNodeVertex() {} // ACCESSORS // Do not make accessor for nodep(), It may change due to // reordering a lower block, but we don't repair it - virtual string name() const { - return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName(); - } + virtual string name() const { return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName(); } virtual FileLine* fileline() const { return nodep()->fileline(); } + public: virtual AstNode* nodep() const { return m_nodep; } }; @@ -143,7 +144,7 @@ public: SplitVarPostVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex(graphp, nodep) {} virtual ~SplitVarPostVertex() {} - virtual string name() const { return string("POST ")+SplitNodeVertex::name(); } + virtual string name() const { return string("POST ") + SplitNodeVertex::name(); } virtual string dotColor() const { return "CadetBlue"; } }; @@ -155,11 +156,12 @@ class SplitEdge : public V3GraphEdge { static uint32_t s_stepNum; // Global step number protected: enum { WEIGHT_NORMAL = 10 }; - SplitEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, - int weight, bool cutable=CUTABLE) + SplitEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, + bool cutable = CUTABLE) : V3GraphEdge(graphp, fromp, top, weight, cutable) , m_ignoreInStep(0) {} virtual ~SplitEdge() {} + public: // Iterator for graph functions static void incrementStep() { ++s_stepNum; } @@ -181,7 +183,7 @@ public: return ignoreThisStep() ? "dotted" : V3GraphEdge::dotStyle(); } }; -uint32_t SplitEdge::s_stepNum = 0; +uint32_t SplitEdge::s_stepNum = 0; class SplitPostEdge : public SplitEdge { public: @@ -240,28 +242,26 @@ private: // AstVarScope::user2p -> Var SplitNodeVertex* for delayed assignment var, 0=not set yet // Ast*::user3p -> Statement SplitLogicVertex* (temporary only) // Ast*::user4 -> Current ordering number (reorderBlock usage) - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser3InUse m_inuser3; - AstUser4InUse m_inuser4; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; + AstUser3InUse m_inuser3; + AstUser4InUse m_inuser4; protected: // TYPES typedef std::vector VStack; // STATE - string m_noReorderWhy; // Reason we can't reorder - VStack m_stmtStackps; // Current statements being tracked - SplitPliVertex* m_pliVertexp; // Element specifying PLI ordering - V3Graph m_graph; // Scoreboard of var usages/dependencies - bool m_inDly; // Inside ASSIGNDLY - VDouble0 m_statSplits; // Statistic tracking + string m_noReorderWhy; // Reason we can't reorder + VStack m_stmtStackps; // Current statements being tracked + SplitPliVertex* m_pliVertexp; // Element specifying PLI ordering + V3Graph m_graph; // Scoreboard of var usages/dependencies + bool m_inDly; // Inside ASSIGNDLY + VDouble0 m_statSplits; // Statistic tracking // CONSTRUCTORS public: - SplitReorderBaseVisitor() { - scoreboardClear(); - } + SplitReorderBaseVisitor() { scoreboardClear(); } virtual ~SplitReorderBaseVisitor() { V3Stats::addStat("Optimizations, Split always", m_statSplits); } @@ -271,7 +271,7 @@ protected: VL_DEBUG_FUNC; // Declare debug() void scoreboardClear() { - //VV***** We reset user1p() and user2p on each block!!! + // VV***** We reset user1p() and user2p on each block!!! m_inDly = false; m_graph.clear(); m_stmtStackps.clear(); @@ -298,14 +298,14 @@ private: } } void scoreboardPushStmt(AstNode* nodep) { - //UINFO(9," push "<user3p(), nodep, "user3p should not be used; cleared in processBlock"); nodep->user3p(vertexp); } void scoreboardPopStmt() { - //UINFO(9," pop"<nextp()) { + for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) { scoreboardPushStmt(nextp); iterate(nextp); scoreboardPopStmt(); @@ -321,17 +321,15 @@ protected: } void pruneDepsOnInputs() { - for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { - if (!vertexp->outBeginp() - && dynamic_cast(vertexp)) { + for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { + if (!vertexp->outBeginp() && dynamic_cast(vertexp)) { if (debug() >= 9) { SplitVarStdVertex* stdp = static_cast(vertexp); - UINFO(0, "Will prune deps on var "<nodep()<nodep() << endl); stdp->nodep()->dumpTree(cout, "- "); } - for (V3GraphEdge* edgep = vertexp->inBeginp(); - edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { SplitEdge* oedgep = dynamic_cast(edgep); oedgep->setIgnoreThisStep(); } @@ -350,7 +348,7 @@ protected: virtual void visit(AstAssignDly* nodep) VL_OVERRIDE { m_inDly = true; - UINFO(4," ASSIGNDLY "<lvalue()) { - UINFO(4," VARREFDLY: "<user2p()) { SplitVarPostVertex* vpostp = new SplitVarPostVertex(&m_graph, vscp); @@ -396,21 +394,21 @@ protected: SplitVarPostVertex* vpostp = reinterpret_cast(vscp->user2p()); // Add edges - for (VStack::iterator it = m_stmtStackps.begin(); - it != m_stmtStackps.end(); ++it) { + for (VStack::iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); + ++it) { new SplitLVEdge(&m_graph, vpostp, *it); } } else { // Nondelayed assignment if (nodep->lvalue()) { // Non-delay; need to maintain existing ordering // with all consumers of the signal - UINFO(4," VARREFLV: "<isPure()) { - UINFO(9," NotSplittable "<=9) { + if (debug() >= 9) { m_graph.dumpDotFilePrefixed("reorderg_nodup", false); - //m_graph.dump(); cout<nextp()) { + for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) { SplitLogicVertex* vvertexp = reinterpret_cast(nextp->user3p()); vvertexp->user(true); } @@ -484,16 +480,17 @@ protected: // For reordering this single block only, mark all logic // vertexes not involved with this step as unimportant - for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { if (SplitLogicVertex* vvertexp = dynamic_cast(vertexp)) { if (!vvertexp->user()) { - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; + edgep = edgep->inNextp()) { SplitEdge* oedgep = dynamic_cast(edgep); oedgep->setIgnoreThisStep(); } - for (V3GraphEdge* edgep = vertexp->outBeginp(); - edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; + edgep = edgep->outNextp()) { SplitEdge* oedgep = dynamic_cast(edgep); oedgep->setIgnoreThisStep(); } @@ -507,7 +504,7 @@ protected: // Add hard orderings between all nodes of same color, in the order they appeared vl_unordered_map lastOfColor; - for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) { + for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) { SplitLogicVertex* vvertexp = reinterpret_cast(nextp->user3p()); uint32_t color = vvertexp->color(); UASSERT_OBJ(color, nextp, "No node color assigned"); @@ -520,20 +517,20 @@ protected: // And a real ordering to get the statements into something reasonable // We don't care if there's cutable violations here... // Non-cutable violations should be impossible; as those edges are program-order - if (debug()>=9) m_graph.dumpDotFilePrefixed(string("splitg_preo"), false); + if (debug() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_preo"), false); m_graph.acyclic(&SplitEdge::followCyclic); m_graph.rank(&SplitEdge::followCyclic); // Or order(), but that's more expensive - if (debug()>=9) m_graph.dumpDotFilePrefixed(string("splitg_opt"), false); + if (debug() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_opt"), false); } void reorderBlock(AstNode* nodep) { // Reorder statements in the completed graph // Map the rank numbers into nodes they associate with - typedef std::multimap RankNodeMap; + typedef std::multimap RankNodeMap; RankNodeMap rankMap; int currOrder = 0; // Existing sequence number of assignment - for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) { + for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) { SplitLogicVertex* vvertexp = reinterpret_cast(nextp->user3p()); rankMap.insert(make_pair(vvertexp->rank(), nextp)); nextp->user4(++currOrder); // Record current ordering @@ -542,23 +539,28 @@ protected: // Is the current ordering OK? bool leaveAlone = true; int newOrder = 0; // New sequence number of assignment - for (RankNodeMap::const_iterator it = rankMap.begin(); - it != rankMap.end(); ++it) { + for (RankNodeMap::const_iterator it = rankMap.begin(); it != rankMap.end(); ++it) { AstNode* nextp = it->second; if (++newOrder != nextp->user4()) leaveAlone = false; } if (leaveAlone) { - UINFO(6," No changes\n"); + UINFO(6, " No changes\n"); } else { AstNRelinker replaceHandle; // Where to add the list AstNode* newListp = NULL; for (RankNodeMap::const_iterator it = rankMap.begin(); it != rankMap.end(); ++it) { AstNode* nextp = it->second; - UINFO(6, " New order: "<unlinkFrBack(&replaceHandle); - else nextp->unlinkFrBack(); - if (newListp) newListp = newListp->addNext(nextp); - else newListp = nextp; + UINFO(6, " New order: " << nextp << endl); + if (nextp == nodep) { + nodep->unlinkFrBack(&replaceHandle); + } else { + nextp->unlinkFrBack(); + } + if (newListp) { + newListp = newListp->addNext(nextp); + } else { + newListp = nextp; + } } replaceHandle.relink(newListp); } @@ -579,19 +581,19 @@ protected: // Just one, so can't reorder. Just look for more blocks/statements. iterate(nodep); } else { - UINFO(9," processBlock "<backp()->nextp()==firstp) firstp = firstp->backp(); - for (AstNode* nextp=firstp; nextp; nextp=nextp->nextp()) { + while (firstp->backp()->nextp() == firstp) firstp = firstp->backp(); + for (AstNode* nextp = firstp; nextp; nextp = nextp->nextp()) { SplitLogicVertex* vvertexp = reinterpret_cast(nextp->user3p()); vvertexp->unlinkDelete(&m_graph); @@ -603,19 +605,20 @@ protected: } virtual void visit(AstAlways* nodep) VL_OVERRIDE { - UINFO(4," ALW "<=9) nodep->dumpTree(cout, " alwIn:: "); + UINFO(4, " ALW " << nodep << endl); + if (debug() >= 9) nodep->dumpTree(cout, " alwIn:: "); scoreboardClear(); processBlock(nodep->bodysp()); - if (debug()>=9) nodep->dumpTree(cout, " alwOut: "); + if (debug() >= 9) nodep->dumpTree(cout, " alwOut: "); } virtual void visit(AstNodeIf* nodep) VL_OVERRIDE { - UINFO(4," IF "<condp()); processBlock(nodep->ifsp()); processBlock(nodep->elsesp()); } + private: VL_UNCOPYABLE(ReorderVisitor); }; @@ -638,9 +641,7 @@ class IfColorVisitor : public AstNVisitor { public: // Visit through *nodep and map each AstNodeIf within to the set of // colors it will participate in. Also find the whole set of colors. - explicit IfColorVisitor(AstAlways* nodep) { - iterate(nodep); - } + explicit IfColorVisitor(AstAlways* nodep) { iterate(nodep); } virtual ~IfColorVisitor() {} // METHODS @@ -660,8 +661,7 @@ private: UINFO(8, " SVL " << vertexp << " has color " << color << "\n"); // Record that all containing ifs have this color. - for (IfStack::const_iterator it = m_ifStack.begin(); - it != m_ifStack.end(); ++it) { + for (IfStack::const_iterator it = m_ifStack.begin(); it != m_ifStack.end(); ++it) { m_ifColors[*it].insert(color); } } @@ -700,9 +700,7 @@ public: // EmitSplitVisitor visits through always block *nodep // and generates its split blocks, writing the split blocks // into *newBlocksp. - EmitSplitVisitor(AstAlways* nodep, - const IfColorVisitor* ifColorp, - AlwaysVec* newBlocksp) + EmitSplitVisitor(AstAlways* nodep, const IfColorVisitor* ifColorp, AlwaysVec* newBlocksp) : m_origAlwaysp(nodep) , m_ifColorp(ifColorp) , m_newBlocksp(newBlocksp) { @@ -715,13 +713,11 @@ public: void go() { // Create a new always for each color const ColorSet& colors = m_ifColorp->colors(); - for (ColorSet::const_iterator color = colors.begin(); - color != colors.end(); ++color) { + for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) { // We don't need to clone m_origAlwaysp->sensesp() here; // V3Activate already moved it to a parent node. - AstAlways* alwaysp = - new AstAlways(m_origAlwaysp->fileline(), VAlwaysKwd::ALWAYS, - NULL, NULL); + AstAlways* alwaysp + = new AstAlways(m_origAlwaysp->fileline(), VAlwaysKwd::ALWAYS, NULL, NULL); // Put a placeholder node into stmtp to track our position. // We'll strip these out after the blocks are fully cloned. AstSplitPlaceholder* placeholderp = makePlaceholderp(); @@ -769,16 +765,12 @@ protected: typedef vl_unordered_map CloneMap; CloneMap clones; - for (ColorSet::const_iterator color = colors.begin(); - color != colors.end(); ++color) { + for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) { // Clone this if into its set of split blocks AstSplitPlaceholder* if_placeholderp = makePlaceholderp(); AstSplitPlaceholder* else_placeholderp = makePlaceholderp(); - AstIf* clonep = - new AstIf(nodep->fileline(), - nodep->condp()->cloneTree(true), - if_placeholderp, - else_placeholderp); + AstIf* clonep = new AstIf(nodep->fileline(), nodep->condp()->cloneTree(true), + if_placeholderp, else_placeholderp); AstIf* origp = VN_CAST(nodep, If); if (origp) { // Preserve pragmas from unique if's @@ -794,15 +786,13 @@ protected: iterateAndNextNull(nodep->ifsp()); - for (ColorSet::const_iterator color = colors.begin(); - color != colors.end(); ++color) { + for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) { m_addAfter[*color] = clones[*color]->elsesp(); } iterateAndNextNull(nodep->elsesp()); - for (ColorSet::const_iterator color = colors.begin(); - color != colors.end(); ++color) { + for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) { m_addAfter[*color] = clones[*color]; } } @@ -817,17 +807,14 @@ class RemovePlaceholdersVisitor : public AstNVisitor { public: explicit RemovePlaceholdersVisitor(AstNode* nodep) { iterate(nodep); - for (NodeSet::const_iterator it = m_removeSet.begin(); - it != m_removeSet.end(); ++it) { + for (NodeSet::const_iterator it = m_removeSet.begin(); it != m_removeSet.end(); ++it) { AstNode* np = *it; np->unlinkFrBack(); // Without next VL_DO_DANGLING(np->deleteTree(), np); } } virtual ~RemovePlaceholdersVisitor() {} - virtual void visit(AstSplitPlaceholder* nodep) VL_OVERRIDE { - m_removeSet.insert(nodep); - } + virtual void visit(AstSplitPlaceholder* nodep) VL_OVERRIDE { m_removeSet.insert(nodep); } virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } private: @@ -854,11 +841,11 @@ public: // Splice newly-split blocks into the tree. Remove placeholders // from newly-split blocks. Delete the original always blocks // that we're replacing. - for (ReplaceMap::iterator it = m_replaceBlocks.begin(); - it != m_replaceBlocks.end(); ++it) { + for (ReplaceMap::iterator it = m_replaceBlocks.begin(); it != m_replaceBlocks.end(); + ++it) { AstAlways* origp = it->first; - for (AlwaysVec::iterator addme = it->second.begin(); - addme != it->second.end(); ++addme) { + for (AlwaysVec::iterator addme = it->second.begin(); addme != it->second.end(); + ++addme) { origp->addNextHere(*addme); RemovePlaceholdersVisitor removePlaceholders(*addme); } @@ -876,9 +863,7 @@ protected: // not rvalues in the if/else bodies. for (VStack::const_iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); ++it) { AstNodeIf* ifNodep = VN_CAST((*it)->nodep(), NodeIf); - if (ifNodep && (m_curIfConditional != ifNodep)) { - continue; - } + if (ifNodep && (m_curIfConditional != ifNodep)) continue; new SplitRVEdge(&m_graph, *it, vstdp); } } @@ -899,8 +884,8 @@ protected: // For any 'if' node whose deps have all been pruned // (meaning, its conditional expression only looks at primary // inputs) prune all edges that depend on the 'if'. - for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); - vertexp; vertexp=vertexp->verticesNextp()) { + for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; + vertexp = vertexp->verticesNextp()) { SplitLogicVertex* logicp = dynamic_cast(vertexp); if (!logicp) continue; @@ -908,8 +893,7 @@ protected: if (!ifNodep) continue; bool pruneMe = true; - for (V3GraphEdge* edgep = logicp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = logicp->outBeginp(); edgep; edgep = edgep->outNextp()) { SplitEdge* oedgep = dynamic_cast(edgep); if (!oedgep->ignoreThisStep()) { // This if conditional depends on something we can't @@ -921,8 +905,8 @@ protected: if (debug() >= 9) { V3GraphVertex* vxp = oedgep->top(); SplitNodeVertex* nvxp = dynamic_cast(vxp); - UINFO(0, "Cannot prune if-node due to edge "<nodep()<nodep() << endl); nvxp->nodep()->dumpTree(cout, "- "); } @@ -933,21 +917,20 @@ protected: if (!pruneMe) continue; // This if can be split; prune dependencies on it. - for (V3GraphEdge* edgep = logicp->inBeginp(); - edgep; edgep = edgep->inNextp()) { + for (V3GraphEdge* edgep = logicp->inBeginp(); edgep; edgep = edgep->inNextp()) { SplitEdge* oedgep = dynamic_cast(edgep); oedgep->setIgnoreThisStep(); } } - if (debug()>=9) m_graph.dumpDotFilePrefixed("splitg_nodup", false); + if (debug() >= 9) m_graph.dumpDotFilePrefixed("splitg_nodup", false); // Weak coloring to determine what needs to remain grouped // in a single always. This follows all edges excluding: // - those we pruned above // - PostEdges, which are done later m_graph.weaklyConnected(&SplitEdge::followScoreboard); - if (debug()>=9) m_graph.dumpDotFilePrefixed("splitg_colored", false); + if (debug() >= 9) m_graph.dumpDotFilePrefixed("splitg_colored", false); } virtual void visit(AstAlways* nodep) VL_OVERRIDE { @@ -957,13 +940,13 @@ protected: if (m_noReorderWhy != "") { // We saw a jump or something else rare that we don't handle. - UINFO(9," NoSplitBlock because "<condp()); m_curIfConditional = NULL; scanBlock(nodep->ifsp()); scanBlock(nodep->elsesp()); } + private: VL_UNCOPYABLE(SplitVisitor); }; @@ -999,16 +982,12 @@ private: // Split class functions void V3Split::splitReorderAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } void V3Split::splitAlwaysAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index 0a4b76736..d600cc819 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -52,8 +52,7 @@ private: // METHODS virtual void visit(AstVarRef* nodep) VL_OVERRIDE { - if (nodep->lvalue() && !m_splitVscp - && nodep->varp()->attrIsolateAssign()) { + if (nodep->lvalue() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) { m_splitVscp = nodep->varScopep(); } } @@ -76,16 +75,16 @@ public: class SplitAsCleanVisitor : public SplitAsBaseVisitor { private: // STATE - AstVarScope* m_splitVscp; // Variable we want to split - bool m_modeMatch; // Remove matching Vscp, else non-matching - bool m_keepStmt; // Current Statement must be preserved - bool m_matches; // Statement below has matching lvalue reference + AstVarScope* m_splitVscp; // Variable we want to split + bool m_modeMatch; // Remove matching Vscp, else non-matching + bool m_keepStmt; // Current Statement must be preserved + bool m_matches; // Statement below has matching lvalue reference // METHODS virtual void visit(AstVarRef* nodep) VL_OVERRIDE { if (nodep->lvalue()) { - if (nodep->varScopep()==m_splitVscp) { - UINFO(6," CL VAR "<varScopep() == m_splitVscp) { + UINFO(6, " CL VAR " << nodep << endl); m_matches = true; } } @@ -95,7 +94,7 @@ private: iterateChildren(nodep); return; } - UINFO(6," CL STMT "<unlinkFrBack(); pushDeletep(nodep); + UINFO(6, " Delete STMT " << nodep << endl); + nodep->unlinkFrBack(); + pushDeletep(nodep); } } // If something below matches, the upper statement remains too. m_keepStmt = oldKeep || m_keepStmt; - UINFO(9," upKeep="< bool. True if already processed - AstUser1InUse m_inuser1; + AstUser1InUse m_inuser1; // STATE VDouble0 m_statSplits; // Statistic tracking @@ -145,20 +144,20 @@ private: // METHODS void splitAlways(AstAlways* nodep) { - UINFO(3,"Split "<=9) nodep->dumpTree(cout, "-in : "); + UINFO(3, "Split " << nodep << endl); + UINFO(3, " For " << m_splitVscp << endl); + if (debug() >= 9) nodep->dumpTree(cout, "-in : "); // Duplicate it and link in AstAlways* newp = nodep->cloneTree(false); newp->user1(true); // So we don't clone it again nodep->addNextHere(newp); - { // Delete stuff we don't want in old - SplitAsCleanVisitor visitor (nodep, m_splitVscp, false); - if (debug()>=9) nodep->dumpTree(cout, "-out0: "); + { // Delete stuff we don't want in old + SplitAsCleanVisitor visitor(nodep, m_splitVscp, false); + if (debug() >= 9) nodep->dumpTree(cout, "-out0: "); } - { // Delete stuff we don't want in new - SplitAsCleanVisitor visitor (newp, m_splitVscp, true); - if (debug()>=9) newp->dumpTree(cout, "-out1: "); + { // Delete stuff we don't want in new + SplitAsCleanVisitor visitor(newp, m_splitVscp, true); + if (debug() >= 9) newp->dumpTree(cout, "-out1: "); } } @@ -168,13 +167,12 @@ private: AstVarScope* lastSplitVscp = NULL; while (!nodep->user1()) { // Find any splittable variables - SplitAsFindVisitor visitor (nodep); + SplitAsFindVisitor visitor(nodep); m_splitVscp = visitor.splitVscp(); if (m_splitVscp && m_splitVscp == lastSplitVscp) { // We did this last time! Something's stuck! nodep->v3fatalSrc("Infinite loop in isolate_assignments removal for: " - <prettyNameQ()) - m_splitVscp = NULL; + << m_splitVscp->prettyNameQ()); } lastSplitVscp = m_splitVscp; // Now isolate the always @@ -207,9 +205,7 @@ public: // SplitAs class functions void V3SplitAs::splitAsAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index fe0f9c057..51d96d6cf 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -133,7 +133,7 @@ struct SplitVarImpl { return new AstAssign(fileline, lhsp, rhsp); } else { return new AstAssignW(fileline, lhsp, rhsp); - } + } } static const char* const notSplitMsg; @@ -523,10 +523,10 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { iterate(argp); if (reason) { for (VarSet::iterator it = m_foundTargetVar.begin(), - it_end = m_foundTargetVar.end(); + it_end = m_foundTargetVar.end(); it != it_end; ++it) { argp->v3warn(SPLITVAR, (*it)->prettyNameQ() - << notSplitMsg << reason << ".\n"); + << notSplitMsg << reason << ".\n"); m_refs.remove(*it); } } @@ -574,7 +574,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { m_refsForPackedSplit[m_modp].add(nodep); } virtual void visit(AstSel* nodep) VL_OVERRIDE { - if (VN_IS(nodep->fromp(), VarRef)) m_refsForPackedSplit[m_modp].add(nodep); + if (VN_IS(nodep->fromp(), VarRef)) m_refsForPackedSplit[m_modp].add(nodep); iterateChildren(nodep); } virtual void visit(AstArraySel* nodep) VL_OVERRIDE { @@ -815,8 +815,10 @@ public: if (dim.second < 1 || !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)) reason = "it is not an unpacked array"; if (!reason) reason = cannotSplitVarCommonReason(nodep); - if (reason) UINFO(5, "Check " << nodep->prettyNameQ() - << " cannot split because" << reason << ".\n"); + if (reason) { + UINFO(5, + "Check " << nodep->prettyNameQ() << " cannot split because" << reason << ".\n"); + } return reason; } }; @@ -900,7 +902,7 @@ class PackedVarRef { std::vector vect; vect.reserve(nodes.size()); for (vl_unordered_map::const_iterator it = nodes.begin(), - it_end = nodes.end(); + it_end = nodes.end(); it != it_end; ++it) { vect.push_back(refs[it->second]); } @@ -1047,11 +1049,13 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { PackedVarRefEntry(nodep, consts[0]->toSInt() + refit->second.basicp()->lsb(), consts[1]->toUInt()), vrefp->lvalue()); - UINFO(5, varp->prettyName() << " [" << consts[0]->toSInt() << ":+" - << consts[1]->toSInt() << "] lsb:" << refit->second.basicp()->lsb() << "\n"); + UINFO(5, varp->prettyName() + << " [" << consts[0]->toSInt() << ":+" << consts[1]->toSInt() + << "] lsb:" << refit->second.basicp()->lsb() << "\n"); } else { - nodep->v3warn(SPLITVAR, vrefp->prettyNameQ() << notSplitMsg - << "its bit range cannot be determined statically."); + nodep->v3warn(SPLITVAR, vrefp->prettyNameQ() + << notSplitMsg + << "its bit range cannot be determined statically."); if (!consts[0]) { UINFO(4, "LSB " << nodep->lsbp() << " is expected to be constant, but not\n"); } @@ -1076,7 +1080,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { const int msb = std::min(ref.msb(), var.msb()); const int bitwidth = msb + 1 - lsb; UINFO(4, var.varp()->prettyNameQ() << "[" << msb << ":" << lsb << "] used for " - << ref.nodep()->prettyNameQ() << '\n'); + << ref.nodep()->prettyNameQ() << '\n'); // LSB of varp is always 0. "lsb - var.lsb()" means this. see also SplitNewVar AstSel* selp = new AstSel(ref.nodep()->fileline(), refp, lsb - var.lsb(), bitwidth); return selp; @@ -1091,9 +1095,9 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { } const bool in = portp->isReadOnly(); for (size_t i = 0; i < vars.size(); ++i) { - AstNode* rhsp = new AstSel(portp->fileline(), - new AstVarRef(portp->fileline(), portp, !in), - vars[i].lsb(), vars[i].bitwidth()); + AstNode* rhsp + = new AstSel(portp->fileline(), new AstVarRef(portp->fileline(), portp, !in), + vars[i].lsb(), vars[i].bitwidth()); AstNode* lhsp = new AstVarRef(portp->fileline(), vars[i].varp(), in); if (!in) std::swap(lhsp, rhsp); AstNodeAssign* assignp = newAssign(portp->fileline(), lhsp, rhsp, portp); @@ -1117,8 +1121,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { = (left == right) ? varp->name() + "__BRA__" + AstNode::encodeNumber(left) + "__KET__" : varp->name() + "__BRA__" + AstNode::encodeNumber(left) - + AstNode::encodeName(":") + AstNode::encodeNumber(right) - + "__KET__"; + + AstNode::encodeName(":") + AstNode::encodeNumber(right) + "__KET__"; AstBasicDType* dtypep; switch (basicp->keyword()) { @@ -1226,9 +1229,8 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { new AstVarRef(varp->fileline(), vars[i].varp(), false), rhsp); } - varp->addNextHere(newAssign(varp->fileline(), - new AstVarRef(varp->fileline(), varp, true), - rhsp, varp)); + varp->addNextHere(newAssign( + varp->fileline(), new AstVarRef(varp->fileline(), varp, true), rhsp, varp)); } else { // the original variable is not used anymore. VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp); } @@ -1274,8 +1276,9 @@ public: } else { reason = "its type is unknown"; } - if (reason) UINFO(5, "Check " << nodep->prettyNameQ() - << " cannot split because" << reason << endl); + if (reason) + UINFO(5, + "Check " << nodep->prettyNameQ() << " cannot split because" << reason << endl); return reason; } VL_DEBUG_FUNC; // Declare debug() diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index 6c4eee97b..f79964434 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -49,10 +49,10 @@ public: class SubstVarWord { protected: // MEMBERS - AstNodeAssign* m_assignp; // Last assignment to each word of this var - int m_step; // Step number of last assignment - bool m_use; // True if each word was consumed - bool m_complex; // True if each word is complex + AstNodeAssign* m_assignp; // Last assignment to each word of this var + int m_step; // Step number of last assignment + bool m_use; // True if each word was consumed + bool m_complex; // True if each word is complex friend class SubstVarEntry; // METHODS void clear() { @@ -68,10 +68,10 @@ protected: class SubstVarEntry { // MEMBERS - AstVar* m_varp; // Variable this tracks - bool m_wordAssign; // True if any word assignments - bool m_wordUse; // True if any individual word usage - SubstVarWord m_whole; // Data for whole vector used at once + AstVar* m_varp; // Variable this tracks + bool m_wordAssign; // True if any word assignments + bool m_wordUse; // True if any individual word usage + SubstVarWord m_whole; // Data for whole vector used at once std::vector m_words; // Data for every word, if multi word variable int debug() { return SubstBaseVisitor::debug(); } @@ -83,20 +83,21 @@ public: m_wordUse = false; m_words.resize(varp->widthWords()); m_whole.clear(); - for (int i=0; iwidthWords(); i++) { - m_words[i].clear(); - } + for (int i = 0; i < varp->widthWords(); i++) m_words[i].clear(); } ~SubstVarEntry() {} + private: // METHODS - bool wordNumOk(int word) const { - return word < m_varp->widthWords(); - } + bool wordNumOk(int word) const { return word < m_varp->widthWords(); } AstNodeAssign* getWordAssignp(int word) const { - if (!wordNumOk(word)) return NULL; - else return m_words[word].m_assignp; + if (!wordNumOk(word)) { + return NULL; + } else { + return m_words[word].m_assignp; + } } + public: void assignWhole(int step, AstNodeAssign* assp) { if (m_whole.m_assignp) m_whole.m_complex = true; @@ -104,8 +105,9 @@ public: m_whole.m_step = step; } void assignWord(int step, int word, AstNodeAssign* assp) { - if (!wordNumOk(word) || getWordAssignp(word) - || m_words[word].m_complex) m_whole.m_complex = true; + if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) { + m_whole.m_complex = true; + } m_wordAssign = true; if (wordNumOk(word)) { m_words[word].m_assignp = assp; @@ -113,13 +115,12 @@ public: } } void assignWordComplex(int word) { - if (!wordNumOk(word) || getWordAssignp(word) - || m_words[word].m_complex) m_whole.m_complex = true; + if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) { + m_whole.m_complex = true; + } m_words[word].m_complex = true; } - void assignComplex() { - m_whole.m_complex = true; - } + void assignComplex() { m_whole.m_complex = true; } void consumeWhole() { //==consumeComplex as we don't know the difference m_whole.m_use = true; } @@ -129,8 +130,7 @@ public: } // ACCESSORS AstNode* substWhole(AstNode* errp) { - if (!m_varp->isWide() - && !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) { + if (!m_varp->isWide() && !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) { AstNodeAssign* assp = m_whole.m_assignp; UASSERT_OBJ(assp, errp, "Reading whole that was never assigned"); return (assp->rhsp()); @@ -138,7 +138,8 @@ public: return NULL; } } - AstNode* substWord(AstNode* errp, int word) { // Return what to substitute given word number for + // Return what to substitute given word number for + AstNode* substWord(AstNode* errp, int word) { if (!m_whole.m_complex && !m_whole.m_assignp && !m_words[word].m_complex) { AstNodeAssign* assp = getWordAssignp(word); UASSERT_OBJ(assp, errp, "Reading a word that was never assigned, or bad word #"); @@ -147,14 +148,16 @@ public: return NULL; } } - int getWholeStep() const { - return m_whole.m_step; - } + int getWholeStep() const { return m_whole.m_step; } int getWordStep(int word) const { - if (!wordNumOk(word)) return 0; else return m_words[word].m_step; + if (!wordNumOk(word)) { + return 0; + } else { + return m_words[word].m_step; + } } void deleteAssign(AstNodeAssign* nodep) { - UINFO(5, "Delete "<unlinkFrBack()->deleteTree(), nodep); } void deleteUnusedAssign() { @@ -162,9 +165,9 @@ public: if (!m_whole.m_use && !m_wordUse && m_whole.m_assignp) { VL_DO_CLEAR(deleteAssign(m_whole.m_assignp), m_whole.m_assignp = NULL); } - for (unsigned i=0; ivarp()->user2()) { - if (m_ok) UINFO(9," RHS variable changed since subst recorded: "< SubstVar* for usage var, 0=not set yet // AstVar::user2 -> int step number for last assignment, 0=not set yet - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; // STATE - std::vector m_entryps; // Nodes to delete when we are finished - int m_ops; // Number of operators on assign rhs - int m_assignStep; // Assignment number to determine var lifetime - VDouble0 m_statSubsts; // Statistic tracking + std::vector m_entryps; // Nodes to delete when we are finished + int m_ops; // Number of operators on assign rhs + int m_assignStep; // Assignment number to determine var lifetime + VDouble0 m_statSubsts; // Statistic tracking - enum { SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in - SUBST_MAX_OPS_NA = 9999 }; // Not allowed to substitute + enum { + SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in + SUBST_MAX_OPS_NA = 9999 + }; // Not allowed to substitute // METHODS SubstVarEntry* getEntryp(AstVarRef* nodep) { @@ -251,57 +258,51 @@ private: return entryp; } } - inline bool isSubstVar(AstVar* nodep) { - return nodep->isStatementTemp() && !nodep->noSubst(); - } + inline bool isSubstVar(AstVar* nodep) { return nodep->isStatementTemp() && !nodep->noSubst(); } // VISITORS virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { m_ops = 0; m_assignStep++; iterateAndNextNull(nodep->rhsp()); - bool hit=false; + bool hit = false; if (AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef)) { if (isSubstVar(varrefp->varp())) { SubstVarEntry* entryp = getEntryp(varrefp); hit = true; if (m_ops > SUBST_MAX_OPS_SUBST) { - UINFO(8," ASSIGNtooDeep "<assignComplex(); } else { - UINFO(8," ASSIGNwhole "<assignWhole(m_assignStep, nodep); } } - } - else if (AstWordSel* wordp = VN_CAST(nodep->lhsp(), WordSel)) { + } else if (AstWordSel* wordp = VN_CAST(nodep->lhsp(), WordSel)) { if (AstVarRef* varrefp = VN_CAST(wordp->lhsp(), VarRef)) { - if (VN_IS(wordp->rhsp(), Const) - && isSubstVar(varrefp->varp())) { + if (VN_IS(wordp->rhsp(), Const) && isSubstVar(varrefp->varp())) { int word = VN_CAST(wordp->rhsp(), Const)->toUInt(); SubstVarEntry* entryp = getEntryp(varrefp); hit = true; if (m_ops > SUBST_MAX_OPS_SUBST) { - UINFO(8," ASSIGNtooDeep "<assignWordComplex(word); } else { - UINFO(8," ASSIGNword"<assignWord(m_assignStep, word, nodep); } } } } - if (!hit) { - iterate(nodep->lhsp()); - } + if (!hit) iterate(nodep->lhsp()); } void replaceSubstEtc(AstNode* nodep, AstNode* substp) { - if (debug()>5) nodep->dumpTree(cout, " substw_old: "); + if (debug() > 5) nodep->dumpTree(cout, " substw_old: "); AstNode* newp = substp->cloneTree(true); if (!nodep->isQuad() && newp->isQuad()) { newp = new AstCCast(newp->fileline(), newp, nodep); } - if (debug()>5) newp->dumpTree(cout, " w_new: "); + if (debug() > 5) newp->dumpTree(cout, " w_new: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); ++m_statSubsts; @@ -310,17 +311,15 @@ private: iterate(nodep->rhsp()); AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef); AstConst* constp = VN_CAST(nodep->rhsp(), Const); - if (varrefp && isSubstVar(varrefp->varp()) - && !varrefp->lvalue() - && constp) { + if (varrefp && isSubstVar(varrefp->varp()) && !varrefp->lvalue() && constp) { // Nicely formed lvalues handled in NodeAssign // Other lvalues handled as unknown mess in AstVarRef int word = constp->toUInt(); - UINFO(8," USEword"<substWord(nodep, word)) { // Check that the RHS hasn't changed value since we recorded it. - SubstUseVisitor visitor (substp, entryp->getWordStep(word)); + SubstUseVisitor visitor(substp, entryp->getWordStep(word)); if (visitor.ok()) { VL_DO_DANGLING(replaceSubstEtc(nodep, substp), nodep); } else { @@ -338,25 +337,25 @@ private: if (nodep->lvalue()) { m_assignStep++; nodep->varp()->user2(m_assignStep); - UINFO(9, " ASSIGNstep u2="<varp()->user2()<<" "<varp())) { SubstVarEntry* entryp = getEntryp(nodep); if (nodep->lvalue()) { - UINFO(8," ASSIGNcpx "<assignComplex(); } else if (AstNode* substp = entryp->substWhole(nodep)) { // Check that the RHS hasn't changed value since we recorded it. - SubstUseVisitor visitor (substp, entryp->getWholeStep()); + SubstUseVisitor visitor(substp, entryp->getWholeStep()); if (visitor.ok()) { - UINFO(8," USEwhole "<consumeWhole(); } } else { // Consumed w/o substitute - UINFO(8," USEwtf "<consumeWhole(); } } @@ -365,11 +364,10 @@ private: virtual void visit(AstConst*) VL_OVERRIDE {} virtual void visit(AstNode* nodep) VL_OVERRIDE { m_ops++; - if (!nodep->isSubstOptimizable()) { - m_ops = SUBST_MAX_OPS_NA; - } + if (!nodep->isSubstOptimizable()) m_ops = SUBST_MAX_OPS_NA; iterateChildren(nodep); } + public: // CONSTRUCTORS explicit SubstVisitor(AstNode* nodep) { @@ -381,8 +379,8 @@ public: } virtual ~SubstVisitor() { V3Stats::addStat("Optimizations, Substituted temps", m_statSubsts); - for (std::vector::iterator it = m_entryps.begin(); - it != m_entryps.end(); ++it) { + for (std::vector::iterator it = m_entryps.begin(); it != m_entryps.end(); + ++it) { (*it)->deleteUnusedAssign(); delete (*it); } @@ -393,9 +391,7 @@ public: // Subst class functions void V3Subst::substituteAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index 2bf83be6c..7ac74a154 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -47,32 +47,33 @@ // Support classes namespace V3TSP { - static unsigned edgeIdNext = 0; +static unsigned edgeIdNext = 0; - static void selfTestStates(); - static void selfTestString(); +static void selfTestStates(); +static void selfTestString(); - VL_DEBUG_FUNC; // Declare debug() +VL_DEBUG_FUNC; // Declare debug() } // namespace V3TSP // Vertex that tracks a per-vertex key -template -class TspVertexTmpl : public V3GraphVertex { +template class TspVertexTmpl : public V3GraphVertex { private: T_Key m_key; + public: TspVertexTmpl(V3Graph* graphp, const T_Key& k) - : V3GraphVertex(graphp), m_key(k) {} + : V3GraphVertex(graphp) + , m_key(k) {} virtual ~TspVertexTmpl() {} const T_Key& key() const { return m_key; } + private: VL_UNCOPYABLE(TspVertexTmpl); }; // TspGraphTmpl represents a complete graph, templatized to work with // different T_Key types. -template -class TspGraphTmpl : public V3Graph { +template class TspGraphTmpl : public V3Graph { public: // TYPES typedef TspVertexTmpl Vertex; @@ -82,14 +83,15 @@ public: VMap m_vertices; // T_Key to Vertex lookup map // CONSTRUCTORS - TspGraphTmpl() : V3Graph() {} + TspGraphTmpl() + : V3Graph() {} virtual ~TspGraphTmpl() {} // METHODS - void addVertex(const T_Key &key) { + void addVertex(const T_Key& key) { typename VMap::iterator itr = m_vertices.find(key); UASSERT(itr == m_vertices.end(), "Vertex already exists with same key"); - Vertex *v = new Vertex(this, key); + Vertex* v = new Vertex(this, key); m_vertices[key] = v; } @@ -118,9 +120,7 @@ public: std::list keysToVertexList(const std::vector& odds) { std::list vertices; - for(unsigned i = 0; i < odds.size(); ++i) { - vertices.push_back(findVertex(odds.at(i))); - } + for (unsigned i = 0; i < odds.size(); ++i) { vertices.push_back(findVertex(odds.at(i))); } return vertices; } @@ -132,7 +132,7 @@ public: // CONSTRUCTORS EdgeCmp() {} // METHODS - bool operator() (const V3GraphEdge* ap, const V3GraphEdge* bp) { + bool operator()(const V3GraphEdge* ap, const V3GraphEdge* bp) { int aCost = ap->weight(); int bCost = bp->weight(); // Sort first on cost, lowest cost edges first: @@ -141,13 +141,12 @@ public: // Costs are equal. Compare edgeId's which should be unique. return ap->user() < bp->user(); } + private: VL_UNCOPYABLE(EdgeCmp); }; - static Vertex* castVertexp(V3GraphVertex* vxp) { - return dynamic_cast(vxp); - } + static Vertex* castVertexp(V3GraphVertex* vxp) { return dynamic_cast(vxp); } // From *this, populate *mstp with the minimum spanning tree. // *mstp must be initially empty. @@ -164,8 +163,7 @@ public: PendingEdgeSet pendingEdges(cmp); vluint32_t vertCount = 0; - for (V3GraphVertex* vxp = verticesBeginp(); - vxp; vxp = vxp->verticesNextp()) { + for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { mstp->addVertex(castVertexp(vxp)->key()); vertCount++; } @@ -174,8 +172,7 @@ public: // all incident edges from this vertex go into a pending edge set. Vertex* start_vertexp = castVertexp(verticesBeginp()); visited_set.insert(start_vertexp); - for (V3GraphEdge* edgep = start_vertexp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = start_vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { pendingEdges.insert(edgep); } @@ -198,9 +195,8 @@ public: Vertex* neighborp = castVertexp(bestEdgep->top()); if (visited_set.find(neighborp) == visited_set.end()) { int bestCost = bestEdgep->weight(); - UINFO(6, "bestCost = "<key() - <<" to "<key()<key() << " to " + << neighborp->key() << endl); // Create the edge in our output MST graph mstp->addEdge(from_vertexp->key(), neighborp->key(), bestCost); @@ -210,13 +206,13 @@ public: visited_set.insert(neighborp); // Update the pending edges with new edges - for (V3GraphEdge* edgep = neighborp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = neighborp->outBeginp(); edgep; + edgep = edgep->outNextp()) { pendingEdges.insert(edgep); } } else { - UINFO(6, "Discarding edge to already-visited neighbor " - <key()<key() << endl); } } @@ -226,8 +222,7 @@ public: // Populate *outp with a minimal perfect matching of *this. // *outp must be initially empty. - void perfectMatching(const std::vector& oddKeys, - TspGraphTmpl* outp) { + void perfectMatching(const std::vector& oddKeys, TspGraphTmpl* outp) { UASSERT(outp->empty(), "Output graph must start empty"); std::list odds = keysToVertexList(oddKeys); @@ -261,8 +256,7 @@ public: PendingEdgeSet pendingEdges(cmp); for (VertexListIt it = odds.begin(); it != odds.end(); ++it) { - for (V3GraphEdge* edgep = (*it)->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = (*it)->outBeginp(); edgep; edgep = edgep->outNextp()) { pendingEdges.insert(edgep); } } @@ -270,8 +264,8 @@ public: // Iterate over all edges, in order from low to high cost. // For any edge whose ends are both odd-order vertices which // haven't been matched yet, match them. - for (typename PendingEdgeSet::iterator it = pendingEdges.begin(); - it != pendingEdges.end(); ++it) { + for (typename PendingEdgeSet::iterator it = pendingEdges.begin(); it != pendingEdges.end(); + ++it) { Vertex* fromp = castVertexp((*it)->fromp()); Vertex* top = castVertexp((*it)->top()); if ((unmatchedOdds.find(fromp) != unmatchedOdds.end()) @@ -298,49 +292,43 @@ public: } } - void findEulerTourRecurse(vl_unordered_set* markedEdgesp, - Vertex* startp, + void findEulerTourRecurse(vl_unordered_set* markedEdgesp, Vertex* startp, std::vector* sortedOutp) { Vertex* cur_vertexp = startp; // Go on a random tour. Fun! std::vector tour; do { - UINFO(6, "Adding "<key()<<" to tour.\n"); + UINFO(6, "Adding " << cur_vertexp->key() << " to tour.\n"); tour.push_back(cur_vertexp); // Look for an arbitrary edge we've not yet marked - for (V3GraphEdge* edgep = cur_vertexp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = cur_vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { vluint32_t edgeId = edgep->user(); if (markedEdgesp->end() == markedEdgesp->find(edgeId)) { // This edge is not yet marked, so follow it. markedEdgesp->insert(edgeId); Vertex* neighborp = castVertexp(edgep->top()); - UINFO(6, "following edge "<key() - <<" to "<key()<key() + << " to " << neighborp->key() << endl); cur_vertexp = neighborp; goto found; } } v3fatalSrc("No unmarked edges found in tour"); - found: - ; + found:; } while (cur_vertexp != startp); - UINFO(6, "stopped, got back to start of tour @ "<key()<key() << endl); // Look for nodes on the tour that still have // un-marked edges. If we find one, recurse. - for (typename std::vector::iterator it = tour.begin(); - it != tour.end(); ++it) { + for (typename std::vector::iterator it = tour.begin(); it != tour.end(); ++it) { Vertex* vxp = *it; bool recursed; do { recursed = false; // Look for an arbitrary edge at vxp we've not yet marked - for (V3GraphEdge* edgep = vxp->outBeginp(); - edgep; edgep = edgep->outNextp()) { + for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { vluint32_t edgeId = edgep->user(); if (markedEdgesp->end() == markedEdgesp->find(edgeId)) { UINFO(6, "Recursing.\n"); @@ -349,38 +337,36 @@ public: goto recursed; } } - recursed: - ; + recursed:; } while (recursed); sortedOutp->push_back(vxp->key()); } UINFO(6, "Tour was: "); - for (typename std::vector::iterator it = tour.begin(); - it != tour.end(); ++it) { + for (typename std::vector::iterator it = tour.begin(); it != tour.end(); ++it) { Vertex* vxp = *it; - UINFONL(6, " "<key()); + UINFONL(6, " " << vxp->key()); } UINFONL(6, "\n"); } void dumpGraph(std::ostream& os, const string& nameComment) const { // UINFO(0) as controlled by caller - os<<"At "<verticesNextp()) { Vertex* tspvp = castVertexp(vxp); - os<<" "<key()<key() << endl; for (V3GraphEdge* edgep = tspvp->outBeginp(); edgep; edgep = edgep->outNextp()) { Vertex* neighborp = castVertexp(edgep->top()); - os<<" has edge "<user()<<" to "<key()<user() << " to " << neighborp->key() << endl; } } } void dumpGraphFilePrefixed(const string& nameComment) const { if (v3Global.opt.dumpTree()) { - string filename = v3Global.debugFilename(nameComment)+".txt"; + string filename = v3Global.debugFilename(nameComment) + ".txt"; const vl_unique_ptr logp(V3File::new_ofstream(filename)); - if (logp->fail()) v3fatal("Can't write "<fail()) v3fatal("Can't write " << filename); dumpGraph(*logp, nameComment); } } @@ -402,9 +388,7 @@ public: for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { degree++; } - if (degree & 1) { - result.push_back(tspvp->key()); - } + if (degree & 1) { result.push_back(tspvp->key()); } } return result; } @@ -427,9 +411,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { // Make this TSP implementation work for graphs of size 0 or 1 // which, unfortunately, is a special case as the following // code assumes >= 2 nodes. - if (states.empty()) { - return; - } + if (states.empty()) { return; } if (states.size() == 1) { resultp->push_back(*(states.begin())); return; @@ -470,8 +452,8 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { // Discard duplicate nodes that the Euler tour might contain. { vl_unordered_set seen; - for (V3TSP::StateVec::iterator it = prelim_result.begin(); - it != prelim_result.end(); ++it) { + for (V3TSP::StateVec::iterator it = prelim_result.begin(); it != prelim_result.end(); + ++it) { const TspStateBase* elemp = *it; if (seen.find(elemp) == seen.end()) { seen.insert(elemp); @@ -492,7 +474,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { for (unsigned i = 0; i < resultp->size(); ++i) { const TspStateBase* ap = (*resultp)[i]; const TspStateBase* bp - = (i+1 == resultp->size()) ? (*resultp)[0] : (*resultp)[i+1]; + = (i + 1 == resultp->size()) ? (*resultp)[0] : (*resultp)[i + 1]; unsigned cost = ap->cost(bp); if (cost > max_cost) { max_cost = cost; @@ -508,12 +490,10 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { V3TSP::StateVec new_result; unsigned i = max_cost_idx + 1; UASSERT(i < resultp->size(), "Algorithm size error"); - while(i != max_cost_idx) { + while (i != max_cost_idx) { new_result.push_back((*resultp)[i]); i++; - if (i >= resultp->size()) { - i = 0; - } + if (i >= resultp->size()) { i = 0; } } new_result.push_back((*resultp)[i]); @@ -527,17 +507,17 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { class TspTestState : public V3TSP::TspStateBase { public: - TspTestState(unsigned xpos, unsigned ypos) : - m_xpos(xpos), - m_ypos(ypos), - m_serial(++m_serialNext) {} + TspTestState(unsigned xpos, unsigned ypos) + : m_xpos(xpos) + , m_ypos(ypos) + , m_serial(++m_serialNext) {} ~TspTestState() {} virtual int cost(const TspStateBase* otherp) const { return cost(dynamic_cast(otherp)); } static unsigned diff(unsigned a, unsigned b) { - if (a>b) return a-b; - return b-a; + if (a > b) return a - b; + return b - a; } virtual int cost(const TspTestState* otherp) const { // For test purposes, each TspTestState is merely a point @@ -546,21 +526,16 @@ public: unsigned xabs, yabs; xabs = diff(otherp->m_xpos, m_xpos); yabs = diff(otherp->m_ypos, m_ypos); - return lround(sqrt(xabs*xabs + yabs*yabs)); - } - unsigned xpos() const { - return m_xpos; - } - unsigned ypos() const { - return m_ypos; + return lround(sqrt(xabs * xabs + yabs * yabs)); } + unsigned xpos() const { return m_xpos; } + unsigned ypos() const { return m_ypos; } - bool operator< (const TspStateBase& other) const { - return operator< (dynamic_cast(other)); - } - bool operator< (const TspTestState& other) const { - return m_serial < other.m_serial; + bool operator<(const TspStateBase& other) const { + return operator<(dynamic_cast(other)); } + bool operator<(const TspTestState& other) const { return m_serial < other.m_serial; } + private: unsigned m_xpos; unsigned m_ypos; @@ -574,11 +549,11 @@ void V3TSP::selfTestStates() { // Linear test -- coords all along the x-axis { V3TSP::StateVec states; - TspTestState s10(10,0); - TspTestState s60(60,0); - TspTestState s20(20,0); - TspTestState s100(100,0); - TspTestState s5(5,0); + TspTestState s10(10, 0); + TspTestState s60(60, 0); + TspTestState s20(20, 0); + TspTestState s100(100, 0); + TspTestState s5(5, 0); states.push_back(&s10); states.push_back(&s60); states.push_back(&s20); @@ -595,12 +570,11 @@ void V3TSP::selfTestStates() { expect.push_back(&s10); expect.push_back(&s5); if (VL_UNCOVERABLE(expect != result)) { - for (V3TSP::StateVec::iterator it = result.begin(); - it != result.end(); ++it) { + for (V3TSP::StateVec::iterator it = result.begin(); it != result.end(); ++it) { const TspTestState* statep = dynamic_cast(*it); - cout<xpos()<<" "; + cout << statep->xpos() << " "; } - cout<(*it); - cout<xpos()<<","<ypos()<<" "; + cout << statep->xpos() << "," << statep->ypos() << " "; } - cout<::const_iterator it = result.begin(); it != result.end(); ++it) { - cout<<*it<<" "; + cout << *it << " "; } - cout< ModTableVector; ModTableVector m_modTableVscs; // All tables created // State cleared on each scope - AstScope* m_scopep; // Current SCOPE + AstScope* m_scopep; // Current SCOPE // State cleared on each always/assignw - bool m_assignDly; // Consists of delayed assignments instead of normal assignments - int m_inWidth; // Input table width - int m_outWidth; // Output table width + bool m_assignDly; // Consists of delayed assignments instead of normal assignments + int m_inWidth; // Input table width + int m_outWidth; // Output table width std::deque m_inVarps; // Input variable list - std::deque m_outVarps; // Output variable list - std::deque m_outNotSet; // True if output variable is not set at some point + std::deque m_outVarps; // Output variable list + std::deque m_outNotSet; // True if output variable is not set at some point // When creating a table - std::deque m_tableVarps; // Table being created + std::deque m_tableVarps; // Table being created // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -105,7 +106,7 @@ private: m_outNotSet.clear(); // Collect stats - TableSimulateVisitor chkvis (this); + TableSimulateVisitor chkvis(this); chkvis.mainTableCheck(nodep); m_assignDly = chkvis.isAssignDly(); // Also sets m_inWidth @@ -115,12 +116,12 @@ private: // Calc data storage in bytes size_t chgWidth = m_outVarps.size(); // Width of one change-it-vector - if (chgWidth<8) chgWidth = 8; + if (chgWidth < 8) chgWidth = 8; double space = (pow(static_cast(2.0), static_cast(m_inWidth)) * static_cast(m_outWidth + chgWidth)); // Instruction count bytes (ok, it's space also not time :) double bytesPerInst = 4; - double time = ((chkvis.instrCount()*bytesPerInst + chkvis.dataCount()) + double time = ((chkvis.instrCount() * bytesPerInst + chkvis.dataCount()) + 1); // +1 so won't div by zero if (chkvis.instrCount() < TABLE_MIN_NODE_COUNT) { chkvis.clearOptimizable(nodep, "Table has too few nodes involved"); @@ -134,16 +135,15 @@ private: if (m_totalBytes > TABLE_TOTAL_BYTES) { chkvis.clearOptimizable(nodep, "Table out of memory"); } - if (!m_outWidth || !m_inWidth) { - chkvis.clearOptimizable(nodep, "Table has no outputs"); - } - UINFO(4, " Test: Opt="<<(chkvis.optimizable()?"OK":"NO") - <<", Instrs="<varScopep(); if (nodep->lvalue()) { m_outWidth += nodep->varp()->dtypeSkipRefp()->widthTotalBytes(); @@ -172,25 +172,21 @@ private: ++m_statTablesCre; // Index into our table - AstVar* indexVarp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, - "__Vtableidx" + cvtToStr(m_modTables), - VFlagBitPacked(), m_inWidth); + AstVar* indexVarp + = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, + "__Vtableidx" + cvtToStr(m_modTables), VFlagBitPacked(), m_inWidth); m_modp->addStmtp(indexVarp); AstVarScope* indexVscp = new AstVarScope(indexVarp->fileline(), m_scopep, indexVarp); m_scopep->addVarp(indexVscp); // Change it variable FileLine* fl = nodep->fileline(); - AstNodeArrayDType* dtypep - = new AstUnpackArrayDType(fl, - nodep->findBitDType(m_outVarps.size(), - m_outVarps.size(), AstNumeric::UNSIGNED), - new AstRange(fl, VL_MASK_I(m_inWidth), 0)); + AstNodeArrayDType* dtypep = new AstUnpackArrayDType( + fl, nodep->findBitDType(m_outVarps.size(), m_outVarps.size(), AstNumeric::UNSIGNED), + new AstRange(fl, VL_MASK_I(m_inWidth), 0)); v3Global.rootp()->typeTablep()->addTypesp(dtypep); - AstVar* chgVarp - = new AstVar(fl, AstVarType::MODULETEMP, - "__Vtablechg" + cvtToStr(m_modTables), - dtypep); + AstVar* chgVarp = new AstVar(fl, AstVarType::MODULETEMP, + "__Vtablechg" + cvtToStr(m_modTables), dtypep); chgVarp->isConst(true); chgVarp->valuep(new AstInitArray(nodep->fileline(), dtypep, NULL)); m_modp->addStmtp(chgVarp); @@ -215,7 +211,7 @@ private: // Keep sensitivity list, but delete all else nodeap->bodysp()->unlinkFrBackWithNext()->deleteTree(); nodeap->addStmtp(stmtsp); - if (debug()>=6) nodeap->dumpTree(cout, " table_new: "); + if (debug() >= 6) nodeap->dumpTree(cout, " table_new: "); } else { // LCOV_EXCL_LINE nodep->v3fatalSrc("Creating table under unknown node type"); } @@ -226,23 +222,22 @@ private: void createTableVars(AstNode* nodep) { // Create table for each output - typedef std::map NameCounts; + typedef std::map NameCounts; NameCounts namecounts; - for (std::deque::iterator it = m_outVarps.begin(); - it != m_outVarps.end(); ++it) { + for (std::deque::iterator it = m_outVarps.begin(); it != m_outVarps.end(); + ++it) { AstVarScope* outvscp = *it; AstVar* outvarp = outvscp->varp(); FileLine* fl = nodep->fileline(); - AstNodeArrayDType* dtypep - = new AstUnpackArrayDType(fl, outvarp->dtypep(), - new AstRange(fl, VL_MASK_I(m_inWidth), 0)); + AstNodeArrayDType* dtypep = new AstUnpackArrayDType( + fl, outvarp->dtypep(), new AstRange(fl, VL_MASK_I(m_inWidth), 0)); v3Global.rootp()->typeTablep()->addTypesp(dtypep); - string name = "__Vtable"+cvtToStr(m_modTables)+"_"+outvarp->name(); + string name = "__Vtable" + cvtToStr(m_modTables) + "_" + outvarp->name(); NameCounts::iterator nit = namecounts.find(name); if (nit != namecounts.end()) { // Multiple scopes can have same var name. We could append the // scope name but that is very long, so just deduplicate. - name += "__dedup"+cvtToStr(++nit->second); + name += "__dedup" + cvtToStr(++nit->second); } else { namecounts[name] = 0; } @@ -261,18 +256,19 @@ private: // Concat inputs into a single temp variable (inside always) // First var in inVars becomes the LSB of the concat AstNode* concatp = NULL; - for (std::deque::iterator it = m_inVarps.begin(); it!=m_inVarps.end(); ++it) { + for (std::deque::iterator it = m_inVarps.begin(); it != m_inVarps.end(); + ++it) { AstVarScope* invscp = *it; AstVarRef* refp = new AstVarRef(nodep->fileline(), invscp, false); if (concatp) { concatp = new AstConcat(nodep->fileline(), refp, concatp); - } else concatp = refp; + } else { + concatp = refp; + } } - AstNode* stmtsp = new AstAssign - (nodep->fileline(), - new AstVarRef(nodep->fileline(), indexVscp, true), - concatp); + AstNode* stmtsp = new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), indexVscp, true), concatp); return stmtsp; } @@ -281,15 +277,15 @@ private: // There may be a simulation path by which the output doesn't change value. // We could bail on these cases, or we can have a "change it" boolean. // We've chosen the latter route, since recirc is common in large FSMs. - for (std::deque::iterator it = m_outVarps.begin(); - it != m_outVarps.end(); ++it) { + for (std::deque::iterator it = m_outVarps.begin(); it != m_outVarps.end(); + ++it) { m_outNotSet.push_back(false); } uint32_t inValueNextInitArray = 0; - TableSimulateVisitor simvis (this); - for (uint32_t inValue=0; inValue <= VL_MASK_I(m_inWidth); inValue++) { + TableSimulateVisitor simvis(this); + for (uint32_t inValue = 0; inValue <= VL_MASK_I(m_inWidth); inValue++) { // Make a new simulation structure so we can set new input values - UINFO(8," Simulating "<::iterator it = m_inVarps.begin(); - it != m_inVarps.end(); ++it) { + for (std::deque::iterator it = m_inVarps.begin(); it != m_inVarps.end(); + ++it) { AstVarScope* invscp = *it; // LSB is first variable, so extract it that way AstConst cnst(invscp->fileline(), AstConst::WidthedValue(), invscp->width(), - VL_MASK_I(invscp->width()) & (inValue>>shift)); + VL_MASK_I(invscp->width()) & (inValue >> shift)); simvis.newValue(invscp, &cnst); shift += invscp->width(); // We're just using32 bit arithmetic, because there's no // way the input table can be 2^32 bytes! UASSERT_OBJ(shift <= 32, nodep, "shift overflow"); - UINFO(8," Input "<name()<<" = "<name() << " = " << cnst.name() << endl); } // Simulate simvis.mainTableEmulate(nodep); UASSERT_OBJ(simvis.optimizable(), simvis.whyNotNodep(), "Optimizable cleared, even though earlier test run said not: " - <::iterator it = m_outVarps.begin(); it != m_outVarps.end(); ++it) { AstVarScope* outvscp = *it; V3Number* outnump = simvis.fetchOutNumberNull(outvscp); AstNode* setp; if (!outnump) { - UINFO(8," Output "<name()<<" never set\n"); + UINFO(8, " Output " << outvscp->name() << " never set\n"); m_outNotSet[outnum] = true; // Value in table is arbitrary, but we need something - setp = new AstConst(outvscp->fileline(), - AstConst::WidthedValue(), outvscp->width(), 0); + setp = new AstConst(outvscp->fileline(), AstConst::WidthedValue(), + outvscp->width(), 0); } else { - UINFO(8," Output "<name()<<" = "<<*outnump<name() << " = " << *outnump << endl); // m_tableVarps[inValue] = num; // Mark changed bit, too outputChgMask.setBit(outnum, 1); @@ -343,7 +339,7 @@ private: outnum++; } - { // Set changed table + { // Set changed table UASSERT_OBJ(inValue == inValueNextInitArray, nodep, "InitArray requires us to have the values in inValue order"); inValueNextInitArray++; @@ -359,7 +355,7 @@ private: AstVar* var1p = vsc1p->varp(); for (std::deque::iterator it = m_modTableVscs.begin(); it != m_modTableVscs.end(); ++it) { - AstVarScope* vsc2p= *it; + AstVarScope* vsc2p = *it; AstVar* var2p = vsc2p->varp(); if (var1p->width() == var2p->width() && (var1p->dtypep()->arrayUnpackedElements() @@ -367,7 +363,7 @@ private: const AstNode* init1p = VN_CAST(var1p->valuep(), InitArray); const AstNode* init2p = VN_CAST(var2p->valuep(), InitArray); if (init1p->sameGateTree(init2p)) { - UINFO(8," Duplicate table var "<unlinkFrBack()->deleteTree(), vsc1p); return vsc2p; } @@ -377,31 +373,30 @@ private: return vsc1p; } - void createOutputAssigns(AstNode* nodep, AstNode* stmtsp, - AstVarScope* indexVscp, AstVarScope* chgVscp) { + void createOutputAssigns(AstNode* nodep, AstNode* stmtsp, AstVarScope* indexVscp, + AstVarScope* chgVscp) { // We walk through the changemask table, and if all ones know // the output is set on all branches and therefore eliminate the // if. If all uses of the changemask disappear, dead code // elimination will remove it for us. // Set each output from array ref into our table int outnum = 0; - for (std::deque::iterator it = m_outVarps.begin(); - it != m_outVarps.end(); ++it) { + for (std::deque::iterator it = m_outVarps.begin(); it != m_outVarps.end(); + ++it) { AstVarScope* outvscp = *it; AstNode* alhsp = new AstVarRef(nodep->fileline(), outvscp, true); - AstNode* arhsp - = new AstArraySel(nodep->fileline(), - new AstVarRef(nodep->fileline(), m_tableVarps[outnum], false), - new AstVarRef(nodep->fileline(), indexVscp, false)); + AstNode* arhsp = new AstArraySel( + nodep->fileline(), new AstVarRef(nodep->fileline(), m_tableVarps[outnum], false), + new AstVarRef(nodep->fileline(), indexVscp, false)); AstNode* outasnp = (m_assignDly - ? static_cast(new AstAssignDly(nodep->fileline(), alhsp, arhsp)) - : static_cast(new AstAssign(nodep->fileline(), alhsp, arhsp))); + ? static_cast(new AstAssignDly(nodep->fileline(), alhsp, arhsp)) + : static_cast(new AstAssign(nodep->fileline(), alhsp, arhsp))); AstNode* outsetp = outasnp; // Is the value set in only some branches of the table? if (m_outNotSet[outnum]) { - V3Number outputChgMask (nodep, m_outVarps.size(), 0); + V3Number outputChgMask(nodep, m_outVarps.size(), 0); outputChgMask.setBit(outnum, 1); outsetp = new AstIf( nodep->fileline(), @@ -418,11 +413,8 @@ private: } } - // VISITORS - virtual void visit(AstNetlist* nodep) VL_OVERRIDE { - iterateChildren(nodep); - } + virtual void visit(AstNetlist* nodep) VL_OVERRIDE { iterateChildren(nodep); } virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { AstNodeModule* origModp = m_modp; int origModTables = m_modTables; @@ -438,13 +430,13 @@ private: m_modTableVscs = origModTableVscs; } virtual void visit(AstScope* nodep) VL_OVERRIDE { - UINFO(4," SCOPE "<= 3); } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index e92e97b21..3ab819107 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -42,13 +42,15 @@ // Graph subclasses class TaskBaseVertex : public V3GraphVertex { - AstNode* m_impurep; // Node causing impure function w/ outside references - bool m_noInline; // Marked with pragma + AstNode* m_impurep; // Node causing impure function w/ outside references + bool m_noInline; // Marked with pragma public: explicit TaskBaseVertex(V3Graph* graphp) - : V3GraphVertex(graphp), m_impurep(NULL), m_noInline(false) {} + : V3GraphVertex(graphp) + , m_impurep(NULL) + , m_noInline(false) {} virtual ~TaskBaseVertex() {} - bool pure() const { return m_impurep==NULL; } + bool pure() const { return m_impurep == NULL; } AstNode* impureNode() const { return m_impurep; } void impure(AstNode* nodep) { m_impurep = nodep; } bool noInline() const { return m_noInline; } @@ -59,9 +61,11 @@ class TaskFTaskVertex : public TaskBaseVertex { // Every task gets a vertex, and we link tasks together based on funcrefs. AstNodeFTask* m_nodep; AstCFunc* m_cFuncp; + public: TaskFTaskVertex(V3Graph* graphp, AstNodeFTask* nodep) - : TaskBaseVertex(graphp), m_nodep(nodep) { + : TaskBaseVertex(graphp) + , m_nodep(nodep) { m_cFuncp = NULL; } virtual ~TaskFTaskVertex() {} @@ -88,7 +92,7 @@ public: TaskEdge(V3Graph* graphp, TaskBaseVertex* fromp, TaskBaseVertex* top) : V3GraphEdge(graphp, fromp, top, 1, false) {} virtual ~TaskEdge() {} - virtual string dotLabel() const { return "w"+cvtToStr(weight()); } + virtual string dotLabel() const { return "w" + cvtToStr(weight()); } }; //###################################################################### @@ -101,16 +105,16 @@ private: // AstNodeFTask::user4p // GraphFTaskVertex* this FTask is under // AstVar::user4p // GraphFTaskVertex* this variable is declared in - AstUser3InUse m_inuser3; - AstUser4InUse m_inuser4; + AstUser3InUse m_inuser3; + AstUser4InUse m_inuser4; // TYPES - typedef std::map,AstVarScope*> VarToScopeMap; + typedef std::map, AstVarScope*> VarToScopeMap; // MEMBERS - VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings - AstAssignW* m_assignwp; // Current assignment - V3Graph m_callGraph; // Task call graph - TaskBaseVertex* m_curVxp; // Current vertex we're adding to + VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings + AstAssignW* m_assignwp; // Current assignment + V3Graph m_callGraph; // Task call graph + TaskBaseVertex* m_curVxp; // Current vertex we're adding to public: // METHODS @@ -124,37 +128,32 @@ public: UASSERT_OBJ(iter != m_varToScopeMap.end(), nodep, "No scope for var"); return iter->second; } - bool ftaskNoInline(AstNodeFTask* nodep) { - return getFTaskVertex(nodep)->noInline(); - } - AstCFunc* ftaskCFuncp(AstNodeFTask* nodep) { - return getFTaskVertex(nodep)->cFuncp(); - } + bool ftaskNoInline(AstNodeFTask* nodep) { return getFTaskVertex(nodep)->noInline(); } + AstCFunc* ftaskCFuncp(AstNodeFTask* nodep) { return getFTaskVertex(nodep)->cFuncp(); } void ftaskCFuncp(AstNodeFTask* nodep, AstCFunc* cfuncp) { getFTaskVertex(nodep)->cFuncp(cfuncp); } - void checkPurity(AstNodeFTask* nodep) { - checkPurity(nodep, getFTaskVertex(nodep)); - } + void checkPurity(AstNodeFTask* nodep) { checkPurity(nodep, getFTaskVertex(nodep)); } void checkPurity(AstNodeFTask* nodep, TaskBaseVertex* vxp) { if (!vxp->pure()) { - nodep->v3warn(IMPURE, "Unsupported: External variable referenced by non-inlined function/task: " - <prettyNameQ()<warnContextPrimary()<impureNode()->warnOther()<<"... Location of the external reference: " - <impureNode()->prettyNameQ()<impureNode()->warnContextSecondary()); + nodep->v3warn( + IMPURE, "Unsupported: External variable referenced by non-inlined function/task: " + << nodep->prettyNameQ() << endl + << nodep->warnContextPrimary() << endl + << vxp->impureNode()->warnOther() + << "... Location of the external reference: " + << vxp->impureNode()->prettyNameQ() << endl + << vxp->impureNode()->warnContextSecondary()); } // And, we need to check all tasks this task calls - for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { checkPurity(nodep, static_cast(edgep->top())); } } + private: TaskFTaskVertex* getFTaskVertex(AstNodeFTask* nodep) { - if (!nodep->user4p()) { - nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep)); - } + if (!nodep->user4p()) nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep)); return static_cast(nodep->user4u().toGraphVertex()); } @@ -164,19 +163,18 @@ private: // pointers to what scope the FTask is to be invoked under. // However, to create variables, we need to track the scopes involved. // Find all var->varscope mappings, for later cleanup - for (AstNode* stmtp = nodep->varsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = nodep->varsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVarScope* vscp = VN_CAST(stmtp, VarScope)) { if (vscp->varp()->isFuncLocal()) { - UINFO(9," funcvsc "<varp()), vscp)); + UINFO(9, " funcvsc " << vscp << endl); + m_varToScopeMap.insert( + std::make_pair(std::make_pair(nodep, vscp->varp()), vscp)); } } } // Likewise, all FTask->scope mappings - for (AstNode* stmtp = nodep->blocksp(); stmtp; stmtp=stmtp->nextp()) { - if (AstNodeFTask* taskp = VN_CAST(stmtp, NodeFTask)) { - taskp->user3p(nodep); - } + for (AstNode* stmtp = nodep->blocksp(); stmtp; stmtp = stmtp->nextp()) { + if (AstNodeFTask* taskp = VN_CAST(stmtp, NodeFTask)) { taskp->user3p(nodep); } } iterateChildren(nodep); } @@ -190,7 +188,7 @@ private: if (m_assignwp) { // Wire assigns must become always statements to deal with insertion // of multiple statements. Perhaps someday make all wassigns into always's? - UINFO(5," IM_WireRep "<convertToAlways(); VL_DO_CLEAR(pushDeletep(m_assignwp), m_assignwp = NULL); } @@ -199,7 +197,7 @@ private: new TaskEdge(&m_callGraph, m_curVxp, getFTaskVertex(nodep->taskp())); } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { - UINFO(9," TASK "<dpiImport()) m_curVxp->noInline(true); @@ -213,8 +211,7 @@ private: // Just mark for the next steps, and we're done with it. m_curVxp->noInline(true); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - else { + } else { iterateChildren(nodep); } } @@ -225,10 +222,7 @@ private: virtual void visit(AstVarRef* nodep) VL_OVERRIDE { iterateChildren(nodep); if (nodep->varp()->user4u().toGraphVertex() != m_curVxp) { - if (m_curVxp->pure() - && !nodep->varp()->isXTemp()) { - m_curVxp->impure(nodep); - } + if (m_curVxp->pure() && !nodep->varp()->isXTemp()) m_curVxp->impure(nodep); } } //-------------------- @@ -264,7 +258,8 @@ private: virtual void visit(AstVarRef* nodep) VL_OVERRIDE { // Similar code in V3Inline if (nodep->varp()->user2p()) { // It's being converted to an alias. - UINFO(9, " relinkVar "<varp()->user2p())<<" "<varp()->user2p()) << " " << nodep << endl); AstVarScope* newvscp = VN_CAST(nodep->varp()->user2p(), VarScope); UASSERT_OBJ(newvscp, nodep, "not linked"); nodep->varScopep(newvscp); @@ -297,33 +292,32 @@ private: // to TaskRelinkVisitor: // AstVar::user2p // AstVarScope* to replace varref with - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; // TYPES - enum InsertMode { - IM_BEFORE, // Pointing at statement ref is in, insert before this - IM_AFTER, // Pointing at last inserted stmt, insert after - IM_WHILE_PRECOND // Pointing to for loop, add to body end + enum InsertMode { + IM_BEFORE, // Pointing at statement ref is in, insert before this + IM_AFTER, // Pointing at last inserted stmt, insert after + IM_WHILE_PRECOND // Pointing to for loop, add to body end }; - typedef std::map > DpiNames; + typedef std::map > DpiNames; // STATE - TaskStateVisitor* m_statep; // Common state between visitors - AstNodeModule* m_modp; // Current module - AstTopScope* m_topScopep; // Current top scope - AstScope* m_scopep; // Current scope - InsertMode m_insMode; // How to insert - AstNode* m_insStmtp; // Where to insert statement - int m_modNCalls; // Incrementing func # for making symbols - DpiNames m_dpiNames; // Map of all created DPI functions + TaskStateVisitor* m_statep; // Common state between visitors + AstNodeModule* m_modp; // Current module + AstTopScope* m_topScopep; // Current top scope + AstScope* m_scopep; // Current scope + InsertMode m_insMode; // How to insert + AstNode* m_insStmtp; // Where to insert statement + int m_modNCalls; // Incrementing func # for making symbols + DpiNames m_dpiNames; // Map of all created DPI functions // METHODS VL_DEBUG_FUNC; // Declare debug() AstVarScope* createFuncVar(AstCFunc* funcp, const string& name, AstVar* examplep) { - AstVar* newvarp = new AstVar(funcp->fileline(), AstVarType::BLOCKTEMP, name, - examplep); + AstVar* newvarp = new AstVar(funcp->fileline(), AstVarType::BLOCKTEMP, name, examplep); newvarp->funcLocal(true); funcp->addInitsp(newvarp); AstVarScope* newvscp = new AstVarScope(funcp->fileline(), m_scopep, newvarp); @@ -345,8 +339,7 @@ private: // It shouldn't matter, as they are only local variables. // We choose to do it under whichever called this function, which results // in more cache locality. - AstVar* newvarp = new AstVar(invarp->fileline(), AstVarType::BLOCKTEMP, - name, invarp); + AstVar* newvarp = new AstVar(invarp->fileline(), AstVarType::BLOCKTEMP, name, invarp); newvarp->funcLocal(false); newvarp->propagateAttrFrom(invarp); m_modp->addStmtp(newvarp); @@ -355,39 +348,38 @@ private: return newvscp; } - AstNode* createInlinedFTask(AstNodeFTaskRef* refp, - const string& namePrefix, AstVarScope* outvscp) { + AstNode* createInlinedFTask(AstNodeFTaskRef* refp, const string& namePrefix, + AstVarScope* outvscp) { // outvscp is the variable for functions only, if NULL, it's a task UASSERT_OBJ(refp->taskp(), refp, "Unlinked?"); AstNode* newbodysp = AstNode::cloneTreeNull(refp->taskp()->stmtsp(), true); // Maybe NULL - AstNode* beginp = new AstComment(refp->fileline(), - string("Function: ")+refp->name(), true); + AstNode* beginp + = new AstComment(refp->fileline(), string("Function: ") + refp->name(), true); if (newbodysp) beginp->addNext(newbodysp); - if (debug()>=9) { beginp->dumpTreeAndNext(cout, "-newbegi:"); } + if (debug() >= 9) beginp->dumpTreeAndNext(cout, "-newbegi:"); // // Create input variables AstNode::user2ClearTree(); V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp); - for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) { + for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { AstVar* portp = it->first; AstArg* argp = it->second; AstNode* pinp = argp->exprp(); - portp->unlinkFrBack(); pushDeletep(portp); // Remove it from the clone (not original) - if (pinp==NULL) { + portp->unlinkFrBack(); + pushDeletep(portp); // Remove it from the clone (not original) + if (!pinp) { // Too few arguments in function call } else { - UINFO(9, " Port "<unlinkFrBack(); // Relinked to assignment below VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); // Args no longer needed // if (portp->isWritable() && VN_IS(pinp, Const)) { - pinp->v3error("Function/task " - +portp->direction().prettyName() // e.g. "output" - +" connected to constant instead of variable: " - +portp->prettyNameQ()); - } - else if (portp->isInoutish()) { + pinp->v3error( + "Function/task " + portp->direction().prettyName() // e.g. "output" + + " connected to constant instead of variable: " + portp->prettyNameQ()); + } else if (portp->isInoutish()) { // Correct lvalue; see comments below V3LinkLValue::linkLValueSet(pinp); @@ -398,10 +390,11 @@ private: portp->user2p(localVscp); pushDeletep(pinp); } else { - pinp->v3warn(E_TASKNSVAR, "Unsupported: Function/task input argument is not simple variable"); + pinp->v3warn( + E_TASKNSVAR, + "Unsupported: Function/task input argument is not simple variable"); } - } - else if (portp->isWritable()) { + } else if (portp->isWritable()) { // Make output variables // Correct lvalue; we didn't know when we linked // This is slightly scary; are we sure no decisions were made @@ -412,24 +405,24 @@ private: // Even if it's referencing a varref, we still make a temporary // Else task(x,x,x) might produce incorrect results AstVarScope* tempvscp - = createVarScope(portp, namePrefix+"__"+portp->shortName()); + = createVarScope(portp, namePrefix + "__" + portp->shortName()); portp->user2p(tempvscp); AstAssign* assp = new AstAssign(pinp->fileline(), pinp, new AstVarRef(tempvscp->fileline(), tempvscp, false)); - assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block + assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, + true); // Ok if in <= block // Put assignment BEHIND of all other statements beginp->addNext(assp); - } - else if (portp->isNonOutput()) { + } else if (portp->isNonOutput()) { // Make input variable AstVarScope* inVscp - = createVarScope(portp, namePrefix+"__"+portp->shortName()); + = createVarScope(portp, namePrefix + "__" + portp->shortName()); portp->user2p(inVscp); - AstAssign* assp = new AstAssign(pinp->fileline(), - new AstVarRef(inVscp->fileline(), inVscp, true), - pinp); - assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block + AstAssign* assp = new AstAssign( + pinp->fileline(), new AstVarRef(inVscp->fileline(), inVscp, true), pinp); + assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, + true); // Ok if in <= block // Put assignment in FRONT of all other statements if (AstNode* afterp = beginp->nextp()) { afterp->unlinkFrBackWithNext(); @@ -442,15 +435,16 @@ private: UASSERT_OBJ(!refp->pinsp(), refp, "Pin wasn't removed by above loop"); { AstNode* nextstmtp; - for (AstNode* stmtp = beginp; stmtp; stmtp=nextstmtp) { + for (AstNode* stmtp = beginp; stmtp; stmtp = nextstmtp) { nextstmtp = stmtp->nextp(); if (AstVar* portp = VN_CAST(stmtp, Var)) { // Any I/O variables that fell out of above loop were already linked if (!portp->user2p()) { // Move it to a new localized variable - portp->unlinkFrBack(); pushDeletep(portp); // Remove it from the clone (not original) + portp->unlinkFrBack(); + pushDeletep(portp); // Remove it from the clone (not original) AstVarScope* localVscp - = createVarScope(portp, namePrefix+"__"+portp->shortName()); + = createVarScope(portp, namePrefix + "__" + portp->shortName()); portp->user2p(localVscp); } } @@ -458,7 +452,7 @@ private: } // Create function output variables if (outvscp) { - //UINFO(0, "setflag on "<fvarp()<<" to "<fvarp() << " to " << outvscp << endl); refp->taskp()->fvarp()->user2p(outvscp); } // Replace variable refs @@ -470,7 +464,7 @@ private: VL_DO_DANGLING(tempp->deleteTree(), tempp); } // - if (debug()>=9) { beginp->dumpTreeAndNext(cout, "-iotask: "); } + if (debug() >= 9) beginp->dumpTreeAndNext(cout, "-iotask: "); return beginp; } @@ -481,8 +475,8 @@ private: AstCFunc* cfuncp = m_statep->ftaskCFuncp(refp->taskp()); UASSERT_OBJ(cfuncp, refp, "No non-inline task associated with this task call?"); // - AstNode* beginp = new AstComment(refp->fileline(), - string("Function: ")+refp->name(), true); + AstNode* beginp + = new AstComment(refp->fileline(), string("Function: ") + refp->name(), true); AstNodeCCall* ccallp; if (AstNew* mrefp = VN_CAST(refp, New)) { AstCNew* cnewp = new AstCNew(refp->fileline(), cfuncp); @@ -500,31 +494,30 @@ private: // Convert complicated outputs to temp signals V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp()); - for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) { + for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { AstVar* portp = it->first; AstNode* pinp = it->second->exprp(); if (!pinp) { // Too few arguments in function call } else { - UINFO(9, " Port "<isWritable() && VN_IS(pinp, Const)) { - pinp->v3error("Function/task " - +portp->direction().prettyName() // e.g. "output" - +" connected to constant instead of variable: " - +portp->prettyNameQ()); - } - else if (portp->isInoutish()) { + pinp->v3error( + "Function/task " + portp->direction().prettyName() // e.g. "output" + + " connected to constant instead of variable: " + portp->prettyNameQ()); + } else if (portp->isInoutish()) { // Correct lvalue; see comments below V3LinkLValue::linkLValueSet(pinp); if (VN_IS(pinp, VarRef)) { // Connect to this exact variable } else { - pinp->v3warn(E_TASKNSVAR, "Unsupported: Function/task input argument is not simple variable"); + pinp->v3warn( + E_TASKNSVAR, + "Unsupported: Function/task input argument is not simple variable"); } - } - else if (portp->isWritable()) { + } else if (portp->isWritable()) { // Make output variables // Correct lvalue; we didn't know when we linked // This is slightly scary; are we sure no decisions were made @@ -559,14 +552,14 @@ private: ccallp->addArgsp(snp); // __Vfilenamep ccallp->addArgsp(new AstCMath(refp->fileline(), - "\""+refp->fileline()->filename()+"\"", 64, true)); + "\"" + refp->fileline()->filename() + "\"", 64, true)); // __Vlineno ccallp->addArgsp(new AstConst(refp->fileline(), refp->fileline()->lineno())); } // Create connections AstNode* nextpinp; - for (AstNode* pinp = refp->pinsp(); pinp; pinp=nextpinp) { + for (AstNode* pinp = refp->pinsp(); pinp; pinp = nextpinp) { nextpinp = pinp->nextp(); // Move pin to the CCall, removing all Arg's AstNode* exprp = VN_CAST(pinp, Arg)->exprp(); @@ -574,11 +567,9 @@ private: ccallp->addArgsp(exprp); } - if (outvscp) { - ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true)); - } + if (outvscp) ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true)); - if (debug()>=9) { beginp->dumpTreeAndNext(cout, "-nitask: "); } + if (debug() >= 9) beginp->dumpTreeAndNext(cout, "-nitask: "); return beginp; } @@ -589,12 +580,15 @@ private: if (nodep->pure()) dpiproto += "pure "; if (nodep->dpiContext()) dpiproto += "context "; dpiproto += rtnvarp ? rtnvarp->dpiArgType(true, true) : "void"; - dpiproto += " "+nodep->cname()+" ("; + dpiproto += " " + nodep->cname() + " ("; string args; - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (const AstVar* portp = VN_CAST(stmtp, Var)) { - if (portp->isIO() && !portp->isFuncReturn() && portp!=rtnvarp) { - if (args != "") { args+= ", "; dpiproto+= ", "; } + if (portp->isIO() && !portp->isFuncReturn() && portp != rtnvarp) { + if (args != "") { + args += ", "; + dpiproto += ", "; + } args += portp->name(); // Leftover so ,'s look nice if (nodep->dpiImport()) dpiproto += portp->dpiArgType(false, false); } @@ -605,7 +599,7 @@ private: } AstNode* createDpiTemp(AstVar* portp, const string& suffix) { - string stmt = portp->dpiArgType(false, true) + " " +portp->name()+suffix; + string stmt = portp->dpiArgType(false, true) + " " + portp->name() + suffix; if (!portp->basicp()->isDpiPrimitive()) { stmt += "[" + cvtToStr(portp->widthWords()) + "]"; } @@ -627,7 +621,7 @@ private: if (useSetWSvlv) { AstNode* linesp = new AstText(portp->fileline(), frstmt); linesp->addNext(new AstVarRef(portp->fileline(), portvscp, true)); - linesp->addNext(new AstText(portp->fileline(), ","+frName+");")); + linesp->addNext(new AstText(portp->fileline(), "," + frName + ");")); return new AstCStmt(portp->fileline(), linesp); } // Use a AstCMath, as we want V3Clean to mask off bits that don't make sense. @@ -639,18 +633,15 @@ private: cwidth = portp->basicp()->keyword().width(); } } - AstNode* newp = new AstAssign(portp->fileline(), - new AstVarRef(portp->fileline(), portvscp, true), - new AstSel(portp->fileline(), - new AstCMath(portp->fileline(), frstmt, cwidth, false), - 0, portp->width())); + AstNode* newp = new AstAssign( + portp->fileline(), new AstVarRef(portp->fileline(), portvscp, true), + new AstSel(portp->fileline(), new AstCMath(portp->fileline(), frstmt, cwidth, false), + 0, portp->width())); return newp; } void makeDpiExportWrapper(AstNodeFTask* nodep, AstVar* rtnvarp) { - AstCFunc* dpip = new AstCFunc(nodep->fileline(), - nodep->cname(), - m_scopep, + AstCFunc* dpip = new AstCFunc(nodep->fileline(), nodep->cname(), m_scopep, (rtnvarp ? rtnvarp->dpiArgType(true, true) : "")); dpip->dontCombine(true); dpip->entryPoint(true); @@ -672,42 +663,44 @@ private: // but the compare is only done on first call then memoized, so // it's not worth optimizing. string stmt; - stmt += "static int __Vfuncnum = -1;\n"; // Static doesn't need save-restore as if below will re-fill proper value + // Static doesn't need save-restore as if below will re-fill proper value + stmt += "static int __Vfuncnum = -1;\n"; // First time init (faster than what the compiler does if we did a singleton stmt += "if (VL_UNLIKELY(__Vfuncnum==-1)) { __Vfuncnum = Verilated::exportFuncNum(\"" - +nodep->cname()+"\"); }\n"; + + nodep->cname() + "\"); }\n"; // If the find fails, it will throw an error stmt += "const VerilatedScope* __Vscopep = Verilated::dpiScope();\n"; // If dpiScope is fails and is null; the exportFind function throws and error - string cbtype = VIdProtect::protect(v3Global.opt.prefix() - +"__Vcb_"+nodep->cname()+"_t"); - stmt += cbtype+" __Vcb = ("+cbtype+")(VerilatedScope::exportFind(__Vscopep, __Vfuncnum));\n"; // Can't use static_cast + string cbtype + = VIdProtect::protect(v3Global.opt.prefix() + "__Vcb_" + nodep->cname() + "_t"); + stmt += cbtype + " __Vcb = (" + cbtype + + ")(VerilatedScope::exportFind(__Vscopep, __Vfuncnum));\n"; // Can't use + // static_cast // If __Vcb is null the exportFind function throws and error dpip->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); } // Convert input/inout DPI arguments to Internal types string args; - args += ("("+EmitCBaseVisitor::symClassName() - +"*)(__Vscopep->symsp())"); // Upcast w/o overhead + args += ("(" + EmitCBaseVisitor::symClassName() + + "*)(__Vscopep->symsp())"); // Upcast w/o overhead AstNode* argnodesp = NULL; - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO() && !portp->isFuncReturn() && portp != rtnvarp) { // No createDpiTemp; we make a real internal variable instead // SAME CODE BELOW - args+= ", "; + args += ", "; if (args != "") { - argnodesp = argnodesp->addNext( - new AstText(portp->fileline(), args, true)); + argnodesp = argnodesp->addNext(new AstText(portp->fileline(), args, true)); args = ""; } - AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp); + AstVarScope* outvscp = createFuncVar(dpip, portp->name() + "__Vcvt", portp); // No information exposure; is already visible in import/export func template outvscp->varp()->protect(false); portp->protect(false); - AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, - portp->isWritable()); + AstVarRef* refp + = new AstVarRef(portp->fileline(), outvscp, portp->isWritable()); argnodesp = argnodesp->addNextNull(refp); if (portp->isNonOutput()) { @@ -723,12 +716,12 @@ private: if (rtnvarp) { AstVar* portp = rtnvarp; // SAME CODE ABOVE - args+= ", "; + args += ", "; if (args != "") { argnodesp = argnodesp->addNext(new AstText(portp->fileline(), args, true)); - args=""; + args = ""; } - AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp); + AstVarScope* outvscp = createFuncVar(dpip, portp->name() + "__Vcvt", portp); // No information exposure; is already visible in import/export func template outvscp->varp()->protect(false); AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isWritable()); @@ -742,13 +735,14 @@ private: stmt += "(*__Vcb)("; args += ");\n"; AstCStmt* newp = new AstCStmt(nodep->fileline(), stmt); - newp->addBodysp(argnodesp); VL_DANGLING(argnodesp); + newp->addBodysp(argnodesp); + VL_DANGLING(argnodesp); newp->addBodysp(new AstText(nodep->fileline(), args, true)); dpip->addStmtsp(newp); } // Convert output/inout arguments back to internal type - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO() && portp->isWritable() && !portp->isFuncReturn()) { dpip->addStmtsp(createAssignInternalToDpi(portp, true, "__Vcvt", "")); @@ -769,16 +763,13 @@ private: void makeDpiImportProto(AstNodeFTask* nodep, AstVar* rtnvarp) { if (nodep->cname() != AstNode::prettyName(nodep->cname())) { nodep->v3error("DPI function has illegal characters in C identifier name: " - <cname())); + << AstNode::prettyNameQ(nodep->cname())); } - AstCFunc* dpip = new AstCFunc(nodep->fileline(), - nodep->cname(), - m_scopep, + AstCFunc* dpip = new AstCFunc(nodep->fileline(), nodep->cname(), m_scopep, (rtnvarp ? rtnvarp->dpiArgType(true, true) - // Tasks (but not void functions) - // return bool indicating disabled - : nodep->dpiTask() ? "int" - : "")); + // Tasks (but not void functions) + // return bool indicating disabled + : nodep->dpiTask() ? "int" : "")); dpip->dontCombine(true); dpip->entryPoint(false); dpip->funcPublic(true); @@ -798,25 +789,24 @@ private: if (iter == m_dpiNames.end()) { m_dpiNames.insert(make_pair(nodep->cname(), make_pair(nodep, dpiproto))); return false; - } - else if (iter->second.second != dpiproto) { - nodep->v3error("Duplicate declaration of DPI function with different formal arguments: " - <prettyNameQ()<warnContextPrimary()<warnMore()<<"... New prototype: "<second.first->warnOther()<<"... Original prototype: " - <second.second<second.first->warnContextSecondary()); + } else if (iter->second.second != dpiproto) { + nodep->v3error( + "Duplicate declaration of DPI function with different formal arguments: " + << nodep->prettyNameQ() << endl + << nodep->warnContextPrimary() << endl + << nodep->warnMore() << "... New prototype: " << dpiproto << endl + << iter->second.first->warnOther() + << "... Original prototype: " << iter->second.second << endl + << iter->second.first->warnContextSecondary()); return true; - } - else { + } else { return true; } } void makePortList(AstNodeFTask* nodep, AstCFunc* dpip) { // Copy nodep's list of function I/O to the new dpip c function - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO()) { // Move it to new function @@ -824,9 +814,11 @@ private: newPortp->funcLocal(true); dpip->addArgsp(newPortp); if (!portp->basicp()) { - portp->v3error("Unsupported: DPI argument of type " - <basicp()->prettyTypeName()<warnMore()<<"... For best portability, use bit, byte, int, or longint"); + portp->v3error( + "Unsupported: DPI argument of type " + << portp->basicp()->prettyTypeName() << endl + << portp->warnMore() + << "... For best portability, use bit, byte, int, or longint"); // We don't warn on logic either, although the 4-stateness is lost. // That's what other simulators do. } @@ -838,41 +830,41 @@ private: void bodyDpiImportFunc(AstNodeFTask* nodep, AstVarScope* rtnvscp, AstCFunc* cfuncp) { // Convert input/inout arguments to DPI types string args; - for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { - AstVarScope* portvscp = VN_CAST(portp->user2p(), VarScope); // Remembered when we created it earlier + AstVarScope* portvscp + = VN_CAST(portp->user2p(), VarScope); // Remembered when we created it earlier if (portp->isIO() && !portp->isFuncReturn() && portvscp != rtnvscp && portp->name() != "__Vscopep" // Passed to dpiContext, not callee - && portp->name() != "__Vfilenamep" - && portp->name() != "__Vlineno") { + && portp->name() != "__Vfilenamep" && portp->name() != "__Vlineno") { - if (args != "") { args+= ", "; } + if (args != "") args += ", "; if (portp->isDpiOpenArray()) { // Ideally we'd make a table of variable // characteristics, and reuse it wherever we can // At least put them into the module's CTOR as static? - string propName = portp->name()+"__Vopenprops"; - string propCode = ("static const VerilatedVarProps "+propName - +"("+portp->vlPropInit()+");\n"); + string propName = portp->name() + "__Vopenprops"; + string propCode = ("static const VerilatedVarProps " + propName + "(" + + portp->vlPropInit() + ");\n"); cfuncp->addStmtsp(new AstCStmt(portp->fileline(), propCode)); // // At runtime we need the svOpenArrayHandle to // point to this task & thread's data, in addition // to static info about the variable - string name = portp->name()+"__Vopenarray"; - string varCode = ("VerilatedDpiOpenVar " - // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - +name+" (&"+propName+", &"+portp->name()+");\n"); + string name = portp->name() + "__Vopenarray"; + string varCode + = ("VerilatedDpiOpenVar " + // NOLINTNEXTLINE(performance-inefficient-string-concatenation) + + name + " (&" + propName + ", &" + portp->name() + ");\n"); cfuncp->addStmtsp(new AstCStmt(portp->fileline(), varCode)); - args += "&"+name; - } - else { + args += "&" + name; + } else { if (portp->isWritable() && portp->basicp()->isDpiPrimitive()) { args += "&"; } - args += portp->name()+"__Vcvt"; + args += portp->name() + "__Vcvt"; cfuncp->addStmtsp(createDpiTemp(portp, "__Vcvt")); if (portp->isNonOutput()) { @@ -897,17 +889,18 @@ private: stmt = rtnvscp->varp()->name() + "__Vcvt"; stmt += rtnvscp->varp()->basicp()->isDpiPrimitive() ? " = " : "[0] = "; } - stmt += nodep->cname()+"("+args+");\n"; + stmt += nodep->cname() + "(" + args + ");\n"; cfuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); } // Convert output/inout arguments back to internal type - for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { portp->protect(false); // No additional exposure - already part of shown proto if (portp->isIO() && (portp->isWritable() || portp->isFuncReturn()) && !portp->isDpiOpenArray()) { - AstVarScope* portvscp = VN_CAST(portp->user2p(), VarScope); // Remembered when we created it earlier + AstVarScope* portvscp = VN_CAST( + portp->user2p(), VarScope); // Remembered when we created it earlier cfuncp->addStmtsp( createAssignDpiToInternal(portvscp, portp->name() + "__Vcvt")); } @@ -953,7 +946,8 @@ private: portp->unlinkFrBack(); rtnvarp = portp; rtnvarp->funcLocal(true); - rtnvarp->name(rtnvarp->name()+"__Vfuncrtn"); // Avoid conflict with DPI function name + rtnvarp->name(rtnvarp->name() + + "__Vfuncrtn"); // Avoid conflict with DPI function name if (nodep->dpiImport() || nodep->dpiExport()) rtnvarp->protect(false); } @@ -961,12 +955,9 @@ private: if (nodep->dpiOpenChild()) { // The parent will make the dpi proto UASSERT_OBJ(!nodep->dpiOpenParent(), nodep, "DPI task should be parent or wrapper, not both"); - } - else { // Parent or not open child, make wrapper + } else { // Parent or not open child, make wrapper string dpiproto = dpiprotoName(nodep, rtnvarp); - if (!duplicatedDpiProto(nodep, dpiproto)) { - makeDpiImportProto(nodep, rtnvarp); - } + if (!duplicatedDpiProto(nodep, dpiproto)) makeDpiImportProto(nodep, rtnvarp); if (nodep->dpiOpenParent()) { // No need to make more than just the c prototype, children will VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -976,9 +967,7 @@ private: } else if (nodep->dpiExport()) { string dpiproto = dpiprotoName(nodep, rtnvarp); - if (!duplicatedDpiProto(nodep, dpiproto)) { - makeDpiExportWrapper(nodep, rtnvarp); - } + if (!duplicatedDpiProto(nodep, dpiproto)) makeDpiExportWrapper(nodep, rtnvarp); } AstVarScope* rtnvscp = NULL; @@ -989,21 +978,21 @@ private: } string prefix; - if (nodep->dpiImport()) prefix = "__Vdpiimwrap_"; - else if (nodep->dpiExport()) prefix = "__Vdpiexp_"; - else if (ftaskNoInline) prefix = "__VnoInFunc_"; + if (nodep->dpiImport()) { + prefix = "__Vdpiimwrap_"; + } else if (nodep->dpiExport()) { + prefix = "__Vdpiexp_"; + } else if (ftaskNoInline) { + prefix = "__VnoInFunc_"; + } // Unless public, v3Descope will not uniquify function names even if duplicate per-scope, // so make it unique now. string suffix; // So, make them unique - if (!nodep->taskPublic()) suffix = "_"+m_scopep->nameDotless(); - string name = ((nodep->name() == "new") ? "new" - : prefix + nodep->name() + suffix); - AstCFunc* cfuncp = new AstCFunc(nodep->fileline(), - name, - m_scopep, - ((nodep->taskPublic() && rtnvarp) - ? rtnvarp->cPubArgType(true, true) - : "")); + if (!nodep->taskPublic()) suffix = "_" + m_scopep->nameDotless(); + string name = ((nodep->name() == "new") ? "new" : prefix + nodep->name() + suffix); + AstCFunc* cfuncp = new AstCFunc( + nodep->fileline(), name, m_scopep, + ((nodep->taskPublic() && rtnvarp) ? rtnvarp->cPubArgType(true, true) : "")); // It's ok to combine imports because this is just a wrapper; // duplicate wrappers can get merged. cfuncp->dontCombine(!nodep->dpiImport()); @@ -1014,7 +1003,7 @@ private: cfuncp->isStatic(!(nodep->dpiImport() || nodep->taskPublic() || nodep->classMethod())); cfuncp->pure(nodep->pure()); cfuncp->isConstructor(nodep->name() == "new"); - //cfuncp->dpiImport // Not set in the wrapper - the called function has it set + // cfuncp->dpiImport // Not set in the wrapper - the called function has it set if (cfuncp->dpiExport()) cfuncp->cname(nodep->cname()); bool needSyms = !nodep->dpiImport(); @@ -1022,9 +1011,8 @@ private: if (nodep->taskPublic()) { // We need to get a pointer to all of our variables (may // have eval'ed something else earlier) - cfuncp->addInitsp( - new AstCStmt(nodep->fileline(), - EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n")); + cfuncp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symClassVar() + + " = this->__VlSymsp;\n")); } else { // Need symbol table cfuncp->argTypes(EmitCBaseVisitor::symClassVar()); @@ -1042,20 +1030,21 @@ private: } if (!nodep->dpiImport()) { - cfuncp->addInitsp(new AstCStmt(nodep->fileline(), - EmitCBaseVisitor::symTopAssign()+"\n")); + cfuncp->addInitsp( + new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign() + "\n")); } if (nodep->dpiExport()) { AstScopeName* snp = nodep->scopeNamep(); UASSERT_OBJ(snp, nodep, "Missing scoping context"); - snp->dpiExport(true); // The AstScopeName is really a statement(ish) for tracking, not a function + snp->dpiExport( + true); // The AstScopeName is really a statement(ish) for tracking, not a function snp->unlinkFrBack(); cfuncp->addInitsp(snp); } // Create list of arguments and move to function - for (AstNode* nextp, *stmtp = nodep->stmtsp(); stmtp; stmtp = nextp) { + for (AstNode *nextp, *stmtp = nodep->stmtsp(); stmtp; stmtp = nextp) { nextp = stmtp->nextp(); if (AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO()) { @@ -1081,10 +1070,11 @@ private: // Move body AstNode* bodysp = nodep->stmtsp(); - if (bodysp) { bodysp->unlinkFrBackWithNext(); cfuncp->addStmtsp(bodysp); } - if (nodep->dpiImport()) { - bodyDpiImportFunc(nodep, rtnvscp, cfuncp); + if (bodysp) { + bodysp->unlinkFrBackWithNext(); + cfuncp->addStmtsp(bodysp); } + if (nodep->dpiImport()) bodyDpiImportFunc(nodep, rtnvscp, cfuncp); // Return statement if (rtnvscp && nodep->taskPublic()) { @@ -1101,7 +1091,7 @@ private: } // Delete rest of cloned task and return new func VL_DO_DANGLING(pushDeletep(nodep), nodep); - if (debug()>=9) { cfuncp->dumpTree(cout, "-userFunc: "); } + if (debug() >= 9) cfuncp->dumpTree(cout, "-userFunc: "); return cfuncp; } @@ -1120,27 +1110,24 @@ private: AstNode* insertBeforeStmt(AstNode* nodep, AstNode* newp) { // Return node that must be visited, if any // See also AstNode::addBeforeStmt; this predates that function - if (debug()>=9) { nodep->dumpTree(cout, "-newstmt:"); } + if (debug() >= 9) nodep->dumpTree(cout, "-newstmt:"); UASSERT_OBJ(m_insStmtp, nodep, "Function not underneath a statement"); AstNode* visitp = NULL; if (m_insMode == IM_BEFORE) { // Add the whole thing before insertAt - UINFO(5," IM_Before "<=9) { newp->dumpTree(cout, "-newfunc:"); } + UINFO(5, " IM_Before " << m_insStmtp << endl); + if (debug() >= 9) newp->dumpTree(cout, "-newfunc:"); m_insStmtp->addHereThisAsNext(newp); - } - else if (m_insMode == IM_AFTER) { - UINFO(5," IM_After "<addNextHere(newp); - } - else if (m_insMode == IM_WHILE_PRECOND) { - UINFO(5," IM_While_Precond "<addPrecondsp(newp); visitp = newp; - } - else { + } else { nodep->v3fatalSrc("Unknown InsertMode"); } m_insMode = IM_AFTER; @@ -1175,17 +1162,17 @@ private: // Includes handling AstMethodCall, AstNew UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked?"); iterateIntoFTask(nodep->taskp()); // First, do hierarchical funcs - UINFO(4," FTask REF "<=9) { nodep->dumpTree(cout, "-inlfunc:"); } + UINFO(4, " FTask REF " << nodep << endl); + if (debug() >= 9) nodep->dumpTree(cout, "-inlfunc:"); UASSERT_OBJ(m_scopep, nodep, "func ref not under scope"); - string namePrefix = ((VN_IS(nodep, FuncRef) ? "__Vfunc_":"__Vtask_") - +nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++)); + string namePrefix = ((VN_IS(nodep, FuncRef) ? "__Vfunc_" : "__Vtask_") + + nodep->taskp()->shortName() + "__" + cvtToStr(m_modNCalls++)); // Create output variable AstVarScope* outvscp = NULL; if (nodep->taskp()->isFunction()) { // Not that it's a FUNCREF, but that we're calling a function (perhaps as a task) - outvscp = createVarScope(VN_CAST(nodep->taskp()->fvarp(), Var), - namePrefix+"__Vfuncout"); + outvscp + = createVarScope(VN_CAST(nodep->taskp()->fvarp(), Var), namePrefix + "__Vfuncout"); } // Create cloned statements AstNode* beginp; @@ -1211,8 +1198,9 @@ private: visitp = insertBeforeStmt(nodep, beginp); } else { if (nodep->taskp()->isFunction()) { - nodep->v3warn(IGNOREDRETURN, - "Ignoring return value of non-void function (IEEE 1800-2017 13.4.1)"); + nodep->v3warn( + IGNOREDRETURN, + "Ignoring return value of non-void function (IEEE 1800-2017 13.4.1)"); } // outvscp maybe non-NULL if calling a function in a taskref, // but if so we want to simply ignore the function result @@ -1220,12 +1208,12 @@ private: } // Cleanup VL_DO_DANGLING(nodep->deleteTree(), nodep); - UINFO(4," FTask REF Done.\n"); + UINFO(4, " FTask REF Done.\n"); // Visit nodes that normal iteration won't find if (visitp) iterateAndNextNull(visitp); } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { - UINFO(4," Inline "<isFunction()) { if (AstVar* portp = VN_CAST(nodep->fvarp(), Var)) { AstVarScope* vscp = m_statep->findVarScope(m_scopep, portp); - UINFO(9," funcremovevsc "<unlinkFrBack()), vscp); } } - for (AstNode* nextp, *stmtp = nodep->stmtsp(); stmtp; stmtp = nextp) { + for (AstNode *nextp, *stmtp = nodep->stmtsp(); stmtp; stmtp = nextp) { nextp = stmtp->nextp(); if (AstVar* portp = VN_CAST(stmtp, Var)) { AstVarScope* vscp = m_statep->findVarScope(m_scopep, portp); - UINFO(9," funcremovevsc "<unlinkFrBack()), vscp); } } @@ -1309,7 +1297,8 @@ private: m_insStmtp = NULL; // Next thing should be new statement } virtual void visit(AstNodeFor* nodep) VL_OVERRIDE { - nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin.cpp"); + nodep->v3fatalSrc( + "For statements should have been converted to while statements in V3Begin.cpp"); } virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE { if (!nodep->isStatement()) { @@ -1386,14 +1375,14 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) NameToIndex::iterator it = nameToIndex.find(argp->name()); if (it == nameToIndex.end()) { pinp->v3error("No such argument " << argp->prettyNameQ() << " in function call to " - << nodep->taskp()->prettyTypeName()); + << nodep->taskp()->prettyTypeName()); // We'll just delete it; seems less error prone than making a false argument VL_DO_DANGLING(pinp->unlinkFrBack()->deleteTree(), pinp); } else { if (tconnects[it->second].second) { pinp->v3error("Duplicate argument " << argp->prettyNameQ() - << " in function call to " - << nodep->taskp()->prettyTypeName()); + << " in function call to " + << nodep->taskp()->prettyTypeName()); } argp->name(""); // Can forget name as will add back in pin order tconnects[it->second].second = argp; @@ -1487,16 +1476,15 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) return tconnects; } -string V3Task::assignInternalToDpi(AstVar* portp, bool isPtr, - const string& frSuffix, const string& toSuffix, - const string& frPrefix) { +string V3Task::assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, + const string& toSuffix, const string& frPrefix) { // Create assignment from internal format into DPI temporary string stmt; string ket; // Someday we'll have better type support, and this can make variables and casts. // But for now, we'll just text-bash it. - string frName = frPrefix+portp->name()+frSuffix; - string toName = portp->name()+toSuffix; + string frName = frPrefix + portp->name() + frSuffix; + string toName = portp->name() + toSuffix; if (portp->basicp()->isDpiBitVec()) { stmt += ("VL_SET_SVBV_" + string(portp->dtypep()->charIQWN()) + "(" + cvtToStr(portp->width()) + ", " + toName + ", " + frName + ")"); @@ -1505,13 +1493,13 @@ string V3Task::assignInternalToDpi(AstVar* portp, bool isPtr, + cvtToStr(portp->width()) + ", " + toName + ", " + frName + ")"); } else { if (isPtr) stmt += "*"; // DPI outputs are pointers - stmt += toName+" = "; - if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) { + stmt += toName + " = "; + if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE) { stmt += "VL_CVT_Q_VP("; ket += ")"; } stmt += frName; - if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING) { + if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING) { stmt += ".c_str()"; } } @@ -1520,8 +1508,8 @@ string V3Task::assignInternalToDpi(AstVar* portp, bool isPtr, } bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt) { - if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) { - frstmt = "VL_CVT_VP_Q("+frName+")"; + if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE) { + frstmt = "VL_CVT_VP_Q(" + frName + ")"; } else if ((portp->basicp() && portp->basicp()->isDpiPrimitive())) { frstmt = frName; } else { @@ -1539,10 +1527,10 @@ bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& fr } void V3Task::taskAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 39602289f..76e125592 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -551,7 +551,7 @@ private: // Assign trace code, add to tree, return node for change tree or null // Look for identical copies uint32_t codePreassigned = 0; - // if (debug()>=9) nodep->dumpTree(cout, "- assnnode: "); + // if (debug() >= 9) nodep->dumpTree(cout, "- assnnode: "); // Find non-duplicated node; note some nodep's maybe null, as they were deleted below TraceTraceVertex* dupvertexp = vvertexp; if (dupvertexp->duplicatep()) { diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 4886e99d6..c2c0e8436 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -82,28 +82,29 @@ public: // Graph support classes class TristateVertex : public V3GraphVertex { - AstNode* m_nodep; - bool m_isTristate; // Logic indicates a tristate - bool m_feedsTri; // Propagates to a tristate node (on RHS) - bool m_processed; // Tristating was cleaned up + AstNode* m_nodep; + bool m_isTristate; // Logic indicates a tristate + bool m_feedsTri; // Propagates to a tristate node (on RHS) + bool m_processed; // Tristating was cleaned up public: TristateVertex(V3Graph* graphp, AstNode* nodep) : V3GraphVertex(graphp) - , m_nodep(nodep), m_isTristate(false), m_feedsTri(false), m_processed(false) {} + , m_nodep(nodep) + , m_isTristate(false) + , m_feedsTri(false) + , m_processed(false) {} virtual ~TristateVertex() {} // ACCESSORS AstNode* nodep() const { return m_nodep; } AstVar* varp() const { return VN_CAST(nodep(), Var); } virtual string name() const { - return ((isTristate() ? "tri\\n" - : feedsTri() ? "feed\\n" : "-\\n") - +(nodep()->prettyTypeName()+" "+cvtToHex(nodep()))); } + return ((isTristate() ? "tri\\n" : feedsTri() ? "feed\\n" : "-\\n") + + (nodep()->prettyTypeName() + " " + cvtToHex(nodep()))); + } virtual string dotColor() const { - return (varp() - ? (isTristate() ? "darkblue" - :feedsTri() ? "blue" : "lightblue") - : (isTristate() ? "darkgreen" - :feedsTri() ? "green" : "lightgreen")); } + return (varp() ? (isTristate() ? "darkblue" : feedsTri() ? "blue" : "lightblue") + : (isTristate() ? "darkgreen" : feedsTri() ? "green" : "lightgreen")); + } virtual FileLine* fileline() const { return nodep()->fileline(); } void isTristate(bool flag) { m_isTristate = flag; } bool isTristate() const { return m_isTristate; } @@ -118,13 +119,13 @@ public: class TristateGraph { // NODE STATE // AstVar::user5p -> TristateVertex* for variable being built - //AstUser5InUse m_inuser5; // In visitor below + // AstUser5InUse m_inuser5; // In visitor below // TYPES public: typedef std::vector VarVec; -private: +private: // MEMBERS V3Graph m_graph; // Logic graph @@ -141,7 +142,7 @@ private: TristateVertex* makeVertex(AstNode* nodep) { TristateVertex* vertexp = reinterpret_cast(nodep->user5p()); if (!vertexp) { - UINFO(6," New vertex "<user5p(vertexp); } @@ -156,21 +157,21 @@ private: if (!vtxp->isTristate()) return; // tristate involved if (vtxp->user() == 1) return; vtxp->user(1); // Recursed - UINFO(9," Mark tri "<varp()) { // not a var where we stop the recursion - for (V3GraphEdge* edgep = vtxp->outBeginp(); edgep; edgep=edgep->outNextp()) { + for (V3GraphEdge* edgep = vtxp->outBeginp(); edgep; edgep = edgep->outNextp()) { TristateVertex* vvertexp = dynamic_cast(edgep->top()); // Doesn't hurt to not check if already set, but by doing so when we // print out the debug messages, we'll see this node at level 0 instead. if (!vvertexp->isTristate()) { vvertexp->isTristate(true); - graphWalkRecurseFwd(vvertexp, level+1); + graphWalkRecurseFwd(vvertexp, level + 1); } } } else { // A variable is tristated. Find all of the LHS VARREFs that // drive this signal now need tristate drivers - for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { TristateVertex* vvertexp = dynamic_cast(edgep->fromp()); if (const AstVarRef* refp = VN_CAST(vvertexp->nodep(), VarRef)) { if (refp->lvalue() @@ -178,7 +179,7 @@ private: // print out the debug messages, we'll see this node at level 0 instead. && !vvertexp->isTristate()) { vvertexp->isTristate(true); - graphWalkRecurseFwd(vvertexp, level+1); + graphWalkRecurseFwd(vvertexp, level + 1); } } } @@ -193,15 +194,15 @@ private: if (!(vtxp->isTristate() || vtxp->feedsTri())) return; // tristate involved if (vtxp->user() == 3) return; vtxp->user(3); // Recursed - UINFO(9," Mark feedstri "<varp()) { // not a var where we stop the recursion - for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep=edgep->inNextp()) { + for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { TristateVertex* vvertexp = dynamic_cast(edgep->fromp()); // Doesn't hurt to not check if already set, but by doing so when we // print out the debug messages, we'll see this node at level 0 instead. if (!vvertexp->feedsTri()) { vvertexp->feedsTri(true); - graphWalkRecurseBack(vvertexp, level+1); + graphWalkRecurseBack(vvertexp, level + 1); } } } @@ -211,32 +212,30 @@ public: // METHODS bool empty() const { return m_graph.empty(); } void clear() { - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { TristateVertex* vvertexp = static_cast(itp); if (vvertexp->isTristate() && !vvertexp->processed()) { // Not v3errorSrc as no reason to stop the world vvertexp->nodep()->v3error("Unsupported tristate construct" " (in graph; not converted): " - <nodep()->prettyTypeName()); + << vvertexp->nodep()->prettyTypeName()); } } m_graph.clear(); AstNode::user5ClearTree(); // Wipe all node user5p's that point to vertexes } void graphWalk(AstNodeModule* nodep) { - //if (debug()>=9) m_graph.dumpDotFilePrefixed("tri_pre__"+nodep->name()); - UINFO(9," Walking "<verticesNextp()) { + // if (debug() >= 9) m_graph.dumpDotFilePrefixed("tri_pre__" + nodep->name()); + UINFO(9, " Walking " << nodep << endl); + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { graphWalkRecurseFwd(static_cast(itp), 0); } - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { graphWalkRecurseBack(static_cast(itp), 0); } - if (debug()>=9) m_graph.dumpDotFilePrefixed("tri_pos__"+nodep->name()); - } - void setTristate(AstNode* nodep) { - makeVertex(nodep)->isTristate(true); + if (debug() >= 9) m_graph.dumpDotFilePrefixed("tri_pos__" + nodep->name()); } + void setTristate(AstNode* nodep) { makeVertex(nodep)->isTristate(true); } void associate(AstNode* fromp, AstNode* top) { new V3GraphEdge(&m_graph, makeVertex(fromp), makeVertex(top), 1); } @@ -253,7 +252,7 @@ public: if (!vertexp) { // Not v3errorSrc as no reason to stop the world nodep->v3error("Unsupported tristate construct (not in propagation graph): " - <prettyTypeName()); + << nodep->prettyTypeName()); } else { // We don't warn if no vertexp->isTristate() as the creation // process makes midling nodes that don't have it set @@ -264,12 +263,10 @@ public: VarVec tristateVars() { // Return all tristate variables VarVec v; - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { + for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { TristateVertex* vvertexp = static_cast(itp); if (vvertexp->isTristate()) { - if (AstVar* nodep = VN_CAST(vvertexp->nodep(), Var)) { - v.push_back(nodep); - } + if (AstVar* nodep = VN_CAST(vvertexp->nodep(), Var)) v.push_back(nodep); } } return v; @@ -286,13 +283,13 @@ class TristatePinVisitor : public TristateBaseVisitor { // VISITORS virtual void visit(AstVarRef* nodep) VL_OVERRIDE { if (m_lvalue && !nodep->lvalue()) { - UINFO(9," Flip-to-LValue "<lvalue(true); } else if (!m_lvalue && nodep->lvalue()) { - UINFO(9," Flip-to-RValue "<lvalue(false); // Mark the ex-output as tristated - UINFO(9," setTristate-subpin "<varp()<varp() << endl); m_tgraph.setTristate(nodep->varp()); } } @@ -311,7 +308,8 @@ class TristatePinVisitor : public TristateBaseVisitor { public: // CONSTRUCTORS TristatePinVisitor(AstNode* nodep, TristateGraph& tgraph, bool lvalue) - : m_tgraph(tgraph), m_lvalue(lvalue) { + : m_tgraph(tgraph) + , m_lvalue(lvalue) { iterate(nodep); } virtual ~TristatePinVisitor() {} @@ -328,43 +326,43 @@ class TristateVisitor : public TristateBaseVisitor { // See TristateGraph: // AstVar::user5p -> TristateVertex* for variable being built // AstStmt*::user5p -> TristateVertex* for this statement - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser3InUse m_inuser3; - AstUser4InUse m_inuser4; - AstUser5InUse m_inuser5; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; + AstUser3InUse m_inuser3; + AstUser4InUse m_inuser4; + AstUser5InUse m_inuser5; // TYPES typedef std::vector RefVec; typedef std::map VarMap; - enum { U2_GRAPHING=1, // bit[0] if did m_graphing visit - U2_NONGRAPH=2, // bit[1] if did !m_graphing visit - U2_BOTH=3 }; // Both bits set + enum { + U2_GRAPHING = 1, // bit[0] if did m_graphing visit + U2_NONGRAPH = 2, // bit[1] if did !m_graphing visit + U2_BOTH = 3 + }; // Both bits set // MEMBERS - bool m_graphing; // Major mode - creating graph + bool m_graphing; // Major mode - creating graph // - AstNodeModule* m_modp; // Current module - AstCell* m_cellp; // current cell - VarMap m_lhsmap; // LHS driver map - int m_unique; - bool m_alhs; // On LHS of assignment - AstNode* m_logicp; // Current logic being built - TristateGraph m_tgraph; // Logic graph + AstNodeModule* m_modp; // Current module + AstCell* m_cellp; // current cell + VarMap m_lhsmap; // LHS driver map + int m_unique; + bool m_alhs; // On LHS of assignment + AstNode* m_logicp; // Current logic being built + TristateGraph m_tgraph; // Logic graph // STATS VDouble0 m_statTriSigs; // stat tracking // METHODS string dbgState() { - string o = (m_graphing?" gr ":" ng "); + string o = (m_graphing ? " gr " : " ng "); if (m_alhs) o += "alhs "; return o; } void associateLogic(AstNode* fromp, AstNode* top) { - if (m_logicp) { - m_tgraph.associate(fromp, top); - } + if (m_logicp) m_tgraph.associate(fromp, top); } AstNode* getEnp(AstNode* nodep) { // checks if user1p() is null, and if so, adds a constant output @@ -381,14 +379,15 @@ class TristateVisitor : public TristateBaseVisitor { AstVar* getCreateEnVarp(AstVar* invarp) { // Return the master __en for the specified input variable if (!invarp->user1p()) { - AstVar* newp = new AstVar(invarp->fileline(), - AstVarType::MODULETEMP, - invarp->name()+"__en", - invarp); - UINFO(9," newenv "<v3error("Unsupported: Creating tristate signal not underneath a module: " - <prettyNameQ()); } - else m_modp->addStmtp(newp); + AstVar* newp = new AstVar(invarp->fileline(), AstVarType::MODULETEMP, + invarp->name() + "__en", invarp); + UINFO(9, " newenv " << newp << endl); + if (!m_modp) { + invarp->v3error("Unsupported: Creating tristate signal not underneath a module: " + << invarp->prettyNameQ()); + } else { + m_modp->addStmtp(newp); + } invarp->user1p(newp); // find envar given invarp } return VN_CAST(invarp->user1p(), Var); @@ -397,34 +396,36 @@ class TristateVisitor : public TristateBaseVisitor { AstVar* getCreateOutVarp(AstVar* invarp) { // Return the master __out for the specified input variable if (!invarp->user4p()) { - AstVar* newp = new AstVar(invarp->fileline(), - AstVarType::MODULETEMP, - invarp->name()+"__out", - invarp); - UINFO(9," newout "<v3error("Unsupported: Creating tristate signal not underneath a module: " - <prettyNameQ()); } - else m_modp->addStmtp(newp); + AstVar* newp = new AstVar(invarp->fileline(), AstVarType::MODULETEMP, + invarp->name() + "__out", invarp); + UINFO(9, " newout " << newp << endl); + if (!m_modp) { + invarp->v3error("Unsupported: Creating tristate signal not underneath a module: " + << invarp->prettyNameQ()); + } else { + m_modp->addStmtp(newp); + } invarp->user4p(newp); // find outvar given invarp } return VN_CAST(invarp->user4p(), Var); } AstVar* getCreateUnconnVarp(AstNode* fromp, AstNodeDType* dtypep) { - AstVar* newp = new AstVar(fromp->fileline(), - AstVarType::MODULETEMP, - "__Vtriunconn"+cvtToStr(m_unique++), - dtypep); - UINFO(9," newunc "<v3error("Unsupported: Creating tristate signal not underneath a module"); } - else m_modp->addStmtp(newp); + AstVar* newp = new AstVar(fromp->fileline(), AstVarType::MODULETEMP, + "__Vtriunconn" + cvtToStr(m_unique++), dtypep); + UINFO(9, " newunc " << newp << endl); + if (!m_modp) { + newp->v3error("Unsupported: Creating tristate signal not underneath a module"); + } else { + m_modp->addStmtp(newp); + } return newp; } void mapInsertLhsVarRef(AstVarRef* nodep) { AstVar* key = nodep->varp(); VarMap::iterator it = m_lhsmap.find(key); - UINFO(9," mapInsertLhsVarRef "<push_back(nodep); @@ -438,11 +439,8 @@ class TristateVisitor : public TristateBaseVisitor { // Form a "deposit" instruction for given enable, using existing select as a template. // Would be nicer if we made this a new AST type AstNode* newp = new AstShiftL(selp->fileline(), - new AstExtend(selp->fileline(), - enp, - selp->fromp()->width()), - selp->lsbp()->cloneTree(false), - selp->fromp()->width()); + new AstExtend(selp->fileline(), enp, selp->fromp()->width()), + selp->lsbp()->cloneTree(false), selp->fromp()->width()); return newp; } @@ -453,9 +451,9 @@ class TristateVisitor : public TristateBaseVisitor { } else { if (oldpullp->direction() != pullp->direction()) { pullp->v3error("Unsupported: Conflicting pull directions.\n" - <warnContextPrimary()<warnOther()<<"... Location of conflicting pull.\n" - <warnContextSecondary()); + << pullp->warnContextPrimary() << endl + << oldpullp->warnOther() << "... Location of conflicting pull.\n" + << oldpullp->warnContextSecondary()); } } } @@ -465,14 +463,14 @@ class TristateVisitor : public TristateBaseVisitor { // The best way would be to visit the tree again and find any user1p() // pointers that did not get picked up and expanded. if (m_alhs && nodep->user1p()) { - nodep->v3error("Unsupported LHS tristate construct: "<prettyTypeName()); + nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName()); } // Ignore Var's because they end up adjacent to statements if ((nodep->op1p() && nodep->op1p()->user1p() && !VN_IS(nodep->op1p(), Var)) || (nodep->op2p() && nodep->op2p()->user1p() && !VN_IS(nodep->op1p(), Var)) || (nodep->op3p() && nodep->op3p()->user1p() && !VN_IS(nodep->op1p(), Var)) || (nodep->op4p() && nodep->op4p()->user1p() && !VN_IS(nodep->op1p(), Var))) { - nodep->v3error("Unsupported tristate construct: "<prettyTypeName()); + nodep->v3error("Unsupported tristate construct: " << nodep->prettyTypeName()); } } @@ -488,14 +486,14 @@ class TristateVisitor : public TristateBaseVisitor { if (it == m_lhsmap.end()) { // set output enable to always be off on this assign // statement so that this var is floating - UINFO(8," Adding driver to var "<fileline(), - AstConst::WidthedValue(), varp->width(), 0); + UINFO(8, " Adding driver to var " << varp << endl); + AstConst* constp = new AstConst(varp->fileline(), AstConst::WidthedValue(), + varp->width(), 0); AstVarRef* varrefp = new AstVarRef(varp->fileline(), varp, true); AstNode* newp = new AstAssignW(varp->fileline(), varrefp, constp); - UINFO(9," newoev "<user1p(new AstConst(varp->fileline(), - AstConst::WidthedValue(), varp->width(), 0)); + UINFO(9, " newoev " << newp << endl); + varrefp->user1p(new AstConst(varp->fileline(), AstConst::WidthedValue(), + varp->width(), 0)); nodep->addStmtp(newp); mapInsertLhsVarRef(varrefp); // insertTristates will convert // // to a varref to the __out# variable @@ -507,7 +505,8 @@ class TristateVisitor : public TristateBaseVisitor { // enable logic for any tristates. // Note there might not be any drivers. for (VarMap::iterator nextit, it = m_lhsmap.begin(); it != m_lhsmap.end(); it = nextit) { - nextit = it; ++nextit; + nextit = it; + ++nextit; AstVar* invarp = it->first; RefVec* refsp = it->second; @@ -539,14 +538,15 @@ class TristateVisitor : public TristateBaseVisitor { outvarp = getCreateOutVarp(invarp); outvarp->varType2Out(); lhsp = outvarp; // Must assign to __out, not to normal input signal - UINFO(9, " TRISTATE propagates up with "<varType2Out(); // outvarp->user1p(envarp); outvarp->user3p(invarp->user3p()); // AstPull* propagation - if (invarp->user3p()) UINFO(9, "propagate pull to "<user3p()) UINFO(9, "propagate pull to " << outvarp << endl); } else if (invarp->user1p()) { envarp = VN_CAST(invarp->user1p(), Var); // From CASEEQ, foo === 1'bz } @@ -561,27 +561,24 @@ class TristateVisitor : public TristateBaseVisitor { int w = lhsp->width(); // create the new lhs driver for this var - AstVar* newlhsp = new AstVar(lhsp->fileline(), - AstVarType::MODULETEMP, - lhsp->name()+"__out"+cvtToStr(m_unique), + AstVar* newlhsp = new AstVar(lhsp->fileline(), AstVarType::MODULETEMP, + lhsp->name() + "__out" + cvtToStr(m_unique), VFlagBitPacked(), w); // 2-state ok; sep enable - UINFO(9," newout "<addStmtp(newlhsp); refp->varp(newlhsp); // assign the new var to the varref refp->name(newlhsp->name()); // create a new var for this drivers enable signal - AstVar* newenp = new AstVar(lhsp->fileline(), - AstVarType::MODULETEMP, - lhsp->name()+"__en"+cvtToStr(m_unique++), - VFlagBitPacked(), w); // 2-state ok - UINFO(9," newenp "<fileline(), AstVarType::MODULETEMP, + lhsp->name() + "__en" + cvtToStr(m_unique++), + VFlagBitPacked(), w); // 2-state ok + UINFO(9, " newenp " << newenp << endl); nodep->addStmtp(newenp); - AstNode* enassp = new AstAssignW(refp->fileline(), - new AstVarRef(refp->fileline(), newenp, true), - getEnp(refp)); - UINFO(9," newass "<fileline(), new AstVarRef(refp->fileline(), newenp, true), getEnp(refp)); + UINFO(9, " newass " << enassp << endl); nodep->addStmtp(enassp); // now append this driver to the driver logic. @@ -598,11 +595,11 @@ class TristateVisitor : public TristateBaseVisitor { } AstNode* tmp = new AstNot(newenp->fileline(), new AstVarRef(newenp->fileline(), newenp, false)); - undrivenp = ((!undrivenp) ? tmp - : new AstAnd(refp->fileline(), tmp, undrivenp)); + undrivenp = ((!undrivenp) ? tmp : new AstAnd(refp->fileline(), tmp, undrivenp)); } if (!undrivenp) { // No drivers on the bus - V3Number ones(invarp, lhsp->width()); ones.setAllBits1(); + V3Number ones(invarp, lhsp->width()); + ones.setAllBits1(); undrivenp = new AstConst(invarp->fileline(), ones); } if (!outvarp) { @@ -612,7 +609,7 @@ class TristateVisitor : public TristateBaseVisitor { AstPull* pullp = static_cast(lhsp->user3p()); if (pullp && pullp->direction() == 1) { pull.setAllBits1(); - UINFO(9,"Has pullup "<deleteTree(), undrivenp); } if (envarp) { - nodep->addStmtp(new AstAssignW(enp->fileline(), - new AstVarRef(envarp->fileline(), - envarp, true), enp)); + nodep->addStmtp(new AstAssignW( + enp->fileline(), new AstVarRef(envarp->fileline(), envarp, true), enp)); } // __out (child) or (parent) = drive-value expression AstNode* assp = new AstAssignW(lhsp->fileline(), - new AstVarRef(lhsp->fileline(), - lhsp, - true), - orp); + new AstVarRef(lhsp->fileline(), lhsp, true), orp); assp->user2(U2_BOTH); // Don't process further; already resolved - if (debug()>=9) assp->dumpTree(cout, "-lhsp-eqn: "); + if (debug() >= 9) assp->dumpTree(cout, "-lhsp-eqn: "); nodep->addStmtp(assp); // Delete the map and vector list now that we have expanded it. m_lhsmap.erase(invarp); @@ -644,11 +637,9 @@ class TristateVisitor : public TristateBaseVisitor { // VISITORS virtual void visit(AstConst* nodep) VL_OVERRIDE { - UINFO(9,dbgState()<num().hasZ()) { - m_tgraph.setTristate(nodep); - } + if (!m_alhs && nodep->num().hasZ()) m_tgraph.setTristate(nodep); } else { // Detect any Z consts and convert them to 0's with an enable that is also 0. if (m_alhs && nodep->user1p()) { @@ -657,21 +648,20 @@ class TristateVisitor : public TristateBaseVisitor { // We can ignore the output override by making a temporary AstVar* varp = getCreateUnconnVarp(nodep, nodep->dtypep()); AstNode* newp = new AstVarRef(nodep->fileline(), varp, true); - UINFO(9," const->"<" << newp << endl); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (m_tgraph.isTristate(nodep)) { + } else if (m_tgraph.isTristate(nodep)) { m_tgraph.didProcess(nodep); FileLine* fl = nodep->fileline(); - V3Number numz (nodep, nodep->width()); + V3Number numz(nodep, nodep->width()); numz.opBitsZ(nodep->num()); // Z->1, else 0 V3Number numz0(nodep, nodep->width()); numz0.opNot(numz); // Z->0, else 1 - V3Number num1 (nodep, nodep->width()); + V3Number num1(nodep, nodep->width()); num1.opAnd(nodep->num(), numz0); // 01X->01X, Z->0 AstConst* newconstp = new AstConst(fl, num1); - AstConst* enp = new AstConst(fl, numz0); + AstConst* enp = new AstConst(fl, numz0); nodep->replaceWith(newconstp); VL_DO_DANGLING(pushDeletep(nodep), nodep); newconstp->user1p(enp); // Propagate up constant with non-Z bits as 1 @@ -691,19 +681,19 @@ class TristateVisitor : public TristateBaseVisitor { } } else { if (m_alhs && nodep->user1p()) { - nodep->v3error("Unsupported LHS tristate construct: " - <prettyTypeName()); + nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName()); return; } iterateChildren(nodep); - UINFO(9,dbgState()<condp(); + AstNode* condp = nodep->condp(); if (condp->user1p()) { - condp->v3error("Unsupported: don't know how to deal with tristate logic in the conditional expression"); + condp->v3error("Unsupported: don't know how to deal with " + "tristate logic in the conditional expression"); } AstNode* expr1p = nodep->expr1p(); AstNode* expr2p = nodep->expr2p(); @@ -714,7 +704,7 @@ class TristateVisitor : public TristateBaseVisitor { // The output enable of a cond is a cond of the output enable of the // two expressions with the same conditional. AstNode* enp = new AstCond(nodep->fileline(), condp->cloneTree(false), en1p, en2p); - UINFO(9," newcond "<user1p(enp); // propagate up COND(lhsp->enable, rhsp->enable) expr1p->user1p(NULL); expr2p->user1p(NULL); @@ -732,27 +722,28 @@ class TristateVisitor : public TristateBaseVisitor { } } else { if (m_alhs) { - UINFO(9,dbgState()<user1p()) { // Form a "deposit" instruction. Would be nicer if we made this a new AST type AstNode* newp = newEnableDeposit(nodep, nodep->user1p()); nodep->fromp()->user1p(newp); // Push to varref (etc) - if (debug()>=9) newp->dumpTree(cout, "-assign-sel; "); + if (debug() >= 9) newp->dumpTree(cout, "-assign-sel; "); m_tgraph.didProcess(nodep); } iterateChildren(nodep); } else { iterateChildren(nodep); - UINFO(9,dbgState()<lsbp()->user1p()) { - nodep->v3error("Unsupported RHS tristate construct: "<prettyTypeName()); + nodep->v3error( + "Unsupported RHS tristate construct: " << nodep->prettyTypeName()); } if (nodep->fromp()->user1p()) { // SEL(VARREF, lsb) AstNode* en1p = getEnp(nodep->fromp()); - AstNode* enp = new AstSel(nodep->fileline(), en1p, - nodep->lsbp()->cloneTree(true), - nodep->widthp()->cloneTree(true)); - UINFO(9," newsel "<fileline(), en1p, nodep->lsbp()->cloneTree(true), + nodep->widthp()->cloneTree(true)); + UINFO(9, " newsel " << enp << endl); nodep->user1p(enp); // propagate up SEL(fromp->enable, value) m_tgraph.didProcess(nodep); } @@ -770,28 +761,24 @@ class TristateVisitor : public TristateBaseVisitor { associateLogic(nodep->lhsp(), nodep); associateLogic(nodep->rhsp(), nodep); } - } - else { + } else { if (m_alhs) { - UINFO(9,dbgState()<user1p()) { // Each half of the concat gets a select of the enable expression AstNode* enp = nodep->user1p(); nodep->user1p(NULL); - nodep->lhsp()->user1p(new AstSel(nodep->fileline(), - enp->cloneTree(true), + nodep->lhsp()->user1p(new AstSel(nodep->fileline(), enp->cloneTree(true), nodep->rhsp()->width(), nodep->lhsp()->width())); - nodep->rhsp()->user1p(new AstSel(nodep->fileline(), - enp, - 0, - nodep->rhsp()->width())); + nodep->rhsp()->user1p( + new AstSel(nodep->fileline(), enp, 0, nodep->rhsp()->width())); m_tgraph.didProcess(nodep); } iterateChildren(nodep); } else { iterateChildren(nodep); - UINFO(9,dbgState()<lhsp(); @@ -801,7 +788,7 @@ class TristateVisitor : public TristateBaseVisitor { AstNode* en1p = getEnp(expr1p); AstNode* en2p = getEnp(expr2p); AstNode* enp = new AstConcat(nodep->fileline(), en1p, en2p); - UINFO(9," newconc "<user1p(enp); // propagate up CONCAT(lhsp->enable, rhsp->enable) expr1p->user1p(NULL); expr2p->user1p(NULL); @@ -813,14 +800,14 @@ class TristateVisitor : public TristateBaseVisitor { virtual void visit(AstBufIf1* nodep) VL_OVERRIDE { // For BufIf1, the enable is the LHS expression iterateChildren(nodep); - UINFO(9,dbgState()<rhsp(), nodep); m_tgraph.setTristate(nodep); } else { - if (debug()>=9) nodep->backp()->dumpTree(cout, "-bufif: "); + if (debug() >= 9) nodep->backp()->dumpTree(cout, "-bufif: "); if (m_alhs) { - nodep->v3error("Unsupported LHS tristate construct: "<prettyTypeName()); + nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName()); return; } m_tgraph.didProcess(nodep); @@ -836,21 +823,21 @@ class TristateVisitor : public TristateBaseVisitor { expr2p->user1p(enp); // Becomes new node // Don't need the BufIf any more, can just have the data direct nodep->replaceWith(expr2p); - UINFO(9," bufif datap="<prettyTypeName()); + nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName()); return; } // ANDs and Z's have issues. Earlier optimizations convert @@ -881,27 +868,19 @@ class TristateVisitor : public TristateBaseVisitor { subexpr2p = new AstNot(nodep->fileline(), subexpr2p); } // calc new output enable - AstNode* enp = new AstOr(nodep->fileline(), - new AstAnd(nodep->fileline(), en1p, en2p), - new AstOr(nodep->fileline(), - new AstAnd(nodep->fileline(), - en1p->cloneTree(false), - subexpr1p), - new AstAnd(nodep->fileline(), - en2p->cloneTree(false), - subexpr2p))); - UINFO(9," neweqn "<fileline(), new AstAnd(nodep->fileline(), en1p, en2p), + new AstOr(nodep->fileline(), + new AstAnd(nodep->fileline(), en1p->cloneTree(false), subexpr1p), + new AstAnd(nodep->fileline(), en2p->cloneTree(false), subexpr2p))); + UINFO(9, " neweqn " << enp << endl); nodep->user1p(enp); expr1p->user1p(NULL); expr2p->user1p(NULL); } } - virtual void visit(AstAnd* nodep) VL_OVERRIDE { - visitAndOr(nodep, true); - } - virtual void visit(AstOr* nodep) VL_OVERRIDE { - visitAndOr(nodep, false); - } + virtual void visit(AstAnd* nodep) VL_OVERRIDE { visitAndOr(nodep, true); } + virtual void visit(AstOr* nodep) VL_OVERRIDE { visitAndOr(nodep, false); } void visitAssign(AstNodeAssign* nodep) { if (m_graphing) { @@ -916,11 +895,13 @@ class TristateVisitor : public TristateBaseVisitor { associateLogic(nodep, nodep->lhsp()); m_logicp = NULL; } else { - if (nodep->user2() & U2_NONGRAPH) return; // Iterated here, or created assignment to ignore + if (nodep->user2() & U2_NONGRAPH) { + return; // Iterated here, or created assignment to ignore + } nodep->user2(U2_NONGRAPH); iterateAndNextNull(nodep->rhsp()); - UINFO(9,dbgState()<=9) nodep->dumpTree(cout, "-assign: "); + UINFO(9, dbgState() << nodep << endl); + if (debug() >= 9) nodep->dumpTree(cout, "-assign: "); // if the rhsp of this assign statement has an output enable driver, // then propagate the corresponding output enable assign statement. // down the lvalue tree by recursion for eventual attachment to @@ -928,7 +909,7 @@ class TristateVisitor : public TristateBaseVisitor { if (nodep->rhsp()->user1p()) { nodep->lhsp()->user1p(nodep->rhsp()->user1p()); nodep->rhsp()->user1p(NULL); - UINFO(9," enp<-rhs "<lhsp()->user1p()<lhsp()->user1p() << endl); m_tgraph.didProcess(nodep); } m_alhs = true; // And user1p() will indicate tristate equation, if any @@ -936,12 +917,8 @@ class TristateVisitor : public TristateBaseVisitor { m_alhs = false; } } - virtual void visit(AstAssignW* nodep) VL_OVERRIDE { - visitAssign(nodep); - } - virtual void visit(AstAssign* nodep) VL_OVERRIDE { - visitAssign(nodep); - } + virtual void visit(AstAssignW* nodep) VL_OVERRIDE { visitAssign(nodep); } + virtual void visit(AstAssign* nodep) VL_OVERRIDE { visitAssign(nodep); } void visitCaseEq(AstNodeBiop* nodep, bool neq) { if (m_graphing) { @@ -953,25 +930,26 @@ class TristateVisitor : public TristateBaseVisitor { // Otherwise we'd need to attach an enable to every signal, then optimize them // away later when we determine the signal has no tristate iterateChildren(nodep); - UINFO(9,dbgState()<lhsp(), Const); // Constification always moves const to LHS + UINFO(9, dbgState() << nodep << endl); + // Constification always moves const to LHS + const AstConst* constp = VN_CAST(nodep->lhsp(), Const); AstVarRef* varrefp = VN_CAST(nodep->rhsp(), VarRef); // Input variable if (constp && constp->user1p() && varrefp) { // 3'b1z0 -> ((3'b101 == in__en) && (3'b100 == in)) varrefp->unlinkFrBack(); FileLine* fl = nodep->fileline(); - V3Number oneIfEn = VN_CAST(constp->user1p(), Const)->num(); // visit(AstConst) already split into en/ones + V3Number oneIfEn = VN_CAST(constp->user1p(), Const) + ->num(); // visit(AstConst) already split into en/ones V3Number oneIfEnOne = constp->num(); AstVar* envarp = getCreateEnVarp(varrefp->varp()); - AstNode* newp = new AstLogAnd(fl, new AstEq(fl, new AstConst(fl, oneIfEn), - new AstVarRef(fl, envarp, false)), - // Keep the caseeq if there are X's present - new AstEqCase(fl, new AstConst(fl, oneIfEnOne), - varrefp)); + AstNode* newp = new AstLogAnd( + fl, new AstEq(fl, new AstConst(fl, oneIfEn), new AstVarRef(fl, envarp, false)), + // Keep the caseeq if there are X's present + new AstEqCase(fl, new AstConst(fl, oneIfEnOne), varrefp)); if (neq) newp = new AstLogNot(fl, newp); - UINFO(9," newceq "<=9) nodep->dumpTree(cout, "-caseeq-old: "); - if (debug()>=9) newp->dumpTree(cout, "-caseeq-new: "); + UINFO(9, " newceq " << newp << endl); + if (debug() >= 9) nodep->dumpTree(cout, "-caseeq-old: "); + if (debug() >= 9) newp->dumpTree(cout, "-caseeq-new: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { @@ -981,30 +959,23 @@ class TristateVisitor : public TristateBaseVisitor { } void visitEqNeqWild(AstNodeBiop* nodep) { if (!VN_IS(nodep->rhsp(), Const)) { - nodep->v3error("Unsupported: RHS of ==? or !=? must be constant to be synthesizable"); // Says spec. + nodep->v3error( // Says spac. + "Unsupported: RHS of ==? or !=? must be constant to be synthesizable"); // rhs we want to keep X/Z intact, so otherwise ignore } iterateAndNextNull(nodep->lhsp()); if (nodep->lhsp()->user1p()) { - nodep->v3error("Unsupported LHS tristate construct: "<prettyTypeName()); + nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName()); return; } } - virtual void visit(AstEqCase* nodep) VL_OVERRIDE { - visitCaseEq(nodep, false); - } - virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { - visitCaseEq(nodep, true); - } - virtual void visit(AstEqWild* nodep) VL_OVERRIDE { - visitEqNeqWild(nodep); - } - virtual void visit(AstNeqWild* nodep) VL_OVERRIDE { - visitEqNeqWild(nodep); - } + virtual void visit(AstEqCase* nodep) VL_OVERRIDE { visitCaseEq(nodep, false); } + virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { visitCaseEq(nodep, true); } + virtual void visit(AstEqWild* nodep) VL_OVERRIDE { visitEqNeqWild(nodep); } + virtual void visit(AstNeqWild* nodep) VL_OVERRIDE { visitEqNeqWild(nodep); } virtual void visit(AstPull* nodep) VL_OVERRIDE { - UINFO(9,dbgState()<lhsp(), VarRef)) { varrefp = VN_CAST(nodep->lhsp(), VarRef); @@ -1013,7 +984,7 @@ class TristateVisitor : public TristateBaseVisitor { varrefp = VN_CAST(VN_CAST(nodep->lhsp(), Sel)->fromp(), VarRef); } if (!varrefp) { - if (debug()>=4) nodep->dumpTree(cout, "- "); + if (debug() >= 4) nodep->dumpTree(cout, "- "); nodep->v3error("Unsupported pullup/down (weak driver) construct."); } else { if (m_graphing) { @@ -1052,9 +1023,7 @@ class TristateVisitor : public TristateBaseVisitor { m_logicp = NULL; } else { // All heavy lifting completed in graph visitor. - if (nodep->exprp()) { - m_tgraph.didProcess(nodep); - } + if (nodep->exprp()) m_tgraph.didProcess(nodep); iterateChildren(nodep); } } @@ -1093,8 +1062,8 @@ class TristateVisitor : public TristateBaseVisitor { return; // No __en signals on this pin } // Tristate exists: - UINFO(9,dbgState()<=9) nodep->dumpTree(cout, "-pin-pre: "); + UINFO(9, dbgState() << nodep << endl); + if (debug() >= 9) nodep->dumpTree(cout, "-pin-pre: "); // Empty/in-only; need Z to propagate bool inDeclProcessing = (nodep->exprp() @@ -1105,7 +1074,7 @@ class TristateVisitor : public TristateBaseVisitor { // to have this. && !nodep->modVarp()->declDirection().isWritable()); if (!nodep->exprp()) { // No-connect; covert to empty connection - UINFO(5,"Unconnected pin terminate "<modVarp()->dtypep()); nodep->exprp(new AstVarRef(nodep->fileline(), ucVarp, // We converted, so use declaration output state @@ -1116,7 +1085,7 @@ class TristateVisitor : public TristateBaseVisitor { // Input only may have driver in underneath module which would stomp // the input value. So make a temporary connection. AstAssignW* reAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, true, true); - UINFO(5,"Input pin buffering: "<lhsp()); } @@ -1126,23 +1095,21 @@ class TristateVisitor : public TristateBaseVisitor { // Create the output enable pin, connect to new signal AstNode* enrefp; { - AstVar* enVarp = new AstVar(nodep->fileline(), - AstVarType::MODULETEMP, + AstVar* enVarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP, nodep->name() + "__en" + cvtToStr(m_unique++), VFlagBitPacked(), enModVarp->width()); - UINFO(9," newenv "<fileline(), - nodep->pinNum(), + UINFO(9, " newenv " << enVarp << endl); + AstPin* enpinp = new AstPin(nodep->fileline(), nodep->pinNum(), enModVarp->name(), // should be {var}"__en" new AstVarRef(nodep->fileline(), enVarp, true)); enpinp->modVarp(enModVarp); - UINFO(9," newpin "<user2(U2_BOTH); // don't iterate the pin later nodep->addNextHere(enpinp); m_modp->addStmtp(enVarp); enrefp = new AstVarRef(nodep->fileline(), enVarp, false); - UINFO(9," newvrf "<=9) enpinp->dumpTree(cout, "-pin-ena: "); + UINFO(9, " newvrf " << enrefp << endl); + if (debug() >= 9) enpinp->dumpTree(cout, "-pin-ena: "); } // Create new output pin AstAssignW* outAssignp = NULL; // If reconnected, the related assignment @@ -1151,16 +1118,16 @@ class TristateVisitor : public TristateBaseVisitor { if (!outModVarp) { // At top, no need for __out as might be input only. Otherwise resolvable. if (!m_modp->isTop()) { - nodep->v3error("Unsupported: tristate in top-level IO: " << nodep->prettyNameQ()); + nodep->v3error( + "Unsupported: tristate in top-level IO: " << nodep->prettyNameQ()); } } else { AstNode* outexprp = nodep->exprp()->cloneTree(false); // Note has lvalue() set - outpinp = new AstPin(nodep->fileline(), - nodep->pinNum(), + outpinp = new AstPin(nodep->fileline(), nodep->pinNum(), outModVarp->name(), // should be {var}"__out" outexprp); outpinp->modVarp(outModVarp); - UINFO(9," newpin "<user2(U2_BOTH); // don't iterate the pin later nodep->addNextHere(outpinp); // Simplify @@ -1170,20 +1137,22 @@ class TristateVisitor : public TristateBaseVisitor { // simple, it will flip ArraySel's and such, but if the // pin is an input the earlier reconnectSimple made it // a VarRef without any ArraySel, etc - TristatePinVisitor visitor (outexprp, m_tgraph, true); + TristatePinVisitor visitor(outexprp, m_tgraph, true); } - if (debug()>=9) outpinp->dumpTree(cout, "-pin-opr: "); - outAssignp = V3Inst::pinReconnectSimple(outpinp, m_cellp, true); // Note may change outpinp->exprp() - if (debug()>=9) outpinp->dumpTree(cout, "-pin-out: "); - if (debug()>=9 && outAssignp) outAssignp->dumpTree(cout, "-pin-out: "); + if (debug() >= 9) outpinp->dumpTree(cout, "-pin-opr: "); + outAssignp = V3Inst::pinReconnectSimple(outpinp, m_cellp, + true); // Note may change outpinp->exprp() + if (debug() >= 9) outpinp->dumpTree(cout, "-pin-out: "); + if (debug() >= 9 && outAssignp) outAssignp->dumpTree(cout, "-pin-out: "); // Must still iterate the outAssignp, as need to build output equation } // Existing pin becomes an input, and we mark each resulting signal as tristate - TristatePinVisitor visitor (nodep->exprp(), m_tgraph, false); - AstNode* inAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, true); // Note may change nodep->exprp() - if (debug()>=9) nodep->dumpTree(cout, "-pin-in: "); - if (debug()>=9 && inAssignp) inAssignp->dumpTree(cout, "-pin-as: "); + TristatePinVisitor visitor(nodep->exprp(), m_tgraph, false); + AstNode* inAssignp = V3Inst::pinReconnectSimple( + nodep, m_cellp, true); // Note may change nodep->exprp() + if (debug() >= 9) nodep->dumpTree(cout, "-pin-in: "); + if (debug() >= 9 && inAssignp) inAssignp->dumpTree(cout, "-pin-as: "); // Connect enable to output signal AstVarRef* exprrefp; // Tristate variable that the Pin's expression refers to @@ -1193,18 +1162,24 @@ class TristateVisitor : public TristateBaseVisitor { } else { // pinReconnect should have converted this exprrefp = VN_CAST(outpinp->exprp(), VarRef); - if (!exprrefp) nodep->v3error("Unsupported tristate port expression: " - <exprp()->prettyTypeName()); + if (!exprrefp) { + nodep->v3error("Unsupported tristate port expression: " + << nodep->exprp()->prettyTypeName()); + } } } else { // pinReconnect should have converted this - exprrefp = VN_CAST(outAssignp->rhsp(), VarRef); // This should be the same var as the output pin - if (!exprrefp) nodep->v3error("Unsupported tristate port expression: " - <exprp()->prettyTypeName()); + exprrefp = VN_CAST(outAssignp->rhsp(), + VarRef); // This should be the same var as the output pin + if (!exprrefp) { + nodep->v3error("Unsupported tristate port expression: " + << nodep->exprp()->prettyTypeName()); + } } if (exprrefp) { - UINFO(9,"outref "<user1p(enrefp); // Mark as now tristated; iteration will pick it up from there + UINFO(9, "outref " << exprrefp << endl); + // Mark as now tristated; iteration will pick it up from there + exprrefp->user1p(enrefp); if (!outAssignp) { mapInsertLhsVarRef(exprrefp); // insertTristates will convert // // to a varref to the __out# variable @@ -1214,7 +1189,7 @@ class TristateVisitor : public TristateBaseVisitor { // Propagate any pullups/pulldowns upwards if necessary if (exprrefp) { if (AstPull* pullp = static_cast(nodep->modVarp()->user3p())) { - UINFO(9, "propagate pull on "<varp(), pullp); } } @@ -1228,13 +1203,13 @@ class TristateVisitor : public TristateBaseVisitor { else { if (nodep->user2() & U2_NONGRAPH) return; // This pin is already expanded nodep->user2(U2_NONGRAPH); - UINFO(9," "<lvalue()) { associateLogic(nodep, nodep->varp()); @@ -1248,18 +1223,18 @@ class TristateVisitor : public TristateBaseVisitor { // VarMap so that after the walk through the module we can expand // any tristate logic on the driver. if (nodep->lvalue() && m_tgraph.isTristate(nodep->varp())) { - UINFO(9," Ref-to-lvalue "<lvalue() - && !nodep->user1p() // Not already processed, nor varref from visit(AstPin) creation - // Reference to another tristate variable - && m_tgraph.isTristate(nodep->varp()) - // and in a position where it feeds upstream to another tristate - && m_tgraph.feedsTri(nodep)) { + } else if (!nodep->lvalue() + // Not already processed, nor varref from visit(AstPin) creation + && !nodep->user1p() + // Reference to another tristate variable + && m_tgraph.isTristate(nodep->varp()) + // and in a position where it feeds upstream to another tristate + && m_tgraph.feedsTri(nodep)) { // Then propagate the enable from the original variable - UINFO(9," Ref-to-tri "<varp()); nodep->user1p(new AstVarRef(nodep->fileline(), enVarp, false)); } @@ -1269,16 +1244,16 @@ class TristateVisitor : public TristateBaseVisitor { virtual void visit(AstVar* nodep) VL_OVERRIDE { iterateChildren(nodep); - UINFO(9,dbgState()<user2() & U2_GRAPHING) return; // Already processed nodep->user2(U2_GRAPHING); if (nodep->isPulldown() || nodep->isPullup()) { - AstNode* newp = new AstPull(nodep->fileline(), - new AstVarRef(nodep->fileline(), nodep, true), - nodep->isPullup()); - UINFO(9," newpul "<fileline(), new AstVarRef(nodep->fileline(), nodep, true), + nodep->isPullup()); + UINFO(9, " newpul " << newp << endl); nodep->addNextHere(newp); // We'll iterate on the new AstPull later } @@ -1288,8 +1263,8 @@ class TristateVisitor : public TristateBaseVisitor { // versions and causes outputs that don't come from anywhere to // possibly create connection errors. // One example of problems is this: "output z; task t; z <= {something}; endtask" - ) { - UINFO(9," setTristate-inout "<= 3); } diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 8178d6742..6f29dcd03 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -51,16 +51,12 @@ class UndrivenVarEntry { public: // CONSTRUCTORS explicit UndrivenVarEntry(AstVar* varp) { // Construction for when a var is used - UINFO(9, "create "<width() * FLAGS_PER_BIT); - for (int i = 0; i < varp->width() * FLAGS_PER_BIT; i++) { - m_bitFlags[i] = false; - } + for (int i = 0; i < varp->width() * FLAGS_PER_BIT; i++) m_bitFlags[i] = false; } ~UndrivenVarEntry() {} @@ -81,60 +77,63 @@ private: bool prev = false; int msb = 0; // bit==-1 loops below; we do one extra iteration so end with prev=false - for (int bit=(m_bitFlags.size()/FLAGS_PER_BIT)-1; bit >= -1; --bit) { - if (bit>=0 + for (int bit = (m_bitFlags.size() / FLAGS_PER_BIT) - 1; bit >= -1; --bit) { + if (bit >= 0 && ((which == BN_UNUSED && !usedFlag(bit) && drivenFlag(bit)) || (which == BN_UNDRIVEN && usedFlag(bit) && !drivenFlag(bit)) || (which == BN_BOTH && !usedFlag(bit) && !drivenFlag(bit)))) { - if (!prev) { prev=true; msb = bit; } + if (!prev) { + prev = true; + msb = bit; + } } else if (prev) { AstBasicDType* bdtypep = m_varp->basicp(); - int lsb = bit+1; + int lsb = bit + 1; if (bits != "") bits += ","; - if (lsb==msb) { - bits += cvtToStr(lsb+bdtypep->lsb()); + if (lsb == msb) { + bits += cvtToStr(lsb + bdtypep->lsb()); } else { if (bdtypep->littleEndian()) { - bits += cvtToStr(lsb+bdtypep->lsb())+":"+cvtToStr(msb+bdtypep->lsb()); + bits += cvtToStr(lsb + bdtypep->lsb()) + ":" + + cvtToStr(msb + bdtypep->lsb()); } else { - bits += cvtToStr(msb+bdtypep->lsb())+":"+cvtToStr(lsb+bdtypep->lsb()); + bits += cvtToStr(msb + bdtypep->lsb()) + ":" + + cvtToStr(lsb + bdtypep->lsb()); } } prev = false; } } - return "["+bits+"]"; + return "[" + bits + "]"; } + public: void usedWhole() { - UINFO(9, "set u[*] "<name()<name() << endl); m_wholeFlags[FLAG_USED] = true; } void drivenWhole() { - UINFO(9, "set d[*] "<name()<name() << endl); m_wholeFlags[FLAG_DRIVEN] = true; } void usedBit(int bit, int width) { - UINFO(9, "set u["<<(bit+width-1)<<":"<name()<name() << endl); for (int i = 0; i < width; i++) { - if (bitNumOk(bit + i)) { - m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_USED] = true; - } + if (bitNumOk(bit + i)) m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_USED] = true; } } void drivenBit(int bit, int width) { - UINFO(9, "set d["<<(bit+width-1)<<":"<name()<name() << endl); for (int i = 0; i < width; i++) { - if (bitNumOk(bit + i)) { - m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN] = true; - } + if (bitNumOk(bit + i)) m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN] = true; } } bool isUsedNotDrivenBit(int bit, int width) const { for (int i = 0; i < width; i++) { if (bitNumOk(bit + i) && (m_wholeFlags[FLAG_USED] || m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_USED]) - && !(m_wholeFlags[FLAG_DRIVEN] || m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN])) + && !(m_wholeFlags[FLAG_DRIVEN] + || m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN])) return true; } return false; @@ -183,39 +182,43 @@ public: // UNDRIVEN is considered more serious - as is more likely a bug, // thus undriven+unused bits get UNUSED warnings, as they're not as buggy. if (!unusedMatch(nodep)) { - nodep->v3warn(UNUSED, "Signal is not driven, nor used: " - <prettyNameQ()); + nodep->v3warn(UNUSED, + "Signal is not driven, nor used: " << nodep->prettyNameQ()); nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once } } else if (allD && !anyU) { if (!unusedMatch(nodep)) { - nodep->v3warn(UNUSED, "Signal is not used: "<prettyNameQ()); + nodep->v3warn(UNUSED, "Signal is not used: " << nodep->prettyNameQ()); nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once } } else if (!anyD && allU) { - nodep->v3warn(UNDRIVEN, "Signal is not driven: "<prettyNameQ()); + nodep->v3warn(UNDRIVEN, "Signal is not driven: " << nodep->prettyNameQ()); nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); // Warn only once } else { // Bits have different dispositions - bool setU=false; bool setD=false; + bool setU = false; + bool setD = false; if (anynotDU && !unusedMatch(nodep)) { nodep->v3warn(UNUSED, "Bits of signal are not driven, nor used: " - <prettyNameQ() - <prettyNameQ() << bitNames(BN_BOTH)); setU = true; } if (anyDnotU && !unusedMatch(nodep)) { - nodep->v3warn(UNUSED, "Bits of signal are not used: "<prettyNameQ() - <v3warn(UNUSED, "Bits of signal are not used: " << nodep->prettyNameQ() + << bitNames(BN_UNUSED)); setU = true; } if (anyUnotD) { - nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "<prettyNameQ() - <v3warn(UNDRIVEN, "Bits of signal are not driven: " + << nodep->prettyNameQ() << bitNames(BN_UNDRIVEN)); setD = true; } - if (setU) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once - if (setD) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); // Warn only once + if (setU) { // Warn only once + nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); + } + if (setD) { // Warn only once + nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); + } } } } @@ -246,17 +249,21 @@ private: VL_DEBUG_FUNC; // Declare debug() UndrivenVarEntry* getEntryp(AstVar* nodep, int which_user) { - if (!(which_user==1 ? nodep->user1p() : nodep->user2p())) { + if (!(which_user == 1 ? nodep->user1p() : nodep->user2p())) { UndrivenVarEntry* entryp = new UndrivenVarEntry(nodep); - //UINFO(9," Associate u="<name()<name()<user1p(entryp); - else if (which_user==2) nodep->user2p(entryp); - else nodep->v3fatalSrc("Bad case"); + if (which_user == 1) { + nodep->user1p(entryp); + } else if (which_user == 2) { + nodep->user2p(entryp); + } else { + nodep->v3fatalSrc("Bad case"); + } return entryp; } else { - UndrivenVarEntry* entryp = reinterpret_cast - (which_user==1 ? nodep->user1p() : nodep->user2p()); + UndrivenVarEntry* entryp = reinterpret_cast( + which_user == 1 ? nodep->user1p() : nodep->user2p()); return entryp; } } @@ -266,35 +273,33 @@ private: if (!varp->isParam() && !varp->isGenVar() && !varp->isUsedLoopIdx() && !m_inBBox // We may have falsely considered a SysIgnore as a driver && !VN_IS(nodep, VarXRef) // Xrefs might point at two different instances - && !varp->fileline()->warnIsOff(V3ErrorCode::ALWCOMBORDER)) { // Warn only once per variable - nodep->v3warn(ALWCOMBORDER, "Always_comb variable driven after use: " - <prettyNameQ()); - varp->fileline()->modifyWarnOff(V3ErrorCode::ALWCOMBORDER, true); // Complain just once for any usage + && !varp->fileline()->warnIsOff( + V3ErrorCode::ALWCOMBORDER)) { // Warn only once per variable + nodep->v3warn(ALWCOMBORDER, + "Always_comb variable driven after use: " << nodep->prettyNameQ()); + varp->fileline()->modifyWarnOff(V3ErrorCode::ALWCOMBORDER, + true); // Complain just once for any usage } } // VISITORS virtual void visit(AstVar* nodep) VL_OVERRIDE { - for (int usr=1; usr<(m_alwaysCombp?3:2); ++usr) { + for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) { // For assigns and non-combo always, do just usr==1, to look // for module-wide undriven etc. // For non-combo always, run both usr==1 for above, and also // usr==2 for always-only checks. UndrivenVarEntry* entryp = getEntryp(nodep, usr); - if (nodep->isNonOutput() - || nodep->isSigPublic() || nodep->isSigUserRWPublic() + if (nodep->isNonOutput() || nodep->isSigPublic() || nodep->isSigUserRWPublic() || (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) { entryp->drivenWhole(); } - if (nodep->isWritable() - || nodep->isSigPublic() || nodep->isSigUserRWPublic() + if (nodep->isWritable() || nodep->isSigPublic() || nodep->isSigUserRWPublic() || nodep->isSigUserRdPublic() || (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) { entryp->usedWhole(); } - if (nodep->valuep()) { - entryp->drivenWhole(); - } + if (nodep->valuep()) entryp->drivenWhole(); } // Discover variables used in bit definitions, etc iterateChildren(nodep); @@ -311,14 +316,14 @@ private: AstNodeVarRef* varrefp = VN_CAST(nodep->fromp(), NodeVarRef); AstConst* constp = VN_CAST(nodep->lsbp(), Const); if (varrefp && constp && !constp->num().isFourState()) { - for (int usr=1; usr<(m_alwaysCombp?3:2); ++usr) { + for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) { UndrivenVarEntry* entryp = getEntryp(varrefp->varp(), usr); int lsb = constp->toUInt(); if (m_inBBox || varrefp->lvalue()) { // Don't warn if already driven earlier as "a=0; if(a) a=1;" is fine. - if (usr==2 && m_alwaysCombp + if (usr == 2 && m_alwaysCombp && entryp->isUsedNotDrivenBit(lsb, nodep->width())) { - UINFO(9," Select. Entryp="<prettyNameQ()); + << " (IEEE 1800-2017 6.5): " + << nodep->prettyNameQ()); } if (m_inContAssign && !nodep->varp()->varType().isContAssignable() && !nodep->fileline()->language().systemVerilog()) { - nodep->v3warn(CONTASSREG, "Continuous assignment to reg, perhaps intended wire" - << " (IEEE 1364-2005 6.1; Verilog only, legal in SV): " - << nodep->prettyNameQ()); + nodep->v3warn(CONTASSREG, + "Continuous assignment to reg, perhaps intended wire" + << " (IEEE 1364-2005 6.1; Verilog only, legal in SV): " + << nodep->prettyNameQ()); } } - for (int usr=1; usr<(m_alwaysCombp?3:2); ++usr) { + for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) { UndrivenVarEntry* entryp = getEntryp(nodep->varp(), usr); - bool fdrv = nodep->lvalue() && nodep->varp()->attrFileDescr(); // FD's are also being read from + bool fdrv = nodep->lvalue() + && nodep->varp()->attrFileDescr(); // FD's are also being read from if (m_inBBox || nodep->lvalue()) { - if (usr==2 && m_alwaysCombp && entryp->isUsedNotDrivenAny()) { - UINFO(9," Full bus. Entryp="<isUsedNotDrivenAny()) { + UINFO(9, " Full bus. Entryp=" << cvtToHex(entryp) << endl); warnAlwCombOrder(nodep); } entryp->drivenWhole(); @@ -398,11 +405,14 @@ private: AstAlways* prevAlwp = m_alwaysCombp; { AstNode::user2ClearTree(); - if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9," "<keyword() == VAlwaysKwd::ALWAYS_COMB) m_alwaysCombp = nodep; - else m_alwaysCombp = NULL; + if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9, " " << nodep << endl); + if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) { + m_alwaysCombp = nodep; + } else { + m_alwaysCombp = NULL; + } iterateChildren(nodep); - if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9," Done "<keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9, " Done " << nodep << endl); } m_alwaysCombp = prevAlwp; } @@ -456,6 +466,6 @@ public: // Undriven class functions void V3Undriven::undrivenAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "< bool. Set true if already processed // AstArraySel::user() -> bool. Set true if already processed // AstNode::user2p() -> AstIf* Inserted if assignment for conditional - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; + AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; // STATE - AstNodeModule* m_modp; // Current module - bool m_constXCvt; // Convert X's - VDouble0 m_statUnkVars; // Statistic tracking - AstAssignW* m_assignwp; // Current assignment - AstAssignDly* m_assigndlyp; // Current assignment + AstNodeModule* m_modp; // Current module + bool m_constXCvt; // Convert X's + VDouble0 m_statUnkVars; // Statistic tracking + AstAssignW* m_assignwp; // Current assignment + AstAssignDly* m_assigndlyp; // Current assignment // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -81,7 +81,7 @@ private: if (m_assignwp) { // Wire assigns must become always statements to deal with insertion // of multiple statements. Perhaps someday make all wassigns into always's? - UINFO(5," IM_WireRep "<convertToAlways(); VL_DO_CLEAR(pushDeletep(m_assignwp), m_assignwp = NULL); } @@ -98,8 +98,7 @@ private: AstNode* prep = nodep; // Scan back to put the condlvalue above all selects (IE top of the lvalue) - while (VN_IS(prep->backp(), NodeSel) - || VN_IS(prep->backp(), Sel)) { + while (VN_IS(prep->backp(), NodeSel) || VN_IS(prep->backp(), Sel)) { prep = prep->backp(); } FileLine* fl = nodep->fileline(); @@ -111,30 +110,24 @@ private: UASSERT_OBJ(!needDly, prep, "Should have already converted to non-delay"); AstNRelinker replaceHandle; AstNode* earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle); - AstNode* newp = new AstLogAnd(condp->fileline(), - condp, earliercondp); - UINFO(4, "Edit BOUNDLVALUE "<fileline(), condp, earliercondp); + UINFO(4, "Edit BOUNDLVALUE " << newp << endl); replaceHandle.relink(newp); - } - else { - string name = (string("__Vlvbound")+cvtToStr(m_modp->varNumGetInc())); - AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name, - prep->dtypep()); + } else { + string name = (string("__Vlvbound") + cvtToStr(m_modp->varNumGetInc())); + AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name, prep->dtypep()); m_modp->addStmtp(varp); AstNode* abovep = prep->backp(); // Grab above point before lose it w/ next replace prep->replaceWith(new AstVarRef(fl, varp, true)); AstIf* newp = new AstIf(fl, condp, - (needDly - ? static_cast - (new AstAssignDly(fl, prep, - new AstVarRef(fl, varp, false))) - : static_cast - (new AstAssign(fl, prep, - new AstVarRef(fl, varp, false)))), + (needDly ? static_cast(new AstAssignDly( + fl, prep, new AstVarRef(fl, varp, false))) + : static_cast(new AstAssign( + fl, prep, new AstVarRef(fl, varp, false)))), NULL); newp->branchPred(VBranchPred::BP_LIKELY); - if (debug()>=9) newp->dumpTree(cout, " _new: "); + if (debug() >= 9) newp->dumpTree(cout, " _new: "); abovep->addNextStmt(newp, abovep); prep->user2p(newp); // Save so we may LogAnd it next time } @@ -142,7 +135,7 @@ private: // VISITORS virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { - UINFO(4," MOD "<EQ "<EQ " << nodep << endl); V3Const::constifyEdit(nodep->lhsp()); // lhsp may change V3Const::constifyEdit(nodep->rhsp()); // rhsp may change if (VN_IS(nodep->lhsp(), Const) && VN_IS(nodep->rhsp(), Const)) { @@ -187,14 +180,16 @@ private: // If we got ==1'bx it can never be true (but 1'bx==1'bx can be!) if (((VN_IS(lhsp, Const) && VN_CAST(lhsp, Const)->num().isFourState()) || (VN_IS(rhsp, Const) && VN_CAST(rhsp, Const)->num().isFourState()))) { - newp = new AstConst(nodep->fileline(), AstConst::WidthedValue(), - 1, (VN_IS(nodep, EqCase) ? 0 : 1)); + newp = new AstConst(nodep->fileline(), AstConst::WidthedValue(), 1, + (VN_IS(nodep, EqCase) ? 0 : 1)); VL_DO_DANGLING(lhsp->deleteTree(), lhsp); VL_DO_DANGLING(rhsp->deleteTree(), rhsp); } else { if (VN_IS(nodep, EqCase)) { newp = new AstEq(nodep->fileline(), lhsp, rhsp); - } else { newp = new AstNeq(nodep->fileline(), lhsp, rhsp); } + } else { + newp = new AstNeq(nodep->fileline(), lhsp, rhsp); + } } nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -203,7 +198,7 @@ private: } } void visitEqNeqWild(AstNodeBiop* nodep) { - UINFO(4," N/EQWILD->EQ "<EQ " << nodep << endl); V3Const::constifyEdit(nodep->lhsp()); // lhsp may change V3Const::constifyEdit(nodep->rhsp()); // rhsp may change if (VN_IS(nodep->lhsp(), Const) && VN_IS(nodep->rhsp(), Const)) { @@ -215,21 +210,24 @@ private: AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNode* newp; if (!VN_IS(rhsp, Const)) { - nodep->v3error("Unsupported: RHS of ==? or !=? must be constant to be synthesizable"); // Says spec. + nodep->v3error("Unsupported: RHS of ==? or !=? must be " + "constant to be synthesizable"); // Says spec. // Replace with anything that won't cause more errors newp = new AstEq(nodep->fileline(), lhsp, rhsp); } else { // X or Z's become mask, ala case statements. - V3Number nummask (rhsp, rhsp->width()); + V3Number nummask(rhsp, rhsp->width()); nummask.opBitsNonX(VN_CAST(rhsp, Const)->num()); - V3Number numval (rhsp, rhsp->width()); + V3Number numval(rhsp, rhsp->width()); numval.opBitsOne(VN_CAST(rhsp, Const)->num()); AstNode* and1p = new AstAnd(nodep->fileline(), lhsp, new AstConst(nodep->fileline(), nummask)); AstNode* and2p = new AstConst(nodep->fileline(), numval); if (VN_IS(nodep, EqWild)) { - newp = new AstEq(nodep->fileline(), and1p, and2p); - } else { newp = new AstNeq(nodep->fileline(), and1p, and2p); } + newp = new AstEq(nodep->fileline(), and1p, and2p); + } else { + newp = new AstNeq(nodep->fileline(), and1p, and2p); + } VL_DO_DANGLING(rhsp->deleteTree(), rhsp); } nodep->replaceWith(newp); @@ -239,42 +237,33 @@ private: } } - virtual void visit(AstEqCase* nodep) VL_OVERRIDE { - visitEqNeqCase(nodep); - } - virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { - visitEqNeqCase(nodep); - } - virtual void visit(AstEqWild* nodep) VL_OVERRIDE { - visitEqNeqWild(nodep); - } - virtual void visit(AstNeqWild* nodep) VL_OVERRIDE { - visitEqNeqWild(nodep); - } + virtual void visit(AstEqCase* nodep) VL_OVERRIDE { visitEqNeqCase(nodep); } + virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { visitEqNeqCase(nodep); } + virtual void visit(AstEqWild* nodep) VL_OVERRIDE { visitEqNeqWild(nodep); } + virtual void visit(AstNeqWild* nodep) VL_OVERRIDE { visitEqNeqWild(nodep); } virtual void visit(AstIsUnknown* nodep) VL_OVERRIDE { iterateChildren(nodep); // Ahh, we're two state, so this is easy - UINFO(4," ISUNKNOWN->0 "<0 " << nodep << endl); AstConst* newp = new AstConst(nodep->fileline(), AstConst::LogicFalse()); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } virtual void visit(AstConst* nodep) VL_OVERRIDE { - if (m_constXCvt - && nodep->num().isFourState()) { - UINFO(4," CONST4 "<=9) nodep->dumpTree(cout, " Const_old: "); + if (m_constXCvt && nodep->num().isFourState()) { + UINFO(4, " CONST4 " << nodep << endl); + if (debug() >= 9) nodep->dumpTree(cout, " Const_old: "); // CONST(num) -> VARREF(newvarp) // -> VAR(newvarp) // -> INITIAL(VARREF(newvarp, OR(num_No_Xs,AND(random,num_1s_Where_X)) - V3Number numb1 (nodep, nodep->width()); + V3Number numb1(nodep, nodep->width()); numb1.opBitsOne(nodep->num()); - V3Number numbx (nodep, nodep->width()); + V3Number numbx(nodep, nodep->width()); numbx.opBitsXZ(nodep->num()); - if (v3Global.opt.xAssign()!="unique") { + if (v3Global.opt.xAssign() != "unique") { // All X bits just become 0; fastest simulation, but not nice - V3Number numnew (nodep, numb1.width()); - if (v3Global.opt.xAssign()=="1") { + V3Number numnew(nodep, numb1.width()); + if (v3Global.opt.xAssign() == "1") { numnew.opOr(numb1, numbx); } else { numnew.opAssign(numb1); @@ -282,42 +271,36 @@ private: AstConst* newp = new AstConst(nodep->fileline(), numnew); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - UINFO(4," -> "< " << newp << endl); } else { // Make a Vxrand variable // We use the special XTEMP type so it doesn't break pure functions UASSERT_OBJ(m_modp, nodep, "X number not under module"); - string newvarname = (string("__Vxrand") - +cvtToStr(m_modp->varNumGetInc())); - AstVar* newvarp - = new AstVar(nodep->fileline(), AstVarType::XTEMP, newvarname, - VFlagLogicPacked(), nodep->width()); + string newvarname = (string("__Vxrand") + cvtToStr(m_modp->varNumGetInc())); + AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::XTEMP, newvarname, + VFlagLogicPacked(), nodep->width()); ++m_statUnkVars; AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, false); replaceHandle.relink(newref1p); // Replace const with varref - AstInitial* newinitp - = new AstInitial( - nodep->fileline(), - new AstAssign( - nodep->fileline(), - new AstVarRef(nodep->fileline(), newvarp, true), - new AstOr(nodep->fileline(), - new AstConst(nodep->fileline(), numb1), - new AstAnd(nodep->fileline(), - new AstConst(nodep->fileline(), numbx), - new AstRand(nodep->fileline(), - nodep->dtypep(), true))))); + AstInitial* newinitp = new AstInitial( + nodep->fileline(), + new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), newvarp, true), + new AstOr( + nodep->fileline(), new AstConst(nodep->fileline(), numb1), + new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), numbx), + new AstRand(nodep->fileline(), nodep->dtypep(), true))))); // Add inits in front of other statement. // In the future, we should stuff the initp into the module's constructor. AstNode* afterp = m_modp->stmtsp()->unlinkFrBackWithNext(); m_modp->addStmtp(newvarp); m_modp->addStmtp(newinitp); m_modp->addStmtp(afterp); - if (debug()>=9) newref1p->dumpTree(cout, " _new: "); - if (debug()>=9) newvarp->dumpTree(cout, " _new: "); - if (debug()>=9) newinitp->dumpTree(cout, " _new: "); + if (debug() >= 9) newref1p->dumpTree(cout, " _new: "); + if (debug() >= 9) newvarp->dumpTree(cout, " _new: "); + if (debug() >= 9) newinitp->dumpTree(cout, " _new: "); VL_DO_DANGLING(nodep->deleteTree(), nodep); } } @@ -334,13 +317,12 @@ private: } // Find range of dtype we are selecting from // Similar code in V3Const::warnSelect - int maxmsb = nodep->fromp()->dtypep()->width()-1; - if (debug()>=9) nodep->dumpTree(cout, "sel_old: "); + int maxmsb = nodep->fromp()->dtypep()->width() - 1; + if (debug() >= 9) nodep->dumpTree(cout, "sel_old: "); // If (maxmsb >= selected), we're in bound AstNode* condp = new AstGte(nodep->fileline(), - new AstConst(nodep->fileline(), - AstConst::WidthedValue(), + new AstConst(nodep->fileline(), AstConst::WidthedValue(), nodep->lsbp()->width(), maxmsb), nodep->lsbp()->cloneTree(false)); // See if the condition is constant true (e.g. always in bound due to constant select) @@ -349,24 +331,20 @@ private: if (condp->isOne()) { // We don't need to add a conditional; we know the existing expression is ok VL_DO_DANGLING(condp->deleteTree(), condp); - } - else if (!lvalue) { + } else if (!lvalue) { // SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}}) AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); - V3Number xnum (nodep, nodep->width()); + V3Number xnum(nodep, nodep->width()); xnum.setAllBitsX(); - AstNode* newp = new AstCondBound(nodep->fileline(), - condp, - nodep, + AstNode* newp = new AstCondBound(nodep->fileline(), condp, nodep, new AstConst(nodep->fileline(), xnum)); - if (debug()>=9) newp->dumpTree(cout, " _new: "); + if (debug() >= 9) newp->dumpTree(cout, " _new: "); // Link in conditional replaceHandle.relink(newp); // Added X's, tristate them too iterate(newp); - } - else { // lvalue + } else { // lvalue replaceBoundLvalue(nodep, condp); } } @@ -378,7 +356,7 @@ private: virtual void visit(AstArraySel* nodep) VL_OVERRIDE { iterateChildren(nodep); if (!nodep->user1SetOnce()) { - if (debug()==9) nodep->dumpTree(cout, "-in: "); + if (debug() == 9) nodep->dumpTree(cout, "-in: "); // Guard against reading/writing past end of arrays AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp()); bool lvalue = false; @@ -396,57 +374,51 @@ private: if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) { declElements = adtypep->elementsConst(); } else { - nodep->v3error("Select from non-array "<prettyTypeName()); + nodep->v3error("Select from non-array " << dtypep->prettyTypeName()); } - if (debug()>=9) nodep->dumpTree(cout, "arraysel_old: "); + if (debug() >= 9) nodep->dumpTree(cout, "arraysel_old: "); // See if the condition is constant true AstNode* condp = new AstGte(nodep->fileline(), new AstConst(nodep->fileline(), AstConst::WidthedValue(), - nodep->bitp()->width(), declElements-1), + nodep->bitp()->width(), declElements - 1), nodep->bitp()->cloneTree(false)); // Note below has null backp(); the Edit function knows how to deal with that. condp = V3Const::constifyEdit(condp); if (condp->isOne()) { // We don't need to add a conditional; we know the existing expression is ok VL_DO_DANGLING(condp->deleteTree(), condp); - } - else if (!lvalue - // Making a scalar would break if we're making an array - && !VN_IS(nodep->dtypep()->skipRefp(), NodeArrayDType)) { + } else if (!lvalue + // Making a scalar would break if we're making an array + && !VN_IS(nodep->dtypep()->skipRefp(), NodeArrayDType)) { // ARRAYSEL(...) -> COND(LT(bitunlinkFrBack(&replaceHandle); - V3Number xnum (nodep, nodep->width()); + V3Number xnum(nodep, nodep->width()); if (nodep->isString()) { xnum = V3Number(V3Number::String(), nodep, ""); } else { xnum.setAllBitsX(); } - AstNode* newp = new AstCondBound(nodep->fileline(), - condp, nodep, + AstNode* newp = new AstCondBound(nodep->fileline(), condp, nodep, new AstConst(nodep->fileline(), xnum)); - if (debug()>=9) newp->dumpTree(cout, " _new: "); + if (debug() >= 9) newp->dumpTree(cout, " _new: "); // Link in conditional, can blow away temp xor replaceHandle.relink(newp); // Added X's, tristate them too iterate(newp); - } - else if (!lvalue) { // Mid-multidimension read, just use zero + } else if (!lvalue) { // Mid-multidimension read, just use zero // ARRAYSEL(...) -> ARRAYSEL(COND(LT(bitbitp()->unlinkFrBack(&replaceHandle); - AstNode* newp = new AstCondBound(bitp->fileline(), - condp, bitp, - new AstConst(bitp->fileline(), - AstConst::WidthedValue(), - bitp->width(), 0)); + AstNode* newp = new AstCondBound( + bitp->fileline(), condp, bitp, + new AstConst(bitp->fileline(), AstConst::WidthedValue(), bitp->width(), 0)); // Added X's, tristate them too - if (debug()>=9) newp->dumpTree(cout, " _new: "); + if (debug() >= 9) newp->dumpTree(cout, " _new: "); replaceHandle.relink(newp); iterate(newp); - } - else { // lvalue + } else { // lvalue replaceBoundLvalue(nodep, condp); } } @@ -463,7 +435,7 @@ public: m_constXCvt = false; iterate(nodep); } - virtual ~UnknownVisitor() { + virtual ~UnknownVisitor() { // V3Stats::addStat("Unknowns, variables created", m_statUnkVars); } }; @@ -472,9 +444,7 @@ public: // Unknown class functions void V3Unknown::unknownAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 3); } diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index d09c42540..3a0191190 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -43,35 +43,32 @@ class UnrollVisitor : public AstNVisitor { private: // STATE - AstVar* m_forVarp; // Iterator variable - AstVarScope* m_forVscp; // Iterator variable scope (NULL for generate pass) - AstConst* m_varValuep; // Current value of loop - AstNode* m_ignoreIncp; // Increment node to ignore - bool m_varModeCheck; // Just checking RHS assignments - bool m_varModeReplace; // Replacing varrefs - bool m_varAssignHit; // Assign var hit - bool m_generate; // Expand single generate For loop - string m_beginName; // What name to give begin iterations - VDouble0 m_statLoops; // Statistic tracking - VDouble0 m_statIters; // Statistic tracking + AstVar* m_forVarp; // Iterator variable + AstVarScope* m_forVscp; // Iterator variable scope (NULL for generate pass) + AstConst* m_varValuep; // Current value of loop + AstNode* m_ignoreIncp; // Increment node to ignore + bool m_varModeCheck; // Just checking RHS assignments + bool m_varModeReplace; // Replacing varrefs + bool m_varAssignHit; // Assign var hit + bool m_generate; // Expand single generate For loop + string m_beginName; // What name to give begin iterations + VDouble0 m_statLoops; // Statistic tracking + VDouble0 m_statIters; // Statistic tracking // METHODS VL_DEBUG_FUNC; // Declare debug() // VISITORS bool cantUnroll(AstNode* nodep, const char* reason) { - if (m_generate) { - nodep->v3error("Unsupported: Can't unroll generate for; "<=9) nodep->dumpTree(cout, "-cant-"); - V3Stats::addStatSum(string("Unrolling gave up, ")+reason, 1); + if (m_generate) nodep->v3error("Unsupported: Can't unroll generate for; " << reason); + UINFO(3, " Can't Unroll: " << reason << " :" << nodep << endl); + // if (debug() >= 9) nodep->dumpTree(cout, "-cant-"); + V3Stats::addStatSum(string("Unrolling gave up, ") + reason, 1); return false; } int unrollCount() { - return m_generate ? v3Global.opt.unrollCount()*16 - : v3Global.opt.unrollCount(); + return m_generate ? v3Global.opt.unrollCount() * 16 : v3Global.opt.unrollCount(); } bool bodySizeOverRecurse(AstNode* nodep, int& bodySize, int bodyLimit) { @@ -88,24 +85,27 @@ private: return bodySizeOverRecurse(nodep->nextp(), bodySize, bodyLimit); } - bool forUnrollCheck(AstNode* nodep, - AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp) - AstNode* precondsp, AstNode* condp, - AstNode* incp, // Maybe under nodep or in bodysp - AstNode* bodysp) { + bool + forUnrollCheck(AstNode* nodep, + AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp) + AstNode* precondsp, AstNode* condp, + AstNode* incp, // Maybe under nodep or in bodysp + AstNode* bodysp) { // To keep the IF levels low, we return as each test fails. - UINFO(4, " FOR Check "<nextp() && initp->nextp()!=nodep), nodep, + UASSERT_OBJ(!(initp->nextp() && initp->nextp() != nodep), nodep, "initial assignment shouldn't be a list"); - if (!VN_IS(initAssp->lhsp(), VarRef)) return cantUnroll(nodep, "no initial assignment to simple variable"); + if (!VN_IS(initAssp->lhsp(), VarRef)) { + return cantUnroll(nodep, "no initial assignment to simple variable"); + } // // Condition check UASSERT_OBJ(!condp->nextp(), nodep, "conditional shouldn't be a list"); @@ -118,9 +118,9 @@ private: m_forVarp = VN_CAST(initAssp->lhsp(), VarRef)->varp(); m_forVscp = VN_CAST(initAssp->lhsp(), VarRef)->varScopep(); if (VN_IS(nodep, GenFor) && !m_forVarp->isGenVar()) { - nodep->v3error("Non-genvar used in generate for: "<prettyNameQ()<isGenVar()) { + nodep->v3error("Non-genvar used in generate for: " // + << m_forVarp->prettyNameQ() << endl); + } else if (!VN_IS(nodep, GenFor) && m_forVarp->isGenVar()) { nodep->v3error("Genvar not legal in non-generate for (IEEE 1800-2017 27.4): " << m_forVarp->prettyNameQ() << endl << nodep->warnMore() @@ -148,28 +148,33 @@ private: if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop"); // - if (m_forVscp) { UINFO(8, " Loop Variable: "<=9) nodep->dumpTree(cout, "- for: "); - + if (m_forVscp) { + UINFO(8, " Loop Variable: " << m_forVscp << endl); + } else { + UINFO(8, " Loop Variable: " << m_forVarp << endl); + } + if (debug() >= 9) nodep->dumpTree(cout, "- for: "); if (!m_generate) { - AstAssign *incpAssign = VN_CAST(incp, Assign); - if (!canSimulate(incpAssign->rhsp())) return cantUnroll(incp, "Unable to simulate increment"); + AstAssign* incpAssign = VN_CAST(incp, Assign); + if (!canSimulate(incpAssign->rhsp())) { + return cantUnroll(incp, "Unable to simulate increment"); + } if (!canSimulate(condp)) return cantUnroll(condp, "Unable to simulate condition"); // Check whether to we actually want to try and unroll. int loops; - if (!countLoops(initAssp, condp, incp, unrollCount(), loops)) + if (!countLoops(initAssp, condp, incp, unrollCount(), loops)) { return cantUnroll(nodep, "Unable to simulate loop"); + } // Less than 10 statements in the body? int bodySize = 0; int bodyLimit = v3Global.opt.unrollStmts(); - if (loops>0) bodyLimit = v3Global.opt.unrollStmts() / loops; - if (bodySizeOverRecurse(precondsp, bodySize/*ref*/, bodyLimit) - || bodySizeOverRecurse(bodysp, bodySize/*ref*/, bodyLimit) - || bodySizeOverRecurse(incp, bodySize/*ref*/, bodyLimit)) { + if (loops > 0) bodyLimit = v3Global.opt.unrollStmts() / loops; + if (bodySizeOverRecurse(precondsp, bodySize /*ref*/, bodyLimit) + || bodySizeOverRecurse(bodysp, bodySize /*ref*/, bodyLimit) + || bodySizeOverRecurse(incp, bodySize /*ref*/, bodyLimit)) { return cantUnroll(nodep, "too many statements"); } } @@ -182,7 +187,7 @@ private: return true; } - bool canSimulate(AstNode *nodep) { + bool canSimulate(AstNode* nodep) { SimulateVisitor simvis; AstNode* clonep = nodep->cloneTree(true); simvis.mainCheckTree(clonep); @@ -190,8 +195,8 @@ private: return simvis.optimizable(); } - bool simulateTree(AstNode *nodep, const V3Number *loopValue, - AstNode *dtypep, V3Number &outNum) { + bool simulateTree(AstNode* nodep, const V3Number* loopValue, AstNode* dtypep, + V3Number& outNum) { AstNode* clonep = nodep->cloneTree(true); UASSERT_OBJ(clonep, nodep, "Failed to clone tree"); if (loopValue) { @@ -210,7 +215,7 @@ private: simvis.mainParamEmulate(clonep); if (!simvis.optimizable()) { UINFO(3, "Unable to simulate" << endl); - if (debug()>=9) nodep->dumpTree(cout, "- _simtree: "); + if (debug() >= 9) nodep->dumpTree(cout, "- _simtree: "); VL_DO_DANGLING(clonep->deleteTree(), clonep); return false; } @@ -223,7 +228,7 @@ private: } // Patch up datatype if (dtypep) { - AstConst new_con (clonep->fileline(), *res); + AstConst new_con(clonep->fileline(), *res); new_con.dtypeFrom(dtypep); outNum = new_con.num(); VL_DO_DANGLING(clonep->deleteTree(), clonep); @@ -234,20 +239,18 @@ private: return true; } - bool countLoops(AstAssign *initp, AstNode *condp, AstNode *incp, int max, int &outLoopsr) { + bool countLoops(AstAssign* initp, AstNode* condp, AstNode* incp, int max, int& outLoopsr) { outLoopsr = 0; V3Number loopValue = V3Number(initp); - if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) { + if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) { // return false; } while (true) { V3Number res = V3Number(initp); - if (!simulateTree(condp, &loopValue, NULL, res)) { + if (!simulateTree(condp, &loopValue, NULL, res)) { // return false; } - if (!res.isEqOne()) { - break; - } + if (!res.isEqOne()) break; outLoopsr++; @@ -258,21 +261,16 @@ private: return false; } loopValue.opAssign(newLoopValue); - if (outLoopsr > max) { - return false; - } + if (outLoopsr > max) return false; } return true; } - bool forUnroller(AstNode* nodep, - AstAssign* initp, - AstNode* condp, - AstNode* precondsp, + bool forUnroller(AstNode* nodep, AstAssign* initp, AstNode* condp, AstNode* precondsp, AstNode* incp, AstNode* bodysp) { - UINFO(9, "forUnroller "<rhsp(), NULL, initp, loopValue)) { + if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) { // return false; } AstNode* stmtsp = NULL; @@ -301,7 +299,7 @@ private: if (stmtsp) { int times = 0; while (true) { - UINFO(8," Looping "<v3error("Loop unrolling failed."); @@ -309,8 +307,7 @@ private: } if (!res.isEqOne()) { break; // Done with the loop - } - else { + } else { // Replace iterator values with constant. AstNode* oneloopp = stmtsp->cloneTree(true); @@ -318,8 +315,8 @@ private: // Iteration requires a back, so put under temporary node if (oneloopp) { - AstBegin* tempp = new AstBegin(oneloopp->fileline(), - "[EditWrapper]", oneloopp); + AstBegin* tempp + = new AstBegin(oneloopp->fileline(), "[EditWrapper]", oneloopp); m_varModeReplace = true; iterateAndNextNull(tempp->stmtsp()); m_varModeReplace = false; @@ -332,19 +329,23 @@ private: oneloopp = new AstBegin(oneloopp->fileline(), nname, oneloopp, true); } VL_DO_CLEAR(pushDeletep(m_varValuep), m_varValuep = NULL); - if (newbodysp) newbodysp->addNext(oneloopp); - else newbodysp = oneloopp; + if (newbodysp) { + newbodysp->addNext(oneloopp); + } else { + newbodysp = oneloopp; + } ++m_statIters; - if (++times > unrollCount()*3) { - nodep->v3error("Loop unrolling took too long;" - " probably this is an infinite loop, or set --unroll-count above " - < unrollCount() * 3) { + nodep->v3error( + "Loop unrolling took too long;" + " probably this is an infinite loop, or set --unroll-count above " + << unrollCount()); break; } // loopValue += valInc - AstAssign *incpass = VN_CAST(incp, Assign); + AstAssign* incpass = VN_CAST(incp, Assign); V3Number newLoopValue = V3Number(nodep); if (!simulateTree(incpass->rhsp(), &loopValue, incpass, newLoopValue)) { nodep->v3error("Loop unrolling failed"); @@ -359,13 +360,16 @@ private: initp = NULL; } // Replace the FOR() - if (newbodysp) nodep->replaceWith(newbodysp); - else nodep->unlinkFrBack(); + if (newbodysp) { + nodep->replaceWith(newbodysp); + } else { + nodep->unlinkFrBack(); + } if (bodysp) { VL_DO_DANGLING(pushDeletep(bodysp), bodysp); } if (precondsp) { VL_DO_DANGLING(pushDeletep(precondsp), precondsp); } if (initp) { VL_DO_DANGLING(pushDeletep(initp), initp); } if (incp && !incp->backp()) { VL_DO_DANGLING(pushDeletep(incp), incp); } - if (debug()>=9 && newbodysp) newbodysp->dumpTree(cout, "- _new: "); + if (debug() >= 9 && newbodysp) newbodysp->dumpTree(cout, "- _new: "); return true; } @@ -374,7 +378,9 @@ private: if (m_varModeCheck || m_varModeReplace) { } else { // Constify before unroll call, as it may change what is underneath. - if (nodep->precondsp()) V3Const::constifyEdit(nodep->precondsp()); // precondsp may change + if (nodep->precondsp()) { + V3Const::constifyEdit(nodep->precondsp()); // precondsp may change + } if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change // Grab initial value AstNode* initp = NULL; // Should be statement before the while. @@ -385,16 +391,17 @@ private: AstNode* incp = NULL; // Should be last statement if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp()); // cppcheck-suppress duplicateCondition - if (nodep->incsp()) incp = nodep->incsp(); - else { + if (nodep->incsp()) { + incp = nodep->incsp(); + } else { + for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} + if (incp) VL_DO_DANGLING(V3Const::constifyEdit(incp), incp); + // Again, as may have changed for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} - if (incp) { VL_DO_DANGLING(V3Const::constifyEdit(incp), incp); } - for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed } // And check it - if (forUnrollCheck(nodep, initp, - nodep->precondsp(), nodep->condp(), - incp, nodep->bodysp())) { + if (forUnrollCheck(nodep, initp, nodep->precondsp(), nodep->condp(), incp, + nodep->bodysp())) { VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement } } @@ -418,9 +425,8 @@ private: // condition, but they'll become while's which can be // deleted by V3Const. VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); - } else if (forUnrollCheck(nodep, nodep->initsp(), - NULL, nodep->condp(), - nodep->incsp(), nodep->bodysp())) { + } else if (forUnrollCheck(nodep, nodep->initsp(), NULL, nodep->condp(), nodep->incsp(), + nodep->bodysp())) { VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement } else { nodep->v3error("For loop doesn't have genvar index, or is malformed"); @@ -436,17 +442,13 @@ private: } virtual void visit(AstVarRef* nodep) VL_OVERRIDE { - if (m_varModeCheck - && nodep->varp() == m_forVarp - && nodep->varScopep() == m_forVscp + if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp && nodep->lvalue()) { - UINFO(8," Itervar assigned to: "<varp() == m_forVarp - && nodep->varScopep() == m_forVscp + if (m_varModeReplace && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp && !nodep->lvalue()) { AstNode* newconstp = m_varValuep->cloneTree(false); nodep->replaceWith(newconstp); @@ -492,20 +494,19 @@ public: //###################################################################### // Unroll class functions -UnrollStateful::UnrollStateful() : m_unrollerp(new UnrollVisitor) { } +UnrollStateful::UnrollStateful() + : m_unrollerp(new UnrollVisitor) {} UnrollStateful::~UnrollStateful() { delete m_unrollerp; } void UnrollStateful::unrollGen(AstNodeFor* nodep, const string& beginName) { - UINFO(5,__FUNCTION__<<": "<process(nodep, true, beginName); } -void UnrollStateful::unrollAll(AstNetlist* nodep) { - m_unrollerp->process(nodep, false, ""); -} +void UnrollStateful::unrollAll(AstNetlist* nodep) { m_unrollerp->process(nodep, false, ""); } void V3Unroll::unrollAll(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<=prelim, <1>=final std::ostream& operator<<(std::ostream& str, const Stage& rhs) { - return str<<("-PFB"[static_cast(rhs)]); + return str << ("-PFB"[static_cast(rhs)]); } enum Determ { - SELF, // Self-determined - CONTEXT, // Context-determined - ASSIGN // Assignment-like where sign comes from RHS only + SELF, // Self-determined + CONTEXT, // Context-determined + ASSIGN // Assignment-like where sign comes from RHS only }; std::ostream& operator<<(std::ostream& str, const Determ& rhs) { static const char* const s_det[] = {"SELF", "CNTX", "ASSN"}; - return str<op4p()) clearWidthRecurse(nodep->op4p()); } } + public: // CONSTRUCTORS - explicit WidthClearVisitor(AstNetlist* nodep) { - clearWidthRecurse(nodep); - } + explicit WidthClearVisitor(AstNetlist* nodep) { clearWidthRecurse(nodep); } virtual ~WidthClearVisitor() {} }; @@ -179,27 +181,27 @@ public: class WidthVisitor : public AstNVisitor { private: // TYPES - typedef std::map, AstVar*> TableMap; - typedef std::map PatVecMap; + typedef std::map, AstVar*> TableMap; + typedef std::map PatVecMap; // STATE - WidthVP* m_vup; // Current node state - bool m_paramsOnly; // Computing parameter value; limit operation - AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations - AstNodeFTask* m_ftaskp; // Current function/task - AstFunc* m_funcp; // Current function - AstInitial* m_initialp; // Current initial block - AstAttrOf* m_attrp; // Current attribute - bool m_doGenerate; // Do errors later inside generate statement - int m_dtTables; // Number of created data type tables - TableMap m_tableMap; // Created tables so can remove duplicates + WidthVP* m_vup; // Current node state + bool m_paramsOnly; // Computing parameter value; limit operation + AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations + AstNodeFTask* m_ftaskp; // Current function/task + AstFunc* m_funcp; // Current function + AstInitial* m_initialp; // Current initial block + AstAttrOf* m_attrp; // Current attribute + bool m_doGenerate; // Do errors later inside generate statement + int m_dtTables; // Number of created data type tables + TableMap m_tableMap; // Created tables so can remove duplicates // ENUMS enum ExtendRule { - EXTEND_EXP, // Extend if expect sign and node signed, e.g. node=y in ADD(x,y), "x + y" - EXTEND_ZERO, // Extend with zeros. e.g. node=y in EQ(x,y), "x == y" - EXTEND_LHS, // Extend with sign if node signed. e.g. node=y in ASSIGN(y,x), "x = y" - EXTEND_OFF // No extension + EXTEND_EXP, // Extend if expect sign and node signed, e.g. node=y in ADD(x,y), "x + y" + EXTEND_ZERO, // Extend with zeros. e.g. node=y in EQ(x,y), "x == y" + EXTEND_LHS, // Extend with sign if node signed. e.g. node=y in ASSIGN(y,x), "x = y" + EXTEND_OFF // No extension }; // METHODS @@ -216,110 +218,122 @@ private: // _Ox=anything // Widths: 1 bit out, lhs 1 bit; Real: converts via compare with 0 - virtual void visit(AstLogNot* nodep) VL_OVERRIDE { visit_log_not(nodep); } + virtual void visit(AstLogNot* nodep) VL_OVERRIDE { visit_log_not(nodep); } // Widths: 1 bit out, lhs 1 bit, rhs 1 bit; Real: converts via compare with 0 - virtual void visit(AstLogAnd* nodep) VL_OVERRIDE { visit_log_and_or(nodep); } - virtual void visit(AstLogOr* nodep) VL_OVERRIDE { visit_log_and_or(nodep); } - virtual void visit(AstLogEq* nodep) VL_OVERRIDE { visit_log_and_or(nodep); } // Conversion from real not in IEEE, but a fallout - virtual void visit(AstLogIf* nodep) VL_OVERRIDE { visit_log_and_or(nodep); } // Conversion from real not in IEEE, but a fallout + virtual void visit(AstLogAnd* nodep) VL_OVERRIDE { visit_log_and_or(nodep); } + virtual void visit(AstLogOr* nodep) VL_OVERRIDE { visit_log_and_or(nodep); } + virtual void visit(AstLogEq* nodep) VL_OVERRIDE { + // Conversion from real not in IEEE, but a fallout + visit_log_and_or(nodep); + } + virtual void visit(AstLogIf* nodep) VL_OVERRIDE { + // Conversion from real not in IEEE, but a fallout + visit_log_and_or(nodep); + } // Widths: 1 bit out, Any width lhs - virtual void visit(AstRedAnd* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } - virtual void visit(AstRedOr* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } - virtual void visit(AstRedXnor* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } - virtual void visit(AstRedXor* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } - virtual void visit(AstOneHot* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } - virtual void visit(AstOneHot0* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } - virtual void visit(AstIsUnknown* nodep) VL_OVERRIDE { visit_red_unknown(nodep); } // Allow real + virtual void visit(AstRedAnd* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } + virtual void visit(AstRedOr* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } + virtual void visit(AstRedXnor* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } + virtual void visit(AstRedXor* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } + virtual void visit(AstOneHot* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } + virtual void visit(AstOneHot0* nodep) VL_OVERRIDE { visit_red_and_or(nodep); } + virtual void visit(AstIsUnknown* nodep) VL_OVERRIDE { + visit_red_unknown(nodep); // Allow real + } // These have different node types, as they operate differently // Must add to case statement below, // Widths: 1 bit out, lhs width == rhs width. real if lhs|rhs real - virtual void visit(AstEq* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstNeq* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstGt* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstGte* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstLt* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstLte* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstGtS* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstGteS* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstLtS* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstLteS* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstEqCase* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstEq* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstNeq* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstGt* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstGte* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstLt* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstLte* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstGtS* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstGteS* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstLtS* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstLteS* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstEqCase* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } + virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, true); } // ... These comparisons don't allow reals - virtual void visit(AstEqWild* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, false); } - virtual void visit(AstNeqWild* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, false); } + virtual void visit(AstEqWild* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, false); } + virtual void visit(AstNeqWild* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, false); } // ... Real compares - virtual void visit(AstEqD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } - virtual void visit(AstNeqD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } - virtual void visit(AstLtD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } - virtual void visit(AstLteD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } - virtual void visit(AstGtD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } - virtual void visit(AstGteD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } + virtual void visit(AstEqD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } + virtual void visit(AstNeqD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } + virtual void visit(AstLtD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } + virtual void visit(AstLteD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } + virtual void visit(AstGtD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } + virtual void visit(AstGteD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); } // ... String compares - virtual void visit(AstEqN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } - virtual void visit(AstNeqN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } - virtual void visit(AstLtN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } - virtual void visit(AstLteN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } - virtual void visit(AstGtN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } - virtual void visit(AstGteN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } + virtual void visit(AstEqN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } + virtual void visit(AstNeqN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } + virtual void visit(AstLtN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } + virtual void visit(AstLteN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } + virtual void visit(AstGtN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } + virtual void visit(AstGteN* nodep) VL_OVERRIDE { visit_cmp_string(nodep); } // Widths: out width = lhs width = rhs width // Signed: Output signed iff LHS & RHS signed. // Real: Not allowed - virtual void visit(AstAnd* nodep) VL_OVERRIDE { visit_boolmath_and_or(nodep); } - virtual void visit(AstOr* nodep) VL_OVERRIDE { visit_boolmath_and_or(nodep); } - virtual void visit(AstXnor* nodep) VL_OVERRIDE { visit_boolmath_and_or(nodep); } - virtual void visit(AstXor* nodep) VL_OVERRIDE { visit_boolmath_and_or(nodep); } - virtual void visit(AstBufIf1* nodep) VL_OVERRIDE { visit_boolmath_and_or(nodep); } // Signed behavior changing in 3.814 + virtual void visit(AstAnd* nodep) VL_OVERRIDE { visit_boolmath_and_or(nodep); } + virtual void visit(AstOr* nodep) VL_OVERRIDE { visit_boolmath_and_or(nodep); } + virtual void visit(AstXnor* nodep) VL_OVERRIDE { visit_boolmath_and_or(nodep); } + virtual void visit(AstXor* nodep) VL_OVERRIDE { visit_boolmath_and_or(nodep); } + virtual void visit(AstBufIf1* nodep) VL_OVERRIDE { + visit_boolmath_and_or(nodep); + } // Signed behavior changing in 3.814 // Width: Max(Lhs,Rhs) sort of. // Real: If either side real // Signed: If both sides real - virtual void visit(AstAdd* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, true); } - virtual void visit(AstSub* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, true); } - virtual void visit(AstDiv* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, true); } - virtual void visit(AstMul* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, true); } + virtual void visit(AstAdd* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, true); } + virtual void visit(AstSub* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, true); } + virtual void visit(AstDiv* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, true); } + virtual void visit(AstMul* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, true); } // These can't promote to real - virtual void visit(AstModDiv* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, false); } - virtual void visit(AstModDivS* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, false); } - virtual void visit(AstMulS* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, false); } - virtual void visit(AstDivS* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, false); } + virtual void visit(AstModDiv* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, false); } + virtual void visit(AstModDivS* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, false); } + virtual void visit(AstMulS* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, false); } + virtual void visit(AstDivS* nodep) VL_OVERRIDE { visit_add_sub_replace(nodep, false); } // Widths: out width = lhs width, but upper matters // Signed: Output signed iff LHS signed; unary operator // Unary promote to real - virtual void visit(AstNegate* nodep) VL_OVERRIDE { visit_negate_not(nodep, true); } + virtual void visit(AstNegate* nodep) VL_OVERRIDE { visit_negate_not(nodep, true); } // Unary never real - virtual void visit(AstNot* nodep) VL_OVERRIDE { visit_negate_not(nodep, false); } + virtual void visit(AstNot* nodep) VL_OVERRIDE { visit_negate_not(nodep, false); } // Real: inputs and output real - virtual void visit(AstAddD* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } - virtual void visit(AstSubD* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } - virtual void visit(AstDivD* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } - virtual void visit(AstMulD* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } - virtual void visit(AstPowD* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } + virtual void visit(AstAddD* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } + virtual void visit(AstSubD* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } + virtual void visit(AstDivD* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } + virtual void visit(AstMulD* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } + virtual void visit(AstPowD* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } virtual void visit(AstNodeSystemBiop* nodep) VL_OVERRIDE { visit_real_add_sub(nodep); } // Real: Output real - virtual void visit(AstNegateD* nodep) VL_OVERRIDE { visit_real_neg_ceil(nodep); } + virtual void visit(AstNegateD* nodep) VL_OVERRIDE { visit_real_neg_ceil(nodep); } virtual void visit(AstNodeSystemUniop* nodep) VL_OVERRIDE { visit_real_neg_ceil(nodep); } // Widths: out signed/unsigned width = lhs width, input un|signed virtual void visit(AstSigned* nodep) VL_OVERRIDE { - visit_signed_unsigned(nodep, AstNumeric::SIGNED); } + visit_signed_unsigned(nodep, AstNumeric::SIGNED); + } virtual void visit(AstUnsigned* nodep) VL_OVERRIDE { - visit_signed_unsigned(nodep, AstNumeric::UNSIGNED); } + visit_signed_unsigned(nodep, AstNumeric::UNSIGNED); + } // Widths: Output width from lhs, rhs<33 bits // Signed: If lhs signed - virtual void visit(AstShiftL* nodep) VL_OVERRIDE { visit_shift(nodep); } - virtual void visit(AstShiftR* nodep) VL_OVERRIDE { visit_shift(nodep); } + virtual void visit(AstShiftL* nodep) VL_OVERRIDE { visit_shift(nodep); } + virtual void visit(AstShiftR* nodep) VL_OVERRIDE { visit_shift(nodep); } // ShiftRS converts to ShiftR, but not vice-versa - virtual void visit(AstShiftRS* nodep) VL_OVERRIDE { visit_shift(nodep); } + virtual void visit(AstShiftRS* nodep) VL_OVERRIDE { visit_shift(nodep); } //======== // Widths: Output real, input integer signed virtual void visit(AstBitsToRealD* nodep) VL_OVERRIDE { visit_Or_Lu64(nodep); } - virtual void visit(AstIToRD* nodep) VL_OVERRIDE { visit_Or_Ls32(nodep); } + virtual void visit(AstIToRD* nodep) VL_OVERRIDE { visit_Or_Ls32(nodep); } // Widths: Output integer signed, input real virtual void visit(AstRToIS* nodep) VL_OVERRIDE { visit_Os32_Lr(nodep); } @@ -344,7 +358,8 @@ private: iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH); iterateCheckSigned32(nodep, "THS", nodep->thsp(), BOTH); - nodep->dtypeSetString(); //AstPutcN returns the new string to be assigned by AstAssign + nodep->dtypeSetString(); // AstPutcN returns the new string to be assigned by + // AstAssign } } virtual void visit(AstGetcN* nodep) VL_OVERRIDE { @@ -407,7 +422,9 @@ private: virtual void visit(AstTime* nodep) VL_OVERRIDE { nodep->dtypeSetUInt64(); } virtual void visit(AstTimeD* nodep) VL_OVERRIDE { nodep->dtypeSetDouble(); } virtual void visit(AstTestPlusArgs* nodep) VL_OVERRIDE { nodep->dtypeSetSigned32(); } - virtual void visit(AstScopeName* nodep) VL_OVERRIDE { nodep->dtypeSetUInt64(); } // A pointer, but not that it matters + virtual void visit(AstScopeName* nodep) VL_OVERRIDE { + nodep->dtypeSetUInt64(); // A pointer, but not that it matters + } // Special cases. So many.... virtual void visit(AstNodeCond* nodep) VL_OVERRIDE { @@ -434,7 +451,7 @@ private: } else if (nodep->expr1p()->isString() || nodep->expr2p()->isString()) { nodep->dtypeSetString(); } else { - int width = std::max(nodep->expr1p()->width(), nodep->expr2p()->width()); + int width = std::max(nodep->expr1p()->width(), nodep->expr2p()->width()); int mwidth = std::max(nodep->expr1p()->widthMin(), nodep->expr2p()->widthMin()); bool issigned = nodep->expr1p()->isSigned() && nodep->expr2p()->isSigned(); nodep->dtypeSetLogicUnsized(width, mwidth, AstNumeric::fromBool(issigned)); @@ -445,8 +462,10 @@ private: AstNodeDType* subDTypep = expDTypep; nodep->dtypeFrom(expDTypep); // Error report and change sizes for suboperands of this node. - iterateCheck(nodep, "Conditional True", nodep->expr1p(), CONTEXT, FINAL, subDTypep, EXTEND_EXP); - iterateCheck(nodep, "Conditional False", nodep->expr2p(), CONTEXT, FINAL, subDTypep, EXTEND_EXP); + iterateCheck(nodep, "Conditional True", nodep->expr1p(), CONTEXT, FINAL, subDTypep, + EXTEND_EXP); + iterateCheck(nodep, "Conditional False", nodep->expr2p(), CONTEXT, FINAL, subDTypep, + EXTEND_EXP); } } virtual void visit(AstConcat* nodep) VL_OVERRIDE { @@ -458,11 +477,12 @@ private: // width: LHS + RHS if (m_vup->prelim()) { AstNodeDType* vdtypep = m_vup->dtypeNullp(); - if (vdtypep && (VN_IS(vdtypep, AssocArrayDType) - || VN_IS(vdtypep, DynArrayDType) - || VN_IS(vdtypep, QueueDType))) { - nodep->v3error("Unsupported: Concatenation to form " - << vdtypep->prettyDTypeNameQ() << "data type"); + if (vdtypep + && (VN_IS(vdtypep, AssocArrayDType) // + || VN_IS(vdtypep, DynArrayDType) // + || VN_IS(vdtypep, QueueDType))) { + nodep->v3error("Unsupported: Concatenation to form " << vdtypep->prettyDTypeNameQ() + << "data type"); } iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); @@ -473,21 +493,20 @@ private: // Cleanup zero width Verilog2001 {x,{0{foo}}} now, // otherwise having width(0) will cause later assertions to fire if (AstReplicate* repp = VN_CAST(nodep->lhsp(), Replicate)) { - if (repp->width()==0) { // Keep rhs + if (repp->width() == 0) { // Keep rhs nodep->replaceWith(nodep->rhsp()->unlinkFrBack()); VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } } if (AstReplicate* repp = VN_CAST(nodep->rhsp(), Replicate)) { - if (repp->width()==0) { // Keep lhs + if (repp->width() == 0) { // Keep lhs nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } } - if (nodep->lhsp()->isString() - || nodep->rhsp()->isString()) { + if (nodep->lhsp()->isString() || nodep->rhsp()->isString()) { AstNode* newp = new AstConcatN(nodep->fileline(), nodep->lhsp()->unlinkFrBack(), nodep->rhsp()->unlinkFrBack()); nodep->replaceWith(newp); @@ -498,8 +517,8 @@ private: if (m_vup->final()) { if (!nodep->dtypep()->widthSized()) { // See also error in V3Number - nodeForUnsizedWarning(nodep) - ->v3warn(WIDTHCONCAT, "Unsized numbers/parameters not allowed in concatenations."); + nodeForUnsizedWarning(nodep)->v3warn( + WIDTHCONCAT, "Unsized numbers/parameters not allowed in concatenations."); } } } @@ -514,8 +533,8 @@ private: if (m_vup->final()) { if (!nodep->dtypep()->widthSized()) { // See also error in V3Number - nodeForUnsizedWarning(nodep) - ->v3warn(WIDTHCONCAT, "Unsized numbers/parameters not allowed in concatenations."); + nodeForUnsizedWarning(nodep)->v3warn( + WIDTHCONCAT, "Unsized numbers/parameters not allowed in concatenations."); } } } @@ -538,21 +557,24 @@ private: if (m_vup->prelim()) { AstNodeDType* vdtypep = m_vup->dtypeNullp(); if (vdtypep - && (VN_IS(vdtypep, AssocArrayDType) - || VN_IS(vdtypep, DynArrayDType) - || VN_IS(vdtypep, QueueDType) - || VN_IS(vdtypep, UnpackArrayDType))) { + && (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType) + || VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, UnpackArrayDType))) { nodep->v3error("Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ() - << " data type"); + << " data type"); } iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change const AstConst* constp = VN_CAST(nodep->rhsp(), Const); - if (!constp) { nodep->v3error("Replication value isn't a constant."); return; } + if (!constp) { + nodep->v3error("Replication value isn't a constant."); + return; + } uint32_t times = constp->toUInt(); - if (times==0 && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. - nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE 1800-2017 11.4.12.1)"); + if (times == 0 + && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. + nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE " + "1800-2017 11.4.12.1)"); times = 1; } if (nodep->lhsp()->isString()) { @@ -570,8 +592,8 @@ private: if (m_vup->final()) { if (!nodep->dtypep()->widthSized()) { // See also error in V3Number - nodeForUnsizedWarning(nodep) - ->v3warn(WIDTHCONCAT, "Unsized numbers/parameters not allowed in replications."); + nodeForUnsizedWarning(nodep)->v3warn( + WIDTHCONCAT, "Unsized numbers/parameters not allowed in replications."); } } } @@ -582,18 +604,23 @@ private: iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change const AstConst* constp = VN_CAST(nodep->rhsp(), Const); - if (!constp) { nodep->v3error("Replication value isn't a constant."); return; } + if (!constp) { + nodep->v3error("Replication value isn't a constant."); + return; + } uint32_t times = constp->toUInt(); - if (times==0 && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. - nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE 1800-2017 11.4.12.1)"); + if (times == 0 + && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. + nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE " + "1800-2017 11.4.12.1)"); } nodep->dtypeSetString(); } if (m_vup->final()) { if (!nodep->dtypep()->widthSized()) { // See also error in V3Number - nodeForUnsizedWarning(nodep) - ->v3warn(WIDTHCONCAT, "Unsized numbers/parameters not allowed in replications."); + nodeForUnsizedWarning(nodep)->v3warn( + WIDTHCONCAT, "Unsized numbers/parameters not allowed in replications."); } } } @@ -604,24 +631,29 @@ private: V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change const AstConst* constp = VN_CAST(nodep->rhsp(), Const); AstBasicDType* basicp = VN_CAST(nodep->rhsp(), BasicDType); - if (!constp && !basicp) { nodep->v3error("Slice size isn't a constant or basic data type."); return; } + if (!constp && !basicp) { + nodep->v3error("Slice size isn't a constant or basic data type."); + return; + } if (basicp) { // Convert data type to a constant size AstConst* newp = new AstConst(basicp->fileline(), basicp->width()); nodep->rhsp()->replaceWith(newp); pushDeletep(basicp); } else { uint32_t sliceSize = constp->toUInt(); - if (!sliceSize) { nodep->v3error("Slice size cannot be zero."); return; } + if (!sliceSize) { + nodep->v3error("Slice size cannot be zero."); + return; + } } - nodep->dtypeSetLogicUnsized(nodep->lhsp()->width(), - nodep->lhsp()->widthMin(), + nodep->dtypeSetLogicUnsized(nodep->lhsp()->width(), nodep->lhsp()->widthMin(), AstNumeric::UNSIGNED); } if (m_vup->final()) { if (!nodep->dtypep()->widthSized()) { // See also error in V3Number - nodeForUnsizedWarning(nodep) - ->v3warn(WIDTHCONCAT, "Unsized numbers/parameters not allowed in streams."); + nodeForUnsizedWarning(nodep)->v3warn( + WIDTHCONCAT, "Unsized numbers/parameters not allowed in streams."); } } } @@ -629,14 +661,14 @@ private: // Real: Not allowed // Signed: unsigned output, input either // Convert all range values to constants - UINFO(6,"RANGE "<msbp()); // May relink pointed to node V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node checkConstantOrReplace(nodep->msbp(), "MSB of bit range isn't a constant"); checkConstantOrReplace(nodep->lsbp(), "LSB of bit range isn't a constant"); int msb = nodep->msbConst(); int lsb = nodep->lsbConst(); - if (msblittleEndian(!nodep->littleEndian()); @@ -648,13 +680,15 @@ private: if (m_vup->prelim()) { // Don't need to iterate because V3Const already constified int width = nodep->elementsConst(); - if (width > (1<<28)) nodep->v3error("Width of bit range is huge; vector of over 1billion bits: 0x" - < (1 << 28)) { + nodep->v3error("Width of bit range is huge; vector of over 1billion bits: 0x" + << std::hex << width); + } // Note width() not set on range; use elementsConst() if (nodep->littleEndian() && !VN_IS(nodep->backp(), UnpackArrayDType) && !VN_IS(nodep->backp(), Cell)) { // For cells we warn in V3Inst nodep->v3warn(LITENDIAN, "Little bit endian vector: MSB < LSB of bit range: " - <lsbConst()<<":"<msbConst()); + << nodep->lsbConst() << ":" << nodep->msbConst()); } } } @@ -666,7 +700,7 @@ private: if (nodep->didWidth()) return; UASSERT_OBJ(m_vup, nodep, "Select under an unexpected context"); if (m_vup->prelim()) { - if (debug()>=9) nodep->dumpTree(cout, "-selWidth: "); + if (debug() >= 9) nodep->dumpTree(cout, "-selWidth: "); userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT, PRELIM).p()); userIterateAndNext(nodep->lsbp(), WidthVP(SELF, PRELIM).p()); checkCvtUS(nodep->fromp()); @@ -676,28 +710,28 @@ private: AstConst* widthConstp = VN_CAST(nodep->widthp(), Const); if (!widthConstp) { nodep->v3error("Width of bit extract isn't a constant"); - nodep->dtypeSetLogicBool(); return; + nodep->dtypeSetLogicBool(); + return; } int width = nodep->widthConst(); UASSERT_OBJ(nodep->dtypep(), nodep, "dtype wasn't set"); // by V3WidthSel - if (VN_IS(nodep->lsbp(), Const) - && nodep->msbConst() < nodep->lsbConst()) { + if (VN_IS(nodep->lsbp(), Const) && nodep->msbConst() < nodep->lsbConst()) { nodep->v3error("Unsupported: MSB < LSB of bit extract: " - <msbConst()<<"<"<lsbConst()); + << nodep->msbConst() << "<" << nodep->lsbConst()); width = (nodep->lsbConst() - nodep->msbConst() + 1); nodep->dtypeSetLogicSized(width, AstNumeric::UNSIGNED); - nodep->widthp()->replaceWith(new AstConst(nodep->widthp()->fileline(), - width)); + nodep->widthp()->replaceWith(new AstConst(nodep->widthp()->fileline(), width)); nodep->lsbp()->replaceWith(new AstConst(nodep->lsbp()->fileline(), 0)); } // We're extracting, so just make sure the expression is at least wide enough. if (nodep->fromp()->width() < width) { - nodep->v3error("Extracting "<fromp()->width()<<" bit number"); + nodep->v3error("Extracting " << width << " bits from only " + << nodep->fromp()->width() << " bit number"); // Extend it. AstNodeDType* subDTypep = nodep->findLogicDType(width, width, nodep->fromp()->dtypep()->numeric()); - widthCheckSized(nodep, "errorless...", nodep->fromp(), subDTypep, EXTEND_EXP, false/*noerror*/); + widthCheckSized(nodep, "errorless...", nodep->fromp(), subDTypep, EXTEND_EXP, + false /*noerror*/); } // Check bit indexes. // What is the MSB? We want the true MSB, not one starting at @@ -707,27 +741,29 @@ private: int fromlsb = 0; int elw = nodep->declElWidth(); // Must adjust to tell user bit ranges if (nodep->declRange().ranged()) { - frommsb = nodep->declRange().hiMaxSelect()*elw + (elw-1); // Corrected for negative lsb - fromlsb = nodep->declRange().lo()*elw; + frommsb = nodep->declRange().hiMaxSelect() * elw + + (elw - 1); // Corrected for negative lsb + fromlsb = nodep->declRange().lo() * elw; } else { - //nodep->v3fatalSrc("Should have been declRanged in V3WidthSel"); + // nodep->v3fatalSrc("Should have been declRanged in V3WidthSel"); } - int selwidth = V3Number::log2b(frommsb+1-1)+1; // Width to address a bit + int selwidth = V3Number::log2b(frommsb + 1 - 1) + 1; // Width to address a bit AstNodeDType* selwidthDTypep = nodep->findLogicDType(selwidth, selwidth, nodep->lsbp()->dtypep()->numeric()); userIterateAndNext(nodep->fromp(), WidthVP(SELF, FINAL).p()); userIterateAndNext(nodep->lsbp(), WidthVP(SELF, FINAL).p()); - if (widthBad(nodep->lsbp(), selwidthDTypep) - && nodep->lsbp()->width()!=32) { + if (widthBad(nodep->lsbp(), selwidthDTypep) && nodep->lsbp()->width() != 32) { if (!nodep->fileline()->warnIsOff(V3ErrorCode::WIDTH)) { - nodep->v3warn(WIDTH, "Bit extraction of var[" - <<(frommsb/elw)<<":"<<(fromlsb/elw)<<"] requires " - <<(selwidth/elw)<<" bit index, not " - <<(nodep->lsbp()->width()/elw) - <<(nodep->lsbp()->width()!=nodep->lsbp()->widthMin() - ?" or "+cvtToStr(nodep->lsbp()->widthMin()/elw):"") - <<" bits."); - UINFO(1," Related node: "<v3warn(WIDTH, + "Bit extraction of var[" + << (frommsb / elw) << ":" << (fromlsb / elw) << "] requires " + << (selwidth / elw) << " bit index, not " + << (nodep->lsbp()->width() / elw) + << (nodep->lsbp()->width() != nodep->lsbp()->widthMin() + ? " or " + cvtToStr(nodep->lsbp()->widthMin() / elw) + : "") + << " bits."); + UINFO(1, " Related node: " << nodep << endl); } } if (VN_IS(nodep->lsbp(), Const) && nodep->msbConst() > frommsb) { @@ -740,12 +776,12 @@ private: // should only trigger the error if the out-of-range access is // actually generated. if (m_doGenerate) { - UINFO(5, "Selection index out of range inside generate."<v3warn(SELRANGE, "Selection index out of range: " - <msbConst()<<":"<lsbConst() - <<" outside "<msbConst() << ":" << nodep->lsbConst() + << " outside " << frommsb << ":" << fromlsb); + UINFO(1, " Related node: " << nodep << endl); } } // iterate FINAL is two blocks above @@ -758,8 +794,8 @@ private: // we want the select to be truncated to fit within the // maximum select range, e.g. turn Xs outside of the select // into something fast which pulls from within the array. - widthCheckSized(nodep, "Extract Range", - nodep->lsbp(), selwidthDTypep, EXTEND_EXP, false/*NOWARN*/); + widthCheckSized(nodep, "Extract Range", nodep->lsbp(), selwidthDTypep, EXTEND_EXP, + false /*NOWARN*/); } } } @@ -778,47 +814,50 @@ private: if (const AstUnpackArrayDType* adtypep = VN_CAST(fromDtp, UnpackArrayDType)) { frommsb = adtypep->msb(); fromlsb = adtypep->lsb(); - if (fromlsb>frommsb) {int t = frommsb; frommsb = fromlsb; fromlsb = t; } + if (fromlsb > frommsb) { + int t = frommsb; + frommsb = fromlsb; + fromlsb = t; + } // However, if the lsb<0 we may go negative, so need more bits! if (fromlsb < 0) frommsb += -fromlsb; nodep->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference - } - else { + } else { // Note PackArrayDType doesn't use an ArraySel but a normal Sel. - UINFO(1," Related dtype: "<v3fatalSrc("Array reference exceeds dimension of array"); frommsb = fromlsb = 0; } - int selwidth = V3Number::log2b(frommsb+1-1)+1; // Width to address a bit + int selwidth = V3Number::log2b(frommsb + 1 - 1) + 1; // Width to address a bit AstNodeDType* selwidthDTypep = nodep->findLogicDType(selwidth, selwidth, nodep->bitp()->dtypep()->numeric()); - if (widthBad(nodep->bitp(), selwidthDTypep) - && nodep->bitp()->width()!=32) { + if (widthBad(nodep->bitp(), selwidthDTypep) && nodep->bitp()->width() != 32) { nodep->v3warn(WIDTH, "Bit extraction of array[" - <bitp()->width() - <<(nodep->bitp()->width()!=nodep->bitp()->widthMin() - ?" or "+cvtToStr(nodep->bitp()->widthMin()):"") - <<" bits."); + << frommsb << ":" << fromlsb << "] requires " << selwidth + << " bit index, not " << nodep->bitp()->width() + << (nodep->bitp()->width() != nodep->bitp()->widthMin() + ? " or " + cvtToStr(nodep->bitp()->widthMin()) + : "") + << " bits."); if (!nodep->fileline()->warnIsOff(V3ErrorCode::WIDTH)) { - UINFO(1," Related node: "<dtypep()<dtypep() << endl); } } if (!m_doGenerate) { // Must check bounds before adding a select that truncates the bound // Note we've already subtracted off LSB if (VN_IS(nodep->bitp(), Const) - && (VN_CAST(nodep->bitp(), Const)->toSInt() > (frommsb-fromlsb) + && (VN_CAST(nodep->bitp(), Const)->toSInt() > (frommsb - fromlsb) || VN_CAST(nodep->bitp(), Const)->toSInt() < 0)) { - nodep->v3warn(SELRANGE, "Selection index out of range: " - <<(VN_CAST(nodep->bitp(), Const)->toSInt()+fromlsb) - <<" outside "<v3warn(SELRANGE, + "Selection index out of range: " + << (VN_CAST(nodep->bitp(), Const)->toSInt() + fromlsb) + << " outside " << frommsb << ":" << fromlsb); + UINFO(1, " Related node: " << nodep << endl); } - widthCheckSized(nodep, "Extract Range", - nodep->bitp(), selwidthDTypep, EXTEND_EXP, false/*NOWARN*/); + widthCheckSized(nodep, "Extract Range", nodep->bitp(), selwidthDTypep, EXTEND_EXP, + false /*NOWARN*/); } } } @@ -829,10 +868,11 @@ private: AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefp(); AstAssocArrayDType* adtypep = VN_CAST(fromDtp, AssocArrayDType); if (!adtypep) { - UINFO(1," Related dtype: "<v3fatalSrc("Associative array reference is not to associative array"); } - iterateCheckTyped(nodep, "Associative select", nodep->bitp(), adtypep->keyDTypep(), BOTH); + iterateCheckTyped(nodep, "Associative select", nodep->bitp(), adtypep->keyDTypep(), + BOTH); nodep->dtypeFrom(adtypep->subDTypep()); } } @@ -846,14 +886,13 @@ private: AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefp(); AstUnpackArrayDType* adtypep = VN_CAST(fromDtp, UnpackArrayDType); if (!adtypep) { - UINFO(1," Related dtype: "<v3fatalSrc("Packed array reference exceeds dimension of array"); } // Build new array Dtype based on the original's base type, but with new bounds - AstNodeDType* newDtp = new AstUnpackArrayDType(nodep->fileline(), - adtypep->subDTypep(), - new AstRange(nodep->fileline(), - nodep->declRange())); + AstNodeDType* newDtp + = new AstUnpackArrayDType(nodep->fileline(), adtypep->subDTypep(), + new AstRange(nodep->fileline(), nodep->declRange())); v3Global.rootp()->typeTablep()->addTypesp(newDtp); nodep->dtypeFrom(newDtp); @@ -863,15 +902,16 @@ private: if ((nodep->declRange().hi() > adtypep->declRange().hi()) || nodep->declRange().lo() < adtypep->declRange().lo()) { // Other simulators warn too - nodep->v3error("Slice selection index '"<< nodep->declRange() << "'" - <<" outside data type's '"<< adtypep->declRange() << "'"); - } - else if ((nodep->declRange().littleEndian() - != adtypep->declRange().littleEndian()) - && nodep->declRange().hi() != nodep->declRange().lo()) { - nodep->v3error("Slice selection '"<< nodep->declRange() << "'" - <<" has backward indexing versus data type's '" - <declRange() << "'"); + nodep->v3error("Slice selection index '" << nodep->declRange() << "'" + << " outside data type's '" + << adtypep->declRange() << "'"); + } else if ((nodep->declRange().littleEndian() + != adtypep->declRange().littleEndian()) + && nodep->declRange().hi() != nodep->declRange().lo()) { + nodep->v3error("Slice selection '" + << nodep->declRange() << "'" + << " has backward indexing versus data type's '" + << adtypep->declRange() << "'"); } } } @@ -884,7 +924,11 @@ private: userIterateAndNext(nodep->thsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel userIterateAndNext(nodep->attrp(), WidthVP(SELF, BOTH).p()); AstNode* selp = V3Width::widthSelNoIterEdit(nodep); - if (selp!=nodep) { nodep = NULL; userIterate(selp, m_vup); return; } + if (selp != nodep) { + nodep = NULL; + userIterate(selp, m_vup); + return; + } nodep->v3fatalSrc("AstSelBit should disappear after widthSel"); } virtual void visit(AstSelExtract* nodep) VL_OVERRIDE { @@ -894,7 +938,11 @@ private: userIterateAndNext(nodep->thsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel userIterateAndNext(nodep->attrp(), WidthVP(SELF, BOTH).p()); AstNode* selp = V3Width::widthSelNoIterEdit(nodep); - if (selp!=nodep) { nodep = NULL; userIterate(selp, m_vup); return; } + if (selp != nodep) { + nodep = NULL; + userIterate(selp, m_vup); + return; + } nodep->v3fatalSrc("AstSelExtract should disappear after widthSel"); } virtual void visit(AstSelPlus* nodep) VL_OVERRIDE { @@ -903,7 +951,11 @@ private: userIterateAndNext(nodep->thsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel userIterateAndNext(nodep->attrp(), WidthVP(SELF, BOTH).p()); AstNode* selp = V3Width::widthSelNoIterEdit(nodep); - if (selp!=nodep) { nodep = NULL; userIterate(selp, m_vup); return; } + if (selp != nodep) { + nodep = NULL; + userIterate(selp, m_vup); + return; + } nodep->v3fatalSrc("AstSelPlus should disappear after widthSel"); } virtual void visit(AstSelMinus* nodep) VL_OVERRIDE { @@ -912,7 +964,11 @@ private: userIterateAndNext(nodep->thsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel userIterateAndNext(nodep->attrp(), WidthVP(SELF, BOTH).p()); AstNode* selp = V3Width::widthSelNoIterEdit(nodep); - if (selp!=nodep) { nodep = NULL; userIterate(selp, m_vup); return; } + if (selp != nodep) { + nodep = NULL; + userIterate(selp, m_vup); + return; + } nodep->v3fatalSrc("AstSelMinus should disappear after widthSel"); } @@ -954,8 +1010,9 @@ private: nodep->ticksp()->unlinkFrBack()->deleteTree(); } else { if (constp->toSInt() > 10) { - constp->v3warn(TICKCOUNT, "$past tick value of "<toSInt() - <<" may have a large performance cost"); + constp->v3warn(TICKCOUNT, "$past tick value of " + << constp->toSInt() + << " may have a large performance cost"); } } } @@ -985,7 +1042,9 @@ private: if (m_vup->final()) { AstNodeDType* expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); nodep->dtypeFrom(expDTypep); // Assume user knows the rules; go with the flow - if (nodep->width()>64) nodep->v3error("Unsupported: $c can't generate wider than 64 bits"); + if (nodep->width() > 64) { + nodep->v3error("Unsupported: $c can't generate wider than 64 bits"); + } } } virtual void visit(AstCLog2* nodep) VL_OVERRIDE { @@ -1032,8 +1091,8 @@ private: } if (newp) { newp->dtypeFrom(nodep); - UINFO(9,"powOld "<replaceWith(newp), nodep); } } @@ -1060,8 +1119,9 @@ private: if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); // If it's a 32 bit number, we need a 6 bit number as we need to return '32'. - int selwidth = V3Number::log2b(nodep->lhsp()->width())+1; - nodep->dtypeSetLogicSized(selwidth, AstNumeric::UNSIGNED); // Spec doesn't indicate if an integer + int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1; + nodep->dtypeSetLogicSized( + selwidth, AstNumeric::UNSIGNED); // Spec doesn't indicate if an integer } } virtual void visit(AstCvtPackString* nodep) VL_OVERRIDE { @@ -1083,11 +1143,11 @@ private: break; case AstAttrType::DIM_DIMENSIONS: case AstAttrType::DIM_UNPK_DIMENSIONS: { - UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, - "Unsized expression"); - std::pair dim = nodep->fromp()->dtypep()->dimensions(true); - int val = (nodep->attrType()==AstAttrType::DIM_UNPK_DIMENSIONS - ? dim.second : (dim.first+dim.second)); + UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, "Unsized expression"); + std::pair dim = nodep->fromp()->dtypep()->dimensions(true); + int val = (nodep->attrType() == AstAttrType::DIM_UNPK_DIMENSIONS + ? dim.second + : (dim.first + dim.second)); nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Signed32(), val)); VL_DO_DANGLING(nodep->deleteTree(), nodep); break; @@ -1108,13 +1168,15 @@ private: newp->dtypeSetSigned32(); newp->didWidth(true); newp->protect(false); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); break; } case AstAttrType::DIM_LEFT: case AstAttrType::DIM_LOW: { AstNode* newp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); break; } case AstAttrType::DIM_RIGHT: @@ -1127,12 +1189,14 @@ private: AstNode* newp = new AstSub(nodep->fileline(), sizep, new AstConst(nodep->fileline(), AstConst::Signed32(), 1)); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); break; } case AstAttrType::DIM_INCREMENT: { AstNode* newp = new AstConst(nodep->fileline(), AstConst::Signed32(), -1); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); break; } case AstAttrType::DIM_BITS: { @@ -1149,14 +1213,15 @@ private: int dim = 1; AstConst* newp = dimensionValue(nodep->fileline(), nodep->fromp()->dtypep(), nodep->attrType(), dim); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (VN_IS(nodep->dimp(), Const)) { int dim = VN_CAST(nodep->dimp(), Const)->toSInt(); AstConst* newp = dimensionValue(nodep->fileline(), nodep->fromp()->dtypep(), nodep->attrType(), dim); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - } - else { // Need a runtime lookup table. Yuk. + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else { // Need a runtime lookup table. Yuk. UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, "Unsized expression"); AstVar* varp @@ -1165,7 +1230,8 @@ private: AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false); varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp()); AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, dimp); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } } break; @@ -1174,13 +1240,14 @@ private: UASSERT_OBJ(nodep->fromp(), nodep, "Unprovided expression"); string result = nodep->fromp()->dtypep()->prettyDTypeName(); AstNode* newp = new AstConst(nodep->fileline(), AstConst::String(), result); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); break; } default: { // Everything else resolved earlier nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::UNSIGNED); // Approximation, unsized 32 - UINFO(1,"Missing ATTR type case node: "<v3fatalSrc("Missing ATTR type case"); break; } @@ -1211,17 +1278,19 @@ private: int width = nodep->subDTypep()->width() * nodep->rangep()->elementsConst(); nodep->widthForce(width, width); } - UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); - if (nodep->keyChildDTypep()) nodep->keyDTypep(moveDTypeEdit(nodep, nodep->keyChildDTypep())); + if (nodep->keyChildDTypep()) { + nodep->keyDTypep(moveDTypeEdit(nodep, nodep->keyChildDTypep())); + } // Iterate into subDTypep() to resolve that type and update pointer. nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); nodep->keyDTypep(iterateEditDTypep(nodep, nodep->keyDTypep())); nodep->dtypep(nodep); // The array itself, not subDtype - UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed @@ -1229,7 +1298,7 @@ private: // Iterate into subDTypep() to resolve that type and update pointer. nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); // The array itself, not subDtype - UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed @@ -1240,7 +1309,7 @@ private: if (VN_IS(nodep->boundp(), Unbounded)) { nodep->boundp()->unlinkFrBack()->deleteTree(); // NULL will represent unbounded } - UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed @@ -1249,7 +1318,7 @@ private: nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); // Cleanup array size nodep->dtypep(nodep); // The array itself, not subDtype - UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed @@ -1261,20 +1330,18 @@ private: // Furthermore the width() calculation would return identical // values. Therefore we can directly replace the width nodep->widthForce(nodep->rangep()->elementsConst(), nodep->rangep()->elementsConst()); - } - else if (nodep->isRanged()) { + } else if (nodep->isRanged()) { nodep->widthForce(nodep->nrange().elements(), nodep->nrange().elements()); - } - else if (nodep->implicit()) { + } else if (nodep->implicit()) { // Parameters may notice implicitness and change to different dtype nodep->widthForce(1, 1); } // else width in node is correct; it was set based on keyword().width() // at construction time. Ditto signed, so "unsigned byte" etc works right. nodep->cvtRangeConst(); - // TODO: If BasicDType now looks like a generic type, we can convert to a real generic dtype - // Instead for now doing this in V3WidthCommit - UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed @@ -1287,11 +1354,11 @@ private: userIterateChildren(nodep, NULL); nodep->dtypep(nodep); // Should already be set, but be clear it's not the subDType nodep->widthFromSub(nodep->subDTypep()); - UINFO(4,"dtWidthed "<doingWidth()) { // Early exit if have circular parameter definition - nodep->v3error("Typedef's type is circular: "<prettyName()); + nodep->v3error("Typedef's type is circular: " << nodep->prettyName()); nodep->dtypeSetLogicBool(); nodep->doingWidth(false); return; @@ -1315,7 +1382,7 @@ private: nodep->dtypeFrom(nodep->defp()); userIterate(nodep->defp(), NULL); nodep->widthFromSub(nodep->subDTypep()); - UINFO(4,"dtWidthed "<doingWidth(false); } virtual void visit(AstTypedef* nodep) VL_OVERRIDE { @@ -1337,20 +1404,20 @@ private: V3Const::constifyParamsEdit(nodep->dtp()); // itemp may change if (AstConst* constp = VN_CAST(nodep->dtp(), Const)) { constp->unlinkFrBack(); - AstNode* newp = new AstCastSize(nodep->fileline(), - nodep->lhsp()->unlinkFrBack(), constp); + AstNode* newp + = new AstCastSize(nodep->fileline(), nodep->lhsp()->unlinkFrBack(), constp); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); userIterate(newp, m_vup); } else { - nodep->v3error("Unsupported: Cast to "<dtp()->prettyTypeName()); + nodep->v3error("Unsupported: Cast to " << nodep->dtp()->prettyTypeName()); nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); } } virtual void visit(AstCast* nodep) VL_OVERRIDE { if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep())); - //if (debug()) nodep->dumpTree(cout, " CastPre: "); + // if (debug()) nodep->dumpTree(cout, " CastPre: "); userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); // When more general casts are supported, the cast elimination will be done later. // For now, replace it ASAP, so widthing can propagate easily @@ -1373,34 +1440,33 @@ private: if (basicp->isSigned()) { newp = new AstRToIRoundS(nodep->fileline(), newp); } else { - newp = new AstUnsigned(nodep->fileline(), - new AstRToIS(nodep->fileline(), newp)); + newp = new AstUnsigned(nodep->fileline(), new AstRToIS(nodep->fileline(), newp)); } } else if (basicp->isSigned() && !newp->isSigned()) { newp = new AstSigned(nodep->fileline(), newp); } else if (!basicp->isSigned() && newp->isSigned()) { newp = new AstUnsigned(nodep->fileline(), newp); } else { - //newp = newp; // Can just remove cast + // newp = newp; // Can just remove cast } nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - //if (debug()) newp->dumpTree(cout, " CastOut: "); + // if (debug()) newp->dumpTree(cout, " CastOut: "); } virtual void visit(AstCastSize* nodep) VL_OVERRIDE { // IEEE: Signedness of result is same as self-determined signedness // However, the result is same as BITSEL, so we do not sign extend the LHS - UASSERT_OBJ(VN_IS(nodep->rhsp(), Const), nodep, - "Unsupported: Non-const cast of size"); - //if (debug()) nodep->dumpTree(cout, " CastSizePre: "); + UASSERT_OBJ(VN_IS(nodep->rhsp(), Const), nodep, "Unsupported: Non-const cast of size"); + // if (debug()) nodep->dumpTree(cout, " CastSizePre: "); if (m_vup->prelim()) { int width = VN_CAST(nodep->rhsp(), Const)->toSInt(); - if (width < 1) { nodep->v3error("Size-changing cast to zero or negative size"); width=1; } + if (width < 1) { + nodep->v3error("Size-changing cast to zero or negative size"); + width = 1; + } userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p()); AstBasicDType* underDtp = VN_CAST(nodep->lhsp()->dtypep(), BasicDType); - if (!underDtp) { - underDtp = nodep->lhsp()->dtypep()->basicp(); - } + if (!underDtp) underDtp = nodep->lhsp()->dtypep()->basicp(); if (!underDtp) { nodep->v3error("Unsupported: Size-changing cast on non-basic data type"); underDtp = VN_CAST(nodep->findLogicBoolDType(), BasicDType); @@ -1411,19 +1477,22 @@ private: // So two steps, first do the calculation's width (max of the two widths) { int calcWidth = std::max(width, underDtp->width()); - AstNodeDType* calcDtp = (underDtp->isFourstate() - ? nodep->findLogicDType(calcWidth, calcWidth, underDtp->numeric()) - : nodep->findBitDType(calcWidth, calcWidth, underDtp->numeric())); + AstNodeDType* calcDtp + = (underDtp->isFourstate() + ? nodep->findLogicDType(calcWidth, calcWidth, underDtp->numeric()) + : nodep->findBitDType(calcWidth, calcWidth, underDtp->numeric())); nodep->dtypep(calcDtp); // We ignore warnings as that is sort of the point of a cast - iterateCheck(nodep, "Cast expr", nodep->lhsp(), CONTEXT, FINAL, calcDtp, EXTEND_EXP, false); + iterateCheck(nodep, "Cast expr", nodep->lhsp(), CONTEXT, FINAL, calcDtp, + EXTEND_EXP, false); } - //if (debug()) nodep->dumpTree(cout, " CastSizeClc: "); + // if (debug()) nodep->dumpTree(cout, " CastSizeClc: "); // Next step, make the proper output width { - AstNodeDType* outDtp = (underDtp->isFourstate() - ? nodep->findLogicDType(width, width, underDtp->numeric()) - : nodep->findBitDType(width, width, underDtp->numeric())); + AstNodeDType* outDtp + = (underDtp->isFourstate() + ? nodep->findLogicDType(width, width, underDtp->numeric()) + : nodep->findBitDType(width, width, underDtp->numeric())); nodep->dtypep(outDtp); // We ignore warnings as that is sort of the point of a cast widthCheckSized(nodep, "Cast expr", nodep->lhsp(), outDtp, EXTEND_EXP, false); @@ -1435,17 +1504,17 @@ private: nodep->replaceWith(underp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - //if (debug()) nodep->dumpTree(cout, " CastSizeOut: "); + // if (debug()) nodep->dumpTree(cout, " CastSizeOut: "); } virtual void visit(AstVar* nodep) VL_OVERRIDE { - //if (debug()) nodep->dumpTree(cout, " InitPre: "); + // if (debug()) nodep->dumpTree(cout, " InitPre: "); // Must have deterministic constant width // We can't skip this step when width()!=0, as creating a AstVar // with non-constant range gets size 1, not size 0. So use didWidth(). if (nodep->didWidth()) return; if (nodep->doingWidth()) { // Early exit if have circular parameter definition UASSERT_OBJ(nodep->valuep(), nodep, "circular, but without value"); - nodep->v3error("Variable's initial value is circular: "<prettyNameQ()); + nodep->v3error("Variable's initial value is circular: " << nodep->prettyNameQ()); pushDeletep(nodep->valuep()->unlinkFrBack()); nodep->valuep(new AstConst(nodep->fileline(), AstConst::LogicTrue())); nodep->dtypeFrom(nodep->valuep()); @@ -1465,15 +1534,13 @@ private: nodep->dtypep(newp); v3Global.rootp()->typeTablep()->addTypesp(newp); } - } - else if (nodep->isIO() && !(VN_IS(nodep->dtypeSkipRefp(), BasicDType) - || VN_IS(nodep->dtypeSkipRefp(), NodeArrayDType) - || VN_IS(nodep->dtypeSkipRefp(), NodeUOrStructDType))) { + } else if (nodep->isIO() + && !(VN_IS(nodep->dtypeSkipRefp(), BasicDType) + || VN_IS(nodep->dtypeSkipRefp(), NodeArrayDType) + || VN_IS(nodep->dtypeSkipRefp(), NodeUOrStructDType))) { nodep->v3error("Unsupported: Inputs and outputs must be simple data types"); } - if (VN_IS(nodep->dtypep()->skipRefToConstp(), ConstDType)) { - nodep->isConst(true); - } + if (VN_IS(nodep->dtypep()->skipRefToConstp(), ConstDType)) nodep->isConst(true); // Parameters if implicit untyped inherit from what they are assigned to AstBasicDType* bdtypep = VN_CAST(nodep->dtypep(), BasicDType); bool didchk = false; @@ -1481,64 +1548,70 @@ private: if (implicitParam) { if (nodep->valuep()) { userIterateAndNext(nodep->valuep(), WidthVP(nodep->dtypep(), PRELIM).p()); - UINFO(9,"implicitParamPRELIMIV "<valuep()<valuep() << endl); // Although nodep will get a different width for parameters // just below, we want the init numbers to retain their // width/minwidth until parameters are replaced. // This prevents width warnings at the location the parameter is substituted in if (nodep->valuep()->isDouble()) { - nodep->dtypeSetDouble(); VL_DANGLING(bdtypep); + nodep->dtypeSetDouble(); + VL_DANGLING(bdtypep); } else { int width = 0; AstBasicDType* valueBdtypep = nodep->valuep()->dtypep()->basicp(); bool issigned = false; if (bdtypep->isNosign()) { if (valueBdtypep && valueBdtypep->isSigned()) issigned = true; - } else issigned = bdtypep->isSigned(); + } else { + issigned = bdtypep->isSigned(); + } if (nodep->valuep()->dtypep()->widthSized()) { width = nodep->valuep()->width(); } else { - if (nodep->valuep()->width()>32) { - nodep->valuep()->v3warn(WIDTH, "Assigning >32 bit to unranged parameter (defaults to 32 bits)"); + if (nodep->valuep()->width() > 32) { + nodep->valuep()->v3warn( + WIDTH, + "Assigning >32 bit to unranged parameter (defaults to 32 bits)"); } width = 32; } // Can't just inherit valuep()->dtypep() as mwidth might not equal width - if (width==1) { + if (width == 1) { // one bit parameter is same as "parameter [0] foo", // not "parameter logic foo" as you can extract // "foo[0]" from a parameter but not a wire nodep->dtypeChgWidthSigned(width, nodep->valuep()->widthMin(), AstNumeric::fromBool(issigned)); - nodep->dtypep(nodep->findLogicRangeDType - (VNumRange(0, 0, false), - nodep->valuep()->widthMin(), - AstNumeric::fromBool(issigned))); + nodep->dtypep(nodep->findLogicRangeDType(VNumRange(0, 0, false), + nodep->valuep()->widthMin(), + AstNumeric::fromBool(issigned))); } else { nodep->dtypeChgWidthSigned(width, nodep->valuep()->widthMin(), AstNumeric::fromBool(issigned)); } didchk = true; } - iterateCheckAssign(nodep, "Initial value", nodep->valuep(), FINAL, nodep->dtypep()); - UINFO(9,"implicitParamFromIV "<valuep()<valuep(), FINAL, + nodep->dtypep()); + UINFO(9, "implicitParamFromIV " << nodep->valuep() << endl); + // UINFO below will print variable nodep } else { // Or, if nothing assigned, they're integral - nodep->dtypeSetSigned32(); VL_DANGLING(bdtypep); + nodep->dtypeSetSigned32(); + VL_DANGLING(bdtypep); } - } - else if (bdtypep && bdtypep->implicit()) { // Implicits get converted to size 1 - nodep->dtypeSetLogicSized(1, bdtypep->numeric()); VL_DANGLING(bdtypep); + } else if (bdtypep && bdtypep->implicit()) { // Implicits get converted to size 1 + nodep->dtypeSetLogicSized(1, bdtypep->numeric()); + VL_DANGLING(bdtypep); } if (nodep->valuep() && !didchk) { - //if (debug()) nodep->dumpTree(cout, " final: "); + // if (debug()) nodep->dumpTree(cout, " final: "); // AstPattern requires assignments to pass datatype on PRELIM userIterateAndNext(nodep->valuep(), WidthVP(nodep->dtypep(), PRELIM).p()); iterateCheckAssign(nodep, "Initial value", nodep->valuep(), FINAL, nodep->dtypep()); } - UINFO(4,"varWidthed "<dumpTree(cout, " InitOut: "); + UINFO(4, "varWidthed " << nodep << endl); + // if (debug()) nodep->dumpTree(cout, " InitOut: "); nodep->didWidth(true); nodep->doingWidth(false); } @@ -1546,8 +1619,10 @@ private: if (nodep->didWidth()) return; if (!nodep->varp()) { if (m_paramsOnly && VN_IS(nodep, VarXRef)) { - checkConstantOrReplace(nodep, "Parameter-resolved constants must not use dotted references: " - +nodep->prettyNameQ()); VL_DANGLING(nodep); + checkConstantOrReplace( + nodep, "Parameter-resolved constants must not use dotted references: " + + nodep->prettyNameQ()); + VL_DANGLING(nodep); return; } else { nodep->v3fatalSrc("Unlinked varref"); @@ -1557,28 +1632,27 @@ private: // Var hasn't been widthed, so make it so. userIterate(nodep->varp(), NULL); } - //if (debug()>=9) { nodep->dumpTree(cout, " VRin "); nodep->varp()->dumpTree(cout, " forvar "); } + // if (debug()>=9) { nodep->dumpTree(cout, " VRin "); + // nodep->varp()->dumpTree(cout, " forvar "); } // Note genvar's are also entered as integers nodep->dtypeFrom(nodep->varp()); if (VN_IS(nodep->backp(), NodeAssign) && nodep->lvalue()) { // On LHS UASSERT_OBJ(nodep->dtypep(), nodep, "LHS var should be dtype completed"); } - //if (debug()>=9) nodep->dumpTree(cout, " VRout "); + // if (debug() >= 9) nodep->dumpTree(cout, " VRout "); if (nodep->lvalue() && nodep->varp()->direction() == VDirection::CONSTREF) { - nodep->v3error("Assigning to const ref variable: "<prettyNameQ()); - } - else if (nodep->lvalue() && nodep->varp()->isConst() - && !m_paramsOnly - && !m_initialp) { // Too loose, but need to allow our generated first assignment - // // Move this to a property of the AstInitial block - nodep->v3error("Assigning to const variable: "<prettyNameQ()); + nodep->v3error("Assigning to const ref variable: " << nodep->prettyNameQ()); + } else if (nodep->lvalue() && nodep->varp()->isConst() && !m_paramsOnly && !m_initialp) { + // Too loose, but need to allow our generated first assignment + // Move this to a property of the AstInitial block + nodep->v3error("Assigning to const variable: " << nodep->prettyNameQ()); } nodep->didWidth(true); } virtual void visit(AstEnumDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - UINFO(5," ENUMDTYPE "<childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); @@ -1586,14 +1660,16 @@ private: // Assign widths userIterateAndNext(nodep->itemsp(), WidthVP(nodep->dtypep(), BOTH).p()); // Assign missing values - V3Number num (nodep, nodep->width(), 0); - V3Number one (nodep, nodep->width(), 1); - std::map inits; - for (AstEnumItem* itemp = nodep->itemsp(); - itemp; itemp = VN_CAST(itemp->nextp(), EnumItem)) { + V3Number num(nodep, nodep->width(), 0); + V3Number one(nodep, nodep->width(), 1); + std::map inits; + for (AstEnumItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), EnumItem)) { if (itemp->valuep()) { - if (debug()>=9) { UINFO(0,"EnumInit "<valuep()->dumpTree(cout, "-EnumInit: "); } + if (debug() >= 9) { + UINFO(0, "EnumInit " << itemp << endl); + itemp->valuep()->dumpTree(cout, "-EnumInit: "); + } V3Const::constifyParamsEdit(itemp->valuep()); // itemp may change if (!VN_IS(itemp->valuep(), Const)) { itemp->valuep()->v3error("Enum value isn't a constant"); @@ -1606,7 +1682,8 @@ private: if (num.isEqZero() && itemp != nodep->itemsp()) itemp->v3error("Enum value illegally wrapped around (IEEE 1800-2017 6.19)"); if (num.isFourState()) - itemp->v3error("Enum value that is unassigned cannot follow value with X/Zs (IEEE 1800-2017 6.19)"); + itemp->v3error("Enum value that is unassigned cannot follow value with X/Zs " + "(IEEE 1800-2017 6.19)"); if (!nodep->dtypep()->basicp() && !nodep->dtypep()->basicp()->keyword().isIntNumeric()) { itemp->v3error("Enum names without values only allowed on numeric types"); @@ -1618,16 +1695,17 @@ private: AstConst* constp = VN_CAST(itemp->valuep(), Const); if (constp->num().isFourState() && nodep->dtypep()->basicp() && !nodep->dtypep()->basicp()->isFourstate()) - itemp->v3error("Enum value with X/Zs cannot be assigned to non-fourstate type (IEEE 1800-2017 6.19)"); + itemp->v3error("Enum value with X/Zs cannot be assigned to non-fourstate type " + "(IEEE 1800-2017 6.19)"); num.opAssign(constp->num()); // Look for duplicates if (inits.find(num) != inits.end()) { // IEEE says illegal AstNode* otherp = inits.find(num)->second; - itemp->v3error("Overlapping enumeration value: "<prettyNameQ()<warnContextPrimary()<warnOther() - <<"... Location of original declaration\n" - <warnContextSecondary()); + itemp->v3error("Overlapping enumeration value: " + << itemp->prettyNameQ() << endl + << itemp->warnContextPrimary() << endl + << otherp->warnOther() << "... Location of original declaration\n" + << otherp->warnContextSecondary()); } else { inits.insert(make_pair(num, itemp)); } @@ -1635,7 +1713,7 @@ private: } } virtual void visit(AstEnumItem* nodep) VL_OVERRIDE { - UINFO(5," ENUMITEM "<dtypep(); UASSERT_OBJ(vdtypep, nodep, "ENUMITEM not under ENUM"); nodep->dtypep(vdtypep); @@ -1644,7 +1722,8 @@ private: userIterateAndNext(nodep->valuep(), WidthVP(CONTEXT, PRELIM).p()); // Minwidth does not come from value, as spec says set based on parent // and if we keep minwidth we'll consider it unsized which is incorrect - iterateCheck(nodep, "Enum value", nodep->valuep(), CONTEXT, FINAL, nodep->dtypep(), EXTEND_EXP); + iterateCheck(nodep, "Enum value", nodep->valuep(), CONTEXT, FINAL, nodep->dtypep(), + EXTEND_EXP); } } virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE { @@ -1652,7 +1731,7 @@ private: // We need to do the whole enum en-mass AstNode* enump = nodep->itemp(); UASSERT_OBJ(enump, nodep, "EnumItemRef not linked"); - for (; enump; enump=enump->backp()) { + for (; enump; enump = enump->backp()) { if (VN_IS(enump, EnumDType)) break; } UASSERT_OBJ(enump, nodep, "EnumItemRef can't deref back to an Enum"); @@ -1660,7 +1739,7 @@ private: } nodep->dtypeFrom(nodep->itemp()); } - virtual void visit(AstInitItem* nodep) VL_OVERRIDE { + virtual void visit(AstInitItem* nodep) VL_OVERRIDE { // userIterateChildren(nodep, m_vup); } virtual void visit(AstInitArray* nodep) VL_OVERRIDE { @@ -1678,29 +1757,30 @@ private: } virtual void visit(AstInside* nodep) VL_OVERRIDE { userIterateAndNext(nodep->exprp(), WidthVP(CONTEXT, PRELIM).p()); - for (AstNode* nextip, *itemp = nodep->itemsp(); itemp; itemp=nextip) { + for (AstNode *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) { nextip = itemp->nextp(); // Prelim may cause the node to get replaced VL_DO_DANGLING(userIterate(itemp, WidthVP(CONTEXT, PRELIM).p()), itemp); } // Take width as maximum across all items int width = nodep->exprp()->width(); int mwidth = nodep->exprp()->widthMin(); - for (AstNode* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()) { + for (AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) { width = std::max(width, itemp->width()); mwidth = std::max(mwidth, itemp->widthMin()); } // Apply width AstNodeDType* subDTypep = nodep->findLogicDType(width, mwidth, nodep->exprp()->dtypep()->numeric()); - iterateCheck(nodep, "Inside expression", nodep->exprp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP); - for (AstNode* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()) { + iterateCheck(nodep, "Inside expression", nodep->exprp(), CONTEXT, FINAL, subDTypep, + EXTEND_EXP); + for (AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) { iterateCheck(nodep, "Inside Item", itemp, CONTEXT, FINAL, subDTypep, EXTEND_EXP); } nodep->dtypeSetLogicBool(); - if (debug()>=9) nodep->dumpTree(cout, "-inside-in: "); + if (debug() >= 9) nodep->dumpTree(cout, "-inside-in: "); // Now rip out the inside and replace with simple math AstNode* newp = NULL; - for (AstNode* nextip, *itemp = nodep->itemsp(); itemp; itemp=nextip) { + for (AstNode *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) { nextip = itemp->nextp(); // Will be unlinking AstNode* inewp; if (AstInsideRange* irangep = VN_CAST(itemp, InsideRange)) { @@ -1708,16 +1788,19 @@ private: inewp = irangep->newAndFromInside(nodep->exprp(), irangep->lhsp()->unlinkFrBack(), irangep->rhsp()->unlinkFrBack()); } else { - inewp = new AstEqWild(itemp->fileline(), - nodep->exprp()->cloneTree(true), + inewp = new AstEqWild(itemp->fileline(), nodep->exprp()->cloneTree(true), itemp->unlinkFrBack()); } - if (newp) newp = new AstOr(nodep->fileline(), newp, inewp); - else newp = inewp; + if (newp) { + newp = new AstOr(nodep->fileline(), newp, inewp); + } else { + newp = inewp; + } } if (!newp) newp = new AstConst(nodep->fileline(), AstConst::LogicFalse()); - if (debug()>=9) newp->dumpTree(cout, "-inside-out: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + if (debug() >= 9) newp->dumpTree(cout, "-inside-out: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } virtual void visit(AstInsideRange* nodep) VL_OVERRIDE { // Just do each side; AstInside will rip these nodes out later @@ -1728,16 +1811,16 @@ private: virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - UINFO(5," IFACEREF "<dtypep(nodep); nodep->widthForce(1, 1); // Not really relevant - UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - UINFO(5," NODECLASS "<=9) nodep->dumpTree("-class-in--"); + UINFO(5, " NODECLASS " << nodep << endl); + // if (debug() >= 9) nodep->dumpTree("-class-in--"); if (!nodep->packed()) { nodep->v3warn(UNPACKED, "Unsupported: Unpacked struct/union"); if (!v3Global.opt.structsPacked()) { @@ -1753,9 +1836,9 @@ private: nodep->isFourstate(false); // MSB is first, so go backwards AstMemberDType* itemp; - for (itemp = nodep->membersp(); - itemp && itemp->nextp(); itemp=VN_CAST(itemp->nextp(), MemberDType)) ; - for (AstMemberDType* backip; itemp; itemp=backip) { + for (itemp = nodep->membersp(); itemp && itemp->nextp(); + itemp = VN_CAST(itemp->nextp(), MemberDType)) {} + for (AstMemberDType* backip; itemp; itemp = backip) { if (itemp->isFourstate()) nodep->isFourstate(true); backip = VN_CAST(itemp->backp(), MemberDType); itemp->lsb(lsb); @@ -1767,7 +1850,7 @@ private: } } nodep->widthForce(width, width); // Signing stays as-is, as parsed from declaration - //if (debug()>=9) nodep->dumpTree("-class-out-"); + // if (debug() >= 9) nodep->dumpTree("-class-out-"); } virtual void visit(AstClass* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; @@ -1791,14 +1874,14 @@ private: nodep->widthFromSub(nodep->subDTypep()); } virtual void visit(AstMemberSel* nodep) VL_OVERRIDE { - UINFO(5," MEMBERSEL "<=9) nodep->dumpTree("-mbs-in: "); + UINFO(5, " MEMBERSEL " << nodep << endl); + if (debug() >= 9) nodep->dumpTree("-mbs-in: "); userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); - if (debug()>=9) nodep->dumpTree("-mbs-ic: "); + if (debug() >= 9) nodep->dumpTree("-mbs-ic: "); // Find the fromp dtype - should be a class if (!nodep->fromp()->dtypep()) nodep->fromp()->v3fatalSrc("Unlinked data type"); AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump(); - UINFO(9," from dt "<warnOther() << "... Location of found object\n" << foundp->warnContextSecondary()); } - } else if (VN_IS(fromDtp, EnumDType) - || VN_IS(fromDtp, AssocArrayDType) - || VN_IS(fromDtp, DynArrayDType) - || VN_IS(fromDtp, QueueDType) + } else if (VN_IS(fromDtp, EnumDType) // + || VN_IS(fromDtp, AssocArrayDType) // + || VN_IS(fromDtp, DynArrayDType) // + || VN_IS(fromDtp, QueueDType) // || VN_IS(fromDtp, BasicDType)) { // Method call on enum without following parenthesis, e.g. "ENUM.next" // Convert this into a method call, and let that visitor figure out what to do next @@ -1859,9 +1942,10 @@ private: classp = classp->extendsp() ? classp->extendsp()->classp() : NULL; } string suggest = speller.bestCandidateMsg(nodep->prettyName()); - nodep->v3error("Member "<prettyNameQ()<<" not found in class " - <prettyNameQ()<<"\n" - <<(suggest.empty() ? "" : nodep->fileline()->warnMore()+suggest)); + nodep->v3error( + "Member " << nodep->prettyNameQ() << " not found in class " + << first_classp->prettyNameQ() << "\n" + << (suggest.empty() ? "" : nodep->fileline()->warnMore() + suggest)); return NULL; // Caller handles error } bool memberSelStruct(AstMemberSel* nodep, AstNodeUOrStructDType* adtypep) { @@ -1879,7 +1963,8 @@ private: newp->didWidth(true); // Don't replace dtype with basic type UINFO(9, " MEMBERSEL -> " << newp << endl); UINFO(9, " dt-> " << newp->dtypep() << endl); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); // Should be able to treat it as a normal-ish nodesel - maybe. // The lhsp() will be strange until this stage; create the number here? } @@ -1897,44 +1982,36 @@ private: virtual void visit(AstMethodCall* nodep) VL_OVERRIDE { UINFO(5, " METHODCALL " << nodep << endl); if (nodep->didWidth()) return; - if (debug()>=9) nodep->dumpTree("-mts-in: "); + if (debug() >= 9) nodep->dumpTree("-mts-in: "); // Should check types the method requires, but at present we don't do much userIterate(nodep->fromp(), WidthVP(SELF, BOTH).p()); - for (AstArg* argp = VN_CAST(nodep->pinsp(), Arg); - argp; argp = VN_CAST(argp->nextp(), Arg)) { + for (AstArg* argp = VN_CAST(nodep->pinsp(), Arg); argp; + argp = VN_CAST(argp->nextp(), Arg)) { if (argp->exprp()) userIterate(argp->exprp(), WidthVP(SELF, BOTH).p()); } // Find the fromp dtype - should be a class - UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, - "Unsized expression"); + UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, "Unsized expression"); AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump(); AstBasicDType* basicp = fromDtp ? fromDtp->basicp() : NULL; - UINFO(9," from dt "<isString()) { + } else if (basicp && basicp->isString()) { methodCallString(nodep, basicp); - } - else { + } else { nodep->v3error("Unsupported: Member call on object '" - <fromp()->prettyTypeName() - <<"' which is a '"<fromp()->dtypep()->prettyTypeName()<<"'"); + << nodep->fromp()->prettyTypeName() << "' which is a '" + << nodep->fromp()->dtypep()->prettyTypeName() << "'"); } } void methodOkArguments(AstMethodCall* nodep, int minArg, int maxArg) { @@ -1945,19 +2022,20 @@ private: } bool ok = (narg >= minArg) && (narg <= maxArg); if (!ok) { - nodep->v3error("The "<prettyName() - <<" method does not match its requiring "<v3error("The " << narg << " arguments passed to ." << nodep->prettyName() + << " method does not match its requiring " << cvtToStr(minArg) + << (minArg == maxArg ? "" : " to " + cvtToStr(maxArg)) + << " arguments"); // Adjust to required argument counts, very bogus, but avoids core dump for (; narg < minArg; ++narg) { - nodep->addPinsp(new AstArg(nodep->fileline(), "", - new AstConst(nodep->fileline(), 0))); + nodep->addPinsp( + new AstArg(nodep->fileline(), "", new AstConst(nodep->fileline(), 0))); } for (; narg > maxArg; --narg) { AstNode* argp = nodep->pinsp(); while (argp->nextp()) argp = argp->nextp(); - argp->unlinkFrBack(); VL_DO_DANGLING(argp->deleteTree(), argp); + argp->unlinkFrBack(); + VL_DO_DANGLING(argp->deleteTree(), argp); } } } @@ -1966,8 +2044,8 @@ private: // Method call on enum without following parenthesis, e.g. "ENUM.next" // Convert this into a method call, and let that visitor figure out what to do next if (adtypep) {} - if (nodep->name() == "num" - || nodep->name() == "first" + if (nodep->name() == "num" // + || nodep->name() == "first" // || nodep->name() == "last") { // Constant value AstConst* newp = NULL; @@ -1978,33 +2056,42 @@ private: newp = new AstConst(nodep->fileline(), AstConst::Signed32(), items); } else if (nodep->name() == "first") { AstEnumItem* itemp = adtypep->itemsp(); - if (!itemp) newp = new AstConst(nodep->fileline(), AstConst::Signed32(), - 0); // Spec doesn't say what to do - else newp = VN_CAST(itemp->valuep()->cloneTree(false), Const); // A const + if (!itemp) { + newp = new AstConst(nodep->fileline(), AstConst::Signed32(), + 0); // Spec doesn't say what to do + } else { + newp = VN_CAST(itemp->valuep()->cloneTree(false), Const); // A const + } } else if (nodep->name() == "last") { AstEnumItem* itemp = adtypep->itemsp(); while (itemp && itemp->nextp()) itemp = VN_CAST(itemp->nextp(), EnumItem); - if (!itemp) newp = new AstConst(nodep->fileline(), AstConst::Signed32(), - 0); // Spec doesn't say what to do - else newp = VN_CAST(itemp->valuep()->cloneTree(false), Const); // A const + if (!itemp) { + newp = new AstConst(nodep->fileline(), AstConst::Signed32(), + 0); // Spec doesn't say what to do + } else { + newp = VN_CAST(itemp->valuep()->cloneTree(false), Const); // A const + } } UASSERT_OBJ(newp, nodep, "Enum method (perhaps enum item) not const"); newp->fileline(nodep->fileline()); // Use method's filename/line number to be clearer; // may have warning disables - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } else if (nodep->name() == "name" - || nodep->name() == "next" - || nodep->name() == "prev") { + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (nodep->name() == "name" || nodep->name() == "next" || nodep->name() == "prev") { AstAttrType attrType; - if (nodep->name() == "name") attrType = AstAttrType::ENUM_NAME; - else if (nodep->name() == "next") attrType = AstAttrType::ENUM_NEXT; - else if (nodep->name() == "prev") attrType = AstAttrType::ENUM_PREV; - else nodep->v3fatalSrc("Bad case"); + if (nodep->name() == "name") { + attrType = AstAttrType::ENUM_NAME; + } else if (nodep->name() == "next") { + attrType = AstAttrType::ENUM_NEXT; + } else if (nodep->name() == "prev") { + attrType = AstAttrType::ENUM_PREV; + } else { + nodep->v3fatalSrc("Bad case"); + } if (nodep->name() == "name") { methodOkArguments(nodep, 0, 0); - } else if (nodep->pinsp() - && !(VN_IS(VN_CAST(nodep->pinsp(), Arg)->exprp(), Const))) { + } else if (nodep->pinsp() && !(VN_IS(VN_CAST(nodep->pinsp(), Arg)->exprp(), Const))) { nodep->pinsp()->v3fatalSrc("Unsupported: enum next/prev with non-const argument"); } else if (nodep->pinsp() && !(VN_IS(VN_CAST(nodep->pinsp(), Arg)->exprp(), Const) @@ -2013,11 +2100,12 @@ private: // Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1) AstMethodCall* clonep = nodep->cloneTree(false); VN_CAST(VN_CAST(clonep->pinsp(), Arg)->exprp(), Const)->num().setLong(1); - uint32_t stepWidth = VN_CAST(VN_CAST(nodep->pinsp(), Arg)->exprp(), Const)->toUInt(); + uint32_t stepWidth + = VN_CAST(VN_CAST(nodep->pinsp(), Arg)->exprp(), Const)->toUInt(); AstConst* constp = new AstConst(nodep->fileline(), stepWidth - 1); AstArg* argp = new AstArg(nodep->fileline(), "", constp); - AstMethodCall* newp = new AstMethodCall(nodep->fileline(), clonep, - nodep->name(), argp); + AstMethodCall* newp + = new AstMethodCall(nodep->fileline(), clonep, nodep->name(), argp); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); return; @@ -2050,7 +2138,8 @@ private: // Select in case widths are // off due to msblen!=width new AstSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(), 0, selwidth)); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { nodep->v3error("Unknown built-in enum method " << nodep->prettyNameQ()); } @@ -2060,20 +2149,18 @@ private: if (nodep->name() == "num" // function int num() || nodep->name() == "size") { methodOkArguments(nodep, 0, 0); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - "size", NULL); // So don't need num() + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size", + NULL); // So don't need num() newp->dtypeSetSigned32(); newp->didWidth(true); newp->protect(false); } else if (nodep->name() == "first" // function int first(ref index) - || nodep->name() == "last" - || nodep->name() == "next" + || nodep->name() == "last" // + || nodep->name() == "next" // || nodep->name() == "prev") { methodOkArguments(nodep, 1, 1); AstNode* index_exprp = methodCallAssocIndexExpr(nodep, adtypep); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), // first/last/next/prev index_exprp->unlinkFrBack()); newp->dtypeSetSigned32(); @@ -2083,9 +2170,8 @@ private: // IEEE really should have made this a "bit" return methodOkArguments(nodep, 1, 1); AstNode* index_exprp = methodCallAssocIndexExpr(nodep, adtypep); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - "exists", index_exprp->unlinkFrBack()); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "exists", + index_exprp->unlinkFrBack()); newp->dtypeSetSigned32(); newp->pure(true); newp->protect(false); @@ -2094,32 +2180,30 @@ private: methodOkArguments(nodep, 0, 1); methodCallLValue(nodep, nodep->fromp(), true); if (!nodep->pinsp()) { - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear", NULL); newp->protect(false); newp->makeStatement(); } else { AstNode* index_exprp = methodCallAssocIndexExpr(nodep, adtypep); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - "erase", - index_exprp->unlinkFrBack()); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + "erase", index_exprp->unlinkFrBack()); newp->protect(false); newp->makeStatement(); } } else { - nodep->v3error("Unknown built-in associative array method "<prettyNameQ()); + nodep->v3error("Unknown built-in associative array method " << nodep->prettyNameQ()); } if (newp) { newp->didWidth(true); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } } AstNode* methodCallAssocIndexExpr(AstMethodCall* nodep, AstAssocArrayDType* adtypep) { AstNode* index_exprp = VN_CAST(nodep->pinsp(), Arg)->exprp(); - iterateCheck(nodep, "index", index_exprp, CONTEXT, FINAL, - adtypep->keyDTypep(), EXTEND_EXP); + iterateCheck(nodep, "index", index_exprp, CONTEXT, FINAL, adtypep->keyDTypep(), + EXTEND_EXP); VL_DANGLING(index_exprp); // May have been edited return VN_CAST(nodep->pinsp(), Arg)->exprp(); } @@ -2127,7 +2211,7 @@ private: AstNodeVarRef* varrefp = VN_CAST(childp, NodeVarRef); if (!varrefp) { nodep->v3error("Unsupported: Non-variable on LHS of built-in method '" - <prettyName()<<"'"); + << nodep->prettyName() << "'"); } else { if (lvalue) varrefp->lvalue(true); } @@ -2137,26 +2221,23 @@ private: if (nodep->name() == "at") { // Created internally for [] methodOkArguments(nodep, 1, 1); methodCallLValue(nodep, nodep->fromp(), true); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - "at", NULL); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at", + NULL); newp->dtypeFrom(adtypep->subDTypep()); newp->protect(false); newp->didWidth(true); } else if (nodep->name() == "size") { methodOkArguments(nodep, 0, 0); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - "size", NULL); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size", + NULL); newp->dtypeSetSigned32(); newp->didWidth(true); newp->protect(false); } else if (nodep->name() == "delete") { // function void delete() methodOkArguments(nodep, 0, 0); methodCallLValue(nodep, nodep->fromp(), true); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - "clear", NULL); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear", + NULL); newp->makeStatement(); } else { nodep->v3error("Unsupported/unknown built-in dynamic array method " @@ -2164,7 +2245,8 @@ private: } if (newp) { newp->didWidth(true); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } } void methodCallQueue(AstMethodCall* nodep, AstQueueDType* adtypep) { @@ -2172,18 +2254,16 @@ private: if (nodep->name() == "at") { // Created internally for [] methodOkArguments(nodep, 1, 1); methodCallLValue(nodep, nodep->fromp(), true); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - "at", NULL); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at", + NULL); newp->dtypeFrom(adtypep->subDTypep()); newp->protect(false); newp->didWidth(true); } else if (nodep->name() == "num" // function int num() - || nodep->name() == "size") { + || nodep->name() == "size") { methodOkArguments(nodep, 0, 0); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - "size", NULL); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size", + NULL); newp->dtypeSetSigned32(); newp->didWidth(true); newp->protect(false); @@ -2191,25 +2271,23 @@ private: methodOkArguments(nodep, 0, 1); methodCallLValue(nodep, nodep->fromp(), true); if (!nodep->pinsp()) { - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear", NULL); newp->protect(false); newp->makeStatement(); } else { AstNode* index_exprp = methodCallQueueIndexExpr(nodep); if (index_exprp->isZero()) { // delete(0) is a pop_front - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "pop_front", NULL); newp->dtypeFrom(adtypep->subDTypep()); newp->protect(false); newp->didWidth(true); newp->makeStatement(); } else { - nodep->v3error("Unsupported: Queue .delete(index) method, as is O(n) complexity and slow."); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), + nodep->v3error("Unsupported: Queue .delete(index) method, as is O(n) " + "complexity and slow."); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "erase", index_exprp->unlinkFrBack()); newp->protect(false); newp->makeStatement(); @@ -2222,51 +2300,45 @@ private: AstArg* argp = VN_CAST(nodep->pinsp()->nextp(), Arg); iterateCheckTyped(nodep, "insert value", argp->exprp(), adtypep->subDTypep(), BOTH); if (index_exprp->isZero()) { // insert(0, ...) is a push_front - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "push_front", argp->exprp()->unlinkFrBack()); newp->protect(false); newp->makeStatement(); } else { - nodep->v3error("Unsupported: Queue .insert method, as is O(n) complexity and slow."); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - nodep->name(), - index_exprp->unlinkFrBack()); + nodep->v3error( + "Unsupported: Queue .insert method, as is O(n) complexity and slow."); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), index_exprp->unlinkFrBack()); newp->addPinsp(argp->exprp()->unlinkFrBack()); newp->protect(false); newp->makeStatement(); } - } else if (nodep->name() == "pop_front" - || nodep->name() == "pop_back") { + } else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") { methodOkArguments(nodep, 0, 0); methodCallLValue(nodep, nodep->fromp(), true); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), NULL); newp->dtypeFrom(adtypep->subDTypep()); newp->protect(false); newp->didWidth(true); - if (!nodep->firstAbovep()) { - newp->makeStatement(); - } - } else if (nodep->name() == "push_back" - || nodep->name() == "push_front") { + if (!nodep->firstAbovep()) { newp->makeStatement(); } + } else if (nodep->name() == "push_back" || nodep->name() == "push_front") { methodOkArguments(nodep, 1, 1); methodCallLValue(nodep, nodep->fromp(), true); AstArg* argp = VN_CAST(nodep->pinsp(), Arg); iterateCheckTyped(nodep, "push value", argp->exprp(), adtypep->subDTypep(), BOTH); - newp = new AstCMethodHard(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), argp->exprp()->unlinkFrBack()); newp->protect(false); newp->makeStatement(); } else { - nodep->v3error("Unsupported/unknown built-in associative array method "<prettyNameQ()); + nodep->v3error("Unsupported/unknown built-in associative array method " + << nodep->prettyNameQ()); } if (newp) { newp->didWidth(true); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } } AstNode* methodCallQueueIndexExpr(AstMethodCall* nodep) { @@ -2308,9 +2380,13 @@ private: enum { UNKNOWN = 0, ARRAY_OR, ARRAY_AND, ARRAY_XOR } methodId; methodId = UNKNOWN; - if (nodep->name() == "or") methodId = ARRAY_OR; - else if (nodep->name() == "and") methodId = ARRAY_AND; - else if (nodep->name() == "xor") methodId = ARRAY_XOR; + if (nodep->name() == "or") { + methodId = ARRAY_OR; + } else if (nodep->name() == "and") { + methodId = ARRAY_AND; + } else if (nodep->name() == "xor") { + methodId = ARRAY_XOR; + } if (methodId) { methodOkArguments(nodep, 0, 0); @@ -2362,11 +2438,13 @@ private: } else if (nodep->name() == "tolower") { methodOkArguments(nodep, 0, 0); AstNode* newp = new AstToLowerN(nodep->fileline(), nodep->fromp()->unlinkFrBack()); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (nodep->name() == "toupper") { methodOkArguments(nodep, 0, 0); AstNode* newp = new AstToUpperN(nodep->fileline(), nodep->fromp()->unlinkFrBack()); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (nodep->name() == "compare" || nodep->name() == "icompare") { const bool ignoreCase = nodep->name()[0] == 'i'; methodOkArguments(nodep, 1, 1); @@ -2374,8 +2452,9 @@ private: AstNode* lhs = nodep->fromp()->unlinkFrBack(); AstNode* rhs = argp->exprp()->unlinkFrBack(); AstNode* newp = new AstCompareNN(nodep->fileline(), lhs, rhs, ignoreCase); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - } else if (nodep->name() == "putc" ) { + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else if (nodep->name() == "putc") { methodOkArguments(nodep, 2, 2); AstArg* arg0p = VN_CAST(nodep->pinsp(), Arg); AstArg* arg1p = VN_CAST(arg0p->nextp(), Arg); @@ -2386,14 +2465,16 @@ private: AstNode* newp = new AstAssign(nodep->fileline(), fromp, new AstPutcN(nodep->fileline(), varrefp, rhsp, thsp)); fromp->lvalue(true); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (nodep->name() == "getc") { methodOkArguments(nodep, 1, 1); AstArg* arg0p = VN_CAST(nodep->pinsp(), Arg); AstNode* lhsp = nodep->fromp()->unlinkFrBack(); AstNode* rhsp = arg0p->exprp()->unlinkFrBack(); AstNode* newp = new AstGetcN(nodep->fileline(), lhsp, rhsp); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (nodep->name() == "substr") { methodOkArguments(nodep, 2, 2); AstArg* arg0p = VN_CAST(nodep->pinsp(), Arg); @@ -2402,24 +2483,32 @@ private: AstNode* rhsp = arg0p->exprp()->unlinkFrBack(); AstNode* thsp = arg1p->exprp()->unlinkFrBack(); AstNode* newp = new AstSubstrN(nodep->fileline(), lhsp, rhsp, thsp); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - } else if (nodep->name() == "atobin" - || nodep->name() == "atohex" - || nodep->name() == "atoi" - || nodep->name() == "atooct" + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else if (nodep->name() == "atobin" || nodep->name() == "atohex" + || nodep->name() == "atoi" || nodep->name() == "atooct" || nodep->name() == "atoreal") { AstAtoN::FmtType fmt; - if (nodep->name() == "atobin") fmt = AstAtoN::ATOBIN; - else if (nodep->name() == "atohex") fmt = AstAtoN::ATOHEX; - else if (nodep->name() == "atoi") fmt = AstAtoN::ATOI; - else if (nodep->name() == "atooct") fmt = AstAtoN::ATOOCT; - else if (nodep->name() == "atoreal") fmt = AstAtoN::ATOREAL; - else { V3ERROR_NA; fmt = AstAtoN::ATOI; } // dummy assignment to suppress compiler warning + if (nodep->name() == "atobin") { + fmt = AstAtoN::ATOBIN; + } else if (nodep->name() == "atohex") { + fmt = AstAtoN::ATOHEX; + } else if (nodep->name() == "atoi") { + fmt = AstAtoN::ATOI; + } else if (nodep->name() == "atooct") { + fmt = AstAtoN::ATOOCT; + } else if (nodep->name() == "atoreal") { + fmt = AstAtoN::ATOREAL; + } else { + V3ERROR_NA; + fmt = AstAtoN::ATOI; + } // dummy assignment to suppress compiler warning methodOkArguments(nodep, 0, 0); AstNode* newp = new AstAtoN(nodep->fileline(), nodep->fromp()->unlinkFrBack(), fmt); - nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { - nodep->v3error("Unknown built-in string method "<prettyNameQ()); + nodep->v3error("Unknown built-in string method " << nodep->prettyNameQ()); } } @@ -2465,13 +2554,15 @@ private: if (nodep->didWidthAndSet()) return; AstDynArrayDType* adtypep = VN_CAST(m_vup->dtypeNullp(), DynArrayDType); if (!adtypep) { // e.g. int a = new; - nodep->v3error("dynamic new() not expected in this context (data type must be dynamic array)"); + nodep->v3error( + "dynamic new() not expected in this context (data type must be dynamic array)"); return; } // The AstNodeAssign visitor will be soon be replacing this node, make sure it gets it if (!VN_IS(nodep->backp(), NodeAssign)) { if (adtypep) UINFO(1, "Got backp " << nodep->backp() << endl); - nodep->v3error("dynamic new() not expected in this context (expected under an assign)"); + nodep->v3error( + "dynamic new() not expected in this context (expected under an assign)"); return; } nodep->dtypep(adtypep); @@ -2486,8 +2577,9 @@ private: virtual void visit(AstPattern* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; - UINFO(9,"PATTERN "<childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern } + UINFO(9, "PATTERN " << nodep << endl); + if (nodep->childDTypep()) + nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern } if (!nodep->dtypep() && m_vup->dtypeNullp()) { // Get it from parent assignment/pin/etc nodep->dtypep(m_vup->dtypep()); } @@ -2495,28 +2587,28 @@ private: if (!dtypep) { nodep->v3error("Unsupported/Illegal: Assignment pattern" " member not underneath a supported construct: " - <backp()->prettyTypeName()); + << nodep->backp()->prettyTypeName()); return; } { dtypep = dtypep->skipRefp(); nodep->dtypep(dtypep); - UINFO(9," dtypep "<dtypep(dtypep); // Determine replication count, and replicate initial value as // widths need to be individually determined - for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); - patp; patp = VN_CAST(patp->nextp(), PatMember)) { + for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp; + patp = VN_CAST(patp->nextp(), PatMember)) { int times = visitPatMemberRep(patp); - for (int i=1; icloneTree(false); patp->addNextHere(newp); // This loop will see the new elements as part of nextp() } } // Convert any PatMember with multiple items to multiple PatMembers - for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); - patp; patp = VN_CAST(patp->nextp(), PatMember)) { + for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp; + patp = VN_CAST(patp->nextp(), PatMember)) { if (patp->lhssp()->nextp()) { // Can't just addNext, as would add to end of all members. // So detach, add next and reattach @@ -2534,8 +2626,8 @@ private: } } AstPatMember* defaultp = NULL; - for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); - patp; patp = VN_CAST(patp->nextp(), PatMember)) { + for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp; + patp = VN_CAST(patp->nextp(), PatMember)) { if (patp->isDefault()) { if (defaultp) nodep->v3error("Multiple '{ default: } clauses"); defaultp = patp; @@ -2547,16 +2639,14 @@ private: } if (AstNodeUOrStructDType* vdtypep = VN_CAST(dtypep, NodeUOrStructDType)) { VL_DO_DANGLING(patternUOrStruct(nodep, vdtypep, defaultp), nodep); - } - else if (AstNodeArrayDType* vdtypep = VN_CAST(dtypep, NodeArrayDType)) { + } else if (AstNodeArrayDType* vdtypep = VN_CAST(dtypep, NodeArrayDType)) { VL_DO_DANGLING(patternArray(nodep, vdtypep, defaultp), nodep); - } - else if (VN_IS(dtypep, BasicDType) - && VN_CAST(dtypep, BasicDType)->isRanged()) { + } else if (VN_IS(dtypep, BasicDType) && VN_CAST(dtypep, BasicDType)->isRanged()) { VL_DO_DANGLING(patternBasic(nodep, dtypep, defaultp), nodep); } else { - nodep->v3error("Unsupported: Assignment pattern applies against non struct/union data type: " - << dtypep->prettyDTypeNameQ()); + nodep->v3error( + "Unsupported: Assignment pattern applies against non struct/union data type: " + << dtypep->prettyDTypeNameQ()); } } } @@ -2566,36 +2656,40 @@ private: // which member each AstPatMember corresponds to before we can // determine the dtypep for that PatMember's value, and then // width the initial value appropriately. - typedef std::map PatMap; + typedef std::map PatMap; PatMap patmap; { AstMemberDType* memp = vdtypep->membersp(); AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); - for (; memp || patp; ) { + for (; memp || patp;) { do { if (patp) { if (patp->keyp()) { if (AstText* textp = VN_CAST(patp->keyp(), Text)) { memp = vdtypep->findMember(textp->text()); if (!memp) { - patp->keyp()->v3error( - "Assignment pattern key '" - <text()<<"' not found as member"); + patp->keyp()->v3error("Assignment pattern key '" + << textp->text() + << "' not found as member"); break; } } else { patp->keyp()->v3error( "Assignment pattern key not supported/understood: " - <keyp()->prettyTypeName()); + << patp->keyp()->prettyTypeName()); } } } if (memp && !patp) { // Missing init elements, warn below - memp = NULL; patp = NULL; break; + memp = NULL; + patp = NULL; + break; } else if (!memp && patp) { patp->v3error("Assignment pattern contains too many elements"); - memp = NULL; patp = NULL; break; + memp = NULL; + patp = NULL; + break; } else { std::pair ret = patmap.insert(make_pair(memp, patp)); @@ -2611,8 +2705,8 @@ private: } } AstNode* newp = NULL; - for (AstMemberDType* memp = vdtypep->membersp(); - memp; memp = VN_CAST(memp->nextp(), MemberDType)) { + for (AstMemberDType* memp = vdtypep->membersp(); memp; + memp = VN_CAST(memp->nextp(), MemberDType)) { PatMap::iterator it = patmap.find(memp); AstPatMember* newpatp = NULL; AstPatMember* patp = NULL; @@ -2620,11 +2714,10 @@ private: if (defaultp) { newpatp = defaultp->cloneTree(false); patp = newpatp; - } - else { + } else { if (!VN_IS(vdtypep, UnionDType)) { nodep->v3error("Assignment pattern missed initializing elements: " - <prettyTypeName()); + << memp->prettyTypeName()); } } } else { @@ -2634,28 +2727,31 @@ private: // Determine initial values patp->dtypep(memp); AstNode* valuep = patternMemberValueIterate(patp); - if (!newp) newp = valuep; - else { + if (!newp) { + newp = valuep; + } else { AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep); newp = concatp; - newp->dtypeSetLogicSized( - concatp->lhsp()->width() + concatp->rhsp()->width(), - nodep->dtypep()->numeric()); + newp->dtypeSetLogicSized(concatp->lhsp()->width() + concatp->rhsp()->width(), + nodep->dtypep()->numeric()); } } if (newpatp) { VL_DO_DANGLING(pushDeletep(newpatp), newpatp); } } - if (newp) nodep->replaceWith(newp); - else nodep->v3error("Assignment pattern with no members"); + if (newp) { + nodep->replaceWith(newp); + } else { + nodep->v3error("Assignment pattern with no members"); + } VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } void patternArray(AstPattern* nodep, AstNodeArrayDType* vdtypep, AstPatMember* defaultp) { AstNodeArrayDType* arrayp = VN_CAST(vdtypep, NodeArrayDType); VNumRange range = arrayp->declRange(); PatVecMap patmap = patVectorMap(nodep, range); - UINFO(9,"ent "<=range.lo(); --ent) { + for (int ent = range.hi(); ent >= range.lo(); --ent) { AstPatMember* newpatp = NULL; AstPatMember* patp = NULL; PatVecMap::iterator it = patmap.find(ent); @@ -2663,10 +2759,8 @@ private: if (defaultp) { newpatp = defaultp->cloneTree(false); patp = newpatp; - } - else { - nodep->v3error("Assignment pattern missed initializing elements: " - <v3error("Assignment pattern missed initializing elements: " << ent); } } else { patp = it->second; @@ -2679,37 +2773,40 @@ private: AstNode* valuep = patternMemberValueIterate(patp); if (VN_IS(arrayp, UnpackArrayDType)) { if (!newp) { - AstInitArray* newap - = new AstInitArray(nodep->fileline(), arrayp, NULL); + AstInitArray* newap = new AstInitArray(nodep->fileline(), arrayp, NULL); newp = newap; } VN_CAST(newp, InitArray)->addIndexValuep(ent - range.lo(), valuep); } else { // Packed. Convert to concat for now. - if (!newp) newp = valuep; - else { + if (!newp) { + newp = valuep; + } else { AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep); newp = concatp; - newp->dtypeSetLogicSized( - concatp->lhsp()->width()+concatp->rhsp()->width(), - nodep->dtypep()->numeric()); + newp->dtypeSetLogicSized(concatp->lhsp()->width() + + concatp->rhsp()->width(), + nodep->dtypep()->numeric()); } } } if (newpatp) { VL_DO_DANGLING(pushDeletep(newpatp), newpatp); } } if (!patmap.empty()) nodep->v3error("Assignment pattern with too many elements"); - if (newp) nodep->replaceWith(newp); - else nodep->v3error("Assignment pattern with no members"); - //if (debug()>=9) newp->dumpTree("-apat-out: "); + if (newp) { + nodep->replaceWith(newp); + } else { + nodep->v3error("Assignment pattern with no members"); + } + // if (debug() >= 9) newp->dumpTree("-apat-out: "); VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } void patternBasic(AstPattern* nodep, AstNodeDType* vdtypep, AstPatMember* defaultp) { AstBasicDType* bdtypep = VN_CAST(vdtypep, BasicDType); VNumRange range = bdtypep->declRange(); PatVecMap patmap = patVectorMap(nodep, range); - UINFO(9,"ent "<=range.lo(); --ent) { + for (int ent = range.hi(); ent >= range.lo(); --ent) { AstPatMember* newpatp = NULL; AstPatMember* patp = NULL; PatVecMap::iterator it = patmap.find(ent); @@ -2717,10 +2814,8 @@ private: if (defaultp) { newpatp = defaultp->cloneTree(false); patp = newpatp; - } - else { - nodep->v3error("Assignment pattern missed initializing elements: " - <v3error("Assignment pattern missed initializing elements: " << ent); } } else { patp = it->second; @@ -2732,22 +2827,26 @@ private: patp->dtypep(vdtypep); AstNode* valuep = patternMemberValueIterate(patp); { // Packed. Convert to concat for now. - if (!newp) newp = valuep; + if (!newp) + newp = valuep; else { AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep); newp = concatp; - newp->dtypeSetLogicSized( - concatp->lhsp()->width()+concatp->rhsp()->width(), - nodep->dtypep()->numeric()); + newp->dtypeSetLogicSized(concatp->lhsp()->width() + + concatp->rhsp()->width(), + nodep->dtypep()->numeric()); } } } if (newpatp) { VL_DO_DANGLING(pushDeletep(newpatp), newpatp); } } if (!patmap.empty()) nodep->v3error("Assignment pattern with too many elements"); - if (newp) nodep->replaceWith(newp); - else nodep->v3error("Assignment pattern with no members"); - //if (debug()>=9) newp->dumpTree("-apat-out: "); + if (newp) { + nodep->replaceWith(newp); + } else { + nodep->v3error("Assignment pattern with no members"); + } + // if (debug() >= 9) newp->dumpTree("-apat-out: "); VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } AstNode* patternMemberValueIterate(AstPatMember* patp) { @@ -2770,7 +2869,7 @@ private: AstNodeDType* vdtypep = m_vup->dtypeNullp(); UASSERT_OBJ(vdtypep, nodep, "Pattern member type not assigned by AstPattern visitor"); nodep->dtypep(vdtypep); - UINFO(9," PATMEMBER "<lhssp()->nextp(), nodep, "PatMember value should be singular w/replicates removed"); // Need to propagate assignment type downwards, even on prelim @@ -2783,10 +2882,19 @@ private: iterateCheckSizedSelf(nodep, "LHS", nodep->repp(), SELF, BOTH); V3Const::constifyParamsEdit(nodep->repp()); // repp may change const AstConst* constp = VN_CAST(nodep->repp(), Const); - if (!constp) { nodep->v3error("Replication value isn't a constant."); times = 0; } - else times = constp->toUInt(); - if (times==0) { nodep->v3error("Pattern replication value of 0 is not legal."); times=1; } - nodep->repp()->unlinkFrBackWithNext()->deleteTree(); // Done with replicate before cloning + if (!constp) { + nodep->v3error("Replication value isn't a constant."); + times = 0; + } else { + times = constp->toUInt(); + } + if (times == 0) { + nodep->v3error("Pattern replication value of 0 is not legal."); + times = 1; + } + nodep->repp() + ->unlinkFrBackWithNext() + ->deleteTree(); // Done with replicate before cloning } return times; } @@ -2796,7 +2904,8 @@ private: iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); userIterateAndNext(nodep->sensesp(), NULL); if (nodep->disablep()) { - iterateCheckBool(nodep, "Disable", nodep->disablep(), BOTH); // it's like an if() condition. + iterateCheckBool(nodep, "Disable", nodep->disablep(), + BOTH); // it's like an if() condition. } nodep->dtypeSetLogicBool(); } @@ -2811,10 +2920,11 @@ private: // Signed: Only if expr, and all items signed assertAtStatement(nodep); userIterateAndNext(nodep->exprp(), WidthVP(CONTEXT, PRELIM).p()); - for (AstCaseItem* nextip, *itemp = nodep->itemsp(); itemp; itemp=nextip) { - nextip = VN_CAST(itemp->nextp(), CaseItem); // Prelim may cause the node to get replaced + for (AstCaseItem *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) { + nextip + = VN_CAST(itemp->nextp(), CaseItem); // Prelim may cause the node to get replaced if (!VN_IS(nodep, GenCase)) userIterateAndNext(itemp->bodysp(), NULL); - for (AstNode* nextcp, *condp = itemp->condsp(); condp; condp=nextcp) { + for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) { nextcp = condp->nextp(); // Prelim may cause the node to get replaced VL_DO_DANGLING(userIterate(condp, WidthVP(CONTEXT, PRELIM).p()), condp); } @@ -2822,25 +2932,28 @@ private: // Take width as maximum across all items, if any is real whole thing is real AstNodeDType* subDTypep = nodep->exprp()->dtypep(); - for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) { - for (AstNode* condp = itemp->condsp(); condp; condp=condp->nextp()) { + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { + for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) { if (condp->dtypep() != subDTypep) { if (condp->dtypep()->isDouble()) { subDTypep = nodep->findDoubleDType(); } else { - int width = std::max(subDTypep->width(), condp->width()); + int width = std::max(subDTypep->width(), condp->width()); int mwidth = std::max(subDTypep->widthMin(), condp->widthMin()); bool issigned = subDTypep->isSigned() && condp->isSigned(); - subDTypep = nodep->findLogicDType(width, mwidth, - AstNumeric::fromBool(issigned)); + subDTypep + = nodep->findLogicDType(width, mwidth, AstNumeric::fromBool(issigned)); } } } } // Apply width - iterateCheck(nodep, "Case expression", nodep->exprp(), CONTEXT, FINAL, subDTypep, EXTEND_LHS); - for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) { - for (AstNode* nextcp, *condp = itemp->condsp(); condp; condp=nextcp) { + iterateCheck(nodep, "Case expression", nodep->exprp(), CONTEXT, FINAL, subDTypep, + EXTEND_LHS); + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), CaseItem)) { + for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) { nextcp = condp->nextp(); // Final may cause the node to get replaced iterateCheck(nodep, "Case Item", condp, CONTEXT, FINAL, subDTypep, EXTEND_LHS); } @@ -2849,10 +2962,10 @@ private: virtual void visit(AstNodeFor* nodep) VL_OVERRIDE { assertAtStatement(nodep); userIterateAndNext(nodep->initsp(), NULL); - iterateCheckBool(nodep, "For Test Condition", nodep->condp(), BOTH); // it's like an if() condition. + iterateCheckBool(nodep, "For Test Condition", nodep->condp(), + BOTH); // it's like an if() condition. if (!VN_IS(nodep, GenFor)) userIterateAndNext(nodep->bodysp(), NULL); userIterateAndNext(nodep->incsp(), NULL); - } virtual void visit(AstRepeat* nodep) VL_OVERRIDE { assertAtStatement(nodep); @@ -2862,19 +2975,20 @@ private: virtual void visit(AstWhile* nodep) VL_OVERRIDE { assertAtStatement(nodep); userIterateAndNext(nodep->precondsp(), NULL); - iterateCheckBool(nodep, "For Test Condition", nodep->condp(), BOTH); // it's like an if() condition. + iterateCheckBool(nodep, "For Test Condition", nodep->condp(), + BOTH); // it's like an if() condition. userIterateAndNext(nodep->bodysp(), NULL); userIterateAndNext(nodep->incsp(), NULL); } virtual void visit(AstNodeIf* nodep) VL_OVERRIDE { assertAtStatement(nodep); - //if (debug()) nodep->dumpTree(cout, " IfPre: "); + // if (debug()) nodep->dumpTree(cout, " IfPre: "); if (!VN_IS(nodep, GenIf)) { // for m_paramsOnly userIterateAndNext(nodep->ifsp(), NULL); userIterateAndNext(nodep->elsesp(), NULL); } iterateCheckBool(nodep, "If", nodep->condp(), BOTH); // it's like an if() condition. - //if (debug()) nodep->dumpTree(cout, " IfOut: "); + // if (debug()) nodep->dumpTree(cout, " IfOut: "); } virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { @@ -2886,22 +3000,22 @@ private: // handled in each visitor. // Then LHS sign-extends only if *RHS* is signed assertAtStatement(nodep); - //if (debug()) nodep->dumpTree(cout, " AssignPre: "); + // if (debug()) nodep->dumpTree(cout, " AssignPre: "); { - //if (debug()) nodep->dumpTree(cout, "- assin: "); + // if (debug()) nodep->dumpTree(cout, "- assin: "); userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); UASSERT_OBJ(nodep->lhsp()->dtypep(), nodep, "How can LHS be untyped?"); - UASSERT_OBJ(nodep->lhsp()->dtypep()->widthSized(), nodep, - "How can LHS be unsized?"); + UASSERT_OBJ(nodep->lhsp()->dtypep()->widthSized(), nodep, "How can LHS be unsized?"); nodep->dtypeFrom(nodep->lhsp()); // // AstPattern needs to know the proposed data type of the lhs, so pass on the prelim userIterateAndNext(nodep->rhsp(), WidthVP(nodep->dtypep(), PRELIM).p()); // - //if (debug()) nodep->dumpTree(cout, "- assign: "); - AstNodeDType* lhsDTypep = nodep->lhsp()->dtypep(); // Note we use rhsp for context determined + // if (debug()) nodep->dumpTree(cout, "- assign: "); + AstNodeDType* lhsDTypep + = nodep->lhsp()->dtypep(); // Note we use rhsp for context determined iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep); - //if (debug()) nodep->dumpTree(cout, " AssignOut: "); + // if (debug()) nodep->dumpTree(cout, " AssignOut: "); } if (AstNewDynamic* dynp = VN_CAST(nodep->rhsp(), NewDynamic)) { UINFO(9, "= new[] -> .resize(): " << nodep); @@ -2928,18 +3042,18 @@ private: // Just let all arguments seek their natural sizes userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); // - UINFO(9," Display in "<text()<text() << endl); string newFormat; bool inPct = false; AstNode* argp = nodep->exprsp(); string txt = nodep->text(); string fmt; - for (string::const_iterator it = txt.begin(); it!=txt.end(); ++it) { + for (string::const_iterator it = txt.begin(); it != txt.end(); ++it) { char ch = *it; - if (!inPct && ch=='%') { + if (!inPct && ch == '%') { inPct = true; fmt = ch; - } else if (inPct && (isdigit(ch) || ch=='.' || ch=='-')) { + } else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) { fmt += ch; } else if (tolower(inPct)) { inPct = false; @@ -2954,8 +3068,7 @@ private: if (argp->isDouble()) { spliceCvtS(argp, true, 64); ch = '~'; - } - else if (argp->isSigned()) { // Convert it + } else if (argp->isSigned()) { // Convert it ch = '~'; } argp = nextp; @@ -2971,16 +3084,15 @@ private: } else if (basicp && basicp->isDouble()) { added = true; newFormat += "%g"; - } else if (VN_IS(dtypep, AssocArrayDType) - || VN_IS(dtypep, ClassRefDType) - || VN_IS(dtypep, DynArrayDType) + } else if (VN_IS(dtypep, AssocArrayDType) // + || VN_IS(dtypep, ClassRefDType) // + || VN_IS(dtypep, DynArrayDType) // || VN_IS(dtypep, QueueDType)) { added = true; newFormat += "%@"; AstNRelinker handle; argp->unlinkFrBack(&handle); - AstCMath* newp = new AstCMath( - nodep->fileline(), "VL_TO_STRING(", 0, true); + AstCMath* newp = new AstCMath(nodep->fileline(), "VL_TO_STRING(", 0, true); newp->addBodysp(argp); newp->addBodysp(new AstText(nodep->fileline(), ")")); newp->dtypeSetString(); @@ -2989,8 +3101,11 @@ private: handle.relink(newp); } else { added = true; - if (fmt == "%0") newFormat += "'h%0h"; // IEEE our choice - else newFormat += "%d"; + if (fmt == "%0") { + newFormat += "'h%0h"; // IEEE our choice + } else { + newFormat += "%d"; + } } if (argp) argp = argp->nextp(); break; @@ -3045,13 +3160,11 @@ private: } } nodep->text(newFormat); - UINFO(9," Display out "<text()<text() << endl); } virtual void visit(AstDisplay* nodep) VL_OVERRIDE { assertAtStatement(nodep); - if (nodep->filep()) { - iterateCheckFileDesc(nodep, nodep->filep(), BOTH); - } + if (nodep->filep()) iterateCheckFileDesc(nodep, nodep->filep(), BOTH); // Just let all arguments seek their natural sizes userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); } @@ -3062,18 +3175,10 @@ private: if (!m_paramsOnly) { V3Const::constifyParamsEdit(nodep->fmtp()); // fmtp may change switch (nodep->displayType()) { - case AstDisplayType::DT_INFO: - nodep->v3warn(USERINFO, nodep->fmtp()->text()); - break; - case AstDisplayType::DT_ERROR: - nodep->v3warn(USERERROR, nodep->fmtp()->text()); - break; - case AstDisplayType::DT_WARNING: - nodep->v3warn(USERWARN, nodep->fmtp()->text()); - break; - case AstDisplayType::DT_FATAL: - nodep->v3warn(USERFATAL, nodep->fmtp()->text()); - break; + case AstDisplayType::DT_INFO: nodep->v3warn(USERINFO, nodep->fmtp()->text()); break; + case AstDisplayType::DT_ERROR: nodep->v3warn(USERERROR, nodep->fmtp()->text()); break; + case AstDisplayType::DT_WARNING: nodep->v3warn(USERWARN, nodep->fmtp()->text()); break; + case AstDisplayType::DT_FATAL: nodep->v3warn(USERFATAL, nodep->fmtp()->text()); break; default: UASSERT_OBJ(false, nodep, "Unexpected elaboration display type"); } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); @@ -3111,9 +3216,7 @@ private: } virtual void visit(AstFFlush* nodep) VL_OVERRIDE { assertAtStatement(nodep); - if (nodep->filep()) { - iterateCheckFileDesc(nodep, nodep->filep(), BOTH); - } + if (nodep->filep()) iterateCheckFileDesc(nodep, nodep->filep(), BOTH); } virtual void visit(AstFRewind* nodep) VL_OVERRIDE { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); @@ -3214,10 +3317,11 @@ private: << nodep->verilogKwd() << " into other than unpacked or associative array"); } - if (subp && (!subp->skipRefp()->basicp() - || !subp->skipRefp()->basicp()->keyword().isIntNumeric())) { + if (subp + && (!subp->skipRefp()->basicp() + || !subp->skipRefp()->basicp()->keyword().isIntNumeric())) { nodep->memp()->v3error("Unsupported: " << nodep->verilogKwd() - << " array values must be integral"); + << " array values must be integral"); } userIterateAndNext(nodep->lsbp(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->msbp(), WidthVP(SELF, BOTH).p()); @@ -3250,7 +3354,7 @@ private: iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); // it's like an if() condition. } virtual void visit(AstPin* nodep) VL_OVERRIDE { - //if (debug()) nodep->dumpTree(cout, "- PinPre: "); + // if (debug()) nodep->dumpTree(cout, "- PinPre: "); // TOP LEVEL NODE if (nodep->modVarp() && nodep->modVarp()->isGParam()) { // Widthing handled as special init() case @@ -3275,84 +3379,89 @@ private: if (conDTypep == pinDTypep // If match, we're golden || similarDTypeRecurse(conDTypep, pinDTypep)) { userIterateAndNext(nodep->exprp(), WidthVP(subDTypep, FINAL).p()); - } - else if (m_cellRangep) { + } else if (m_cellRangep) { int numInsts = m_cellRangep->elementsConst(); if (conwidth == pinwidth) { // Arrayed instants: widths match so connect to each instance subDTypep = conDTypep; // = same expr dtype - } else if (conwidth == numInsts*pinwidth) { + } else if (conwidth == numInsts * pinwidth) { // Arrayed instants: one bit for each of the instants (each // assign is 1 pinwidth wide) subDTypep = conDTypep; // = same expr dtype (but numInst*pin_dtype) } else { // Must be a error according to spec // (Because we need to know if to connect to one or all instants) - nodep->v3error(ucfirst(nodep->prettyOperatorName())<<" as part of a module instance array" - <<" requires "<exprp()->prettyTypeName() - <<" generates "<v3error(ucfirst(nodep->prettyOperatorName()) + << " as part of a module instance array" + << " requires " << pinwidth << " or " << pinwidth * numInsts + << " bits, but connection's " + << nodep->exprp()->prettyTypeName() << " generates " << conwidth + << " bits."); subDTypep = conDTypep; // = same expr dtype } userIterateAndNext(nodep->exprp(), WidthVP(subDTypep, FINAL).p()); } else { if (nodep->modVarp()->direction() == VDirection::REF) { - nodep->v3error("Ref connection "<modVarp()->prettyNameQ() - <<" requires matching types;" - <<" ref requires "<prettyDTypeNameQ() - <<" data type but connection is " - <prettyDTypeNameQ()<<" data type."<v3error("Ref connection " + << nodep->modVarp()->prettyNameQ() + << " requires matching types;" + << " ref requires " << pinDTypep->prettyDTypeNameQ() + << " data type but connection is " + << conDTypep->prettyDTypeNameQ() << " data type." << endl); } else if (nodep->modVarp()->isTristate()) { if (pinwidth != conwidth) { - nodep->v3error("Unsupported: "<prettyOperatorName()) - <<" to inout signal requires "<exprp()->prettyTypeName() - <<" generates "<v3error("Unsupported: " << ucfirst(nodep->prettyOperatorName()) + << " to inout signal requires " << pinwidth + << " bits, but connection's " + << nodep->exprp()->prettyTypeName() + << " generates " << conwidth << " bits."); // otherwise would need some mess to force both sides to proper size } } // Check if an interface is connected to a non-interface and vice versa AstNodeDType* modDTypep = nodep->modVarp()->dtypep(); AstNodeDType* exprDTypep = nodep->exprp()->dtypep(); - if ((VN_IS(modDTypep, IfaceRefDType) && !VN_IS(exprDTypep, IfaceRefDType)) || - (VN_IS(exprDTypep, IfaceRefDType) && !VN_IS(modDTypep, IfaceRefDType))) { - nodep->v3error("Illegal "<prettyOperatorName()<<"," - <<" mismatch between port which is" - <<(VN_CAST(modDTypep, IfaceRefDType)?"":" not") - <<" an interface," - <<" and expression which is" - <<(VN_CAST(exprDTypep, IfaceRefDType)?"":" not") - <<" an interface."); + if ((VN_IS(modDTypep, IfaceRefDType) && !VN_IS(exprDTypep, IfaceRefDType)) + || (VN_IS(exprDTypep, IfaceRefDType) && !VN_IS(modDTypep, IfaceRefDType))) { + nodep->v3error("Illegal " << nodep->prettyOperatorName() << "," + << " mismatch between port which is" + << (VN_CAST(modDTypep, IfaceRefDType) ? "" : " not") + << " an interface," + << " and expression which is" + << (VN_CAST(exprDTypep, IfaceRefDType) ? "" : " not") + << " an interface."); } // TODO Simple dtype checking, should be a more general check AstNodeArrayDType* exprArrayp = VN_CAST(exprDTypep->skipRefp(), UnpackArrayDType); - AstNodeArrayDType* modArrayp = VN_CAST(modDTypep->skipRefp(), UnpackArrayDType); + AstNodeArrayDType* modArrayp = VN_CAST(modDTypep->skipRefp(), UnpackArrayDType); if (exprArrayp && modArrayp && VN_IS(exprArrayp->subDTypep()->skipRefp(), IfaceRefDType) && exprArrayp->declRange().elements() != modArrayp->declRange().elements()) { int exprSize = exprArrayp->declRange().elements(); int modSize = modArrayp->declRange().elements(); - nodep->v3error("Illegal "<prettyOperatorName()<<"," - <<" mismatch between port which is an interface array of size " - <skipRefp()<skipRefp()<v3error("Illegal " + << nodep->prettyOperatorName() << "," + << " mismatch between port which is an interface array of size " + << modSize << "," + << " and expression which is an interface array of size " + << exprSize << "."); + UINFO(1, " Related lo: " << modDTypep->skipRefp() << endl); + UINFO(1, " Related hi: " << exprDTypep->skipRefp() << endl); } else if ((exprArrayp && !modArrayp && pinwidth != conwidth) || (!exprArrayp && modArrayp && pinwidth != conwidth)) { - nodep->v3error("Illegal "<prettyOperatorName()<<"," - <<" mismatch between port which is"<<(modArrayp?"":" not")<<" an array," - <<" and expression which is"<<(exprArrayp?"":" not")<<" an array."); - UINFO(1," Related lo: "<skipRefp()<skipRefp()<v3error("Illegal " << nodep->prettyOperatorName() << "," + << " mismatch between port which is" + << (modArrayp ? "" : " not") << " an array," + << " and expression which is" + << (exprArrayp ? "" : " not") << " an array."); + UINFO(1, " Related lo: " << modDTypep->skipRefp() << endl); + UINFO(1, " Related hi: " << exprDTypep->skipRefp() << endl); } iterateCheckAssign(nodep, "pin connection", nodep->exprp(), FINAL, subDTypep); } } - //if (debug()) nodep->dumpTree(cout, "- PinOut: "); + // if (debug()) nodep->dumpTree(cout, "- PinOut: "); } virtual void visit(AstCell* nodep) VL_OVERRIDE { if (!m_paramsOnly) { @@ -3360,8 +3469,8 @@ private: // We've resolved parameters and hit a module that we couldn't resolve. It's // finally time to report it. // Note only here in V3Width as this is first visitor after V3Dead. - nodep->modNameFileline() - ->v3error("Cannot find file containing module: '"<modName()<<"'"); + nodep->modNameFileline()->v3error("Cannot find file containing module: '" + << nodep->modName() << "'"); v3Global.opt.filePathLookedMsg(nodep->modNameFileline(), nodep->modName()); } if (nodep->rangep()) { @@ -3386,12 +3495,10 @@ private: if (conwidth == 1 && pinwidth > 1) { // Multiple connections AstNodeDType* subDTypep = nodep->findLogicDType(1, 1, conDTypep->numeric()); userIterateAndNext(nodep->exprp(), WidthVP(subDTypep, FINAL).p()); - AstNode* newp = new AstReplicate(nodep->fileline(), - nodep->exprp()->unlinkFrBack(), + AstNode* newp = new AstReplicate(nodep->fileline(), nodep->exprp()->unlinkFrBack(), numInsts); nodep->replaceWith(newp); - } - else { + } else { // Eliminating so pass down all of vup userIterateAndNext(nodep->exprp(), m_vup); nodep->replaceWith(nodep->exprp()->unlinkFrBack()); @@ -3409,7 +3516,8 @@ private: return; } // Function hasn't been widthed, so make it so. - nodep->doingWidth(true); // Would use user1 etc, but V3Width called from too many places to spend a user + // Would use user1 etc, but V3Width called from too many places to spend a user + nodep->doingWidth(true); m_ftaskp = nodep; userIterateChildren(nodep, NULL); if (nodep->isConstructor()) { @@ -3424,10 +3532,9 @@ private: nodep->doingWidth(false); m_funcp = NULL; m_ftaskp = NULL; - if (nodep->dpiImport() - && !nodep->dpiOpenParent() - && markHasOpenArray(nodep)) { - nodep->dpiOpenParentInc(); // Mark so V3Task will wait for a child to build calling func + if (nodep->dpiImport() && !nodep->dpiOpenParent() && markHasOpenArray(nodep)) { + nodep->dpiOpenParentInc(); // Mark so V3Task will wait for a child to build calling + // func } } virtual void visit(AstReturn* nodep) VL_OVERRIDE { @@ -3451,7 +3558,7 @@ private: virtual void visit(AstFuncRef* nodep) VL_OVERRIDE { visit(VN_CAST(nodep, NodeFTaskRef)); nodep->dtypeFrom(nodep->taskp()); - //if (debug()) nodep->dumpTree(cout, " FuncOut: "); + // if (debug()) nodep->dumpTree(cout, " FuncOut: "); } void processFTaskRefArgs(AstNodeFTaskRef* nodep) { // For arguments, is assignment-like context; see IEEE rules in AstNodeAssign @@ -3500,8 +3607,7 @@ private: // Connection list is now incorrect (has extra args in it). goto reloop; // so exit early; next loop will correct it } // - else if (portp->basicp() - && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING + else if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING && !VN_IS(pinp, CvtPackString) && !VN_IS(pinp, SFormatF) // Already generates a string && !(VN_IS(pinp, VarRef) @@ -3601,15 +3707,15 @@ private: // Default virtual void visit(AstNodeMath* nodep) VL_OVERRIDE { if (!nodep->didWidth()) { - nodep->v3fatalSrc("Visit function missing? Widthed function missing for math node: " - <v3fatalSrc( + "Visit function missing? Widthed function missing for math node: " << nodep); } userIterateChildren(nodep, NULL); } virtual void visit(AstNode* nodep) VL_OVERRIDE { // Default: Just iterate UASSERT_OBJ(!m_vup, nodep, - "Visit function missing? Widthed expectation for this node: "<rhsp(), WidthVP(CONTEXT, PRELIM).p()); if (nodep->lhsp()->isDouble() || nodep->rhsp()->isDouble()) { if (!realok) nodep->v3error("Real not allowed as operand to in ?== operator"); - if (AstNodeBiop* newp = replaceWithDVersion(nodep)) { VL_DANGLING(nodep); + if (AstNodeBiop* newp = replaceWithDVersion(nodep)) { + VL_DANGLING(nodep); nodep = newp; // Process new node instead iterateCheckReal(nodep, "LHS", nodep->lhsp(), FINAL); iterateCheckReal(nodep, "RHS", nodep->rhsp(), FINAL); } } else if (nodep->lhsp()->isString() || nodep->rhsp()->isString()) { - if (AstNodeBiop* newp = replaceWithNVersion(nodep)) { VL_DANGLING(nodep); + if (AstNodeBiop* newp = replaceWithNVersion(nodep)) { + VL_DANGLING(nodep); nodep = newp; // Process new node instead iterateCheckString(nodep, "LHS", nodep->lhsp(), FINAL); iterateCheckString(nodep, "RHS", nodep->rhsp(), FINAL); } } else { bool signedFl = nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned(); - if (AstNodeBiop* newp = replaceWithUOrSVersion(nodep, signedFl)) { VL_DANGLING(nodep); + if (AstNodeBiop* newp = replaceWithUOrSVersion(nodep, signedFl)) { + VL_DANGLING(nodep); nodep = newp; // Process new node instead } - int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width()); + int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width()); int ewidth = std::max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin()); - AstNodeDType* subDTypep = nodep->findLogicDType(width, ewidth, - AstNumeric::fromBool(signedFl)); + AstNodeDType* subDTypep + = nodep->findLogicDType(width, ewidth, AstNumeric::fromBool(signedFl)); bool warnOn = true; if (!signedFl && width == 32) { // Waive on unsigned < or <= if RHS is narrower, since can't give wrong answer @@ -3825,7 +3934,8 @@ private: } if (real_ok && nodep->lhsp()->isDouble()) { spliceCvtD(nodep->lhsp()); - if (AstNodeUniop* newp = replaceWithDVersion(nodep)) { VL_DANGLING(nodep); + if (AstNodeUniop* newp = replaceWithDVersion(nodep)) { + VL_DANGLING(nodep); nodep = newp; // Process new node instead iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH); nodep->dtypeSetDouble(); @@ -3835,9 +3945,7 @@ private: // Note there aren't yet uniops that need version changes // So no need to call replaceWithUOrSVersion(nodep, nodep->isSigned()) } - if (m_vup->prelim()) { - nodep->dtypeFrom(nodep->lhsp()); - } + if (m_vup->prelim()) nodep->dtypeFrom(nodep->lhsp()); if (m_vup->final()) { AstNodeDType* expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); nodep->dtypep(expDTypep); // Propagate expression type to negation @@ -3866,7 +3974,7 @@ private: } } - void visit_shift(AstNodeBiop* nodep) { + void visit_shift(AstNodeBiop* nodep) { // CALLER: ShiftL, ShiftR, ShiftRS // Widths: Output width from lhs, rhs<33 bits // Signed: Output signed iff LHS signed; unary operator @@ -3874,10 +3982,11 @@ private: // RHS is self-determined. RHS is always treated as unsigned, has no effect on result. iterate_shift_prelim(nodep); nodep->dtypeChgSigned(nodep->lhsp()->isSigned()); - AstNodeBiop* newp = iterate_shift_final(nodep); VL_DANGLING(nodep); + AstNodeBiop* newp = iterate_shift_final(nodep); + VL_DANGLING(nodep); if (newp) {} // Ununused } - void iterate_shift_prelim(AstNodeBiop* nodep) { + void iterate_shift_prelim(AstNodeBiop* nodep) { // Shifts // See IEEE-2012 11.4.10 and Table 11-21. // RHS is self-determined. RHS is always treated as unsigned, has no effect on result. @@ -3888,7 +3997,7 @@ private: nodep->dtypeFrom(nodep->lhsp()); } } - AstNodeBiop* iterate_shift_final(AstNodeBiop* nodep) { + AstNodeBiop* iterate_shift_final(AstNodeBiop* nodep) { // Nodep maybe edited if (m_vup->final()) { AstNodeDType* expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); @@ -3896,19 +4005,22 @@ private: nodep->dtypeFrom(expDTypep); // ShiftRS converts to ShiftR, but not vice-versa if (VN_IS(nodep, ShiftRS)) { - if (AstNodeBiop* newp = replaceWithUOrSVersion(nodep, nodep->isSigned())) { VL_DANGLING(nodep); + if (AstNodeBiop* newp = replaceWithUOrSVersion(nodep, nodep->isSigned())) { + VL_DANGLING(nodep); nodep = newp; // Process new node instead } } bool warnOn = true; // No warning if "X = 1'b1<lhsp()->isOne() && VN_IS(nodep->backp(), NodeAssign)) warnOn = false; - iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP, warnOn); - if (nodep->rhsp()->width()>32) { + iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP, + warnOn); + if (nodep->rhsp()->width() > 32) { AstConst* shiftp = VN_CAST(nodep->rhsp(), Const); if (shiftp && shiftp->num().mostSetBitP1() <= 32) { // If (number)<<96'h1, then make it into (number)<<32'h1 - V3Number num (shiftp, 32, 0); num.opAssign(shiftp->num()); + V3Number num(shiftp, 32, 0); + num.opAssign(shiftp->num()); AstNode* shiftrhsp = nodep->rhsp(); nodep->rhsp()->replaceWith(new AstConst(shiftrhsp->fileline(), num)); VL_DO_DANGLING(shiftrhsp->deleteTree(), shiftrhsp); @@ -3934,7 +4046,7 @@ private: userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p()); checkCvtUS(nodep->lhsp()); checkCvtUS(nodep->rhsp()); - int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width()); + int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width()); int mwidth = std::max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin()); bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()); nodep->dtypeChgWidthSigned(width, mwidth, AstNumeric::fromBool(expSigned)); @@ -3961,7 +4073,7 @@ private: // because the rhs could be larger, and we need to have proper editing to get the widths // to be the same for our operations. // - //if (debug()>=9) { UINFO(0,"-rus "<dumpTree(cout, "-rusin-"); } + // if (debug() >= 9) { UINFO(0,"-rus "<dumpTree(cout, "-rusin-"); } if (m_vup->prelim()) { // First stage evaluation // Determine expression widths only relying on what's in the subops userIterateAndNext(nodep->lhsp(), WidthVP(CONTEXT, PRELIM).p()); @@ -3973,7 +4085,8 @@ private: if (nodep->lhsp()->isDouble() || nodep->rhsp()->isDouble()) { spliceCvtD(nodep->lhsp()); spliceCvtD(nodep->rhsp()); - if (AstNodeBiop* newp = replaceWithDVersion(nodep)) { VL_DANGLING(nodep); + if (AstNodeBiop* newp = replaceWithDVersion(nodep)) { + VL_DANGLING(nodep); nodep = newp; // Process new node instead } nodep->dtypeSetDouble(); @@ -3981,7 +4094,7 @@ private: iterateCheckReal(nodep, "RHS", nodep->rhsp(), FINAL); return; } else { - int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width()); + int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width()); int mwidth = std::max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin()); bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()); nodep->dtypeChgWidthSigned(width, mwidth, AstNumeric::fromBool(expSigned)); @@ -3993,25 +4106,30 @@ private: AstNodeDType* subDTypep = expDTypep; nodep->dtypeFrom(expDTypep); // We don't use LHS && RHS -- unspecified language corner, see t_math_signed5 test - //bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()); - if (AstNodeBiop* newp = replaceWithUOrSVersion(nodep, expDTypep->isSigned())) { VL_DANGLING(nodep); + // bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()); + if (AstNodeBiop* newp = replaceWithUOrSVersion(nodep, expDTypep->isSigned())) { + VL_DANGLING(nodep); nodep = newp; // Process new node instead } // Some warning suppressions - bool lhsWarn = true; bool rhsWarn = true; + bool lhsWarn = true; + bool rhsWarn = true; if (VN_IS(nodep, Add) || VN_IS(nodep, Sub)) { - if (subDTypep->widthMin() == (nodep->lhsp()->widthMin()+1)) lhsWarn = false; // Warn if user wants extra bit from carry - if (subDTypep->widthMin() == (nodep->rhsp()->widthMin()+1)) rhsWarn = false; // Warn if user wants extra bit from carry + // Warn if user wants extra bit from carry + if (subDTypep->widthMin() == (nodep->lhsp()->widthMin() + 1)) lhsWarn = false; + if (subDTypep->widthMin() == (nodep->rhsp()->widthMin() + 1)) rhsWarn = false; } else if (VN_IS(nodep, Mul) || VN_IS(nodep, MulS)) { if (subDTypep->widthMin() >= (nodep->lhsp()->widthMin())) lhsWarn = false; if (subDTypep->widthMin() >= (nodep->rhsp()->widthMin())) rhsWarn = false; } // Final call, so make sure children check their sizes // Error report and change sizes for suboperands of this node. - iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP, lhsWarn); - iterateCheck(nodep, "RHS", nodep->rhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP, rhsWarn); + iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP, + lhsWarn); + iterateCheck(nodep, "RHS", nodep->rhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP, + rhsWarn); } - //if (debug()>=9) nodep->dumpTree(cout, "-rusou-"); + // if (debug() >= 9) nodep->dumpTree(cout, "-rusou-"); } void visit_real_add_sub(AstNodeBiop* nodep) { // CALLER: AddD, MulD, ... @@ -4038,17 +4156,17 @@ private: int expWidth = expDTypep->width(); int expWidthMin = expDTypep->widthMin(); UASSERT_OBJ(nodep->dtypep(), nodep, - "Under node "<prettyTypeName() - <<" has no dtype?? Missing Visitor func?"); + "Under node " << nodep->prettyTypeName() + << " has no dtype?? Missing Visitor func?"); UASSERT_OBJ(nodep->width() != 0, nodep, - "Under node "<prettyTypeName() - <<" has no expected width?? Missing Visitor func?"); + "Under node " << nodep->prettyTypeName() + << " has no expected width?? Missing Visitor func?"); UASSERT_OBJ(expWidth != 0, nodep, - "Node "<prettyTypeName() - <<" has no expected width?? Missing Visitor func?"); - if (expWidthMin==0) expWidthMin = expWidth; + "Node " << nodep->prettyTypeName() + << " has no expected width?? Missing Visitor func?"); + if (expWidthMin == 0) expWidthMin = expWidth; if (nodep->dtypep()->width() == expWidth) return false; - if (nodep->dtypep()->widthSized() && nodep->width() != expWidthMin) return true; + if (nodep->dtypep()->widthSized() && nodep->width() != expWidthMin) return true; if (!nodep->dtypep()->widthSized() && nodep->widthMin() > expWidthMin) return true; return false; } @@ -4064,20 +4182,21 @@ private: // node, while the output dtype is the *expected* sign. // It is reasonable to have sign extension with unsigned output, // for example $unsigned(a)+$signed(b), the SIGNED(B) will be unsigned dtype out - UINFO(4," widthExtend_(r="<width(); if (constp && !constp->num().isNegative()) { // Save later constant propagation work, just right-size it. - V3Number num (nodep, expWidth); + V3Number num(nodep, expWidth); num.opAssign(constp->num()); num.isSigned(false); AstNode* newp = new AstConst(nodep->fileline(), num); constp->replaceWith(newp); - VL_DO_DANGLING(pushDeletep(constp), constp); VL_DANGLING(nodep); + VL_DO_DANGLING(pushDeletep(constp), constp); + VL_DANGLING(nodep); nodep = newp; - } else if (expWidthwidth()) { + } else if (expWidth < nodep->width()) { // Trunc - Extract AstNRelinker linker; nodep->unlinkFrBack(&linker); @@ -4092,13 +4211,13 @@ private: bool doSigned = false; switch (extendRule) { case EXTEND_ZERO: doSigned = false; break; - case EXTEND_EXP: doSigned = nodep->isSigned() && expDTypep->isSigned(); break; - case EXTEND_LHS: doSigned = nodep->isSigned(); break; + case EXTEND_EXP: doSigned = nodep->isSigned() && expDTypep->isSigned(); break; + case EXTEND_LHS: doSigned = nodep->isSigned(); break; default: nodep->v3fatalSrc("bad case"); } - AstNode* newp = (doSigned - ? static_cast(new AstExtendS(nodep->fileline(), nodep)) - : static_cast(new AstExtend (nodep->fileline(), nodep))); + AstNode* newp + = (doSigned ? static_cast(new AstExtendS(nodep->fileline(), nodep)) + : static_cast(new AstExtend(nodep->fileline(), nodep))); linker.relink(newp); nodep = newp; } @@ -4110,7 +4229,7 @@ private: nodep = newp; } nodep->dtypeFrom(expDTypep); - UINFO(4," _new: "<num()); num.isSigned(expSigned); AstNode* newp = new AstConst(nodep->fileline(), num); constp->replaceWith(newp); - VL_DO_DANGLING(constp->deleteTree(), constp); VL_DANGLING(nodep); + VL_DO_DANGLING(constp->deleteTree(), constp); + VL_DANGLING(nodep); nodep = newp; } else { AstNRelinker linker; @@ -4138,20 +4258,20 @@ private: nodep = newp; } nodep->dtypeChgWidthSigned(expWidth, expWidth, AstNumeric::fromBool(expSigned)); - UINFO(4," _new: "<num().autoExtend() && !constp->num().sized() && constp->width()==1) { + if (constp->num().autoExtend() && !constp->num().sized() && constp->width() == 1) { // Make it the proper size. Careful of proper extension of 0's/1's - V3Number num (constp, expWidth); + V3Number num(constp, expWidth); num.opRepl(constp->num(), expWidth); // {width{'1}} AstNode* newp = new AstConst(constp->fileline(), num); // Spec says always unsigned with proper width - if (debug()>4) constp->dumpTree(cout, " fixAutoExtend_old: "); - if (debug()>4) newp->dumpTree(cout, " _new: "); + if (debug() > 4) constp->dumpTree(cout, " fixAutoExtend_old: "); + if (debug() > 4) newp->dumpTree(cout, " _new: "); constp->replaceWith(newp); VL_DO_DANGLING(constp->deleteTree(), constp); // Tell caller the new constp, and that we changed it. @@ -4163,13 +4283,13 @@ private: // Make it the proper size. Careful of proper extension of 0's/1's && expWidth > 32 && constp->num().isMsbXZ()) { constp->v3warn(WIDTH, "Unsized constant being X/Z extended to " - <prettyName()); - V3Number num (constp, expWidth); + << expWidth << " bits: " << constp->prettyName()); + V3Number num(constp, expWidth); num.opExtendXZ(constp->num(), constp->width()); AstNode* newp = new AstConst(constp->fileline(), num); // Spec says always unsigned with proper width - if (debug()>4) constp->dumpTree(cout, " fixUnszExtend_old: "); - if (debug()>4) newp->dumpTree(cout, " _new: "); + if (debug() > 4) constp->dumpTree(cout, " fixUnszExtend_old: "); + if (debug() > 4) newp->dumpTree(cout, " _new: "); constp->replaceWith(newp); VL_DO_DANGLING(constp->deleteTree(), constp); // Tell caller the new constp, and that we changed it. @@ -4188,7 +4308,8 @@ private: // underp may change as a result of replacement underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p()); AstNodeDType* expDTypep = underp->findUInt32DType(); - underp = iterateCheck(nodep, "file_descriptor", underp, SELF, FINAL, expDTypep, EXTEND_EXP); + underp + = iterateCheck(nodep, "file_descriptor", underp, SELF, FINAL, expDTypep, EXTEND_EXP); if (underp) {} // cppcheck } void iterateCheckSigned32(AstNode* nodep, const char* side, AstNode* underp, Stage stage) { @@ -4239,31 +4360,33 @@ private: } if (underp) {} // cppcheck } - void iterateCheckSizedSelf(AstNode* nodep, const char* side, AstNode* underp, - Determ determ, Stage stage) { + void iterateCheckSizedSelf(AstNode* nodep, const char* side, AstNode* underp, Determ determ, + Stage stage) { // Coerce child to any sized-number data type; child is self-determined // i.e. isolated from expected type. // e.g. nodep=CONCAT, underp=lhs in CONCAT(lhs,rhs) UASSERT_OBJ(determ == SELF, nodep, "Bad call"); UASSERT_OBJ(stage == FINAL || stage == BOTH, nodep, "Bad call"); // underp may change as a result of replacement - if (stage & PRELIM) underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p()); + if (stage & PRELIM) { + underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p()); + } underp = checkCvtUS(underp); AstNodeDType* expDTypep = underp->dtypep(); underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP); if (underp) {} // cppcheck } - void iterateCheckAssign(AstNode* nodep, const char* side, - AstNode* rhsp, Stage stage, AstNodeDType* lhsDTypep) { + void iterateCheckAssign(AstNode* nodep, const char* side, AstNode* rhsp, Stage stage, + AstNodeDType* lhsDTypep) { // Check using assignment-like context rules - //if (debug()) nodep->dumpTree(cout, "-checkass: "); + // if (debug()) nodep->dumpTree(cout, "-checkass: "); UASSERT_OBJ(stage == FINAL, nodep, "Bad width call"); // We iterate and size the RHS based on the result of RHS evaluation - bool lhsStream = (VN_IS(nodep, NodeAssign) - && VN_IS(VN_CAST(nodep, NodeAssign)->lhsp(), NodeStream)); + bool lhsStream + = (VN_IS(nodep, NodeAssign) && VN_IS(VN_CAST(nodep, NodeAssign)->lhsp(), NodeStream)); rhsp = iterateCheck(nodep, side, rhsp, ASSIGN, FINAL, lhsDTypep, lhsStream ? EXTEND_OFF : EXTEND_LHS); - //if (debug()) nodep->dumpTree(cout, "-checkout: "); + // if (debug()) nodep->dumpTree(cout, "-checkout: "); if (rhsp) {} // cppcheck } @@ -4281,39 +4404,42 @@ private: // // For DOUBLE under a logical op, add implied test against zero, never a warning if (underp && underp->isDouble()) { - UINFO(6," spliceCvtCmpD0: "<unlinkFrBack(&linker); - AstNode* newp = new AstNeqD( - nodep->fileline(), underp, - new AstConst(nodep->fileline(), AstConst::RealDouble(), 0.0)); + AstNode* newp + = new AstNeqD(nodep->fileline(), underp, + new AstConst(nodep->fileline(), AstConst::RealDouble(), 0.0)); linker.relink(newp); } else if (!underp->dtypep()->basicp()) { - nodep->v3error("Logical Operator "<prettyTypeName() - <<" expects a non-complex data type on the "<v3error("Logical Operator " << nodep->prettyTypeName() + << " expects a non-complex data type on the " + << side << "."); underp->replaceWith(new AstConst(nodep->fileline(), AstConst::LogicFalse())); VL_DO_DANGLING(pushDeletep(underp), underp); } else { bool bad = widthBad(underp, nodep->findLogicBoolDType()); if (bad) { { // if (warnOn), but not needed here - if (debug()>4) nodep->backp()->dumpTree(cout, " back: "); - nodep->v3warn(WIDTH, "Logical Operator "<prettyTypeName() - <<" expects 1 bit on the "<prettyTypeName()<<" generates "<width() - <<(underp->width()!=underp->widthMin() - ?" or "+cvtToStr(underp->widthMin()):"") - <<" bits."); + if (debug() > 4) nodep->backp()->dumpTree(cout, " back: "); + nodep->v3warn(WIDTH, "Logical Operator " + << nodep->prettyTypeName() << " expects 1 bit on the " + << side << ", but " << side << "'s " + << underp->prettyTypeName() << " generates " + << underp->width() + << (underp->width() != underp->widthMin() + ? " or " + cvtToStr(underp->widthMin()) + : "") + << " bits."); } - VL_DO_DANGLING(fixWidthReduce(underp), underp); //Changed + VL_DO_DANGLING(fixWidthReduce(underp), underp); // Changed } } } - AstNode* iterateCheck(AstNode* nodep, const char* side, AstNode* underp, - Determ determ, Stage stage, AstNodeDType* expDTypep, - ExtendRule extendRule, - bool warnOn=true) { + AstNode* iterateCheck(AstNode* nodep, const char* side, AstNode* underp, Determ determ, + Stage stage, AstNodeDType* expDTypep, ExtendRule extendRule, + bool warnOn = true) { // Perform data type check on underp, which is underneath nodep used for error reporting // Returns the new underp // Conversion to/from doubles and integers are before iterating. @@ -4323,8 +4449,8 @@ private: if (VN_IS(underp, NodeDType)) { // Note the node itself, not node's data type // Must be near top of these checks as underp->dtypep() will look normal underp->v3error(ucfirst(nodep->prettyOperatorName()) - <<" expected non-datatype "<name()<<"' is a datatype."); + << " expected non-datatype " << side << " but '" << underp->name() + << "' is a datatype."); } else if (expDTypep == underp->dtypep()) { // Perfect underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, FINAL).p()); } else if (expDTypep->isDouble() && underp->isDouble()) { // Also good @@ -4357,7 +4483,7 @@ private: std::max(subDTypep->width(), underp->width()), std::max(subDTypep->widthMin(), underp->widthMin()), AstNumeric::fromBool(underp->isSigned())); - UINFO(9,"Assignment of opposite-signed RHS to LHS: "<dtypep(), IfaceRefDType)) { + } else if (!VN_IS(expDTypep, IfaceRefDType) + && VN_IS(underp->dtypep(), IfaceRefDType)) { underp->v3error(ucfirst(nodep->prettyOperatorName()) - <<" expected non-interface on "<name()<<"' is an interface."); - } - else { + << " expected non-interface on " << side << " but '" + << underp->name() << "' is an interface."); + } else { // Hope it just works out } } @@ -4382,23 +4506,23 @@ private: void widthCheckSized(AstNode* nodep, const char* side, AstNode* underp, // Node to be checked or have typecast added in front of - AstNodeDType* expDTypep, - ExtendRule extendRule, - bool warnOn=true) { + AstNodeDType* expDTypep, ExtendRule extendRule, bool warnOn = true) { // Issue warnings on sized number width mismatches, then do appropriate size extension // Generally iterateCheck is what is wanted instead of this - //UINFO(9,"wchk "<basicp(); AstBasicDType* underBasicp = underp->dtypep()->basicp(); if (expDTypep == underp->dtypep()) { return; // Same type must match - } else if (!expBasicp || expBasicp->isDouble() - || !underBasicp || underBasicp->isDouble()) { + } else if (!expBasicp || expBasicp->isDouble() || !underBasicp + || underBasicp->isDouble()) { // This is perhaps a v3fatalSrc as we should have checked the types // before calling widthCheck, but we may have missed a non-sized // check in earlier code, so might as well assume it is the users' // fault. - nodep->v3error(ucfirst(nodep->prettyOperatorName())<<" expected non-complex non-double "<v3error(ucfirst(nodep->prettyOperatorName()) + << " expected non-complex non-double " << side << " in width check"); #if VL_DEBUG nodep->v3fatalSrc("widthCheckSized should not be called on doubles/complex types"); #endif @@ -4406,10 +4530,9 @@ private: } else { int expWidth = expDTypep->width(); int expWidthMin = expDTypep->widthMin(); - if (expWidthMin==0) expWidthMin = expWidth; + if (expWidthMin == 0) expWidthMin = expWidth; bool bad = widthBad(underp, expDTypep); - if ((bad || underp->width() != expWidth) - && fixAutoExtend(underp/*ref*/, expWidth)) { + if ((bad || underp->width() != expWidth) && fixAutoExtend(underp /*ref*/, expWidth)) { underp = NULL; // Changes underp return; } @@ -4420,25 +4543,27 @@ private: // Maybe this should be a special warning? Not for now. warnOn = false; } - if ((VN_IS(nodep, Add) && underp->width()==1 && underp->isOne()) - || (VN_IS(nodep, Sub) && underp->width()==1 && underp->isOne() - && 0==strcmp(side, "RHS"))) { + if ((VN_IS(nodep, Add) && underp->width() == 1 && underp->isOne()) + || (VN_IS(nodep, Sub) && underp->width() == 1 && underp->isOne() + && 0 == strcmp(side, "RHS"))) { // "foo + 1'b1", or "foo - 1'b1" are very common, people assume // they extend correctly warnOn = false; } if (bad && warnOn) { - if (debug()>4) nodep->backp()->dumpTree(cout, " back: "); - nodep->v3warn(WIDTH, ucfirst(nodep->prettyOperatorName()) - <<" expects "<prettyTypeName()<<" generates "<width() - <<(underp->width()!=underp->widthMin() - ?" or "+cvtToStr(underp->widthMin()):"") - <<" bits."); + if (debug() > 4) nodep->backp()->dumpTree(cout, " back: "); + nodep->v3warn( + WIDTH, ucfirst(nodep->prettyOperatorName()) + << " expects " << expWidth + << (expWidth != expWidthMin ? " or " + cvtToStr(expWidthMin) : "") + << " bits on the " << side << ", but " << side << "'s " + << underp->prettyTypeName() << " generates " << underp->width() + << (underp->width() != underp->widthMin() + ? " or " + cvtToStr(underp->widthMin()) + : "") + << " bits."); } - if (bad || underp->width()!=expWidth) { + if (bad || underp->width() != expWidth) { // If we're in an NodeAssign, don't truncate the RHS if the LHS is // a NodeStream. The streaming operator changes the rules regarding // which bits to truncate. @@ -4447,7 +4572,7 @@ private: if (assignp && VN_IS(assignp->lhsp(), NodeStream)) { } else if (pinp && pinp->modVarp()->direction() != VDirection::INPUT) { // V3Inst::pinReconnectSimple must deal - UINFO(5,"pinInSizeMismatch: "<isDouble()) { nodep->v3error("Expected integral (non-" << nodep->dtypep()->prettyDTypeName() - << ") input to " << nodep->backp()->prettyTypeName()); + << ") input to " + << nodep->backp()->prettyTypeName()); nodep = spliceCvtS(nodep, true, 32); } return nodep; @@ -4471,7 +4597,7 @@ private: // For integer used in REAL context, convert to real // We don't warn here, "2.0 * 2" is common and reasonable if (nodep && !nodep->dtypep()->skipRefp()->isDouble()) { - UINFO(6," spliceCvtD: "<unlinkFrBack(&linker); AstNode* newp = new AstIToRD(nodep->fileline(), nodep); @@ -4510,9 +4636,8 @@ private: AstNode* spliceCvtString(AstNode* nodep) { // IEEE-2012 11.8.1: Signed: Type coercion creates signed // 11.8.2: Argument to convert is self-determined - if (nodep && !(nodep->dtypep()->basicp() - && nodep->dtypep()->basicp()->isString())) { - UINFO(6," spliceCvtString: "<dtypep()->basicp() && nodep->dtypep()->basicp()->isString())) { + UINFO(6, " spliceCvtString: " << nodep << endl); AstNRelinker linker; nodep->unlinkFrBack(&linker); AstNode* newp = new AstCvtPackString(nodep->fileline(), nodep); @@ -4525,20 +4650,18 @@ private: AstNodeBiop* replaceWithUOrSVersion(AstNodeBiop* nodep, bool signedFlavorNeeded) { // Given a signed/unsigned node type, create the opposite type // Return new node or NULL if nothing - if (signedFlavorNeeded == nodep->signedFlavor()) { - return NULL; - } + if (signedFlavorNeeded == nodep->signedFlavor()) return NULL; if (!nodep->dtypep()) nodep->dtypeFrom(nodep->lhsp()); // To simplify callers, some node types don't need to change switch (nodep->type()) { - case AstType::atEq: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; - case AstType::atNeq: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; + case AstType::atEq: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; + case AstType::atNeq: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; case AstType::atEqCase: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; case AstType::atNeqCase: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; case AstType::atEqWild: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; case AstType::atNeqWild: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; - case AstType::atAdd: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; - case AstType::atSub: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; + case AstType::atAdd: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; + case AstType::atSub: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; case AstType::atShiftL: nodep->dtypeChgSigned(signedFlavorNeeded); return NULL; default: break; } @@ -4547,27 +4670,27 @@ private: AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNodeBiop* newp = NULL; switch (nodep->type()) { - case AstType::atGt: newp = new AstGtS (fl, lhsp, rhsp); break; - case AstType::atGtS: newp = new AstGt (fl, lhsp, rhsp); break; - case AstType::atGte: newp = new AstGteS (fl, lhsp, rhsp); break; - case AstType::atGteS: newp = new AstGte (fl, lhsp, rhsp); break; - case AstType::atLt: newp = new AstLtS (fl, lhsp, rhsp); break; - case AstType::atLtS: newp = new AstLt (fl, lhsp, rhsp); break; - case AstType::atLte: newp = new AstLteS (fl, lhsp, rhsp); break; - case AstType::atLteS: newp = new AstLte (fl, lhsp, rhsp); break; - case AstType::atDiv: newp = new AstDivS (fl, lhsp, rhsp); break; - case AstType::atDivS: newp = new AstDiv (fl, lhsp, rhsp); break; - case AstType::atModDiv: newp = new AstModDivS (fl, lhsp, rhsp); break; - case AstType::atModDivS: newp = new AstModDiv (fl, lhsp, rhsp); break; - case AstType::atMul: newp = new AstMulS (fl, lhsp, rhsp); break; - case AstType::atMulS: newp = new AstMul (fl, lhsp, rhsp); break; - case AstType::atShiftR: newp = new AstShiftRS (fl, lhsp, rhsp); break; - case AstType::atShiftRS: newp = new AstShiftR (fl, lhsp, rhsp); break; + case AstType::atGt: newp = new AstGtS(fl, lhsp, rhsp); break; + case AstType::atGtS: newp = new AstGt(fl, lhsp, rhsp); break; + case AstType::atGte: newp = new AstGteS(fl, lhsp, rhsp); break; + case AstType::atGteS: newp = new AstGte(fl, lhsp, rhsp); break; + case AstType::atLt: newp = new AstLtS(fl, lhsp, rhsp); break; + case AstType::atLtS: newp = new AstLt(fl, lhsp, rhsp); break; + case AstType::atLte: newp = new AstLteS(fl, lhsp, rhsp); break; + case AstType::atLteS: newp = new AstLte(fl, lhsp, rhsp); break; + case AstType::atDiv: newp = new AstDivS(fl, lhsp, rhsp); break; + case AstType::atDivS: newp = new AstDiv(fl, lhsp, rhsp); break; + case AstType::atModDiv: newp = new AstModDivS(fl, lhsp, rhsp); break; + case AstType::atModDivS: newp = new AstModDiv(fl, lhsp, rhsp); break; + case AstType::atMul: newp = new AstMulS(fl, lhsp, rhsp); break; + case AstType::atMulS: newp = new AstMul(fl, lhsp, rhsp); break; + case AstType::atShiftR: newp = new AstShiftRS(fl, lhsp, rhsp); break; + case AstType::atShiftRS: newp = new AstShiftR(fl, lhsp, rhsp); break; default: - nodep->v3fatalSrc("Node needs sign change, but bad case: "<v3fatalSrc("Node needs sign change, but bad case: " << nodep << endl); break; } - UINFO(6," ReplaceWithUOrSVersion: "<replaceWith(newp); newp->dtypeFrom(nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -4576,31 +4699,37 @@ private: AstNodeBiop* replaceWithDVersion(AstNodeBiop* nodep) { // Given a signed/unsigned node type, create the opposite type // Return new node or NULL if nothing - if (nodep->doubleFlavor()) { - return NULL; - } + if (nodep->doubleFlavor()) { return NULL; } FileLine* fl = nodep->fileline(); AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNodeBiop* newp = NULL; // No width change on output;... // All below have bool or double outputs switch (nodep->type()) { - case AstType::atAdd: newp = new AstAddD(fl, lhsp, rhsp); break; - case AstType::atSub: newp = new AstSubD(fl, lhsp, rhsp); break; - case AstType::atPow: newp = new AstPowD(fl, lhsp, rhsp); break; - case AstType::atEq: case AstType::atEqCase: newp = new AstEqD (fl, lhsp, rhsp); break; - case AstType::atNeq: case AstType::atNeqCase: newp = new AstNeqD(fl, lhsp, rhsp); break; - case AstType::atGt: case AstType::atGtS: newp = new AstGtD (fl, lhsp, rhsp); break; - case AstType::atGte: case AstType::atGteS: newp = new AstGteD(fl, lhsp, rhsp); break; - case AstType::atLt: case AstType::atLtS: newp = new AstLtD (fl, lhsp, rhsp); break; - case AstType::atLte: case AstType::atLteS: newp = new AstLteD(fl, lhsp, rhsp); break; - case AstType::atDiv: case AstType::atDivS: newp = new AstDivD(fl, lhsp, rhsp); break; - case AstType::atMul: case AstType::atMulS: newp = new AstMulD(fl, lhsp, rhsp); break; + case AstType::atAdd: newp = new AstAddD(fl, lhsp, rhsp); break; + case AstType::atSub: newp = new AstSubD(fl, lhsp, rhsp); break; + case AstType::atPow: newp = new AstPowD(fl, lhsp, rhsp); break; + case AstType::atEq: + case AstType::atEqCase: newp = new AstEqD(fl, lhsp, rhsp); break; + case AstType::atNeq: + case AstType::atNeqCase: newp = new AstNeqD(fl, lhsp, rhsp); break; + case AstType::atGt: + case AstType::atGtS: newp = new AstGtD(fl, lhsp, rhsp); break; + case AstType::atGte: + case AstType::atGteS: newp = new AstGteD(fl, lhsp, rhsp); break; + case AstType::atLt: + case AstType::atLtS: newp = new AstLtD(fl, lhsp, rhsp); break; + case AstType::atLte: + case AstType::atLteS: newp = new AstLteD(fl, lhsp, rhsp); break; + case AstType::atDiv: + case AstType::atDivS: newp = new AstDivD(fl, lhsp, rhsp); break; + case AstType::atMul: + case AstType::atMulS: newp = new AstMulD(fl, lhsp, rhsp); break; default: - nodep->v3fatalSrc("Node needs conversion to double, but bad case: "<v3fatalSrc("Node needs conversion to double, but bad case: " << nodep << endl); break; } - UINFO(6," ReplaceWithDVersion: "<replaceWith(newp); // No width change; the default created type (bool or double) is correct VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -4609,26 +4738,30 @@ private: AstNodeBiop* replaceWithNVersion(AstNodeBiop* nodep) { // Given a signed/unsigned node type, replace with string version // Return new node or NULL if nothing - if (nodep->stringFlavor()) { - return NULL; - } + if (nodep->stringFlavor()) return NULL; FileLine* fl = nodep->fileline(); AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNodeBiop* newp = NULL; // No width change on output;... // All below have bool or double outputs switch (nodep->type()) { - case AstType::atEq: case AstType::atEqCase: newp = new AstEqN (fl, lhsp, rhsp); break; - case AstType::atNeq: case AstType::atNeqCase: newp = new AstNeqN(fl, lhsp, rhsp); break; - case AstType::atGt: case AstType::atGtS: newp = new AstGtN (fl, lhsp, rhsp); break; - case AstType::atGte: case AstType::atGteS: newp = new AstGteN(fl, lhsp, rhsp); break; - case AstType::atLt: case AstType::atLtS: newp = new AstLtN (fl, lhsp, rhsp); break; - case AstType::atLte: case AstType::atLteS: newp = new AstLteN(fl, lhsp, rhsp); break; + case AstType::atEq: + case AstType::atEqCase: newp = new AstEqN(fl, lhsp, rhsp); break; + case AstType::atNeq: + case AstType::atNeqCase: newp = new AstNeqN(fl, lhsp, rhsp); break; + case AstType::atGt: + case AstType::atGtS: newp = new AstGtN(fl, lhsp, rhsp); break; + case AstType::atGte: + case AstType::atGteS: newp = new AstGteN(fl, lhsp, rhsp); break; + case AstType::atLt: + case AstType::atLtS: newp = new AstLtN(fl, lhsp, rhsp); break; + case AstType::atLte: + case AstType::atLteS: newp = new AstLteN(fl, lhsp, rhsp); break; default: - nodep->v3fatalSrc("Node needs conversion to string, but bad case: "<v3fatalSrc("Node needs conversion to string, but bad case: " << nodep << endl); break; } - UINFO(6," ReplaceWithNVersion: "<replaceWith(newp); // No width change; the default created type (bool or string) is correct VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -4637,19 +4770,17 @@ private: AstNodeUniop* replaceWithDVersion(AstNodeUniop* nodep) { // Given a signed/unsigned node type, create the opposite type // Return new node or NULL if nothing - if (nodep->doubleFlavor()) { - return NULL; - } + if (nodep->doubleFlavor()) return NULL; FileLine* fl = nodep->fileline(); AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNodeUniop* newp = NULL; switch (nodep->type()) { case AstType::atNegate: newp = new AstNegateD(fl, lhsp); break; default: - nodep->v3fatalSrc("Node needs conversion to double, but bad case: "<v3fatalSrc("Node needs conversion to double, but bad case: " << nodep << endl); break; } - UINFO(6," ReplaceWithDVersion: "<replaceWith(newp); newp->dtypeFrom(nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -4663,14 +4794,13 @@ private: // For string.itoa and similar, replace with SFormatF AstArg* argp = VN_CAST(nodep->pinsp(), Arg); if (!argp) { - nodep->v3error("Argument needed for string." - +nodep->prettyName()+" method"); + nodep->v3error("Argument needed for string." + nodep->prettyName() + " method"); return; } AstNodeVarRef* fromp = VN_CAST(nodep->fromp()->unlinkFrBack(), VarRef); - AstNode* newp = new AstAssign(nodep->fileline(), fromp, - new AstSFormatF(nodep->fileline(), format, false, - argp->exprp()->unlinkFrBack())); + AstNode* newp = new AstAssign( + nodep->fileline(), fromp, + new AstSFormatF(nodep->fileline(), format, false, argp->exprp()->unlinkFrBack())); fromp->lvalue(true); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -4683,7 +4813,7 @@ private: // DTypes at parse time get added as a e.g. childDType to some node types such as AstVars. // Move type to global scope, so removing/changing a variable won't lose the dtype. UASSERT_OBJ(dtnodep, nodep, "Caller should check for NULL before calling moveDTypeEdit"); - UINFO(9,"moveDTypeEdit "<unlinkFrBack(); // Make non-child v3Global.rootp()->typeTablep()->addTypesp(dtnodep); return dtnodep; @@ -4706,12 +4836,13 @@ private: return nodep; } - AstConst* dimensionValue(FileLine* fileline, AstNodeDType* nodep, AstAttrType attrType, int dim) { + AstConst* dimensionValue(FileLine* fileline, AstNodeDType* nodep, AstAttrType attrType, + int dim) { // Return the dimension value for the specified attribute and constant dimension AstNodeDType* dtypep = nodep->skipRefp(); VNumRange declRange; // ranged() set false for (int i = 1; i <= dim; ++i) { - //UINFO(9, " dim at "<declRange(); @@ -4732,7 +4863,7 @@ private: case AstAttrType::DIM_BITS: { int bits = 1; while (dtypep) { - //UINFO(9, " bits at "<declRange().elements(); dtypep = adtypep->subDTypep()->skipRefp(); @@ -4748,53 +4879,41 @@ private: } if (dim == 0) { val = 0; - } else if (dim == 1 && !declRange.ranged() && bits==1) { // $bits should be sane for non-arrays + } else if (dim == 1 && !declRange.ranged() + && bits == 1) { // $bits should be sane for non-arrays val = nodep->width(); } else { val = bits; } - break; } - case AstAttrType::DIM_HIGH: - val = !declRange.ranged() ? 0 : declRange.hi(); - break; - case AstAttrType::DIM_LEFT: - val = !declRange.ranged() ? 0 : declRange.left(); - break; - case AstAttrType::DIM_LOW: - val = !declRange.ranged() ? 0 : declRange.lo(); - break; - case AstAttrType::DIM_RIGHT: - val = !declRange.ranged() ? 0 : declRange.right(); break; + } + case AstAttrType::DIM_HIGH: val = !declRange.ranged() ? 0 : declRange.hi(); break; + case AstAttrType::DIM_LEFT: val = !declRange.ranged() ? 0 : declRange.left(); break; + case AstAttrType::DIM_LOW: val = !declRange.ranged() ? 0 : declRange.lo(); break; + case AstAttrType::DIM_RIGHT: val = !declRange.ranged() ? 0 : declRange.right(); break; case AstAttrType::DIM_INCREMENT: val = (declRange.ranged() && declRange.littleEndian()) ? -1 : 1; break; - case AstAttrType::DIM_SIZE: - val = !declRange.ranged() ? 0 : declRange.elements(); - break; - default: - nodep->v3fatalSrc("Missing DIM ATTR type case"); - break; + case AstAttrType::DIM_SIZE: val = !declRange.ranged() ? 0 : declRange.elements(); break; + default: nodep->v3fatalSrc("Missing DIM ATTR type case"); break; } if (!valp) valp = new AstConst(fileline, AstConst::Signed32(), val); - UINFO(9," $dimension "<isConst(true); varp->isStatic(true); @@ -4803,7 +4922,7 @@ private: v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp); // Element 0 is a non-index and has speced values initp->addValuep(dimensionValue(nodep->fileline(), nodep, attrType, 0)); - for (unsigned i=1; iaddValuep(dimensionValue(nodep->fileline(), nodep, attrType, i)); } userIterate(varp, NULL); // May have already done $unit so must do this var @@ -4813,26 +4932,22 @@ private: AstVar* enumVarp(AstEnumDType* nodep, AstAttrType attrType, uint32_t msbdim) { // Return a variable table which has specified dimension properties for this variable TableMap::iterator pos = m_tableMap.find(make_pair(nodep, attrType)); - if (pos != m_tableMap.end()) { - return pos->second; - } - UINFO(9, "Construct Venumtab attr="<second; + UINFO(9, "Construct Venumtab attr=" << attrType.ascii() << " max=" << msbdim << " for " + << nodep << endl); AstNodeDType* basep; if (attrType == AstAttrType::ENUM_NAME) { basep = nodep->findStringDType(); } else { basep = nodep->dtypep(); } - AstNodeArrayDType* vardtypep - = new AstUnpackArrayDType(nodep->fileline(), - basep, - new AstRange(nodep->fileline(), msbdim, 0)); + AstNodeArrayDType* vardtypep = new AstUnpackArrayDType( + nodep->fileline(), basep, new AstRange(nodep->fileline(), msbdim, 0)); AstInitArray* initp = new AstInitArray(nodep->fileline(), vardtypep, NULL); v3Global.rootp()->typeTablep()->addTypesp(vardtypep); AstVar* varp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP, "__Venumtab_" + VString::downcase(attrType.ascii()) - + cvtToStr(m_dtTables++), + + cvtToStr(m_dtTables++), vardtypep); varp->isConst(true); varp->isStatic(true); @@ -4843,8 +4958,7 @@ private: // Default for all unspecified values if (attrType == AstAttrType::ENUM_NAME) { initp->defaultp(new AstConst(nodep->fileline(), AstConst::String(), "")); - } else if (attrType == AstAttrType::ENUM_NEXT - || attrType == AstAttrType::ENUM_PREV) { + } else if (attrType == AstAttrType::ENUM_NEXT || attrType == AstAttrType::ENUM_PREV) { initp->defaultp(new AstConst(nodep->fileline(), V3Number(nodep, nodep->width(), 0))); } else { nodep->v3fatalSrc("Bad case"); @@ -4853,10 +4967,8 @@ private: // Find valid values and populate UASSERT_OBJ(nodep->itemsp(), nodep, "enum without items"); std::vector values; - values.resize(msbdim+1); - for (unsigned i=0; i<(msbdim+1); ++i) { - values[i] = NULL; - } + values.resize(msbdim + 1); + for (unsigned i = 0; i < (msbdim + 1); ++i) values[i] = NULL; { AstEnumItem* firstp = nodep->itemsp(); AstEnumItem* prevp = firstp; // Prev must start with last item @@ -4880,7 +4992,7 @@ private: } } // Add all specified values to table - for (unsigned i=0; i<(msbdim+1); ++i) { + for (unsigned i = 0; i < (msbdim + 1); ++i) { AstNode* valp = values[i]; if (valp) initp->addIndexValuep(i, valp); } @@ -4892,18 +5004,18 @@ private: PatVecMap patVectorMap(AstPattern* nodep, const VNumRange& range) { PatVecMap patmap; int element = range.left(); - for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); - patp; patp = VN_CAST(patp->nextp(), PatMember)) { + for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp; + patp = VN_CAST(patp->nextp(), PatMember)) { if (patp->keyp()) { if (const AstConst* constp = VN_CAST(patp->keyp(), Const)) { element = constp->toSInt(); } else { patp->keyp()->v3error("Assignment pattern key not supported/understood: " - <keyp()->prettyTypeName()); + << patp->keyp()->prettyTypeName()); } } if (patmap.find(element) != patmap.end()) { - patp->v3error("Assignment pattern key used multiple times: "<v3error("Assignment pattern key used multiple times: " << element); } else { patmap.insert(make_pair(element, patp)); } @@ -4913,7 +5025,7 @@ private: } void makeOpenArrayShell(AstNodeFTaskRef* nodep) { - UINFO(4,"Replicate openarray function "<taskp()<taskp() << endl); AstNodeFTask* oldTaskp = nodep->taskp(); oldTaskp->dpiOpenParentInc(); UASSERT_OBJ(!oldTaskp->dpiOpenChild(), oldTaskp, @@ -4921,27 +5033,25 @@ private: AstNodeFTask* newTaskp = oldTaskp->cloneTree(false); newTaskp->dpiOpenChild(true); newTaskp->dpiOpenParentClear(); - newTaskp->name(newTaskp->name()+"__Vdpioc"+cvtToStr(oldTaskp->dpiOpenParent())); + newTaskp->name(newTaskp->name() + "__Vdpioc" + cvtToStr(oldTaskp->dpiOpenParent())); oldTaskp->addNextHere(newTaskp); // Relink reference to new function nodep->taskp(newTaskp); nodep->name(nodep->taskp()->name()); // Replace open array arguments with the callee's task V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); - for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) { + for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { AstVar* portp = it->first; AstArg* argp = it->second; AstNode* pinp = argp->exprp(); if (!pinp) continue; // Argument error we'll find later - if (hasOpenArrayIterateDType(portp->dtypep())) { - portp->dtypep(pinp->dtypep()); - } + if (hasOpenArrayIterateDType(portp->dtypep())) portp->dtypep(pinp->dtypep()); } } bool markHasOpenArray(AstNodeFTask* nodep) { bool hasOpen = false; - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) { + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isDpiOpenArray() || hasOpenArrayIterateDType(portp->dtypep())) { portp->isDpiOpenArray(true); @@ -4962,8 +5072,8 @@ private: // METHODS - special type detection void assertAtStatement(AstNode* nodep) { if (VL_UNCOVERABLE(m_vup && !m_vup->selfDtm())) { - UINFO(1,"-: "<v3fatalSrc("No dtype expected at statement "<prettyTypeName()); + UINFO(1, "-: " << m_vup << endl); + nodep->v3fatalSrc("No dtype expected at statement " << nodep->prettyTypeName()); } } void checkConstantOrReplace(AstNode* nodep, const string& message) { @@ -4977,8 +5087,7 @@ private: } AstNode* nodeForUnsizedWarning(AstNode* nodep) { // Return a nodep to use for unsized warnings, reporting on child if can - if (nodep->op1p() && nodep->op1p()->dtypep() - && !nodep->op1p()->dtypep()->widthSized()) { + if (nodep->op1p() && nodep->op1p()->dtypep() && !nodep->op1p()->dtypep()->widthSized()) { return nodep->op1p(); } else if (nodep->op2p() && nodep->op2p()->dtypep() && !nodep->op2p()->dtypep()->widthSized()) { @@ -5070,11 +5179,11 @@ int V3Width::debug() { } void V3Width::width(AstNetlist* nodep) { - UINFO(2,__FUNCTION__<<": "<= 6); } diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index 25036ebd2..04320bffb 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -120,13 +120,15 @@ private: nodep->replaceWith(newp); AstNode* oldp = nodep; nodep = newp; - // if (debug()>4) oldp->dumpTree(cout, " fixConstSize_old: "); - // if (debug()>4) newp->dumpTree(cout, " _new: "); + // if (debug() > 4) oldp->dumpTree(cout, " fixConstSize_old: "); + // if (debug() > 4) newp->dumpTree(cout, " _new: "); VL_DO_DANGLING(pushDeletep(oldp), oldp); } editDType(nodep); } - virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { visitIterateNodeDType(nodep); } + virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { // + visitIterateNodeDType(nodep); + } virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE { if (nodep->user1SetOnce()) return; // Process once visitIterateNodeDType(nodep); diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 61facc612..78622792c 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -65,13 +65,16 @@ private: AstNodeDType* m_errp; // Node that was found, for error reporting if not known type AstNodeDType* m_dtypep; // Data type for the 'from' slice VNumRange m_fromRange; // Numeric range bounds for the 'from' slice - FromData(AstNodeDType* errp, AstNodeDType* dtypep, const VNumRange& fromRange) - { m_errp = errp; m_dtypep = dtypep; m_fromRange = fromRange; } + FromData(AstNodeDType* errp, AstNodeDType* dtypep, const VNumRange& fromRange) { + m_errp = errp; + m_dtypep = dtypep; + m_fromRange = fromRange; + } ~FromData() {} }; FromData fromDataForArray(AstNode* nodep, AstNode* basefromp) { // What is the data type and information for this SEL-ish's from()? - UINFO(9," fromData start ddtypep = "<dtypep()->skipRefp(); AstNodeDType* errp = ddtypep; - UINFO(9," fromData.ddtypep = "<rangep() + && (!VN_IS(adtypep->rangep()->msbp(), Const) + || !VN_IS(adtypep->rangep()->lsbp(), Const))), + nodep, + "Non-constant variable range; errored earlier"); // in constifyParam(bfdtypep) fromRange = adtypep->declRange(); } else { nodep->v3error("Illegal bit or array select; type does not have a bit range, or " << "bad dimension: data type is " << errp->prettyDTypeNameQ()); } - } - else { + } else { nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: " << "data type is " << errp->prettyDTypeNameQ()); } @@ -123,7 +122,7 @@ private: return lhsp; } else if (VN_IS(lhsp, Const)) { // Optional vs just making add/sub below, but saves constification some work - V3Number num (lhsp, lhsp->width()); + V3Number num(lhsp, lhsp->width()); num.opSub(VN_CAST(lhsp, Const)->num(), V3Number(lhsp, 32, rhs)); num.isSigned(lhsp->isSigned()); AstNode* newp = new AstConst(lhsp->fileline(), num); @@ -135,8 +134,9 @@ private: newp->dtypeFrom(lhsp); return newp; } else { // rhs < 0; - AstNode* newp = new AstAdd(lhsp->fileline(), lhsp, - new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs)); + AstNode* newp + = new AstAdd(lhsp->fileline(), lhsp, + new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs)); // We must make sure sub gets sign of original value, not from the constant newp->dtypeFrom(lhsp); return newp; @@ -145,9 +145,8 @@ private: AstNode* newSubNeg(vlsint32_t lhs, AstNode* rhsp) { // Return lhs-rhs // We must make sure sub gets sign of original value - AstNode* newp = new AstSub(rhsp->fileline(), - new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs), - rhsp); + AstNode* newp = new AstSub( + rhsp->fileline(), new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs), rhsp); newp->dtypeFrom(rhsp); // Important as AstSub default is lhs's sign return newp; } @@ -176,13 +175,13 @@ private: AstNodeDType* sliceDType(AstPackArrayDType* nodep, int msb, int lsb) { // Return slice needed for msb/lsb, either as original dtype or a new slice dtype - if (nodep->declRange().elements() == (msb-lsb+1) // Extracting whole of original array + if (nodep->declRange().elements() == (msb - lsb + 1) // Extracting whole of original array && nodep->declRange().lo() == lsb) { return nodep; } else { // Need a slice data type, which is an array of the extracted // type, but with (presumably) different size - VNumRange newRange (msb, lsb, nodep->declRange().littleEndian()); + VNumRange newRange(msb, lsb, nodep->declRange().littleEndian()); AstNodeDType* vardtypep = new AstPackArrayDType(nodep->fileline(), nodep->subDTypep(), // Need to strip off array reference @@ -198,85 +197,78 @@ private: virtual void visit(AstSelBit* nodep) VL_OVERRIDE { // Select of a non-width specified part of an array, i.e. "array[2]" // This select style has a lsb and msb (no user specified width) - UINFO(6,"SELBIT "<=9) nodep->backp()->dumpTree(cout, "--SELBT0: "); + UINFO(6, "SELBIT " << nodep << endl); + if (debug() >= 9) nodep->backp()->dumpTree(cout, "--SELBT0: "); // lhsp/rhsp do not need to be constant AstNode* fromp = nodep->lhsp()->unlinkFrBack(); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); // bit we're extracting - if (debug()>=9) nodep->dumpTree(cout, "--SELBT2: "); + if (debug() >= 9) nodep->dumpTree(cout, "--SELBT2: "); FromData fromdata = fromDataForArray(nodep, fromp); AstNodeDType* ddtypep = fromdata.m_dtypep; VNumRange fromRange = fromdata.m_fromRange; - UINFO(6," ddtypep "< ARRAYSEL(array, index) AstNode* subp = rhsp; - if (fromRange.lo()!=0 || fromRange.hi()<0) { + if (fromRange.lo() != 0 || fromRange.hi() < 0) { subp = newSubNeg(subp, fromRange.lo()); } - AstArraySel* newp = new AstArraySel(nodep->fileline(), - fromp, subp); + AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, subp); newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference - if (debug()>=9) newp->dumpTree(cout, "--SELBTn: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) { + if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) { // SELBIT(array, index) -> SEL(array, index*width-of-subindex, width-of-subindex) AstNode* subp = rhsp; - if (fromRange.lo()!=0 || fromRange.hi()<0) { + if (fromRange.lo() != 0 || fromRange.hi() < 0) { if (fromRange.littleEndian()) { subp = newSubNeg(fromRange.hi(), subp); } else { subp = newSubNeg(subp, fromRange.lo()); } } - UASSERT_OBJ(!(!fromRange.elements() - || (adtypep->width() % fromRange.elements())!=0), adtypep, - "Array extraction with width miscomputed " - <width()<<"/"<width() % fromRange.elements()) != 0), + adtypep, + "Array extraction with width miscomputed " << adtypep->width() << "/" + << fromRange.elements()); int elwidth = adtypep->width() / fromRange.elements(); - AstSel* newp - = new AstSel(nodep->fileline(), - fromp, - new AstMul(nodep->fileline(), - new AstConst(nodep->fileline(), - AstConst::Unsized32(), elwidth), - subp), - new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth)); + AstSel* newp = new AstSel( + nodep->fileline(), fromp, + new AstMul(nodep->fileline(), + new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth), subp), + new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth)); newp->declRange(fromRange); newp->declElWidth(elwidth); newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference - if (debug()>=9) newp->dumpTree(cout, "--SELBTn: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (AstAssocArrayDType* adtypep = VN_CAST(ddtypep, AssocArrayDType)) { + if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (AstAssocArrayDType* adtypep = VN_CAST(ddtypep, AssocArrayDType)) { // SELBIT(array, index) -> ASSOCSEL(array, index) AstNode* subp = rhsp; - AstAssocSel* newp = new AstAssocSel(nodep->fileline(), - fromp, subp); + AstAssocSel* newp = new AstAssocSel(nodep->fileline(), fromp, subp); newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference - if (debug()>=9) newp->dumpTree(cout, "--SELBTn: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (AstDynArrayDType* adtypep = VN_CAST(ddtypep, DynArrayDType)) { + if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (AstDynArrayDType* adtypep = VN_CAST(ddtypep, DynArrayDType)) { // SELBIT(array, index) -> CMETHODCALL(queue, "at", index) AstNode* subp = rhsp; - AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(), - fromp, "at", subp); + AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(), fromp, "at", subp); newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference - if (debug()>=9) newp->dumpTree(cout, "--SELBTq: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (AstQueueDType* adtypep = VN_CAST(ddtypep, QueueDType)) { + if (debug() >= 9) newp->dumpTree(cout, "--SELBTq: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (AstQueueDType* adtypep = VN_CAST(ddtypep, QueueDType)) { // SELBIT(array, index) -> CMETHODCALL(queue, "at", index) AstNode* subp = rhsp; - AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(), - fromp, "at", subp); + AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(), fromp, "at", subp); newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference - if (debug()>=9) newp->dumpTree(cout, "--SELBTq: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) { + if (debug() >= 9) newp->dumpTree(cout, "--SELBTq: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) { // SELBIT(string, index) -> GETC(string, index) AstNodeVarRef* varrefp = VN_CAST(fromp, NodeVarRef); if (!varrefp) nodep->v3error("Unsupported: String array operation on non-variable"); @@ -291,29 +283,25 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (VN_IS(ddtypep, BasicDType)) { // SELBIT(range, index) -> SEL(array, index, 1) - AstSel* newp = new AstSel(nodep->fileline(), - fromp, - newSubLsbOf(rhsp, fromRange), + AstSel* newp = new AstSel(nodep->fileline(), fromp, newSubLsbOf(rhsp, fromRange), // Unsized so width from user new AstConst(nodep->fileline(), AstConst::Unsized32(), 1)); newp->declRange(fromRange); - UINFO(6," new "<=9) newp->dumpTree(cout, "--SELBTn: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (VN_IS(ddtypep, NodeUOrStructDType)) { // A bit from the packed struct + UINFO(6, " new " << newp << endl); + if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (VN_IS(ddtypep, NodeUOrStructDType)) { // A bit from the packed struct // SELBIT(range, index) -> SEL(array, index, 1) - AstSel* newp = new AstSel(nodep->fileline(), - fromp, - newSubLsbOf(rhsp, fromRange), + AstSel* newp = new AstSel(nodep->fileline(), fromp, newSubLsbOf(rhsp, fromRange), // Unsized so width from user new AstConst(nodep->fileline(), AstConst::Unsized32(), 1)); newp->declRange(fromRange); - UINFO(6," new "<=9) newp->dumpTree(cout, "--SELBTn: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else { // NULL=bad extract, or unknown node type + UINFO(6, " new " << newp << endl); + if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else { // NULL=bad extract, or unknown node type nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: " << "data type is" << fromdata.m_errp->prettyDTypeNameQ()); // How to recover? We'll strip a dimension. @@ -326,20 +314,22 @@ private: // Select of a range specified part of an array, i.e. "array[2:3]" // SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb) // This select style has a (msb or lsb) and width - UINFO(6,"SELEXTRACT "<=9) nodep->dumpTree(cout, "--SELEX0: "); + UINFO(6, "SELEXTRACT " << nodep << endl); + // if (debug() >= 9) nodep->dumpTree(cout, "--SELEX0: "); // Below 2 lines may change nodep->widthp() V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node - //if (debug()>=9) nodep->dumpTree(cout, "--SELEX3: "); - checkConstantOrReplace(nodep->lsbp(), "First value of [a:b] isn't a constant, maybe you want +: or -:"); - checkConstantOrReplace(nodep->msbp(), "Second value of [a:b] isn't a constant, maybe you want +: or -:"); + // if (debug() >= 9) nodep->dumpTree(cout, "--SELEX3: "); + checkConstantOrReplace(nodep->lsbp(), + "First value of [a:b] isn't a constant, maybe you want +: or -:"); + checkConstantOrReplace(nodep->msbp(), + "Second value of [a:b] isn't a constant, maybe you want +: or -:"); AstNode* fromp = nodep->lhsp()->unlinkFrBack(); AstNode* msbp = nodep->rhsp()->unlinkFrBack(); AstNode* lsbp = nodep->thsp()->unlinkFrBack(); vlsint32_t msb = VN_CAST(msbp, Const)->toSInt(); vlsint32_t lsb = VN_CAST(lsbp, Const)->toSInt(); - vlsint32_t elem = (msb>lsb) ? (msb-lsb+1) : (lsb-msb+1); + vlsint32_t elem = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1); FromData fromdata = fromDataForArray(nodep, fromp); AstNodeDType* ddtypep = fromdata.m_dtypep; VNumRange fromRange = fromdata.m_fromRange; @@ -347,90 +337,101 @@ private: // Slice extraction if (fromRange.elements() == elem && fromRange.lo() == lsb) { // Extracting whole of original array - nodep->replaceWith(fromp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->replaceWith(fromp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (fromRange.elements() == 1) { // Extracting single element AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, lsbp); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { // Slice AstSliceSel* newp = new AstSliceSel(nodep->fileline(), fromp, - VNumRange(VNumRange::LeftRight(), - msb, lsb)); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + VNumRange(VNumRange::LeftRight(), msb, lsb)); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } - } - else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) { + } else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) { // SELEXTRACT(array, msb, lsb) -> SEL(array, // lsb*width-of-subindex, width-of-subindex*(msb-lsb)) - UASSERT_OBJ(!(!fromRange.elements() - || (adtypep->width() % fromRange.elements())!=0), adtypep, - "Array extraction with width miscomputed " - <width()<<"/"<width() % fromRange.elements()) != 0), + adtypep, + "Array extraction with width miscomputed " << adtypep->width() << "/" + << fromRange.elements()); if (fromRange.littleEndian()) { // Below code assumes big bit endian; just works out if we swap - int x = msb; msb = lsb; lsb = x; + int x = msb; + msb = lsb; + lsb = x; } if (lsb > msb) { - nodep->v3error("["<v3error("[" + << msb << ":" << lsb + << "] Range extract has backward bit ordering, perhaps you wanted [" + << lsb << ":" << msb << "]"); + int x = msb; + msb = lsb; + lsb = x; } int elwidth = adtypep->width() / fromRange.elements(); - AstSel* newp = new AstSel(nodep->fileline(), - fromp, - new AstMul(nodep->fileline(), newSubLsbOf(lsbp, fromRange), - new AstConst(nodep->fileline(), - AstConst::Unsized32(), elwidth)), - new AstConst(nodep->fileline(), - AstConst::Unsized32(), (msb-lsb+1)*elwidth)); + AstSel* newp = new AstSel( + nodep->fileline(), fromp, + new AstMul(nodep->fileline(), newSubLsbOf(lsbp, fromRange), + new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth)), + new AstConst(nodep->fileline(), AstConst::Unsized32(), (msb - lsb + 1) * elwidth)); newp->declRange(fromRange); newp->declElWidth(elwidth); newp->dtypeFrom(sliceDType(adtypep, msb, lsb)); - //if (debug()>=9) newp->dumpTree(cout, "--EXTBTn: "); + // if (debug() >= 9) newp->dumpTree(cout, "--EXTBTn: "); UASSERT_OBJ(newp->widthMin() == newp->widthConst(), nodep, "Width mismatch"); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (VN_IS(ddtypep, BasicDType)) { + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (VN_IS(ddtypep, BasicDType)) { if (fromRange.littleEndian()) { // Below code assumes big bit endian; just works out if we swap - int x = msb; msb = lsb; lsb = x; + int x = msb; + msb = lsb; + lsb = x; } if (lsb > msb) { - nodep->v3error("["<v3error("[" + << msb << ":" << lsb + << "] Range extract has backward bit ordering, perhaps you wanted [" + << lsb << ":" << msb << "]"); + int x = msb; + msb = lsb; + lsb = x; } AstNode* widthp = new AstConst(msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user - msb +1-lsb); - AstSel* newp = new AstSel(nodep->fileline(), - fromp, - newSubLsbOf(lsbp, fromRange), - widthp); + msb + 1 - lsb); + AstSel* newp + = new AstSel(nodep->fileline(), fromp, newSubLsbOf(lsbp, fromRange), widthp); newp->declRange(fromRange); - UINFO(6," new "<=9) newp->dumpTree(cout, "--SELEXnew: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else if (VN_IS(ddtypep, NodeUOrStructDType)) { + UINFO(6, " new " << newp << endl); + // if (debug() >= 9) newp->dumpTree(cout, "--SELEXnew: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (VN_IS(ddtypep, NodeUOrStructDType)) { // Classes aren't little endian if (lsb > msb) { - nodep->v3error("["<v3error("[" + << msb << ":" << lsb + << "] Range extract has backward bit ordering, perhaps you wanted [" + << lsb << ":" << msb << "]"); + int x = msb; + msb = lsb; + lsb = x; } AstNode* widthp = new AstConst(msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user - msb +1-lsb); - AstSel* newp = new AstSel(nodep->fileline(), - fromp, - newSubLsbOf(lsbp, fromRange), - widthp); + msb + 1 - lsb); + AstSel* newp + = new AstSel(nodep->fileline(), fromp, newSubLsbOf(lsbp, fromRange), widthp); newp->declRange(fromRange); - UINFO(6," new "<=9) newp->dumpTree(cout, "--SELEXnew: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else { // NULL=bad extract, or unknown node type + UINFO(6, " new " << newp << endl); + // if (debug() >= 9) newp->dumpTree(cout, "--SELEXnew: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else { // NULL=bad extract, or unknown node type nodep->v3error("Illegal range select; type already selected, or bad dimension: " << "data type is " << fromdata.m_errp->prettyDTypeNameQ()); UINFO(1, " Related ddtype: " << ddtypep << endl); @@ -447,38 +448,40 @@ private: void replaceSelPlusMinus(AstNodePreSel* nodep) { // Select of a range specified with +: or -:, i.e. "array[2+:3], [2-:3]" // This select style has a lsb and width - UINFO(6,"SELPLUS/MINUS "<widthp() - if (debug()>=9) nodep->dumpTree(cout, "--SELPM0: "); + if (debug() >= 9) nodep->dumpTree(cout, "--SELPM0: "); V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant"); - if (debug()>=9) nodep->dumpTree(cout, "--SELPM3: "); + if (debug() >= 9) nodep->dumpTree(cout, "--SELPM3: "); // Now replace it with an AstSel AstNode* fromp = nodep->lhsp()->unlinkFrBack(); - AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); + AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNode* widthp = nodep->thsp()->unlinkFrBack(); int width = VN_CAST(widthp, Const)->toSInt(); - if (width > (1<<28)) nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: " - <prettyName()); - if (width<0) nodep->v3error("Width of :+ or :- is < 0: "<prettyName()); + if (width > (1 << 28)) { + nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: " + << widthp->prettyName()); + } + if (width < 0) nodep->v3error("Width of :+ or :- is < 0: " << widthp->prettyName()); FromData fromdata = fromDataForArray(nodep, fromp); AstNodeDType* ddtypep = fromdata.m_dtypep; VNumRange fromRange = fromdata.m_fromRange; - if (VN_IS(ddtypep, BasicDType) - || VN_IS(ddtypep, PackArrayDType) + if (VN_IS(ddtypep, BasicDType) || VN_IS(ddtypep, PackArrayDType) || (VN_IS(ddtypep, NodeUOrStructDType) && VN_CAST(ddtypep, NodeUOrStructDType)->packedUnsup())) { int elwidth = 1; AstNode* newwidthp = widthp; if (const AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) { elwidth = adtypep->width() / fromRange.elements(); - newwidthp = new AstConst(nodep->fileline(), AstConst::Unsized32(), width * elwidth); + newwidthp + = new AstConst(nodep->fileline(), AstConst::Unsized32(), width * elwidth); } AstNode* newlsbp = NULL; if (VN_IS(nodep, SelPlus)) { if (fromRange.littleEndian()) { // SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width) - newlsbp = newSubNeg((fromRange.hi()-width+1), rhsp); + newlsbp = newSubNeg((fromRange.hi() - width + 1), rhsp); } else { // SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width) newlsbp = newSubNeg(rhsp, fromRange.lo()); @@ -489,22 +492,23 @@ private: newlsbp = newSubNeg(fromRange.hi(), rhsp); } else { // SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#) - newlsbp = newSubNeg(rhsp, fromRange.lo()+(width-1)); + newlsbp = newSubNeg(rhsp, fromRange.lo() + (width - 1)); } } else { nodep->v3fatalSrc("Bad Case"); } - if (elwidth != 1) newlsbp = new AstMul(nodep->fileline(), newlsbp, - new AstConst(nodep->fileline(), elwidth)); - AstSel* newp = new AstSel(nodep->fileline(), - fromp, newlsbp, newwidthp); + if (elwidth != 1) { + newlsbp = new AstMul(nodep->fileline(), newlsbp, + new AstConst(nodep->fileline(), elwidth)); + } + AstSel* newp = new AstSel(nodep->fileline(), fromp, newlsbp, newwidthp); newp->declRange(fromRange); newp->declElWidth(elwidth); - UINFO(6," new "<=9) newp->dumpTree(cout, "--SELNEW: "); - nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - else { // NULL=bad extract, or unknown node type + UINFO(6, " new " << newp << endl); + if (debug() >= 9) newp->dumpTree(cout, "--SELNEW: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else { // NULL=bad extract, or unknown node type nodep->v3error("Illegal +: or -: select; type already selected, or bad dimension: " << "data type is " << fromdata.m_errp->prettyDTypeNameQ()); // How to recover? We'll strip a dimension. @@ -516,12 +520,8 @@ private: if (!rhsp->backp()) { VL_DO_DANGLING(pushDeletep(rhsp), rhsp); } if (!widthp->backp()) { VL_DO_DANGLING(pushDeletep(widthp), widthp); } } - virtual void visit(AstSelPlus* nodep) VL_OVERRIDE { - replaceSelPlusMinus(nodep); - } - virtual void visit(AstSelMinus* nodep) VL_OVERRIDE { - replaceSelPlusMinus(nodep); - } + virtual void visit(AstSelPlus* nodep) VL_OVERRIDE { replaceSelPlusMinus(nodep); } + virtual void visit(AstSelMinus* nodep) VL_OVERRIDE { replaceSelPlusMinus(nodep); } // If adding new visitors, ensure V3Width's visit(TYPE) calls into here //-------------------- @@ -534,9 +534,7 @@ private: public: // CONSTRUCTORS WidthSelVisitor() {} - AstNode* mainAcceptEdit(AstNode* nodep) { - return iterateSubtreeReturnEdits(nodep); - } + AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); } virtual ~WidthSelVisitor() {} }; @@ -544,7 +542,7 @@ public: // Width class functions AstNode* V3Width::widthSelNoIterEdit(AstNode* nodep) { - UINFO(4,__FUNCTION__<<": "< Date: Wed, 15 Apr 2020 22:26:15 +0100 Subject: [PATCH 054/127] Fix run-time formatting of variable wider than 1023 bits (#2261) --- src/V3EmitC.cpp | 7 +++--- test_regress/t/t_format_wide_decimal.out | 2 ++ test_regress/t/t_format_wide_decimal.v | 31 ++++++++++++++++++------ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index f0c81b11d..ba95d9fee 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2042,9 +2042,10 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const string pfmt; if ((fmtLetter == '#' || fmtLetter == 'd' || fmtLetter == 't') && !isScan && vfmt == "") { // Size decimal output. Spec says leading spaces, not zeros - double mantissabits = argp->widthMin() - ((fmtLetter == 'd') ? 1 : 0); - double maxval = pow(2.0, mantissabits); - double dchars = log10(maxval) + 1.0; + const double mantissabits = argp->widthMin() - ((fmtLetter == 'd') ? 1 : 0); + // This is log10(2**mantissabits) as log2(2**mantissabits)/log2(10), + // + 1.0 rounding bias. + double dchars = mantissabits / 3.321928094887362 + 1.0; if (fmtLetter == 'd') dchars++; // space for sign int nchars = int(dchars); pfmt = string("%") + cvtToStr(nchars) + fmtLetter; diff --git a/test_regress/t/t_format_wide_decimal.out b/test_regress/t/t_format_wide_decimal.out index 4c5c7138a..8dd14a9b7 100644 --- a/test_regress/t/t_format_wide_decimal.out +++ b/test_regress/t/t_format_wide_decimal.out @@ -1,2 +1,4 @@ 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137215 + 89884656743115795386465259539451236680898848947115328636715040578866337902750481566354238661203768010560056939935696678829394884407208311246423715319737062188883946712432742638151109800623047059726541476042502884419075341171231440736956555270413618581675255342293149119973622969239858152417678164812112068607 + 44942328371557897693232629769725618340449424473557664318357520289433168951375240783177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146574559986811484619929076208839082406056034303 *-* All Finished *-* diff --git a/test_regress/t/t_format_wide_decimal.v b/test_regress/t/t_format_wide_decimal.v index c901f959d..2b2a04835 100644 --- a/test_regress/t/t_format_wide_decimal.v +++ b/test_regress/t/t_format_wide_decimal.v @@ -6,15 +6,32 @@ // Version 2.0. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -module t_format_wide_decimal; +module t_format_wide_decimal(/*AUTOARG*/ + // Inputs + clk + ); + input clk; - initial begin - // Format very wide constant number (which has more bits than can - // be counted in exponent of a double precision float), with %d. - $display("%d", 1024'hffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + int cycle = 0; + bit [1023:0] x = '1; - $write("*-* All Finished *-*\n"); - $finish; + always @(posedge clk) begin + if (cycle == 0) begin + // Format very wide constant number (which has more bits than can + // be counted in exponent of a double precision float), with %d. + $display("%d", 1024'hffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + end else begin + // Same, but for a variable with value only known at run-time + $display("%d", x); + end + + cycle <= cycle + 1; + x <= x >> 1; + + if (cycle == 2) begin + $write("*-* All Finished *-*\n"); + $finish; + end end endmodule From 1883ab29cb33f442e03b3578d82a4d15bebbdbd1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Apr 2020 17:36:48 -0400 Subject: [PATCH 055/127] clang-format 10.0 forward compatibility. No functional change. --- src/V3Ast.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 3f461b777..3380517c0 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -273,17 +273,17 @@ public: switch (other.m_e) { case VEdgeType::ET_NEGEDGE: // FALLTHRU case VEdgeType::ET_LOWEDGE: return true; - default: {} + default:; } break; case VEdgeType::ET_NEGEDGE: switch (other.m_e) { case VEdgeType::ET_POSEDGE: // FALLTHRU case VEdgeType::ET_HIGHEDGE: return true; - default: {} + default:; } break; - default: {} + default:; } return false; } From 18412f93220bd979e1ba71fd8c889e5229293023 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Thu, 16 Apr 2020 06:44:21 +0900 Subject: [PATCH 056/127] Add --build option to call make/cmake as subprocess (#2249) * Add --build, -j, -MAKEFLAGS, and --no-verilate options * Verilator: Can build on both gmake and cmake --- bin/verilator | 35 +++++++++ src/V3Options.cpp | 27 ++++++- src/V3Options.h | 10 +++ src/V3Os.cpp | 20 +++++ src/V3Os.h | 5 ++ src/Verilator.cpp | 110 ++++++++++++++++++++------- test_regress/t/t_flag_build_cmake.pl | 42 ++++++++++ test_regress/t/t_flag_build_make.pl | 32 ++++++++ test_regress/t/t_flag_verilate.pl | 60 +++++++++++++++ 9 files changed, 313 insertions(+), 28 deletions(-) create mode 100755 test_regress/t/t_flag_build_cmake.pl create mode 100755 test_regress/t/t_flag_build_make.pl create mode 100755 test_regress/t/t_flag_verilate.pl diff --git a/bin/verilator b/bin/verilator index d49fc5e08..2f554a77c 100755 --- a/bin/verilator +++ b/bin/verilator @@ -271,6 +271,7 @@ detailed descriptions in L for more information. --bbox-sys Blackbox unknown $system calls --bbox-unsup Blackbox unsupported language features --bin Override Verilator binary + --build Call make system to build executable after Verilation -CFLAGS C++ Compiler flags for makefile --cc Create C++ output --cdc Clock domain crossing analysis @@ -309,6 +310,7 @@ detailed descriptions in L for more information. --getenv Get environment variable with defaults --help Display this help -I Directory to search for includes + -j Parallelism for --build --gate-stmts Tune gate optimizer depth --if-depth Tune IFDEPTH warning +incdir+ Directory to search for includes @@ -319,6 +321,7 @@ detailed descriptions in L for more information. --language Default language standard to parse +libext++[ext]... Extensions for finding modules --lint-only Lint, but do not make output + -MAKEFLAGS Options to make/cmake during --build --max-num-width Maximum number width (default: 64K) --MMD Create .d dependency files --MP Create phony dependency targets @@ -334,6 +337,7 @@ detailed descriptions in L for more information. -O Selectable optimizations -o Name of final executable --no-order-clock-delay Disable ordering clock enable assignments + --no-verilate Skip verilation and just compile previously verilated code. --output-split Split .cpp files into pieces --output-split-cfuncs Split .cpp functions --output-split-ctrace Split tracing functions @@ -533,6 +537,11 @@ dependency (.d) file is created, this filename will become a source dependency, such that a change in this binary will have make rebuild the output files. +=item --build + +After generating the SystemC/C++ code, Verilator will use the make system +to build a library or executable. See also C<--make> and C<--exe>. + =item -CFLAGS I Add specified C compiler flag to the generated makefiles. For multiple @@ -584,6 +593,9 @@ Generates a script for the specified make system. Supported make systems are gmake and cmake. Both can be specified. If no make system is specified, gmake is assumed. +The executable of gmake can be configured via environment variable "MAKE". + +See also --build. =item --compiler I @@ -925,6 +937,12 @@ values, or a value < 1 will inline everything, will lead to longer compile times, but potentially faster simulation runtimes. This setting is ignored for very small modules; they will always be inlined, if allowed. +=item -j + +Specify the parallelism for make system. This option is used when --build +options is specified. must be a positive integer or can be omitted. +Build system exploits maximum parallelism when is omitted. + =item -LDFLAGS I Add specified C linker flags to the generated makefiles. For multiple @@ -970,6 +988,13 @@ stylistic and not enabled by default. If the design is not to be completely Verilated see also the --bbox-sys and --bbox-unsup options. +=item -MAKEFLAGS + +When using --build, add the specified flag to the make/cmake command line. +For multiple flags either pass them as a single argument with space separators +quoted in the shell (e.g. C<-MAKEFLAGS "-a -b">), or use multiple -MAKEFLAGS +arguments (e.g. C<-MAKEFLAGS -l -MAKEFLAGS -k>). + =item --max-num-width I Set the maximum number literal width (e.g. in 1024'd22 this it the 1024). @@ -1510,6 +1535,10 @@ Read the filename as a Verilog library. Any modules in the file may be used to resolve cell instantiations in the top level module, else ignored. Note -v is fairly standard across Verilog tools. +=item --no-verilate + +When using --build, disable generation of C++/SC code, and only run make/cmake. + =item +verilog1995ext+I =item +verilog2001ext+I @@ -2126,6 +2155,12 @@ A generic Linux/OS variable specifying what directories have shared object (.so) files. This path should include SystemC and any other shared objects needed at simulation runtime. +=item MAKE + +Executable of the make command used in --build option. +Some operating systems may require "gmake" to this variable to launch GNU make. +If this variable is not specified, "make" is used. + =item OBJCACHE Optionally specifies a caching or distribution program to place in front of diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 36a54708b..e39e52449 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -198,6 +198,7 @@ void V3Options::checkParameters() { void V3Options::addCppFile(const string& filename) { m_cppFiles.insert(filename); } void V3Options::addCFlags(const string& filename) { m_cFlags.push_back(filename); } void V3Options::addLdLibs(const string& filename) { m_ldLibs.push_back(filename); } +void V3Options::addMakeFlags(const string& filename) { m_makeFlags.push_back(filename); } void V3Options::addFuture(const string& flag) { m_futures.insert(flag); } bool V3Options::isFuture(const string& flag) const { return m_futures.find(flag) != m_futures.end(); @@ -393,7 +394,9 @@ V3LangCode V3Options::fileLanguage(const string& filename) { // Environment string V3Options::getenvBuiltins(const string& var) { - if (var == "PERL") { + if (var == "MAKE") { + return getenvMAKE(); + } else if (var == "PERL") { return getenvPERL(); } else if (var == "SYSTEMC") { return getenvSYSTEMC(); @@ -410,6 +413,8 @@ string V3Options::getenvBuiltins(const string& var) { } } +string V3Options::getenvMAKE() { return V3Os::getenvStr("MAKE", "make"); } + string V3Options::getenvPERL() { // return V3Os::getenvStr("PERL", "perl"); } @@ -723,6 +728,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if ( onoff (sw, "-autoflush", flag/*ref*/)) { m_autoflush = flag; } else if ( onoff (sw, "-bbox-sys", flag/*ref*/)) { m_bboxSys = flag; } else if ( onoff (sw, "-bbox-unsup", flag/*ref*/)) { m_bboxUnsup = flag; } + else if (!strcmp(sw, "-build")) { m_build = true; } else if (!strcmp(sw, "-cc")) { m_outFormatOk = true; m_systemC = false; } else if ( onoff (sw, "-cdc", flag/*ref*/)) { m_cdc = flag; } else if ( onoff (sw, "-coverage", flag/*ref*/)) { coverage(flag); } @@ -783,6 +789,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if ( onoff (sw, "-trace-structs", flag/*ref*/)) { m_traceStructs = flag; } else if ( onoff (sw, "-trace-underscore", flag/*ref*/)) { m_traceUnderscore = flag; } else if ( onoff (sw, "-underline-zero", flag/*ref*/)) { m_underlineZero = flag; } // Undocumented, old Verilator-2 + else if ( onoff (sw, "-verilate", flag/*ref*/)) { m_verilate = flag; } else if ( onoff (sw, "-vpi", flag/*ref*/)) { m_vpi = flag; } else if ( onoff (sw, "-Wpedantic", flag/*ref*/)) { m_pedantic = flag; } else if ( onoff (sw, "-x-initial-edge", flag/*ref*/)) { m_xInitialEdge = flag; } @@ -889,6 +896,17 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char } else if (!strcmp(sw, "-inline-mult") && (i + 1) < argc) { shift; m_inlineMult = atoi(argv[i]); + } else if (!strcmp(sw, "-j")) { + if ((i + 1) >= argc || !isdigit(argv[i + 1][0])) { // No value is given + m_buildJobs = 0; // Unlimited parallelism + } else { + shift; + m_buildJobs = atoi(argv[i]); + if (m_buildJobs <= 0) { + fl->v3error("-j accepts positive integer, but " << argv[i] + << " is passed"); + } + } } else if (!strcmp(sw, "-LDFLAGS") && (i + 1) < argc) { shift; addLdLibs(argv[i]); @@ -906,6 +924,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char } else { fl->v3fatal("Unknown --make system specified: '" << argv[i] << "'"); } + } else if (!strcmp(sw, "-MAKEFLAGS") && (i + 1) < argc) { + shift; + addMakeFlags(argv[i]); } else if (!strcmp(sw, "-max-num-width")) { shift; m_maxNumWidth = atoi(argv[i]); @@ -1355,6 +1376,7 @@ void V3Options::showVersion(bool verbose) { cout << endl; cout << "Environment:\n"; + cout << " MAKE = " << V3Os::getenvStr("MAKE", "") << endl; cout << " PERL = " << V3Os::getenvStr("PERL", "") << endl; cout << " SYSTEMC = " << V3Os::getenvStr("SYSTEMC", "") << endl; cout << " SYSTEMC_ARCH = " << V3Os::getenvStr("SYSTEMC_ARCH", "") << endl; @@ -1374,6 +1396,7 @@ V3Options::V3Options() { m_autoflush = false; m_bboxSys = false; m_bboxUnsup = false; + m_build = false; m_cdc = false; m_cmake = false; m_context = true; @@ -1434,10 +1457,12 @@ V3Options::V3Options() { m_traceStructs = false; m_traceUnderscore = false; m_underlineZero = false; + m_verilate = true; m_vpi = false; m_xInitialEdge = false; m_xmlOnly = false; + m_buildJobs = 1; m_convergeLimit = 100; m_dumpTree = 0; m_gateStmts = 100; diff --git a/src/V3Options.h b/src/V3Options.h index b51d4e48f..f9f17ef88 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -114,6 +114,7 @@ private: V3StringSet m_cppFiles; // argument: C++ files to link against V3StringList m_cFlags; // argument: user CFLAGS V3StringList m_ldLibs; // argument: user LDFLAGS + V3StringList m_makeFlags; // argument: user MAKEFLAGS V3StringSet m_futures; // argument: -Wfuture- list V3StringSet m_libraryFiles; // argument: Verilog -v files V3StringSet m_clockers; // argument: Verilog -clk signals @@ -131,6 +132,7 @@ private: bool m_autoflush; // main switch: --autoflush bool m_bboxSys; // main switch: --bbox-sys bool m_bboxUnsup; // main switch: --bbox-unsup + bool m_build; // main switch: --build bool m_cdc; // main switch: --cdc bool m_cmake; // main switch: --make cmake bool m_context; // main switch: --Wcontext @@ -184,10 +186,12 @@ private: bool m_traceStructs; // main switch: --trace-structs bool m_traceUnderscore;// main switch: --trace-underscore bool m_underlineZero;// main switch: --underline-zero; undocumented old Verilator 2 + bool m_verilate; // main swith: --verilate bool m_vpi; // main switch: --vpi bool m_xInitialEdge; // main switch: --x-initial-edge bool m_xmlOnly; // main switch: --xml-netlist + int m_buildJobs; // main switch: -j int m_convergeLimit;// main switch: --converge-limit int m_dumpTree; // main switch: --dump-tree int m_gateStmts; // main switch: --gate-stmts @@ -292,6 +296,7 @@ public: void addCppFile(const string& filename); void addCFlags(const string& filename); void addLdLibs(const string& filename); + void addMakeFlags(const string& filename); void addLibraryFile(const string& filename); void addClocker(const string& signame); void addNoClocker(const string& signame); @@ -316,6 +321,7 @@ public: bool autoflush() const { return m_autoflush; } bool bboxSys() const { return m_bboxSys; } bool bboxUnsup() const { return m_bboxUnsup; } + bool build() const { return m_build; } bool cdc() const { return m_cdc; } bool cmake() const { return m_cmake; } bool context() const { return m_context; } @@ -364,10 +370,12 @@ public: bool quietExit() const { return m_quietExit; } bool relativeCFuncs() const { return m_relativeCFuncs; } bool reportUnoptflat() const { return m_reportUnoptflat; } + bool verilate() const { return m_verilate; } bool vpi() const { return m_vpi; } bool xInitialEdge() const { return m_xInitialEdge; } bool xmlOnly() const { return m_xmlOnly; } + int buildJobs() const { return m_buildJobs; } int convergeLimit() const { return m_convergeLimit; } int dumpTree() const { return m_dumpTree; } int gateStmts() const { return m_gateStmts; } @@ -422,6 +430,7 @@ public: const V3StringSet& cppFiles() const { return m_cppFiles; } const V3StringList& cFlags() const { return m_cFlags; } const V3StringList& ldLibs() const { return m_ldLibs; } + const V3StringList& makeFlags() const { return m_makeFlags; } const V3StringSet& libraryFiles() const { return m_libraryFiles; } const V3StringList& vFiles() const { return m_vFiles; } const V3StringList& forceIncs() const { return m_forceIncs; } @@ -478,6 +487,7 @@ public: // see the README. If adding new variables, also see src/Makefile_obj.in // Also add to V3Options::showVersion() static string getenvBuiltins(const string& var); + static string getenvMAKE(); static string getenvPERL(); static string getenvSYSTEMC(); static string getenvSYSTEMC_ARCH(); diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 03f7dc142..86e5b266d 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -242,6 +242,8 @@ void V3Os::unlinkRegexp(const string& dir, const string& regexp) { } } +std::string V3Os::getcwd() { return filenameRealPath("."); } + //###################################################################### // METHODS (random) @@ -333,3 +335,21 @@ void V3Os::u_sleep(int64_t usec) { ::usleep(usec); #endif } + +//###################################################################### +// METHODS (sub command) + +int V3Os::system(const string& command) { + UINFO(1, "Running system: " << command << endl); + const int ret = ::system(command.c_str()); + if (ret == -1) { + v3fatal("Failed to execute command:" << command << " " << strerror(errno)); + return -1; + } else { + UASSERT(WIFEXITED(ret), "system(" << command << ") returned unexpected value of " << ret); + const int exit_code = WEXITSTATUS(ret); + UINFO(1, command << " returned exit code of " << exit_code << std::endl); + UASSERT(exit_code >= 0, "exit code must not be negative"); + return exit_code; + } +} diff --git a/src/V3Os.h b/src/V3Os.h index cfebdfc7e..8e511257d 100644 --- a/src/V3Os.h +++ b/src/V3Os.h @@ -53,6 +53,7 @@ public: // METHODS (directory utilities) static void createDir(const string& dirname); static void unlinkRegexp(const string& dir, const string& regexp); + static std::string getcwd(); // Return the current working directory // METHODS (random) static vluint64_t rand64(vluint64_t* statep); @@ -63,6 +64,10 @@ public: /// Return wall time since epoch in microseconds, or 0 if not implemented static uint64_t timeUsecs(); static uint64_t memUsageBytes(); ///< Return memory usage in bytes, or 0 if not implemented + + // METHODS (sub command) + /// Run system command, returns the exit code of the child process. + static int system(const string& command); }; #endif // Guard diff --git a/src/Verilator.cpp b/src/Verilator.cpp index d27137487..a5b2afa2b 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -492,32 +492,8 @@ static void process() { // Note early return above when opt.cdc() } -//###################################################################### - -int main(int argc, char** argv, char** env) { - // General initialization - std::ios::sync_with_stdio(); - - time_t randseed; - time(&randseed); - srand(static_cast(randseed)); - - // Post-constructor initialization of netlists - v3Global.boot(); - - // Preprocessor - // Before command parsing so we can handle -Ds on command line. - V3PreShell::boot(env); - - // Command option parsing - v3Global.opt.bin(argv[0]); - string argString = V3Options::argString(argc - 1, argv + 1); - v3Global.opt.parseOpts(new FileLine(FileLine::commandLineFilename()), argc - 1, argv + 1); - - // Validate settings (aka Boost.Program_options) - v3Global.opt.notify(); - - V3Error::abortIfErrors(); +static void verilate(const string& argString) { + UINFO(1, "Option --verilate: Start Verilation\n"); // Can we skip doing everything if times are ok? V3File::addSrcDepend(v3Global.opt.bin()); @@ -526,7 +502,7 @@ int main(int argc, char** argv, char** env) { + "__verFiles.dat", argString)) { UINFO(1, "--skip-identical: No change to any source files, exiting\n"); - exit(0); + return; } // Undocumented debugging - cannot be a switch as then command line // would mismatch forcing non-identicalness when we set it @@ -584,6 +560,86 @@ int main(int argc, char** argv, char** env) { v3Global.clear(); #endif FileLine::deleteAllRemaining(); +} + +static void execBuildJob() { + UASSERT(v3Global.opt.build(), "--build is not specified."); + UINFO(1, "Start Build\n"); + + std::stringstream cmd; + const V3StringList& makeFlags = v3Global.opt.makeFlags(); + const int jobs = v3Global.opt.buildJobs(); + UASSERT(jobs >= 0, "-j option parser in V3Options.cpp filters out negative value"); + if (v3Global.opt.gmake()) { // If both gmake and cmake are chosen, use gmake to build. + cmd << v3Global.opt.getenvMAKE(); + cmd << " -C " << v3Global.opt.makeDir(); + cmd << " -f " << v3Global.opt.prefix() << ".mk"; + if (jobs == 0) { + cmd << " -j"; + } else if (jobs > 1) { + cmd << " -j " << jobs; + } + for (V3StringList::const_iterator it = makeFlags.begin(); it != makeFlags.end(); ++it) { + cmd << ' ' << *it; + } + } else { + UASSERT(v3Global.opt.cmake(), "cmake or gmake must be chosen in V3Options.cpp"); + cmd << "cd " << v3Global.opt.makeDir() << " && "; + cmd << "cmake"; + for (V3StringList::const_iterator it = makeFlags.begin(); it != makeFlags.end(); ++it) { + cmd << ' ' << *it; + } + cmd << ' ' << V3Os::getcwd() << " && "; + cmd << "cmake --build . "; + if (jobs == 0) { + cmd << " -j"; + } else if (jobs > 1) { + cmd << " -j " << jobs; + } + } + const std::string cmdStr = cmd.str(); + + const int exit_code = V3Os::system(cmdStr); + if (exit_code != 0) { + v3error(cmdStr << " exitted with " << exit_code << std::endl); + exit(exit_code); + } +} + +//###################################################################### + +int main(int argc, char** argv, char** env) { + // General initialization + std::ios::sync_with_stdio(); + + time_t randseed; + time(&randseed); + srand(static_cast(randseed)); + + // Post-constructor initialization of netlists + v3Global.boot(); + + // Preprocessor + // Before command parsing so we can handle -Ds on command line. + V3PreShell::boot(env); + + // Command option parsing + v3Global.opt.bin(argv[0]); + string argString = V3Options::argString(argc - 1, argv + 1); + v3Global.opt.parseOpts(new FileLine(FileLine::commandLineFilename()), argc - 1, argv + 1); + + // Validate settings (aka Boost.Program_options) + v3Global.opt.notify(); + + V3Error::abortIfErrors(); + + if (v3Global.opt.verilate()) { + verilate(argString); + } else { + UINFO(1, "Option --no-verilate: Skip Verilation\n"); + } + + if (v3Global.opt.build()) execBuildJob(); UINFO(1, "Done, Exiting...\n"); } diff --git a/test_regress/t/t_flag_build_cmake.pl b/test_regress/t/t_flag_build_cmake.pl new file mode 100755 index 000000000..2f4c919d8 --- /dev/null +++ b/test_regress/t/t_flag_build_cmake.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + + +scenarios(simulator => 1); +top_filename("t/t_flag_make_cmake.v"); + +compile( # Don't call cmake nor gmake from driver.pl + verilator_make_cmake => 0, + verilator_make_gmake => 0, + verilator_flags2 => ['--exe --cc --build -j 2 --make cmake', + '../' . $Self->{main_filename}, + ' -MAKEFLAGS "-DTEST_NAME=' . $Self->{name} . '"', + ' -MAKEFLAGS "-DTEST_CSOURCES=' . $Self->{main_filename} . '"', + ' -MAKEFLAGS "-DTEST_OPT_FAST=-Os"', + ' -MAKEFLAGS "-DTEST_VERILATOR_ROOT=' . $ENV{VERILATOR_ROOT} . '"', + ' -MAKEFLAGS "-DTEST_VERILATOR_ARGS=\"--prefix ' . $Self->{VM_PREFIX} . ' --cc \""', + ' -MAKEFLAGS "-DTEST_VERILATOR_SOURCES=./t/t_flag_make_cmake.v"', + ' -MAKEFLAGS "-DTEST_SYSTEMC=0"', + ' -MAKEFLAGS "-DTEST_VERBOSE=0"', + ' -MAKEFLAGS "-DTEST_VERILATION=1"', + ' -MAKEFLAGS -DCMAKE_BUILD_TYPE=Debug', + ' -MAKEFLAGS -L'], + ); + +execute( + check_finished => 1, + ); + +# If '-MAKEFLAGS -DCMAKE_BUILD_TYPE=Debug' and '-MAKEFLAGS -L' are not properly processed, +# the log will not contain 'CMAKE_BUILD_TYPE:STRING=Debug'. +file_grep($Self->{obj_dir} . '/vlt_compile.log', /^CMAKE_BUILD_TYPE:STRING=(\w+)$/, 'Debug'); + +ok(1); +1; diff --git a/test_regress/t/t_flag_build_make.pl b/test_regress/t/t_flag_build_make.pl new file mode 100755 index 000000000..400e3c51e --- /dev/null +++ b/test_regress/t/t_flag_build_make.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + + +scenarios(simulator => 1); +top_filename("t/t_flag_make_cmake.v"); + +compile( # Don't call cmake nor gmake from driver.pl + verilator_make_cmake => 0, + verilator_make_gmake => 0, + verilator_flags2 => ['--exe --cc --build -j 2 --make gmake', + '../' . $Self->{main_filename}, + '-MAKEFLAGS --trace'], + ); + +execute( + check_finished => 1, + ); + +# If '-MAKEFLAGS --trace' is not properly processed, +# the log will not contain 'CMAKE_BUILD_TYPE:STRING=Debug'. +file_grep($Self->{obj_dir} . '/vlt_compile.log', /^Vt_flag_build_make.mk:\d+: update target \'(\w+)\' due to:/, 'Vt_flag_build_make'); + +ok(1); +1; diff --git a/test_regress/t/t_flag_verilate.pl b/test_regress/t/t_flag_verilate.pl new file mode 100755 index 000000000..c28d235b6 --- /dev/null +++ b/test_regress/t/t_flag_verilate.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + + +scenarios(simulator => 1); +top_filename("t/t_flag_make_cmake.v"); + +compile( # Don't call cmake nor gmake from driver.pl. Nothing should be done here. + verilator_make_cmake => 0, + verilator_make_gmake => 0, + verilator_flags2 => ['--exe --cc --no-verilate', + '../' . $Self->{main_filename}] + ); + +# --no-verilate should skip verilation +if ( -e $Self->{obj_dir} . '/Vt_flag_verilate.mk' ) { + $Self->error('Vt_flag_verilate.mk is unexpectedly created'); +} + +# --verilate this time +compile( # Don't call cmake nor gmake from driver.pl. Just verilate here. + verilator_make_cmake => 0, + verilator_make_gmake => 0, + verilator_flags2 => ['--exe --cc --make gmake --verilate', + '../' . $Self->{main_filename}] + ); + +# must be verilated this time +if ( ! -e $Self->{obj_dir} . '/Vt_flag_verilate.mk' ) { + $Self->error('Vt_flag_verilate.mk does not exist'); +} + +# Just build, no verilation. .tree must not be saved even with --dump-tree option. +compile( # Don't call cmake nor gmake from driver.pl. Just build here + verilator_make_cmake => 0, + verilator_make_gmake => 0, + verilator_flags2 => ['--exe --cc --build --make gmake --no-verilate', + '../' . $Self->{main_filename}, + '--debugi 1 --dump-tree'], + ); + +# The previous run must not verilated, only build is expected. +if ( -e $Self->{obj_dir} . '/Vt_flag_verilate_990_final.tree' ) { + $Self->error('Unexpectedly verilated.'); +} + +execute( + check_finished => 1, + ); + + +ok(1); +1; From 58091edd680c2088d00cc288b7aa33264306f073 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Apr 2020 18:08:31 -0400 Subject: [PATCH 057/127] Tests: Fix cmake -j unknown --- test_regress/t/t_flag_build_cmake.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/t/t_flag_build_cmake.pl b/test_regress/t/t_flag_build_cmake.pl index 2f4c919d8..a58be70f6 100755 --- a/test_regress/t/t_flag_build_cmake.pl +++ b/test_regress/t/t_flag_build_cmake.pl @@ -15,7 +15,7 @@ top_filename("t/t_flag_make_cmake.v"); compile( # Don't call cmake nor gmake from driver.pl verilator_make_cmake => 0, verilator_make_gmake => 0, - verilator_flags2 => ['--exe --cc --build -j 2 --make cmake', + verilator_flags2 => ['--exe --cc --build --make cmake', '../' . $Self->{main_filename}, ' -MAKEFLAGS "-DTEST_NAME=' . $Self->{name} . '"', ' -MAKEFLAGS "-DTEST_CSOURCES=' . $Self->{main_filename} . '"', From 9b8aebb00cd7243a8806994257e1ba290df46927 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Apr 2020 18:08:37 -0400 Subject: [PATCH 058/127] Commentary on --build --- Changes | 2 ++ bin/verilator | 11 ++++------- examples/cmake_hello_c/Makefile | 4 ++-- examples/cmake_hello_sc/Makefile | 4 ++-- examples/cmake_protect_lib/Makefile | 4 ++-- examples/cmake_tracing_c/Makefile | 4 ++-- examples/cmake_tracing_sc/Makefile | 4 ++-- examples/make_hello_c/Makefile | 6 ++---- examples/make_hello_sc/Makefile | 6 ++---- examples/make_tracing_c/Makefile | 12 +++++++----- examples/make_tracing_sc/Makefile | 10 ++++++---- 11 files changed, 33 insertions(+), 34 deletions(-) diff --git a/Changes b/Changes index 053cbda98..0d40e8d85 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Add simplistic class support with many restrictions, see manual, #377. +** Add --build to call make automatically, #2249. [Yutetsu TAKATSUKASA] + ** Configuring with ccache present now defaults to using it; see OBJCACHE. ** Fix DPI import/export to be standard compliant, #2236. [Geza Lore] diff --git a/bin/verilator b/bin/verilator index 2f554a77c..a361583f5 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1867,20 +1867,17 @@ compiled Verilator, you need to point to the kit: Now we run Verilator on our little example. - verilator -Wall --cc our.v --exe sim_main.cpp + verilator -Wall --cc our.v --exe --build sim_main.cpp We can see the source code under the "obj_dir" directory. See the FILES section below for descriptions of some of the files that were created. ls -l obj_dir -We then can compile it - - make -j -C obj_dir -f Vour.mk Vour - (Verilator included a default compile rule and link rule, since we used ---exe and passed a .cpp file on the Verilator command line. You can also -write your own compile rules, as we'll show in the SYSTEMC section.) +--exe and passed a .cpp file on the Verilator command line. Verilator also +then used C to build a final executable. You can also write your own +compile rules, and run make yourself as we'll show in the SYSTEMC section.) And now we run it diff --git a/examples/cmake_hello_c/Makefile b/examples/cmake_hello_c/Makefile index 2e3120f65..03740f816 100644 --- a/examples/cmake_hello_c/Makefile +++ b/examples/cmake_hello_c/Makefile @@ -51,11 +51,11 @@ run: @echo "-- Verilator CMake hello world example" @echo - @echo "-- CMake ----------------" + @echo "-- VERILATE ----------------" mkdir -p build && cd build && cmake .. @echo - @echo "-- COMPILE -----------------" + @echo "-- BUILD -------------------" cmake --build build @echo diff --git a/examples/cmake_hello_sc/Makefile b/examples/cmake_hello_sc/Makefile index b63fe2d4b..c9405ce09 100644 --- a/examples/cmake_hello_sc/Makefile +++ b/examples/cmake_hello_sc/Makefile @@ -87,11 +87,11 @@ run: @echo "-- Verilator CMake SystemC hello-world simple example" @echo - @echo "-- CMake ----------------" + @echo "-- VERILATE ----------------" mkdir -p build && cd build && cmake .. @echo - @echo "-- COMPILE -----------------" + @echo "-- BUILD -------------------" cmake --build build @echo diff --git a/examples/cmake_protect_lib/Makefile b/examples/cmake_protect_lib/Makefile index 2e08b2a9a..6f43eab02 100644 --- a/examples/cmake_protect_lib/Makefile +++ b/examples/cmake_protect_lib/Makefile @@ -51,11 +51,11 @@ run: @echo "-- Verilator CMake protect_lib example" @echo - @echo "-- CMake ----------------" + @echo "-- VERILATE ----------------" mkdir -p build && cd build && cmake .. @echo - @echo "-- COMPILE -----------------" + @echo "-- BUILD -------------------" cmake --build build @echo diff --git a/examples/cmake_tracing_c/Makefile b/examples/cmake_tracing_c/Makefile index fe61cc730..14a518002 100644 --- a/examples/cmake_tracing_c/Makefile +++ b/examples/cmake_tracing_c/Makefile @@ -51,11 +51,11 @@ run: @echo "-- Verilator CMake tracing example" @echo - @echo "-- CMake ----------------" + @echo "-- VERILATE ----------------" mkdir -p build && cd build && cmake .. @echo - @echo "-- COMPILE -----------------" + @echo "-- BUILD -------------------" cmake --build build @echo diff --git a/examples/cmake_tracing_sc/Makefile b/examples/cmake_tracing_sc/Makefile index 6332ed2d5..fe59d8a16 100644 --- a/examples/cmake_tracing_sc/Makefile +++ b/examples/cmake_tracing_sc/Makefile @@ -87,11 +87,11 @@ run: @echo "-- Verilator CMake SystemC tracing example" @echo - @echo "-- CMake ----------------" + @echo "-- VERILATE ----------------" mkdir -p build && cd build && cmake .. @echo - @echo "-- COMPILE -----------------" + @echo "-- BUILD -------------------" cmake --build build @echo diff --git a/examples/make_hello_c/Makefile b/examples/make_hello_c/Makefile index 940c0bf25..2130e9756 100644 --- a/examples/make_hello_c/Makefile +++ b/examples/make_hello_c/Makefile @@ -36,10 +36,8 @@ endif default: @echo "-- Verilator hello-world simple example" - @echo "-- VERILATE ----------------" - $(VERILATOR) -cc --exe top.v sim_main.cpp - @echo "-- COMPILE -----------------" - $(MAKE) -j 4 -C obj_dir -f Vtop.mk + @echo "-- VERILATE & BUILD --------" + $(VERILATOR) -cc --exe --build -j top.v sim_main.cpp @echo "-- RUN ---------------------" obj_dir/Vtop @echo "-- DONE --------------------" diff --git a/examples/make_hello_sc/Makefile b/examples/make_hello_sc/Makefile index dc074b90e..3a4340017 100644 --- a/examples/make_hello_sc/Makefile +++ b/examples/make_hello_sc/Makefile @@ -45,10 +45,8 @@ endif run: @echo "-- Verilator hello-world simple example" - @echo "-- VERILATE ----------------" - $(VERILATOR) -sc --exe top.v sc_main.cpp - @echo "-- COMPILE -----------------" - $(MAKE) -j 4 -C obj_dir -f Vtop.mk + @echo "-- VERILATE & COMPILE ------" + $(VERILATOR) -sc --exe --build -j top.v sc_main.cpp @echo "-- RUN ---------------------" obj_dir/Vtop @echo "-- DONE --------------------" diff --git a/examples/make_tracing_c/Makefile b/examples/make_tracing_c/Makefile index ba4b30bc3..bd043c697 100644 --- a/examples/make_tracing_c/Makefile +++ b/examples/make_tracing_c/Makefile @@ -68,11 +68,13 @@ run: $(VERILATOR) $(VERILATOR_FLAGS) $(VERILATOR_INPUT) @echo - @echo "-- COMPILE -----------------" -# To compile, we can either just do what Verilator asks, -# or call a submakefile where we can override the rules ourselves -# $(MAKE) -j 4 -C obj_dir -f Vtop.mk - $(MAKE) -j 4 -C obj_dir -f ../Makefile_obj + @echo "-- BUILD -------------------" +# To compile, we can either +# 1. Pass --build to Verilator by editing VERILATOR_FLAGS above. +# 2. Or, run the make rules Verilator does: +# $(MAKE) -j -C obj_dir -f Vtop.mk +# 3. Or, call a submakefile where we can override the rules ourselves: + $(MAKE) -j -C obj_dir -f ../Makefile_obj @echo @echo "-- RUN ---------------------" diff --git a/examples/make_tracing_sc/Makefile b/examples/make_tracing_sc/Makefile index 4b91f5ddc..149d4238c 100644 --- a/examples/make_tracing_sc/Makefile +++ b/examples/make_tracing_sc/Makefile @@ -77,10 +77,12 @@ run: @echo @echo "-- COMPILE -----------------" -# To compile, we can either just do what Verilator asks, -# or call a submakefile where we can override the rules ourselves -# $(MAKE) -j 4 -C obj_dir -f Vtop.mk - $(MAKE) -j 4 -C obj_dir -f ../Makefile_obj +# To compile, we can either +# 1. Pass --build to Verilator by editing VERILATOR_FLAGS above. +# 2. Or, run the make rules Verilator does: +# $(MAKE) -j -C obj_dir -f Vtop.mk +# 3. Or, call a submakefile where we can override the rules ourselves: + $(MAKE) -j -C obj_dir -f ../Makefile_obj @echo @echo "-- RUN ---------------------" From d4f7f5297a0efca79bfa8f2aed6bb6b6be0206a3 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Apr 2020 19:39:03 -0400 Subject: [PATCH 059/127] Support IEEE time units and time precisions, #234. (#2253) Includes `timescale, $printtimescale, $timeformat. VL_TIME_MULTIPLIER, VL_TIME_PRECISION, VL_TIME_UNIT have been removed and the time precision must now match the SystemC time precision. To get closer behavior to older versions, use e.g. --timescale-override "1ps/1ps". --- Changes | 7 + bin/verilator | 60 +- include/verilated.cpp | 179 +++- include/verilated.h | 66 +- include/verilated_fst_c.cpp | 2 + include/verilated_fst_c.h | 4 +- include/verilated_heavy.h | 2 + include/verilated_imp.h | 37 +- include/verilated_save.cpp | 6 +- include/verilated_vcd_c.cpp | 4 +- include/verilated_vcd_c.h | 4 +- include/verilated_vpi.cpp | 17 +- src/V3Assert.cpp | 2 +- src/V3Ast.h | 3 + src/V3AstNodes.cpp | 31 + src/V3AstNodes.h | 116 +- src/V3Begin.cpp | 4 +- src/V3Const.cpp | 4 + src/V3EmitC.cpp | 44 +- src/V3EmitCSyms.cpp | 33 +- src/V3Error.h | 6 +- src/V3Inline.cpp | 3 +- src/V3LinkLevel.cpp | 41 + src/V3LinkLevel.h | 3 + src/V3LinkParse.cpp | 22 + src/V3Options.cpp | 110 ++ src/V3Options.h | 89 ++ src/V3ParseImp.cpp | 72 ++ src/V3ParseImp.h | 8 + src/V3ProtectLib.cpp | 8 + src/V3String.cpp | 9 + src/V3String.h | 2 + src/V3Width.cpp | 53 +- src/Verilator.cpp | 1 + src/verilog.l | 14 +- src/verilog.y | 57 +- test_regress/driver.pl | 42 +- test_regress/t/t_clocker.out | 2 +- test_regress/t/t_cover_line_trace.out | 2 +- test_regress/t/t_cover_sva_trace.out | 2 +- test_regress/t/t_display_time.out | 2 +- test_regress/t/t_display_time.pl | 2 - test_regress/t/t_display_wide.out | 4 +- test_regress/t/t_display_wide.pl | 1 - test_regress/t/t_flag_timescale.out | 2 + test_regress/t/t_flag_timescale.pl | 24 + test_regress/t/t_flag_timescale.v | 13 + test_regress/t/t_flag_timescale_override.out | 2 + test_regress/t/t_flag_timescale_override.pl | 24 + test_regress/t/t_flag_timescale_override.v | 15 + test_regress/t/t_flag_timescale_override2.out | 2 + test_regress/t/t_flag_timescale_override2.pl | 26 + test_regress/t/t_inst_sv.v | 5 - test_regress/t/t_interface_ref_trace.out | 2 +- test_regress/t/t_math_real_public.v | 3 - test_regress/t/t_order_clkinst.out | 2 +- test_regress/t/t_split_var_2_trace.out | 2 +- test_regress/t/t_time_literals.pl | 21 + test_regress/t/t_time_literals.v | 32 + test_regress/t/t_time_passed.out | 3 + test_regress/t/t_time_passed.pl | 23 + test_regress/t/t_time_passed.v | 64 ++ test_regress/t/t_time_print.out | 10 + test_regress/t/t_time_print.pl | 23 + test_regress/t/t_time_print.v | 37 + test_regress/t/t_time_sc.v | 31 + test_regress/t/t_time_sc_bad.out | 2 + test_regress/t/t_time_sc_bad.pl | 29 + test_regress/t/t_time_sc_fs.out | 3 + test_regress/t/t_time_sc_fs.pl | 29 + test_regress/t/t_time_sc_ms.out | 6 + test_regress/t/t_time_sc_ms.pl | 29 + test_regress/t/t_time_sc_ns.out | 3 + test_regress/t/t_time_sc_ns.pl | 29 + test_regress/t/t_time_sc_sec.out | 6 + test_regress/t/t_time_sc_sec.pl | 29 + test_regress/t/t_time_sc_us.out | 6 + test_regress/t/t_time_sc_us.pl | 29 + test_regress/t/t_time_stamp64.pl | 26 + test_regress/t/t_time_stamp64.v | 25 + test_regress/t/t_time_stamp_double.pl | 28 + test_regress/t/t_time_vpi.v | 50 + test_regress/t/t_time_vpi_10ms10ns.out | 15 + test_regress/t/t_time_vpi_10ms10ns.pl | 30 + test_regress/t/t_time_vpi_1fs1fs.out | 15 + test_regress/t/t_time_vpi_1fs1fs.pl | 30 + test_regress/t/t_time_vpi_1ms10ns.out | 15 + test_regress/t/t_time_vpi_1ms10ns.pl | 32 + test_regress/t/t_time_vpi_1ns1ns.out | 15 + test_regress/t/t_time_vpi_1ns1ns.pl | 32 + test_regress/t/t_time_vpi_1ps1fs.out | 15 + test_regress/t/t_time_vpi_1ps1fs.pl | 30 + test_regress/t/t_time_vpi_1s10ns.out | 15 + test_regress/t/t_time_vpi_1s10ns.pl | 30 + test_regress/t/t_time_vpi_1us1ns.out | 15 + test_regress/t/t_time_vpi_1us1ns.pl | 30 + test_regress/t/t_time_vpi_c.cpp | 62 ++ test_regress/t/t_timescale_default.out | 2 + test_regress/t/t_timescale_default.pl | 23 + test_regress/t/t_timescale_default.v | 15 + test_regress/t/t_timescale_lint_bad.out | 5 + test_regress/t/t_timescale_lint_bad.pl | 20 + test_regress/t/t_timescale_lint_bad.v | 18 + test_regress/t/t_timescale_parse.cpp | 22 + test_regress/t/t_timescale_parse.pl | 24 + test_regress/t/t_timescale_parse.v | 103 ++ test_regress/t/t_timescale_parse_bad.out | 25 + test_regress/t/t_timescale_parse_bad.pl | 19 + test_regress/t/t_timescale_parse_bad.v | 20 + test_regress/t/t_trace_cat.out | 2 +- test_regress/t/t_trace_cat_renew.out | 2 +- test_regress/t/t_trace_cat_renew_0000.out | 2 +- test_regress/t/t_trace_cat_renew_0100.out | 2 +- test_regress/t/t_trace_cat_reopen.out | 2 +- test_regress/t/t_trace_cat_reopen_0000.out | 2 +- test_regress/t/t_trace_cat_reopen_0100.out | 2 +- test_regress/t/t_trace_complex.out | 2 +- test_regress/t/t_trace_complex_params.out | 2 +- test_regress/t/t_trace_complex_structs.out | 2 +- test_regress/t/t_trace_ena_cc.out | 2 +- test_regress/t/t_trace_ena_sc.out | 262 ++--- test_regress/t/t_trace_public.out | 2 +- test_regress/t/t_trace_timescale.cpp | 45 - test_regress/t/t_trace_timescale.out | 988 +----------------- test_regress/t/t_trace_timescale.pl | 5 +- test_regress/t/t_trace_timescale.v | 15 +- test_regress/t/t_trace_two_dump_cc.out | 2 +- test_regress/t/t_trace_two_hdr_cc.out | 2 +- test_regress/t/t_trace_two_port_cc.out | 2 +- test_regress/t/t_var_escape.out | 2 +- test_regress/t/t_var_nonamebegin.out | 2 +- 131 files changed, 2611 insertions(+), 1290 deletions(-) create mode 100644 test_regress/t/t_flag_timescale.out create mode 100755 test_regress/t/t_flag_timescale.pl create mode 100644 test_regress/t/t_flag_timescale.v create mode 100644 test_regress/t/t_flag_timescale_override.out create mode 100755 test_regress/t/t_flag_timescale_override.pl create mode 100644 test_regress/t/t_flag_timescale_override.v create mode 100644 test_regress/t/t_flag_timescale_override2.out create mode 100755 test_regress/t/t_flag_timescale_override2.pl create mode 100755 test_regress/t/t_time_literals.pl create mode 100644 test_regress/t/t_time_literals.v create mode 100644 test_regress/t/t_time_passed.out create mode 100755 test_regress/t/t_time_passed.pl create mode 100644 test_regress/t/t_time_passed.v create mode 100644 test_regress/t/t_time_print.out create mode 100755 test_regress/t/t_time_print.pl create mode 100644 test_regress/t/t_time_print.v create mode 100644 test_regress/t/t_time_sc.v create mode 100644 test_regress/t/t_time_sc_bad.out create mode 100755 test_regress/t/t_time_sc_bad.pl create mode 100644 test_regress/t/t_time_sc_fs.out create mode 100755 test_regress/t/t_time_sc_fs.pl create mode 100644 test_regress/t/t_time_sc_ms.out create mode 100755 test_regress/t/t_time_sc_ms.pl create mode 100644 test_regress/t/t_time_sc_ns.out create mode 100755 test_regress/t/t_time_sc_ns.pl create mode 100644 test_regress/t/t_time_sc_sec.out create mode 100755 test_regress/t/t_time_sc_sec.pl create mode 100644 test_regress/t/t_time_sc_us.out create mode 100755 test_regress/t/t_time_sc_us.pl create mode 100755 test_regress/t/t_time_stamp64.pl create mode 100644 test_regress/t/t_time_stamp64.v create mode 100755 test_regress/t/t_time_stamp_double.pl create mode 100644 test_regress/t/t_time_vpi.v create mode 100644 test_regress/t/t_time_vpi_10ms10ns.out create mode 100755 test_regress/t/t_time_vpi_10ms10ns.pl create mode 100644 test_regress/t/t_time_vpi_1fs1fs.out create mode 100755 test_regress/t/t_time_vpi_1fs1fs.pl create mode 100644 test_regress/t/t_time_vpi_1ms10ns.out create mode 100755 test_regress/t/t_time_vpi_1ms10ns.pl create mode 100644 test_regress/t/t_time_vpi_1ns1ns.out create mode 100755 test_regress/t/t_time_vpi_1ns1ns.pl create mode 100644 test_regress/t/t_time_vpi_1ps1fs.out create mode 100755 test_regress/t/t_time_vpi_1ps1fs.pl create mode 100644 test_regress/t/t_time_vpi_1s10ns.out create mode 100755 test_regress/t/t_time_vpi_1s10ns.pl create mode 100644 test_regress/t/t_time_vpi_1us1ns.out create mode 100755 test_regress/t/t_time_vpi_1us1ns.pl create mode 100644 test_regress/t/t_time_vpi_c.cpp create mode 100644 test_regress/t/t_timescale_default.out create mode 100755 test_regress/t/t_timescale_default.pl create mode 100644 test_regress/t/t_timescale_default.v create mode 100644 test_regress/t/t_timescale_lint_bad.out create mode 100755 test_regress/t/t_timescale_lint_bad.pl create mode 100644 test_regress/t/t_timescale_lint_bad.v create mode 100644 test_regress/t/t_timescale_parse.cpp create mode 100755 test_regress/t/t_timescale_parse.pl create mode 100644 test_regress/t/t_timescale_parse.v create mode 100644 test_regress/t/t_timescale_parse_bad.out create mode 100755 test_regress/t/t_timescale_parse_bad.pl create mode 100644 test_regress/t/t_timescale_parse_bad.v delete mode 100644 test_regress/t/t_trace_timescale.cpp diff --git a/Changes b/Changes index 0d40e8d85..27a11f24c 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,13 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Add simplistic class support with many restrictions, see manual, #377. +** Support IEEE time units and time precisions, #234. + Includes `timescale, $printtimescale, $timeformat. + VL_TIME_MULTIPLIER, VL_TIME_PRECISION, VL_TIME_UNIT have been removed + and the time precision must now match the SystemC time precision. To + get closer behavior to older versions, use e.g. --timescale-override + "1ps/1ps". + ** Add --build to call make automatically, #2249. [Yutetsu TAKATSUKASA] ** Configuring with ccache present now defaults to using it; see OBJCACHE. diff --git a/bin/verilator b/bin/verilator index a361583f5..fed1cb08d 100755 --- a/bin/verilator +++ b/bin/verilator @@ -372,6 +372,8 @@ detailed descriptions in L for more information. --threads Enable multithreading --threads-dpi Enable multithreaded DPI --threads-max-mtasks Tune maximum mtask partitioning + --timescale Sets default timescale + --timescale-override Overrides all timescales --top-module Name of top level input module --trace Enable waveform creation --trace-depth Depth of tracing @@ -1266,6 +1268,10 @@ This allows for the secure delivery of sensitive IP without the need for encrypted RTL (i.e. IEEE P1735). See examples/make_protect_lib in the distribution for a demonstration of how to build and use the DPI library. +When using --protect-lib it is advised to also use C<--timescale-override +/1fs> to ensure the model has a time resolution that is always compatible +with the time precision of the upper instantiating module. + =item --private Opposite of --public. Is the default; this option exists for backwards @@ -1424,6 +1430,24 @@ Rarely needed. When using --threads, specify the number of mtasks the model is to be partitioned into. If unspecified, Verilator approximates a good value. +=item --timescale I/I + +Sets default timescale, timeunit and timeprecision for when `timescale does +not occur in sources. Default is "1ps/1ps" (to match SystemC). This is +overriden by C<--timescale-override>. + +=item --timescale-override I/I + +=item --timescale-override /I + +Overrides all `timescales in sources. The timeunit may be left empty to +specify only to override the timeprecision, e.g. "/1fs". + +The time precision must be consistent with SystemC's +sc_set_time_resolution, or the C++ code instantiating the Verilated module. +As 1fs is the finest time precision it may be desirable to always use a +precision of 1fs. + =item --top-module I When the input Verilog contains more than one top level module, specifies @@ -1786,10 +1810,10 @@ Defaults to "profile_threads.dat". =item +verilator+prof+threads+start+I When using --prof-threads at simulation runtime, Verilator will wait until -$time is at this value, then start the profiling warmup, then -capturing. Generally this should be set to some time that is well within -the normal operation of the simulation, i.e. outside of reset. If 0, the -dump is disabled. Defaults to 1. +$time is at this value (expressed in units of the time precision), then +start the profiling warmup, then capturing. Generally this should be set to +some time that is well within the normal operation of the simulation, +i.e. outside of reset. If 0, the dump is disabled. Defaults to 1. =item +verilator+prof+threads+window+I @@ -2249,7 +2273,8 @@ example: vluint64_t main_time = 0; // Current simulation time // This is a 64-bit integer to reduce wrap over issues and - // allow modulus. You can also use a double, if you wish. + // allow modulus. This is in units of the timeprecision + // used in Verilog (or from --timescale-override) double sc_time_stamp () { // Called by $time in Verilog return main_time; // converts to double, to match @@ -3788,7 +3813,7 @@ This section describes specific limitations for each language keyword. `begin_keywords, `begin_keywords, `define, `else, `elsif, `end_keywords, `endif, `error, `ifdef, `ifndef, `include, `line, `systemc_ctor, `systemc_dtor, `systemc_header, `systemc_imp_header, -`systemc_implementation, `systemc_interface, `timescale, `undef, `verilog +`systemc_implementation, `systemc_interface, `undef, `verilog Fully supported. @@ -3940,13 +3965,6 @@ Supported, but the instantiating C++/SystemC testbench must call to register the command line before calling $test$plusargs or $value$plusargs. -=item $timeformat - -Not supported as Verilator needs to determine all formatting at compile -time. Generally you can just ifdef them out for no ill effect. Note also -VL_TIME_MULTIPLIER can be defined at compile time to move the decimal point -when displaying all times, model wide. - =back @@ -4619,6 +4637,18 @@ increases. Ignoring this warning will only slow simulations, it will simulate correctly. +=item TIMESCALEMOD + +Error that `timescale is used in some but not all modules. +Recommend using --timescale argument, or in front of all modules use: + + `include "timescale.vh" + +Then in that file set the timescale. + +This is an error due to IEEE specifications, but it may be disabled similar +to warnings. Ignoring this error may result in a module having an +unexpected timescale. =item UNDRIVEN @@ -5008,8 +5038,8 @@ to VerilatedVcdSc in the examples/make_tracing_sc/sc_main.cpp file of the distribution, and below. Alternatively you may use the C++ trace mechanism described in the previous -question, however the timescale and timeprecision will not inherited from -your SystemC settings. +question, note the timescale and timeprecision will be inherited from your +SystemC settings. You also need to compile verilated_vcd_sc.cpp and verilated_vcd_c.cpp and add them to your link, preferably by adding the dependencies in diff --git a/include/verilated.cpp b/include/verilated.cpp index 8dd0b39b3..43fa648c9 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include // mkdir // clang-format off @@ -101,8 +102,12 @@ void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { 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( // Not VL_PRINTF_MT, already on main thread - "%%Error: %s:%d: %s\n", filename, linenum, msg); + if (filename && filename[0]) { + // Not VL_PRINTF_MT, already on main thread + VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg); + } else { + VL_PRINTF("%%Error: %s\n", msg); + } Verilated::flushCall(); VL_PRINTF("Aborting...\n"); // Not VL_PRINTF_MT, already on main thread @@ -238,6 +243,8 @@ Verilated::Serialized::Serialized() { s_errorLimit = 1; s_randReset = 0; s_randSeed = 0; + s_timeunit = -VL_TIME_UNIT; // Initial value until overriden by _Vconfigure + s_timeprecision = -VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure } Verilated::NonSerialized::NonSerialized() { @@ -252,6 +259,9 @@ Verilated::NonSerialized::~NonSerialized() { } } +size_t Verilated::serialized2Size() VL_PURE { return sizeof(VerilatedImp::m_ser); } +void* Verilated::serialized2Ptr() VL_MT_UNSAFE { return &VerilatedImp::s_s.m_ser; } + //=========================================================================== // Random -- Mostly called at init time, so not inline. @@ -608,6 +618,31 @@ std::string VL_DECIMAL_NW(int width, WDataInP lwp) VL_MT_SAFE { return output; } +std::string _vl_vsformat_time(char* tmp, double ld, bool left, size_t width) { + // Double may lose precision, but sc_time_stamp has similar limit + std::string suffix = VerilatedImp::timeFormatSuffix(); + int userUnits = VerilatedImp::timeFormatUnits(); // 0..-15 + int fracDigits = VerilatedImp::timeFormatPrecision(); // 0..N + int prec = Verilated::timeprecision(); // 0..-15 + int shift = prec - userUnits + fracDigits; // 0..-15 + double shiftd = vl_time_multiplier(shift); + double scaled = ld * shiftd; + QData fracDiv = static_cast(vl_time_multiplier(fracDigits)); + QData whole = static_cast(scaled) / fracDiv; + QData fraction = static_cast(scaled) % fracDiv; + int digits; + if (!fracDigits) { + digits = sprintf(tmp, "%" VL_PRI64 "u%s", whole, suffix.c_str()); + } else { + digits = sprintf(tmp, "%" VL_PRI64 "u.%0*" VL_PRI64 "u%s", whole, fracDigits, fraction, + suffix.c_str()); + } + int needmore = width - digits; + std::string padding; + if (needmore > 0) padding.append(needmore, ' '); // Pad with spaces + return left ? (tmp + padding) : (padding + tmp); +} + // Do a va_arg returning a quad, assuming input argument is anything less than wide #define _VL_VA_ARG_Q(ap, bits) (((bits) <= VL_IDATASIZE) ? va_arg(ap, IData) : va_arg(ap, QData)) @@ -688,10 +723,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA if (lbits) {} // UNUSED - always 64 switch (fmt) { case '^': { // Realtime - int digits = sprintf(tmp, "%g", d / VL_TIME_MULTIPLIER); - int needmore = width - digits; - if (needmore > 0) output.append(needmore, ' '); // Pre-pad spaces - output += tmp; + if (!widthSet) width = VerilatedImp::timeFormatWidth(); + output += _vl_vsformat_time(tmp, d, left, width); break; } default: { @@ -792,20 +825,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA break; } case 't': { // Time - int digits; - if (VL_TIME_MULTIPLIER == 1) { - digits = sprintf(tmp, "%" VL_PRI64 "u", ld); - } else if (VL_TIME_MULTIPLIER == 1000) { - digits = sprintf(tmp, "%" VL_PRI64 "u.%03" VL_PRI64 "u", - static_cast(ld / VL_TIME_MULTIPLIER), - static_cast(ld % VL_TIME_MULTIPLIER)); - } else { - VL_FATAL_MT(__FILE__, __LINE__, "", "Unsupported VL_TIME_MULTIPLIER"); - } - int needmore = width - digits; - std::string padding; - if (needmore > 0) padding.append(needmore, ' '); // Pad with spaces - output += left ? (tmp + padding) : (padding + tmp); + if (!widthSet) width = VerilatedImp::timeFormatWidth(); + output += _vl_vsformat_time(tmp, static_cast(ld), left, width); break; } case 'b': @@ -1984,6 +2005,69 @@ int VL_TIME_STR_CONVERT(const char* strp) { if (*strp) return 0; return scale; } +static const char* vl_time_str(int scale) { + static const char* const names[] + = {"1s", "100ms", "10ms", "1ms", "100us", "10us", "1us", "100ns", + "10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"}; + if (scale < 0) scale = -scale; + if (VL_UNLIKELY(scale > 15)) scale = 0; + return names[scale]; +} +double vl_time_multiplier(int scale) { + // Return timescale multipler -15 to +15 + // For speed, this does not check for illegal values + static double pow10[] = {1.0, + 10.0, + 100.0, + 1000.0, + 10000.0, + 100000.0, + 1000000.0, + 10000000.0, + 100000000.0, + 1000000000.0, + 10000000000.0, + 100000000000.0, + 1000000000000.0, + 10000000000000.0, + 100000000000000.0, + 1000000000000000.0}; + static double neg10[] = {1.0, + 0.1, + 0.01, + 0.001, + 0.0001, + 0.00001, + 0.000001, + 0.0000001, + 0.00000001, + 0.000000001, + 0.0000000001, + 0.00000000001, + 0.000000000001, + 0.0000000000001, + 0.00000000000001, + 0.000000000000001}; + if (scale < 0) { + return neg10[-scale]; + } else { + return pow10[scale]; + } +} +const char* Verilated::timeunitString() VL_MT_SAFE { return vl_time_str(timeunit()); } +const char* Verilated::timeprecisionString() VL_MT_SAFE { return vl_time_str(timeprecision()); } + +void VL_PRINTTIMESCALE(const char* namep, const char* timeunitp) VL_MT_SAFE { + VL_PRINTF_MT("Time scale of %s is %s / %s\n", namep, timeunitp, + Verilated::timeprecisionString()); +} +void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix, + int width) VL_MT_SAFE { + VerilatedImp::timeFormatUnits(units); + VerilatedImp::timeFormatPrecision(precision); + VerilatedImp::timeFormatSuffix(suffix); + VerilatedImp::timeFormatWidth(width); +} //=========================================================================== // Verilated:: Methods @@ -2051,6 +2135,43 @@ void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE { VerilatedLockGuard lock(m_mutex); s_s.s_fatalOnVpiError = flag; } +void Verilated::timeunit(int value) VL_MT_SAFE { + if (value < 0) value = -value; // Stored as 0..15 + VerilatedLockGuard lock(m_mutex); + s_s.s_timeunit = value; +} +void Verilated::timeprecision(int value) VL_MT_SAFE { + if (value < 0) value = -value; // Stored as 0..15 + VerilatedLockGuard lock(m_mutex); + s_s.s_timeprecision = value; +#ifdef SYSTEMC_VERSION + sc_time sc_res = sc_get_time_resolution(); + int sc_prec = 99; + if (sc_res == sc_time(1, SC_SEC)) { + sc_prec = 0; + } else if (sc_res == sc_time(1, SC_MS)) { + sc_prec = 3; + } else if (sc_res == sc_time(1, SC_US)) { + sc_prec = 6; + } else if (sc_res == sc_time(1, SC_NS)) { + sc_prec = 9; + } else if (sc_res == sc_time(1, SC_PS)) { + sc_prec = 12; + } else if (sc_res == sc_time(1, SC_FS)) { + sc_prec = 15; + } + if (value != sc_prec) { + std::ostringstream msg; + msg << "SystemC's sc_set_time_resolution is 10^-" << sc_prec + << ", which does not match Verilog timeprecision 10^-" << value + << ". Suggest use 'sc_set_time_resolution(" << vl_time_str(value) + << ")', or Verilator '--timescale-override " << vl_time_str(sc_prec) << "/" + << vl_time_str(sc_prec) << "'"; + std::string msgs = msg.str(); + VL_FATAL_MT("", 0, "", msgs.c_str()); + } +#endif +} void Verilated::profThreadsStart(vluint64_t flag) VL_MT_SAFE { VerilatedLockGuard lock(m_mutex); s_ns.s_profThreadsStart = flag; @@ -2180,6 +2301,20 @@ void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE { //=========================================================================== // VerilatedImp:: Methods +std::string VerilatedImp::timeFormatSuffix() VL_MT_SAFE { + VerilatedLockGuard lock(s_s.m_sergMutex); + return s_s.m_serg.m_timeFormatSuffix; +} +void VerilatedImp::timeFormatSuffix(const std::string& value) VL_MT_SAFE { + VerilatedLockGuard lock(s_s.m_sergMutex); + s_s.m_serg.m_timeFormatSuffix = value; +} +void VerilatedImp::timeFormatUnits(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatUnits = value; } +void VerilatedImp::timeFormatPrecision(int value) VL_MT_SAFE { + s_s.m_ser.m_timeFormatPrecision = value; +} +void VerilatedImp::timeFormatWidth(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatWidth = value; } + void VerilatedImp::internalsDump() VL_MT_SAFE { VerilatedLockGuard lock(s_s.m_argMutex); VL_PRINTF_MT("internalsDump:\n"); @@ -2349,11 +2484,13 @@ VerilatedScope::~VerilatedScope() { } void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp, - const char* identifier, const Type type) VL_MT_UNSAFE { + const char* identifier, vlsint8_t timeunit, + const Type type) 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; m_type = type; + m_timeunit = timeunit; char* namep = new char[strlen(prefixp) + strlen(suffixp) + 2]; strcpy(namep, prefixp); if (*prefixp && *suffixp) strcat(namep, "."); diff --git a/include/verilated.h b/include/verilated.h index 217911eb0..c49226ce4 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -329,19 +329,21 @@ private: VerilatedVarNameMap* m_varsp; ///< Variable map const char* m_namep; ///< Scope name (Slowpath) const char* m_identifierp; ///< Identifier of scope (with escapes removed) + vlsint8_t m_timeunit; ///< Timeunit in negative power-of-10 Type m_type; ///< Type of the scope public: // But internals only - called from VerilatedModule's VerilatedScope(); ~VerilatedScope(); void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp, - const char* identifier, const Type type) VL_MT_UNSAFE; + const char* identifier, vlsint8_t timeunit, const Type type) VL_MT_UNSAFE; void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE; void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE; // ACCESSORS const char* name() const { return m_namep; } const char* identifier() const { return m_identifierp; } + vlsint8_t timeunit() const { return m_timeunit; } inline VerilatedSyms* symsp() const { return m_symsp; } VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT; VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; } @@ -383,6 +385,8 @@ class Verilated { bool s_assertOn; ///< Assertions are enabled bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported // Slow path + unsigned s_timeunit : 4; ///< Time unit as 0..15 + unsigned s_timeprecision : 4; ///< Time precision as 0..15 int s_errorCount; ///< Number of errors int s_errorLimit; ///< Stop on error number int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random @@ -481,6 +485,13 @@ public: /// Enable/disable vpi fatal static void fatalOnVpiError(bool flag) VL_MT_SAFE; static bool fatalOnVpiError() VL_MT_SAFE { return s_s.s_fatalOnVpiError; } + /// Time handling + static int timeunit() VL_MT_SAFE { return -s_s.s_timeunit; } + static const char* timeunitString() VL_MT_SAFE; + static void timeunit(int value) VL_MT_SAFE; + static int timeprecision() VL_MT_SAFE { return -s_s.s_timeprecision; } + static const char* timeprecisionString() VL_MT_SAFE; + static void timeprecision(int value) VL_MT_SAFE; /// --prof-threads related settings static void profThreadsStart(vluint64_t flag) VL_MT_SAFE; static vluint64_t profThreadsStart() VL_MT_SAFE { return s_ns.s_profThreadsStart; } @@ -555,8 +566,10 @@ public: static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; } static int exportFuncNum(const char* namep) VL_MT_SAFE; - static size_t serializedSize() VL_PURE { return sizeof(s_s); } - static void* serializedPtr() VL_MT_UNSAFE { return &s_s; } // Unsafe, for Serialize only + static size_t serialized1Size() VL_PURE { return sizeof(s_s); } + static void* serialized1Ptr() VL_MT_UNSAFE { return &s_s; } // Unsafe, for Serialize only + static size_t serialized2Size() VL_PURE; + static void* serialized2Ptr() VL_MT_UNSAFE; #ifdef VL_THREADED /// Set the mtaskId, called when an mtask starts static void mtaskId(vluint32_t id) VL_MT_SAFE { t_s.t_mtaskId = id; } @@ -650,6 +663,8 @@ inline QData VL_RDTSC_Q() { } #endif +extern void VL_PRINTTIMESCALE(const char* namep, const char* timeunitp) VL_MT_SAFE; + /// Math extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus); @@ -787,37 +802,54 @@ extern void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp); extern int VL_TIME_STR_CONVERT(const char* strp) VL_PURE; +// These are deprecated and used only to establish the default precision/units. +// Use Verilator timescale-override for better control. // clang-format off #ifndef VL_TIME_PRECISION # ifdef VL_TIME_PRECISION_STR # define VL_TIME_PRECISION VL_TIME_STR_CONVERT(VL_STRINGIFY(VL_TIME_PRECISION_STR)) # else -# define VL_TIME_PRECISION (-12) ///< Timescale units only for for VPI return - picoseconds +# define VL_TIME_PRECISION (-12) ///< Timescale default units if not in Verilog - picoseconds # endif #endif #ifndef VL_TIME_UNIT # ifdef VL_TIME_UNIT_STR # define VL_TIME_UNIT VL_TIME_STR_CONVERT(VL_STRINGIFY(VL_TIME_PRECISION_STR)) # else -# define VL_TIME_UNIT (-12) ///< Timescale units only for for VPI return - picoseconds +# define VL_TIME_UNIT (-12) ///< Timescale default units if not in Verilog - picoseconds # endif #endif -#ifndef VL_TIME_MULTIPLIER -# define VL_TIME_MULTIPLIER 1 -#endif /// Return current simulation time -#if defined(SYSTEMC_VERSION) && (SYSTEMC_VERSION>20011000) -# define VL_TIME_I() (static_cast(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER)) -# define VL_TIME_Q() (static_cast(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER)) -# define VL_TIME_D() (static_cast(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER)) -#else -# define VL_TIME_I() (static_cast(sc_time_stamp()*VL_TIME_MULTIPLIER)) -# define VL_TIME_Q() (static_cast(sc_time_stamp()*VL_TIME_MULTIPLIER)) -# define VL_TIME_D() (static_cast(sc_time_stamp()*VL_TIME_MULTIPLIER)) -extern double sc_time_stamp(); +#if defined(SYSTEMC_VERSION) +# if SYSTEMC_VERSION > 20011000 +// Already defined: extern sc_time sc_time_stamp(); +inline vluint64_t vl_time_stamp64() { return sc_time_stamp().value(); } +# else // Before SystemC changed to integral time representation +// Already defined: extern double sc_time_stamp(); +inline vluint64_t vl_time_stamp64() { return static_cast(sc_time_stamp()); } +# endif +#else // Non-SystemC +# ifdef VL_TIME_STAMP64 +extern vluint64_t vl_time_stamp64(); +# else +extern double sc_time_stamp(); // Verilator 4.032 and newer +inline vluint64_t vl_time_stamp64() { return static_cast(sc_time_stamp()); } +# endif #endif +#define VL_TIME_I() (static_cast(vl_time_stamp64())) +#define VL_TIME_Q() (static_cast(vl_time_stamp64())) +#define VL_TIME_D() (static_cast(vl_time_stamp64())) + +/// Time scaled from 1-per-precision into a module's time units ("Unit"-ed, not "United") +// Optimized assuming scale is always constant. +// Can't use multiply in Q flavor, as might lose precision +#define VL_TIME_UNITED_Q(scale) (VL_TIME_Q() / static_cast(scale)) +#define VL_TIME_UNITED_D(scale) (VL_TIME_D() * (1.0 / (scale))) +/// Time imported from units to time precision +double vl_time_multiplier(int scale); + /// Evaluate expression if debug enabled #ifdef VL_DEBUG # define VL_DEBUG_IF(text) {if (VL_UNLIKELY(Verilated::debug())) {text}} diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 5654cf9e8..afbf007ea 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -86,6 +86,8 @@ VerilatedFst::VerilatedFst(void* fst) , m_symbolp(NULL) , m_sigs_oldvalp(NULL) { m_valueStrBuffer.reserve(64 + 1); // Need enough room for quad + set_time_unit(Verilated::timeunitString()); + set_time_resolution(Verilated::timeprecisionString()); } VerilatedFst::~VerilatedFst() { diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 341514adc..ed41eb031 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -235,11 +235,11 @@ public: void dump(vluint32_t timestamp) { dump(static_cast(timestamp)); } void dump(int timestamp) { dump(static_cast(timestamp)); } /// Set time units (s/ms, defaults to ns) - /// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h + /// For Verilated models, these propage from the Verilated default --timeunit void set_time_unit(const char* unitp) { m_sptrace.set_time_unit(unitp); } void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); } /// Set time resolution (s/ms, defaults to ns) - /// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h + /// For Verilated models, these propage from the Verilated default --timeunit void set_time_resolution(const char* unitp) { m_sptrace.set_time_resolution(unitp); } void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); } diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 2a92390aa..ee71d867d 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -438,6 +438,8 @@ 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, ...) VL_MT_SAFE; extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE; +extern void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix, + int width) VL_MT_SAFE; extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE; inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, CData& rdr) VL_MT_SAFE { WData rwp[2]; // WData must always be at least 2 diff --git a/include/verilated_imp.h b/include/verilated_imp.h index 7d8f23a4e..d8cb73785 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -173,6 +173,8 @@ public: class VerilatedImp { // Whole class is internal use only - Global information shared between verilated*.cpp files. +protected: + friend class Verilated; // TYPES typedef std::vector ArgVec; @@ -182,7 +184,24 @@ class VerilatedImp { // MEMBERS static VerilatedImp s_s; ///< Static Singleton; One and only static this - // Nothing here is save-restored; users expected to re-register appropriately + struct Serialized { // All these members serialized/deserialized + int m_timeFormatUnits; // $timeformat units + int m_timeFormatPrecision; // $timeformat number of decimal places + int m_timeFormatWidth; // $timeformat character width + enum { UNITS_NONE = 99 }; // Default based on precision + Serialized() + : m_timeFormatUnits(UNITS_NONE) + , m_timeFormatPrecision(0) + , m_timeFormatWidth(20) {} + ~Serialized() {} + } m_ser; + + VerilatedMutex m_sergMutex; ///< Protect m_ser + struct SerializedG { // All these members serialized/deserialized and guarded + std::string m_timeFormatSuffix; // $timeformat printf format + } m_serg VL_GUARDED_BY(m_sergMutex); + + // Nothing below here is save-restored; users expected to re-register appropriately VerilatedMutex m_argMutex; ///< Protect m_argVec, m_argVecLoaded /// Argument list (NOT save-restored, may want different results) @@ -411,6 +430,22 @@ public: // But only for verilated*.cpp // We don't free up m_exportMap until the end, because we can't be sure // what other models are using the assigned funcnum's. +public: // But only for verilated*.cpp + // METHODS - timeformat + static std::string timeFormatSuffix() VL_MT_SAFE; + static void timeFormatSuffix(const std::string& value) VL_MT_SAFE; + static int timeFormatUnits() VL_MT_SAFE { + if (s_s.m_ser.m_timeFormatUnits == Serialized::UNITS_NONE) { + return Verilated::timeprecision(); + } + return s_s.m_ser.m_timeFormatUnits; + } + static int timeFormatPrecision() VL_MT_SAFE { return s_s.m_ser.m_timeFormatPrecision; } + static int timeFormatWidth() VL_MT_SAFE { return s_s.m_ser.m_timeFormatWidth; } + static void timeFormatUnits(int value) VL_MT_SAFE; + static void timeFormatPrecision(int value) VL_MT_SAFE; + static void timeFormatWidth(int value) VL_MT_SAFE; + public: // But only for verilated*.cpp // METHODS - file IO static IData fdNew(FILE* fp) VL_MT_SAFE { diff --git a/include/verilated_save.cpp b/include/verilated_save.cpp index 2c91e384e..3b6e3732b 100644 --- a/include/verilated_save.cpp +++ b/include/verilated_save.cpp @@ -79,7 +79,8 @@ void VerilatedSerialize::header() VL_MT_UNSAFE_ONE { // Verilated doesn't do it itself, as if we're not using save/restore // it doesn't need to compile this stuff in - os.write(Verilated::serializedPtr(), Verilated::serializedSize()); + os.write(Verilated::serialized1Ptr(), Verilated::serialized1Size()); + os.write(Verilated::serialized2Ptr(), Verilated::serialized2Size()); } void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE { @@ -91,7 +92,8 @@ void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE { VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str()); close(); } - os.read(Verilated::serializedPtr(), Verilated::serializedSize()); + os.read(Verilated::serialized1Ptr(), Verilated::serialized1Size()); + os.read(Verilated::serialized2Ptr(), Verilated::serialized2Size()); } void VerilatedSerialize::trailer() VL_MT_UNSAFE_ONE { diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index d5bde2a92..21ce58cd5 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -159,7 +159,6 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) m_fileNewed = (filep == NULL); m_filep = m_fileNewed ? new VerilatedVcdFile : filep; m_namemapp = NULL; - m_timeRes = m_timeUnit = 1e-9; m_timeLastDump = 0; m_sigs_oldvalp = NULL; m_evcd = false; @@ -171,6 +170,9 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) m_writep = m_wrBufp; m_wroteBytes = 0; m_suffixesp = NULL; + m_timeRes = m_timeUnit = 1e-9; + set_time_unit(Verilated::timeunitString()); + set_time_resolution(Verilated::timeprecisionString()); } void VerilatedVcd::open(const char* filename) { diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 95128bba6..7e5dd2860 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -458,11 +458,11 @@ public: void dump(vluint32_t timestamp) { dump(static_cast(timestamp)); } void dump(int timestamp) { dump(static_cast(timestamp)); } /// Set time units (s/ms, defaults to ns) - /// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h + /// For Verilated models, these propage from the Verilated default --timeunit void set_time_unit(const char* unit) { m_sptrace.set_time_unit(unit); } void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); } /// Set time resolution (s/ms, defaults to ns) - /// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h + /// For Verilated models, these propage from the Verilated default --timeunit void set_time_resolution(const char* unit) { m_sptrace.set_time_resolution(unit); } void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); } diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index eaba5a782..6d8b099a8 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -1241,10 +1241,12 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) { _VL_VPI_ERROR_RESET(); switch (property) { case vpiTimePrecision: { - return VL_TIME_PRECISION; + return Verilated::timeprecision(); } case vpiTimeUnit: { - return VL_TIME_UNIT; + VerilatedVpioScope* vop = VerilatedVpioScope::castp(object); + if (!vop) return Verilated::timeunit(); // Null asks for global, not unlikely + return vop->scopep()->timeunit(); } case vpiType: { VerilatedVpio* vop = VerilatedVpio::castp(object); @@ -1903,7 +1905,7 @@ void vpi_put_value_array(vpiHandle /*object*/, p_vpi_arrayvalue /*arrayvalue_p*/ // time processing -void vpi_get_time(vpiHandle /*object*/, p_vpi_time time_p) { +void vpi_get_time(vpiHandle object, p_vpi_time time_p) { VerilatedVpiImp::assertOneCheck(); // cppcheck-suppress nullPointer if (VL_UNLIKELY(!time_p)) { @@ -1917,6 +1919,15 @@ void vpi_get_time(vpiHandle /*object*/, p_vpi_time time_p) { time_p->low = itime[0]; time_p->high = itime[1]; return; + } else if (time_p->type == vpiScaledRealTime) { + double dtime = VL_TIME_D(); + if (VerilatedVpioScope* vop = VerilatedVpioScope::castp(object)) { + int scalePow10 = Verilated::timeprecision() - vop->scopep()->timeunit(); + double scale = vl_time_multiplier(scalePow10); // e.g. 0.0001 + dtime *= scale; + } + time_p->real = dtime; + return; } _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported type (%d)", VL_FUNC, time_p->type); } diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 1dd64a7da..254301efa 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -55,7 +55,7 @@ private: nodep->displayType(AstDisplayType::DT_WRITE); nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text())); // cppcheck-suppress nullPointer - AstNode* timenewp = new AstTime(nodep->fileline()); + AstNode* timenewp = new AstTime(nodep->fileline(), m_modp->timeunit()); if (AstNode* timesp = nodep->fmtp()->exprsp()) { timesp->unlinkFrBackWithNext(); timenewp->addNext(timesp); diff --git a/src/V3Ast.h b/src/V3Ast.h index 3380517c0..2b227bb60 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2671,6 +2671,7 @@ private: int m_level; // 1=top module, 2=cell off top module, ... int m_varNum; // Incrementing variable number int m_typeNum; // Incrementing implicit type number + VTimescale m_timeunit; // Global time unit VOptionBool m_unconnectedDrive; // State of `unconnected_drive public: AstNodeModule(AstType t, FileLine* fl, const string& name) @@ -2721,6 +2722,8 @@ public: bool recursive() const { return m_recursive; } void recursiveClone(bool flag) { m_recursiveClone = flag; } bool recursiveClone() const { return m_recursiveClone; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } }; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 4ca1f3646..86fa52c26 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -225,6 +225,16 @@ AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode return newp; } +void AstNetlist::timeprecisionMerge(FileLine*, const VTimescale& value) { + VTimescale prec = v3Global.opt.timeComputePrec(value); + if (prec.isNone() || prec == m_timeprecision) { + } else if (m_timeprecision.isNone()) { + m_timeprecision = prec; + } else if (prec < m_timeprecision) { + m_timeprecision = prec; + } +} + bool AstVar::isSigPublic() const { return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar())); } @@ -1181,6 +1191,22 @@ void AstPin::dump(std::ostream& str) const { } if (svImplicit()) str << " [.SV]"; } +void AstPrintTimeScale::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " " << timeunit(); +} +void AstTime::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " " << timeunit(); +} +void AstTimeD::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " " << timeunit(); +} +void AstTimeImport::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " " << timeunit(); +} void AstTypedef::dump(std::ostream& str) const { this->AstNode::dump(str); if (attrPublic()) str << " [PUBLIC]"; @@ -1254,6 +1280,10 @@ string AstUnpackArrayDType::prettyDTypeName() const { os << subp->prettyDTypeName() << "$" << ranges; return os.str(); } +void AstNetlist::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " [" << timeunit() << "/" << timeprecision() << "]"; +} void AstNodeModule::dump(std::ostream& str) const { this->AstNode::dump(str); str << " L" << level(); @@ -1265,6 +1295,7 @@ void AstNodeModule::dump(std::ostream& str) const { } else if (recursive()) { str << " [RECURSIVE]"; } + str << " [" << timeunit() << "]"; } void AstPackageExport::dump(std::ostream& str) const { this->AstNode::dump(str); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index aa05bd09c..bfca78855 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -113,6 +113,13 @@ public: m_num.width(32, true); dtypeSetLogicUnsized(32, m_num.widthMin(), AstNumeric::SIGNED); } + class Unsized64 {}; // for creator type-overload selection + AstConst(FileLine* fl, Unsized64, vluint64_t num) + : ASTGEN_SUPER(fl) + , m_num(this, 64, 0) { + m_num.setQuad(num); + dtypeSetLogicSized(64, AstNumeric::UNSIGNED); + } class SizedEData {}; // for creator type-overload selection AstConst(FileLine* fl, SizedEData, vluint64_t num) : ASTGEN_SUPER(fl) @@ -2677,12 +2684,15 @@ private: string m_name; // Cell name, possibly {a}__DOT__{b}... string m_origModName; // Original name of the module, ignoring name() changes, for dot lookup AstScope* m_scopep; // The scope that the cell is inlined into + VTimescale m_timeunit; // Parent module time unit public: - AstCellInline(FileLine* fl, const string& name, const string& origModName) + AstCellInline(FileLine* fl, const string& name, const string& origModName, + const VTimescale& timeunit) : ASTGEN_SUPER(fl) , m_name(name) , m_origModName(origModName) - , m_scopep(NULL) {} + , m_scopep(NULL) + , m_timeunit(timeunit) {} ASTNODE_NODE_FUNCS(CellInline) virtual void dump(std::ostream& str) const; virtual const char* broken() const { @@ -2695,6 +2705,8 @@ public: virtual void name(const string& name) { m_name = name; } void scopep(AstScope* scp) { m_scopep = scp; } AstScope* scopep() const { return m_scopep; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } }; class AstCellRef : public AstNode { @@ -3478,6 +3490,7 @@ class AstSFormatF : public AstNode { bool m_hidden; // Under display, etc bool m_hasFormat; // Has format code char m_missingArgChar; // Format code when argument without format, 'h'/'o'/'b' + VTimescale m_timeunit; // Parent module time unit public: class NoFormat {}; AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, @@ -3523,6 +3536,8 @@ public: void hasFormat(bool flag) { m_hasFormat = flag; } bool hasFormat() const { return m_hasFormat; } char missingArgChar() const { return m_missingArgChar; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } }; class AstDisplay : public AstNodeStmt { @@ -4620,6 +4635,28 @@ public: } }; +class AstPrintTimeScale : public AstNodeStmt { + // Parents: stmtlist + string m_name; // Parent module name + VTimescale m_timeunit; // Parent module time unit +public: + AstPrintTimeScale(FileLine* fl) + : ASTGEN_SUPER(fl) {} + ASTNODE_NODE_FUNCS(PrintTimeScale) + virtual void name(const string& name) { m_name = name; } + virtual string name() const { return m_name; } // * = Var name + virtual void dump(std::ostream& str) const; + virtual string verilogKwd() const { return "$printtimescale"; } + virtual bool isGateOptimizable() const { return false; } + virtual bool isPredictOptimizable() const { return false; } + virtual bool isPure() const { return false; } + virtual bool isOutputter() const { return true; } + virtual int instrCount() const { return instrCountPli(); } + virtual V3Hash sameHash() const { return V3Hash(); } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; + class AstStop : public AstNodeStmt { public: AstStop(FileLine* fl, bool maybe) @@ -4671,6 +4708,31 @@ public: virtual bool same(const AstNode* samep) const { return fileline() == samep->fileline(); } }; +class AstTimeFormat : public AstNodeStmt { + // Parents: stmtlist +public: + AstTimeFormat(FileLine* fl, AstNode* unitsp, AstNode* precisionp, AstNode* suffixp, + AstNode* widthp) + : ASTGEN_SUPER(fl) { + setOp1p(unitsp); + setOp2p(precisionp); + setOp3p(suffixp); + setOp4p(widthp); + } + ASTNODE_NODE_FUNCS(TimeFormat) + virtual string verilogKwd() const { return "$timeformat"; } + virtual bool isGateOptimizable() const { return false; } + virtual bool isPredictOptimizable() const { return false; } + virtual bool isPure() const { return false; } + virtual bool isOutputter() const { return true; } + virtual int instrCount() const { return instrCountPli(); } + virtual V3Hash sameHash() const { return V3Hash(); } + AstNode* unitsp() const { return op1p(); } + AstNode* precisionp() const { return op2p(); } + AstNode* suffixp() const { return op3p(); } + AstNode* widthp() const { return op4p(); } +}; + class AstTraceDecl : public AstNodeStmt { // Trace point declaration // Separate from AstTraceInc; as a declaration can't be deleted @@ -4924,37 +4986,47 @@ public: }; class AstTime : public AstNodeTermop { + VTimescale m_timeunit; // Parent module time unit public: - explicit AstTime(FileLine* fl) - : ASTGEN_SUPER(fl) { + AstTime(FileLine* fl, const VTimescale& timeunit) + : ASTGEN_SUPER(fl) + , m_timeunit(timeunit) { dtypeSetUInt64(); } ASTNODE_NODE_FUNCS(Time) virtual string emitVerilog() { return "%f$time"; } - virtual string emitC() { return "VL_TIME_%nq()"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual int instrCount() const { return instrCountTime(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { return true; } + virtual void dump(std::ostream& str = std::cout) const; + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } }; class AstTimeD : public AstNodeTermop { + VTimescale m_timeunit; // Parent module time unit public: - explicit AstTimeD(FileLine* fl) - : ASTGEN_SUPER(fl) { + AstTimeD(FileLine* fl, const VTimescale& timeunit) + : ASTGEN_SUPER(fl) + , m_timeunit(timeunit) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(TimeD) virtual string emitVerilog() { return "%f$realtime"; } - virtual string emitC() { return "VL_TIME_D()"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { return true; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual int instrCount() const { return instrCountTime(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { return true; } + virtual void dump(std::ostream& str = std::cout) const; + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } }; class AstUCFunc : public AstNodeMath { @@ -5813,6 +5885,23 @@ public: virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } }; +class AstTimeImport : public AstNodeUniop { + // Take a constant that represents a time and needs conversion based on time units + VTimescale m_timeunit; // Parent module time unit +public: + AstTimeImport(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER(fl, lhsp) {} + ASTNODE_NODE_FUNCS(TimeImport) + virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } + virtual string emitVerilog() { return "%l"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { return false; } + virtual bool cleanLhs() const { return false; } + virtual bool sizeMattersLhs() const { return false; } + virtual void dump(std::ostream& str = std::cout) const; + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; class AstAtoN : public AstNodeUniop { // string.atoi(), atobin(), atohex(), atooct(), atoireal() @@ -8272,6 +8361,8 @@ private: AstPackage* m_dollarUnitPkgp; // $unit AstCFunc* m_evalp; // The '_eval' function AstExecGraph* m_execGraphp; // Execution MTask graph for threads>1 mode + VTimescale m_timeunit; // Global time unit + VTimescale m_timeprecision; // Global time precision public: AstNetlist() : ASTGEN_SUPER(new FileLine(FileLine::builtInFilename())) @@ -8285,6 +8376,7 @@ public: BROKEN_RTN(m_evalp && !m_evalp->brokeExists()); return NULL; } + virtual void dump(std::ostream& str) const; AstNodeModule* modulesp() const { // op1 = List of modules return VN_CAST(op1p(), NodeModule); } @@ -8317,6 +8409,14 @@ public: void evalp(AstCFunc* evalp) { m_evalp = evalp; } AstExecGraph* execGraphp() const { return m_execGraphp; } void execGraphp(AstExecGraph* graphp) { m_execGraphp = graphp; } + VTimescale timeunit() const { return m_timeunit; } + void timeunit(const VTimescale& value) { m_timeunit = value; } + VTimescale timeprecision() const { return m_timeprecision; } + void timeInit() { + m_timeunit = v3Global.opt.timeDefaultUnit(); + m_timeprecision = v3Global.opt.timeDefaultPrec(); + } + void timeprecisionMerge(FileLine*, const VTimescale& value); }; //###################################################################### diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index e1fc1cbf9..900f1f6f6 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -135,8 +135,8 @@ private: } // Create CellInline for dotted var resolution if (!m_ftaskp) { - AstCellInline* inlinep - = new AstCellInline(nodep->fileline(), m_unnamedScope, "__BEGIN__"); + AstCellInline* inlinep = new AstCellInline( + nodep->fileline(), m_unnamedScope, "__BEGIN__", m_modp->timeunit()); m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells } } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index f0f173c84..dcaec4787 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2067,6 +2067,10 @@ private: case '%': break; // %% - just output a % case 'm': break; // %m - auto insert "name" case 'l': break; // %l - auto insert "library" + case 't': // FALLTHRU + case '^': // %t/%^ - don't know $timeformat so can't constify + if (argp) argp = argp->nextp(); + break; default: // Most operators, just move to next argument if (argp) { AstNode* nextp = argp->nextp(); diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index ba95d9fee..056f77d52 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -748,6 +748,38 @@ public: puts(cvtToStr(nodep->fileline()->lineno())); puts(", \"\");\n"); } + virtual void visit(AstPrintTimeScale* nodep) VL_OVERRIDE { + puts("VL_PRINTTIMESCALE("); + putsQuoted(protect(nodep->name())); + puts(", "); + putsQuoted(nodep->timeunit().ascii()); + puts(");\n"); + } + virtual void visit(AstTime* nodep) VL_OVERRIDE { + puts("VL_TIME_UNITED_Q("); + if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units"); + puts(cvtToStr(nodep->timeunit().multiplier() + / v3Global.rootp()->timeprecision().multiplier())); + puts(")"); + } + virtual void visit(AstTimeD* nodep) VL_OVERRIDE { + puts("VL_TIME_UNITED_D("); + if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$realtime has no units"); + puts(cvtToStr(nodep->timeunit().multiplier() + / v3Global.rootp()->timeprecision().multiplier())); + puts(")"); + } + virtual void visit(AstTimeFormat* nodep) VL_OVERRIDE { + puts("VL_TIMEFORMAT_IINI("); + iterateAndNextNull(nodep->unitsp()); + puts(", "); + iterateAndNextNull(nodep->precisionp()); + puts(", "); + emitCvtPackStr(nodep->suffixp()); + puts(", "); + iterateAndNextNull(nodep->widthp()); + puts(");\n"); + } virtual void visit(AstNodeSimpleText* nodep) VL_OVERRIDE { if (nodep->tracking() || m_trackText) { puts(nodep->text()); @@ -2040,7 +2072,7 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const // string pfmt = "%"+displayFormat(argp, vfmt, fmtLetter)+fmtLetter; string pfmt; - if ((fmtLetter == '#' || fmtLetter == 'd' || fmtLetter == 't') && !isScan + if ((fmtLetter == '#' || fmtLetter == 'd') && !isScan && vfmt == "") { // Size decimal output. Spec says leading spaces, not zeros const double mantissabits = argp->widthMin() - ((fmtLetter == 'd') ? 1 : 0); // This is log10(2**mantissabits) as log2(2**mantissabits)/log2(10), @@ -2251,7 +2283,15 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) { puts("if (false && first) {} // Prevent unused\n"); puts("this->__VlSymsp = vlSymsp;\n"); // First, as later stuff needs it. puts("if (false && this->__VlSymsp) {} // Prevent unused\n"); - if (v3Global.opt.coverage()) puts(protect("_configure_coverage") + "(vlSymsp, first);\n"); + if (v3Global.opt.coverage()) { puts(protect("_configure_coverage") + "(vlSymsp, first);\n"); } + if (modp->isTop() && !v3Global.rootp()->timeunit().isNone()) { + puts("Verilated::timeunit(" + cvtToStr(v3Global.rootp()->timeunit().negativeInt()) + + ");\n"); + } + if (modp->isTop() && !v3Global.rootp()->timeprecision().isNone()) { + puts("Verilated::timeprecision(" + + cvtToStr(v3Global.rootp()->timeprecision().negativeInt()) + ");\n"); + } puts("}\n"); splitSizeInc(10); } diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 39489097d..807886536 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -42,10 +42,13 @@ class EmitCSyms : EmitCBaseVisitor { struct ScopeData { string m_symName; string m_prettyName; + int m_timeunit; string m_type; - ScopeData(const string& symName, const string& prettyName, const string& type) + ScopeData(const string& symName, const string& prettyName, int timeunit, + const string& type) : m_symName(symName) , m_prettyName(prettyName) + , m_timeunit(timeunit) , m_type(type) {} }; struct ScopeFuncData { @@ -220,7 +223,7 @@ class EmitCSyms : EmitCBaseVisitor { if (v3Global.opt.vpi()) varHierarchyScopes(scpName); if (m_scopeNames.find(scpSym) == m_scopeNames.end()) { m_scopeNames.insert( - make_pair(scpSym, ScopeData(scpSym, scpPretty, "SCOPE_OTHER"))); + make_pair(scpSym, ScopeData(scpSym, scpPretty, 0, "SCOPE_OTHER"))); } m_scopeVars.insert( make_pair(scpSym + " " + varp->name(), @@ -289,8 +292,9 @@ class EmitCSyms : EmitCBaseVisitor { string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" : "SCOPE_MODULE"; string name = nodep->scopep()->name() + "__DOT__" + nodep->name(); string name_dedot = AstNode::dedotName(name); + int timeunit = m_modp->timeunit().negativeInt(); m_vpiScopeCandidates.insert( - make_pair(name, ScopeData(scopeSymString(name), name_dedot, type))); + make_pair(name, ScopeData(scopeSymString(name), name_dedot, timeunit, type))); } } virtual void visit(AstScope* nodep) VL_OVERRIDE { @@ -301,18 +305,20 @@ class EmitCSyms : EmitCBaseVisitor { if (v3Global.opt.vpi() && !nodep->isTop()) { string name_dedot = AstNode::dedotName(nodep->shortName()); + int timeunit = m_modp->timeunit().negativeInt(); m_vpiScopeCandidates.insert( - make_pair(nodep->name(), - ScopeData(scopeSymString(nodep->name()), name_dedot, "SCOPE_MODULE"))); + make_pair(nodep->name(), ScopeData(scopeSymString(nodep->name()), name_dedot, + timeunit, "SCOPE_MODULE"))); } } virtual void visit(AstScopeName* nodep) VL_OVERRIDE { string name = nodep->scopeSymName(); - // UINFO(9,"scnameins sp "<name()<<" sp "<scopePrettySymName()<<" ss - // "<name()<<" sp "<scopePrettySymName() + // <<" ss"<timeunit().negativeInt() : 0; if (m_scopeNames.find(name) == m_scopeNames.end()) { - m_scopeNames.insert( - make_pair(name, ScopeData(name, nodep->scopePrettySymName(), "SCOPE_OTHER"))); + m_scopeNames.insert(make_pair( + name, ScopeData(name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER"))); } if (nodep->dpiExport()) { UASSERT_OBJ(m_funcp, nodep, "ScopeName not under DPI function"); @@ -320,9 +326,10 @@ class EmitCSyms : EmitCBaseVisitor { make_pair(name + " " + m_funcp->name(), ScopeFuncData(nodep, m_funcp, m_modp))); } else { if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) { - m_scopeNames.insert(make_pair( - nodep->scopeDpiName(), - ScopeData(nodep->scopeDpiName(), nodep->scopePrettyDpiName(), "SCOPE_OTHER"))); + m_scopeNames.insert( + make_pair(nodep->scopeDpiName(), + ScopeData(nodep->scopeDpiName(), nodep->scopePrettyDpiName(), + timeunit, "SCOPE_OTHER"))); } } } @@ -683,6 +690,8 @@ void EmitCSyms::emitSymImp() { putsQuoted(protectWordsIf(it->second.m_prettyName, true)); puts(", "); putsQuoted(protect(scopeDecodeIdentifier(it->second.m_prettyName))); + puts(", "); + puts(cvtToStr(it->second.m_timeunit)); puts(", VerilatedScope::" + it->second.m_type + ");\n"); ++m_numStmts; } diff --git a/src/V3Error.h b/src/V3Error.h index 31f06185f..db32d6e04 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -105,6 +105,7 @@ public: SYMRSVDWORD, // Symbol is Reserved Word SYNCASYNCNET, // Mixed sync + async reset TICKCOUNT, // Too large tick count + TIMESCALEMOD, // Need timescale for module UNDRIVEN, // No drivers UNOPT, // Unoptimizable block UNOPTFLAT, // Unoptimizable block after flattening @@ -158,7 +159,7 @@ public: "PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE", "REALCVT", "REDEFMACRO", "SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", - "TICKCOUNT", + "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSED", "USERERROR", "USERFATAL", "USERINFO", "USERWARN", @@ -176,7 +177,8 @@ public: // Later -Werror- options may make more of these. bool pretendError() const { return (m_e == ASSIGNIN || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG - || m_e == IMPURE || m_e == PROCASSWIRE); + || m_e == IMPURE || m_e == PROCASSWIRE // + || m_e == TIMESCALEMOD); // Says IEEE } // Warnings to mention manual bool mentionManual() const { diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 13aa8735b..dce048684 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -552,7 +552,8 @@ private: { InlineCollectVisitor(nodep->modp()); } // {} to destroy visitor immediately // Create data for dotted variable resolution AstCellInline* inlinep - = new AstCellInline(nodep->fileline(), nodep->name(), nodep->modp()->origName()); + = new AstCellInline(nodep->fileline(), nodep->name(), nodep->modp()->origName(), + nodep->modp()->timeunit()); m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells // Create assignments to the pins for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 7e6643543..7231c96eb 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -72,6 +72,8 @@ void V3LinkLevel::modSortByLevel() { } } + timescaling(mods); + // Reorder the netlist's modules to have modules in level sorted order stable_sort(mods.begin(), mods.end(), CmpLevel()); // Sort the vector UINFO(9, "modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666 @@ -90,6 +92,44 @@ void V3LinkLevel::modSortByLevel() { V3Global::dumpCheckGlobalTree("cells", false, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); } +void V3LinkLevel::timescaling(const ModVec& mods) { + // Timescale determination + AstNodeModule* modTimedp = NULL; + VTimescale unit(VTimescale::NONE); + // Use highest level module as default unit - already sorted in proper order + for (ModVec::const_iterator it = mods.begin(); it != mods.end(); ++it) { + if (!modTimedp && !(*it)->timeunit().isNone()) { + modTimedp = *it; + unit = modTimedp->timeunit(); + break; + } + } + unit = v3Global.opt.timeComputeUnit(unit); // Apply override + if (unit.isNone()) unit = VTimescale(VTimescale::TS_DEFAULT); + v3Global.rootp()->timeunit(unit); + + for (ModVec::const_iterator it = mods.begin(); it != mods.end(); ++it) { + AstNodeModule* nodep = *it; + if (nodep->timeunit().isNone()) { + if (modTimedp && !VN_IS(nodep, Iface) + && !(VN_IS(nodep, Package) && VN_CAST(nodep, Package)->isDollarUnit())) { + nodep->v3warn(TIMESCALEMOD, + "Timescale missing on this module as other modules have " + "it (IEEE 1800-2017 3.14.2.2)\n" + << modTimedp->warnOther() + << "... Location of module with timescale\n" + << modTimedp->warnContextSecondary()); + } + nodep->timeunit(unit); + } + } + + if (v3Global.rootp()->timeprecision().isNone()) { + v3Global.rootp()->timeprecisionMerge(v3Global.rootp()->fileline(), + VTimescale(VTimescale::TS_DEFAULT)); + } +} + //###################################################################### // Wrapping @@ -108,6 +148,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) { newmodp->level(1); newmodp->modPublic(true); newmodp->protect(false); + newmodp->timeunit(oldmodp->timeunit()); rootp->addModulep(newmodp); // TODO the module creation above could be done after linkcells, but diff --git a/src/V3LinkLevel.h b/src/V3LinkLevel.h index f17861e6e..4143efa4e 100644 --- a/src/V3LinkLevel.h +++ b/src/V3LinkLevel.h @@ -27,6 +27,9 @@ class V3LinkLevel { private: + typedef std::vector ModVec; + + static void timescaling(const ModVec& mods); static void wrapTopCell(AstNetlist* rootp); static void wrapTopPackages(AstNetlist* rootp); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index c1ef8ebc5..1d5e7a510 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -497,6 +497,28 @@ private: cleanFileline(nodep); iterateChildren(nodep); } + virtual void visit(AstPrintTimeScale* nodep) VL_OVERRIDE { + // Inlining may change hierarchy, so just save timescale where needed + iterateChildren(nodep); + nodep->name(m_modp->name()); + nodep->timeunit(m_modp->timeunit()); + } + virtual void visit(AstSFormatF* nodep) VL_OVERRIDE { + iterateChildren(nodep); + nodep->timeunit(m_modp->timeunit()); + } + virtual void visit(AstTime* nodep) VL_OVERRIDE { + iterateChildren(nodep); + nodep->timeunit(m_modp->timeunit()); + } + virtual void visit(AstTimeD* nodep) VL_OVERRIDE { + iterateChildren(nodep); + nodep->timeunit(m_modp->timeunit()); + } + virtual void visit(AstTimeImport* nodep) VL_OVERRIDE { + iterateChildren(nodep); + nodep->timeunit(m_modp->timeunit()); + } virtual void visit(AstNode* nodep) VL_OVERRIDE { // Default: Just iterate diff --git a/src/V3Options.cpp b/src/V3Options.cpp index e39e52449..51a889cb6 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -31,6 +31,7 @@ #ifndef _WIN32 # include #endif +#include #include #include #include @@ -117,6 +118,75 @@ V3LangCode::V3LangCode(const char* textp) { m_e = V3LangCode::L_ERROR; } +//###################################################################### +// VTimescale class functions + +VTimescale::VTimescale(const string& value, bool& badr) + : m_e(VTimescale::NONE) { + badr = true; + string spaceless = VString::removeWhitespace(value); + for (int i = TS_1S; i < _ENUM_END; ++i) { + VTimescale ts(i); + if (spaceless == ts.ascii()) { + badr = false; + m_e = ts.m_e; + break; + } + } +} + +void VTimescale::parseSlashed(FileLine* fl, const char* textp, VTimescale& unitr, + VTimescale& precr, bool allowEmpty) { + // Parse `timescale of / + unitr = VTimescale::NONE; + precr = VTimescale::NONE; + + const char* cp = textp; + for (; isspace(*cp); ++cp) {} + const char* unitp = cp; + for (; *cp && *cp != '/'; ++cp) {} + string unitStr(unitp, cp - unitp); + for (; isspace(*cp); ++cp) {} + string precStr; + if (*cp == '/') { + ++cp; + for (; isspace(*cp); ++cp) {} + const char* precp = cp; + for (; *cp && *cp != '/'; ++cp) {} + precStr = string(precp, cp - precp); + } + for (; isspace(*cp); ++cp) {} + if (*cp) { + fl->v3error("`timescale syntax error: '" << textp << "'"); + return; + } + + bool unitbad; + VTimescale unit(unitStr, unitbad /*ref*/); + if (unitbad && !(unitStr.empty() && allowEmpty)) { + fl->v3error("`timescale timeunit syntax error: '" << unitStr << "'"); + return; + } + unitr = unit; + + if (!precStr.empty()) { + VTimescale prec(VTimescale::NONE); + bool precbad; + prec = VTimescale(precStr, precbad /*ref*/); + if (precbad) { + fl->v3error("`timescale timeprecision syntax error: '" << precStr << "'"); + return; + } + if (!unit.isNone() && !prec.isNone() && unit < prec) { + fl->v3error("`timescale timeunit '" + << unitStr << "' must be greater than or equal to timeprecision '" + << precStr << "'"); + return; + } + precr = prec; + } +} + //###################################################################### // V3Options class functions @@ -590,6 +660,26 @@ void V3Options::throwSigsegv() { #endif } +VTimescale V3Options::timeComputePrec(const VTimescale& flag) const { + if (!timeOverridePrec().isNone()) { + return timeOverridePrec(); + } else if (flag.isNone()) { + return timeDefaultPrec(); + } else { + return flag; + } +} + +VTimescale V3Options::timeComputeUnit(const VTimescale& flag) const { + if (!timeOverrideUnit().isNone()) { + return timeOverrideUnit(); + } else if (flag.isNone()) { + return timeDefaultUnit(); + } else { + return flag; + } +} + //###################################################################### // V3 Options utilities @@ -1127,6 +1217,26 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char m_threadsMaxMTasks = atoi(argv[i]); if (m_threadsMaxMTasks < 1) fl->v3fatal("--threads-max-mtasks must be >= 1: " << argv[i]); + } else if (!strcmp(sw, "-timescale") && (i + 1) < argc) { + shift; + VTimescale unit; + VTimescale prec; + VTimescale::parseSlashed(fl, argv[i], unit /*ref*/, prec /*ref*/); + if (!unit.isNone() && timeOverrideUnit().isNone()) m_timeDefaultUnit = unit; + if (!prec.isNone() && timeOverridePrec().isNone()) m_timeDefaultPrec = prec; + } else if (!strcmp(sw, "-timescale-override") && (i + 1) < argc) { + shift; + VTimescale unit; + VTimescale prec; + VTimescale::parseSlashed(fl, argv[i], unit /*ref*/, prec /*ref*/, true); + if (!unit.isNone()) { + m_timeDefaultUnit = unit; + m_timeOverrideUnit = unit; + } + if (!prec.isNone()) { + m_timeDefaultPrec = prec; + m_timeOverridePrec = prec; + } } else if (!strcmp(sw, "-top-module") && (i + 1) < argc) { shift; m_topModule = argv[i]; diff --git a/src/V3Options.h b/src/V3Options.h index f9f17ef88..c5ef514ed 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -69,6 +69,85 @@ inline std::ostream& operator<<(std::ostream& os, const VOptionBool& rhs) { //###################################################################### +class VTimescale { +public: + enum en { + TS_1S = 0, + // clang-format off + TS_100MS = 1, TS_10MS = 2, TS_1MS = 3, + TS_100US = 4, TS_10US = 5, TS_1US = 6, + TS_100NS = 7, TS_10NS = 8, TS_1NS = 9, + TS_100PS = 10, TS_10PS = 11, TS_1PS = 12, + TS_100FS = 13, TS_10FS = 14, TS_1FS = 15, + // clang-format on + NONE = 16, + _ENUM_END + }; + enum { TS_DEFAULT = TS_1PS }; + enum en m_e; + // CONSTRUCTOR + inline VTimescale() + : m_e(NONE) {} + // cppcheck-suppress noExplicitConstructor + inline VTimescale(en _e) + : m_e(_e) {} + explicit inline VTimescale(int _e) + : m_e(static_cast(_e)) {} + int negativeInt() { return -static_cast(m_e); } + // Construct from string + VTimescale(const string& value, bool& badr); + VTimescale(double value, bool& badr) { + badr = false; + // clang-format off + if (value == 1e0) m_e = TS_1S; + else if (value == 1e-1) m_e = TS_100MS; + else if (value == 1e-2) m_e = TS_10MS; + else if (value == 1e-3) m_e = TS_1MS; + else if (value == 1e-4) m_e = TS_100US; + else if (value == 1e-5) m_e = TS_10US; + else if (value == 1e-6) m_e = TS_1US; + else if (value == 1e-7) m_e = TS_100NS; + else if (value == 1e-8) m_e = TS_10NS; + else if (value == 1e-9) m_e = TS_1NS; + else if (value == 1e-10) m_e = TS_100PS; + else if (value == 1e-11) m_e = TS_10PS; + else if (value == 1e-12) m_e = TS_1PS; + else if (value == 1e-13) m_e = TS_100FS; + else if (value == 1e-14) m_e = TS_10FS; + else if (value == 1e-15) m_e = TS_1FS; + // clang-format on + else { + m_e = NONE; + badr = true; + } + } + bool isNone() const { return m_e == NONE; } + // Parse a "unit/precision" string into two VTimescales, with error checking + static void parseSlashed(FileLine* fl, const char* textp, VTimescale& unitr, VTimescale& precr, + bool allowEmpty = false); + const char* ascii() const { + static const char* const names[] + = {"1s", "100ms", "10ms", "1ms", "100us", "10us", "1us", "100ns", "10ns", + "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs", "NONE"}; + return names[m_e]; + } + double multiplier() const { + static double values[] = {1, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, + 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 0}; + return values[m_e]; + } +}; +inline bool operator==(const VTimescale& lhs, const VTimescale& rhs) { return lhs.m_e == rhs.m_e; } +inline bool operator==(const VTimescale& lhs, VTimescale::en rhs) { return lhs.m_e == rhs; } +inline bool operator==(VTimescale::en lhs, const VTimescale& rhs) { return lhs == rhs.m_e; } +// Comparisons are based on time, not enum values, so seconds > milliseconds +inline bool operator<(const VTimescale& lhs, const VTimescale& rhs) { return lhs.m_e > rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VTimescale& rhs) { + return os << rhs.ascii(); +} + +//###################################################################### + class TraceFormat { public: enum en { VCD = 0, FST, FST_THREAD } m_e; @@ -207,6 +286,10 @@ private: VOptionBool m_skipIdentical; // main switch: --skip-identical int m_threads; // main switch: --threads (0 == --no-threads) int m_threadsMaxMTasks; // main switch: --threads-max-mtasks + VTimescale m_timeDefaultPrec; // main switch: --timescale + VTimescale m_timeDefaultUnit; // main switch: --timescale + VTimescale m_timeOverridePrec; // main switch: --timescale-override + VTimescale m_timeOverrideUnit; // main switch: --timescale-override int m_traceDepth; // main switch: --trace-depth TraceFormat m_traceFormat; // main switch: --trace or --trace-fst int m_traceMaxArray;// main switch: --trace-max-array @@ -392,6 +475,12 @@ public: int threads() const { return m_threads; } int threadsMaxMTasks() const { return m_threadsMaxMTasks; } bool mtasks() const { return (m_threads > 1); } + VTimescale timeDefaultPrec() const { return m_timeDefaultPrec; } + VTimescale timeDefaultUnit() const { return m_timeDefaultUnit; } + VTimescale timeOverridePrec() const { return m_timeOverridePrec; } + VTimescale timeOverrideUnit() const { return m_timeOverrideUnit; } + VTimescale timeComputePrec(const VTimescale& flag) const; + VTimescale timeComputeUnit(const VTimescale& flag) const; int traceDepth() const { return m_traceDepth; } TraceFormat traceFormat() const { return m_traceFormat; } int traceMaxArray() const { return m_traceMaxArray; } diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 2294d08f4..390eff981 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -86,6 +86,44 @@ void V3ParseImp::ppline(const char* textp) { } } +void V3ParseImp::timescalePreproc(FileLine* fl, const char* textp) { + // Parse `timescale of / + VTimescale unit; + VTimescale prec; + VTimescale::parseSlashed(fl, textp, unit /*ref*/, prec /*ref*/); + m_timeLastUnit = v3Global.opt.timeComputeUnit(unit); + v3Global.rootp()->timeprecisionMerge(fileline(), prec); +} +void V3ParseImp::timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, double unitVal, + bool precSet, double precVal) { + VTimescale unit(VTimescale::NONE); + if (unitSet) { + bool bad; + unit = VTimescale(unitVal, bad /*ref*/); + if (bad) { + UINFO(1, "Value = " << unitVal << endl); + fl->v3error("timeunit illegal value"); + } + } + VTimescale prec(VTimescale::NONE); + if (precSet) { + bool bad; + prec = VTimescale(precVal, bad /*ref*/); + if (bad) { + UINFO(1, "Value = " << precVal << endl); + fl->v3error("timeprecision illegal value"); + } + } + if (!unit.isNone()) { + if (modp) { + modp->timeunit(v3Global.opt.timeComputeUnit(unit)); + } else { + fl->v3error("timeunit/timeprecision not under a module"); + } + } + v3Global.rootp()->timeprecisionMerge(fileline(), prec); +} + void V3ParseImp::verilatorCmtLintSave() { m_lintState.push_back(*parsep()->fileline()); } void V3ParseImp::verilatorCmtLintRestore() { @@ -171,6 +209,40 @@ double V3ParseImp::parseDouble(const char* textp, size_t length, bool* successp) return d; } +double V3ParseImp::parseTimenum(const char* textp) { + size_t length = strlen(textp); + char* strgp = new char[length + 1]; + char* dp = strgp; + const char* sp = textp; + for (; isdigit(*sp) || *sp == '_' || *sp == '.'; ++sp) { + if (*sp != '_') *dp++ = *sp; + } + *dp++ = '\0'; + double d = strtod(strgp, NULL); + string suffix(sp); + + double divisor = 1; + if (suffix == "s") { + divisor = 1; + } else if (suffix == "ms") { + divisor = 1e3; + } else if (suffix == "us") { + divisor = 1e6; + } else if (suffix == "ns") { + divisor = 1e9; + } else if (suffix == "ps") { + divisor = 1e12; + } else if (suffix == "fs") { + divisor = 1e15; + } else { + // verilog.l checks the suffix for us, so this is an assert + v3fatalSrc("Unknown time suffix " << suffix); + } + + VL_DO_DANGLING(delete[] strgp, strgp); + return d / divisor; +} + //###################################################################### // Parser tokenization diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index cc75b3ca8..05ceeb87d 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -124,6 +124,8 @@ class V3ParseImp { string m_tag; // Contents (if any) of current verilator tag AstNode* m_tagNodep; // Points to the node to set to m_tag or NULL to not set. + VTimescale m_timeLastUnit; // Last `timescale's unit + public: // Note these are an exception to using the filename as the debug type static int debugBison() { @@ -152,7 +154,12 @@ public: void tag(const char* text); void tagNodep(AstNode* nodep) { m_tagNodep = nodep; } AstNode* tagNodep() const { return m_tagNodep; } + void timescalePreproc(FileLine* fl, const char* textp); + void timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, double unitVal, + bool precSet, double precVal); + VTimescale timeLastUnit() const { return m_timeLastUnit; } + static double parseTimenum(const char* text); static double parseDouble(const char* text, size_t length, bool* successp = NULL); void pushBeginKeywords(int state) { m_inBeginKwd++; @@ -246,6 +253,7 @@ public: m_prevBisonVal.token = 0; // m_aheadVal not used as m_ahead = false, and not all compilers support initing it m_tagNodep = NULL; + m_timeLastUnit = v3Global.opt.timeDefaultUnit(); } ~V3ParseImp(); void parserClear(); diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index 49b78d76f..6a2aac6e9 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -138,6 +138,14 @@ private: txtp->addNodep(m_modPortsp); txtp->addText(fl, ");\n\n"); + // Timescale + addComment(txtp, fl, + "Precision of submodule" + " (commented out to avoid requiring timescale on all modules)"); + addComment(txtp, fl, string("timeunit ") + v3Global.rootp()->timeunit().ascii() + ";"); + addComment(txtp, fl, + string("timeprecision ") + v3Global.rootp()->timeprecision().ascii() + ";\n"); + // DPI declarations hashComment(txtp, fl); txtp->addText(fl, "import \"DPI-C\" function void " + m_libName diff --git a/src/V3String.cpp b/src/V3String.cpp index 48f1d76d2..70c0f8a80 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -109,6 +109,15 @@ string VString::spaceUnprintable(const string& str) { return out; } +string VString::removeWhitespace(const string& str) { + string out; + out.reserve(str.size()); + for (string::const_iterator pos = str.begin(); pos != str.end(); ++pos) { + if (!isspace(*pos)) out += *pos; + } + return out; +} + bool VString::isWhitespace(const string& str) { for (string::const_iterator pos = str.begin(); pos != str.end(); ++pos) { if (!isspace(*pos)) return false; diff --git a/src/V3String.h b/src/V3String.h index 6519303ae..1d22a7f08 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -87,6 +87,8 @@ public: // Replace any unprintable with space // This includes removing tabs, so column tracking is correct static string spaceUnprintable(const string& str); + // Remove any whitespace + static string removeWhitespace(const string& str); // Return true if only whitespace or "" static bool isWhitespace(const string& str); }; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f176bd9fd..a21e85daf 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1129,6 +1129,21 @@ private: userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); // Type set in constructor } + virtual void visit(AstTimeImport* nodep) VL_OVERRIDE { + // LHS is a real number in seconds + // Need to round to time units and precision + userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); + AstConst* constp = VN_CAST(nodep->lhsp(), Const); + if (!constp || !constp->isDouble()) nodep->v3fatalSrc("Times should be doubles"); + if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time import no units"); + double time = constp->num().toDouble(); + if (v3Global.rootp()->timeprecision().isNone()) nodep->v3fatalSrc("Never set precision?"); + time /= nodep->timeunit().multiplier(); + // IEEE claims you should round to time precision here, but no simulator seems to do this + AstConst* newp = new AstConst(nodep->fileline(), AstConst::RealDouble(), time); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } virtual void visit(AstAttrOf* nodep) VL_OVERRIDE { AstAttrOf* oldAttr = m_attrp; m_attrp = nodep; @@ -3118,10 +3133,35 @@ private: break; } case 't': { // Convert decimal time to realtime - if (argp && argp->isDouble()) { // Convert it - ch = '^'; + if (argp) { + AstNode* nextp = argp->nextp(); + if (argp->isDouble()) ch = '^'; // Convert it + if (nodep->timeunit().isNone()) { + nodep->v3fatalSrc("display %t has no time units"); + } + double scale = nodep->timeunit().multiplier() + / v3Global.rootp()->timeprecision().multiplier(); + if (scale != 1.0) { + AstNode* newp; + AstNRelinker relinkHandle; + argp->unlinkFrBack(&relinkHandle); + if (argp->isDouble()) { // Convert it + ch = '^'; + newp = new AstMulD( + argp->fileline(), + new AstConst(argp->fileline(), AstConst::RealDouble(), scale), + argp); + } else { + newp = new AstMul(argp->fileline(), + new AstConst(argp->fileline(), + AstConst::Unsized64(), + llround(scale)), + argp); + } + relinkHandle.relink(newp); + } + argp = nextp; } - if (argp) argp = argp->nextp(); break; } case 'f': // FALLTHRU @@ -3333,6 +3373,13 @@ private: nodep->dtypeChgWidthSigned(32, 1, AstNumeric::SIGNED); // Spec says integer return } } + virtual void visit(AstTimeFormat* nodep) VL_OVERRIDE { + assertAtStatement(nodep); + iterateCheckSigned32(nodep, "units", nodep->unitsp(), BOTH); + iterateCheckSigned32(nodep, "precision", nodep->precisionp(), BOTH); + iterateCheckString(nodep, "suffix", nodep->suffixp(), BOTH); + iterateCheckSigned32(nodep, "width", nodep->widthp(), BOTH); + } virtual void visit(AstUCStmt* nodep) VL_OVERRIDE { // Just let all arguments seek their natural sizes assertAtStatement(nodep); diff --git a/src/Verilator.cpp b/src/Verilator.cpp index a5b2afa2b..23471fe7e 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -630,6 +630,7 @@ int main(int argc, char** argv, char** env) { // Validate settings (aka Boost.Program_options) v3Global.opt.notify(); + v3Global.rootp()->timeInit(); V3Error::abortIfErrors(); diff --git a/src/verilog.l b/src/verilog.l index 9ab7bfdeb..6c4e01df9 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -242,6 +242,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$nochange" { FL; return yaTIMINGSPEC; } "$period" { FL; return yaTIMINGSPEC; } "$pow" { FL; return yD_POW; } + "$printtimescale" { FL; return yD_PRINTTIMESCALE; } "$random" { FL; return yD_RANDOM; } "$readmemb" { FL; return yD_READMEMB; } "$readmemh" { FL; return yD_READMEMH; } @@ -275,6 +276,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$test$plusargs" { FL; return yD_TESTPLUSARGS; } "$time" { FL; return yD_TIME; } "$timeskew" { FL; return yaTIMINGSPEC; } + "$timeformat" { FL; return yD_TIMEFORMAT; } "$typename" { FL; return yD_TYPENAME; } "$ungetc" { FL; return yD_UNGETC; } "$value$plusargs" { FL; return yD_VALUEPLUSARGS; } @@ -891,8 +893,12 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} FL; yylval.cdouble = PARSEP->parseDouble(yytext, yyleng); return yaFLOATNUM; } - [0-9][_0-9]*(\.[_0-9]+)?(fs|ps|ns|us|ms|s|step) { - FL; yylval.cdouble = 0; /* Only for times, not used yet */ + [0-9][_0-9]*(\.[_0-9]+)?(fs|ps|ns|us|ms|s) { + FL; yylval.cdouble = PARSEP->parseTimenum(yytext); + return yaTIMENUM; + } + 1step { + FL; yylval.cdouble = 0; // Unsupported return yaTIMENUM; } } @@ -975,7 +981,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "`resetall" { FL; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); return yaT_RESETALL; } // Rest handled by preproc "`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility - "`timescale"{ws}+[^\n\r]* { FL_FWD; FL_BRK; } // Verilog spec - not supported + "`timescale"{ws}+[^\n\r]* { FL_FWD; PARSEP->timescalePreproc(PARSEP->fileline(), + yytext + strlen("`timescale")); + FL_BRK; } "`unconnected_drive"{ws}+"pull0" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_FALSE); FL_BRK; } "`unconnected_drive"{ws}+"pull1" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_TRUE); FL_BRK; } "`unconnected_drive" { FL_FWD; yyerrorf("Bad `unconnected_drive syntax"); FL_BRK; } diff --git a/src/verilog.y b/src/verilog.y index 2fee40057..42eee81cf 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -55,6 +55,7 @@ public: AstCase* m_caseAttrp; // Current case statement for attribute adding AstNodeDType* m_varDTypep; // Pointer to data type for next signal declaration AstNodeDType* m_memDTypep; // Pointer to data type for next member declaration + AstNodeModule* m_modp; // Last module for timeunits bool m_pinAnsi; // In ANSI port list int m_pinNum; // Pin number currently parsing FileLine* m_instModuleFl; // Fileline of module referenced for instantiations @@ -73,6 +74,7 @@ public: m_varDTypep = NULL; m_gateRangep = NULL; m_memDTypep = NULL; + m_modp = NULL; m_pinAnsi = false; m_pinNum = -1; m_instModuleFl = NULL; @@ -600,6 +602,7 @@ class AstSenTree; %token yD_ONEHOT0 "$onehot0" %token yD_PAST "$past" %token yD_POW "$pow" +%token yD_PRINTTIMESCALE "$printtimescale" %token yD_RANDOM "$random" %token yD_READMEMB "$readmemb" %token yD_READMEMH "$readmemh" @@ -629,6 +632,7 @@ class AstSenTree; %token yD_TANH "$tanh" %token yD_TESTPLUSARGS "$test$plusargs" %token yD_TIME "$time" +%token yD_TIMEFORMAT "$timeformat" %token yD_TYPENAME "$typename" %token yD_UNGETC "$ungetc" %token yD_UNIT "$unit" @@ -820,9 +824,12 @@ description: // ==IEEE: description ; timeunits_declaration: // ==IEEE: timeunits_declaration - yTIMEUNIT yaTIMENUM ';' { $$ = NULL; } - | yTIMEUNIT yaTIMENUM '/' yaTIMENUM ';' { $$ = NULL; } - | yTIMEPRECISION yaTIMENUM ';' { $$ = NULL; } + yTIMEUNIT yaTIMENUM ';' + { PARSEP->timescaleMod($2, GRAMMARP->m_modp, true, $2, false, 0); $$ = NULL; } + | yTIMEUNIT yaTIMENUM '/' yaTIMENUM ';' + { PARSEP->timescaleMod($2, GRAMMARP->m_modp, true, $2, true, $4); $$ = NULL; } + | yTIMEPRECISION yaTIMENUM ';' + { PARSEP->timescaleMod($2, GRAMMARP->m_modp, false, 0, true, $2); $$ = NULL; } ; //********************************************************************** @@ -832,6 +839,7 @@ package_declaration: // ==IEEE: package_declaration packageFront package_itemListE yENDPACKAGE endLabelE { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc if ($2) $1->addStmtp($2); + GRAMMARP->m_modp = NULL; SYMP->popScope($1); GRAMMARP->endLabel($4,$1,$4); } ; @@ -841,8 +849,10 @@ packageFront: { $$ = new AstPackage($3, *$3); $$->inLibrary(true); // packages are always libraries; don't want to make them a "top" $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); + $$->timeunit(PARSEP->timeLastUnit()); PARSEP->rootp()->addModulep($$); - SYMP->pushNew($$); } + SYMP->pushNew($$); + GRAMMARP->m_modp = $$; } ; package_itemListE: // IEEE: [{ package_item }] @@ -931,6 +941,7 @@ module_declaration: // ==IEEE: module_declaration { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3); if ($5) $1->addStmtp($5); + GRAMMARP->m_modp = NULL; SYMP->popScope($1); GRAMMARP->endLabel($7,$1,$7); } | udpFront parameter_port_listE portsStarE ';' @@ -939,6 +950,7 @@ module_declaration: // ==IEEE: module_declaration if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3); if ($5) $1->addStmtp($5); GRAMMARP->m_tracingParse = true; + GRAMMARP->m_modp = NULL; SYMP->popScope($1); GRAMMARP->endLabel($7,$1,$7); } // @@ -953,9 +965,11 @@ modFront: { $$ = new AstModule($3,*$3); $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); + $$->timeunit(PARSEP->timeLastUnit()); $$->unconnectedDrive(PARSEP->unconnectedDrive()); PARSEP->rootp()->addModulep($$); - SYMP->pushNew($$); } + SYMP->pushNew($$); + GRAMMARP->m_modp = $$; } ; importsAndParametersE: // IEEE: common part of module_declaration, interface_declaration, program_declaration @@ -982,7 +996,7 @@ parameter_value_assignmentE: // IEEE: [ parameter_value_assignment ] | '#' yaFLOATNUM { $$ = new AstPin($2, 1, "", new AstConst($2, AstConst::Unsized32(), (int)(($2<0)?($2-0.5):($2+0.5)))); } - //UNSUP '#' yaTIMENUM { UNSUP } + | '#' timeNumAdjusted { $$ = new AstPin($2, 1, "", $2); } | '#' idClassSel { $$ = new AstPin($2, 1, "", $2); } // // Not needed in Verilator: // // Side effect of combining *_instantiations @@ -1224,6 +1238,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_header + pr { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3); if ($5) $1->addStmtp($5); + GRAMMARP->m_modp = NULL; SYMP->popScope($1); GRAMMARP->endLabel($7,$1,$7); } | yEXTERN pgmFront parameter_port_listE portsStarE ';' @@ -1236,8 +1251,10 @@ pgmFront: { $$ = new AstModule($3,*$3); $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); + $$->timeunit(PARSEP->timeLastUnit()); PARSEP->rootp()->addModulep($$); - SYMP->pushNew($$); } + SYMP->pushNew($$); + GRAMMARP->m_modp = $$; } ; program_itemListE: // ==IEEE: [{ program_item }] @@ -2272,14 +2289,11 @@ delay_value: // ==IEEE:delay_value ps_id_etc { } | yaINTNUM { } | yaFLOATNUM { } - | yaTIMENUM { } + | timeNumAdjusted { DEL($1); } ; delayExpr: expr { DEL($1); } - // // Verilator doesn't support yaTIMENUM, so not in expr - //UNSUP below doesn't belong here: - | yaTIMENUM { } ; minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression @@ -3285,6 +3299,11 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_FATAL, NULL, NULL); $$->addNext(new AstStop($1, false)); DEL($3); } | yD_FATAL '(' expr ',' exprListE ')' { $$ = new AstDisplay($1,AstDisplayType::DT_FATAL, NULL, $5); $$->addNext(new AstStop($1, false)); DEL($3); } // + | yD_PRINTTIMESCALE { $$ = new AstPrintTimeScale($1); } + | yD_PRINTTIMESCALE '(' ')' { $$ = new AstPrintTimeScale($1); } + | yD_PRINTTIMESCALE '(' idClassSel ')' { $$ = new AstPrintTimeScale($1); DEL($3); } + | yD_TIMEFORMAT '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstTimeFormat($1, $3, $5, $7, $9); } + // | yD_READMEMB '(' expr ',' idClassSel ')' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); } | yD_READMEMB '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); } | yD_READMEMB '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); } @@ -3366,7 +3385,7 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); } | yD_RANDOM '(' expr ')' { $$ = NULL; $1->v3error("Unsupported: Seeding $random doesn't map to C++, use $c(\"srand\")"); } | yD_RANDOM parenE { $$ = new AstRand($1); } - | yD_REALTIME parenE { $$ = new AstTimeD($1); } + | yD_REALTIME parenE { $$ = new AstTimeD($1, VTimescale(VTimescale::NONE)); } | yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); } | yD_REWIND '(' idClassSel ')' { $$ = new AstFSeek($1, $3, new AstConst($1, 0), new AstConst($1, 0)); } | yD_RIGHT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_RIGHT,$3,NULL); } @@ -3382,11 +3401,11 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_SIZE '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_SIZE,$3,$5); } | yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); } | yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); } - | yD_STIME parenE { $$ = new AstSel($1,new AstTime($1),0,32); } + | yD_STIME parenE { $$ = new AstSel($1, new AstTime($1, VTimescale(VTimescale::NONE)), 0, 32); } | yD_TAN '(' expr ')' { $$ = new AstTanD($1,$3); } | yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); } | yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); } - | yD_TIME parenE { $$ = new AstTime($1); } + | yD_TIME parenE { $$ = new AstTime($1, VTimescale(VTimescale::NONE)); } | yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf($1, AstAttrType::TYPENAME, $3); } | yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC($1, $5, $3); } // Arg swap to file first | yD_UNPACKED_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); } @@ -3779,7 +3798,7 @@ expr: // IEEE: part of expression/constant_expression/primary // // IEEE: primary_literal (minus string, which is handled specially) | yaINTNUM { $$ = new AstConst($1,*$1); } | yaFLOATNUM { $$ = new AstConst($1,AstConst::RealDouble(),$1); } - //UNSUP yaTIMENUM { UNSUP } + | timeNumAdjusted { $$ = $1; } | strAsInt~noStr__IGNORE~ { $$ = $1; } // // // IEEE: "... hierarchical_identifier select" see below @@ -5728,6 +5747,14 @@ memberQualOne: // IEEE: property_qualifier + method_qualifier //UNSUP | ySTATIC__CONSTRAINT { $$ = true; } //UNSUP ; +//********************************************************************** +// Constants + +timeNumAdjusted: // Time constant, adjusted to module's time units/precision + yaTIMENUM + { $$ = new AstTimeImport($1, new AstConst($1, AstConst::RealDouble(), $1)); } + ; + //********************************************************************** // VLT Files diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 3e4731613..9ef588a21 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -35,16 +35,16 @@ $SIG{TERM} = sub { $Fork->kill_tree_all('TERM') if $Fork; die "Quitting...\n"; } # Map of all scenarios, with the names used to enable them our %All_Scenarios - = (dist => [ "dist"], - atsim => [ "simulator", "atsim"], - ghdl => ["linter", "simulator", "ghdl"], - iv => [ "simulator", "iv"], - ms => ["linter", "simulator", "ms"], - nc => ["linter", "simulator", "nc"], - vcs => ["linter", "simulator", "vcs"], - xsim => ["linter", "simulator", "xsim"], - vlt => ["linter", "simulator", "vlt_all", "vlt"], - vltmt => [ "simulator", "vlt_all", "vltmt"], + = (dist => [ "dist"], + atsim => [ "simulator", "simulator_st", "atsim"], + ghdl => ["linter", "simulator", "simulator_st", "ghdl"], + iv => [ "simulator", "simulator_st", "iv"], + ms => ["linter", "simulator", "simulator_st", "ms"], + nc => ["linter", "simulator", "simulator_st", "nc"], + vcs => ["linter", "simulator", "simulator_st", "vcs"], + xsim => ["linter", "simulator", "simulator_st", "xsim"], + vlt => ["linter", "simulator", "simulator_st", "vlt_all", "vlt"], + vltmt => [ "simulator", "vlt_all", "vltmt"], ); #====================================================================== @@ -546,6 +546,7 @@ sub new { make_top_shell => 1, # Make a default __top.v file make_main => 1, # Make __main.cpp make_pli => 0, # need to compile pli + sc_time_resolution => "SC_PS", # Keep - PS is SystemC default sim_time => 1100, benchmark => $opt_benchmark, verbose => $opt_verbose, @@ -1613,7 +1614,7 @@ sub _make_main { my $fh = IO::File->new(">$filename") or die "%Error: $! $filename,"; print $fh "// Test defines\n"; - print $fh "#define VL_TIME_MULTIPLIER $self->{vl_time_multiplier}\n" if $self->{vl_time_multiplier}; + print $fh "#define MAIN_TIME_MULTIPLIER ".($self->{main_time_multiplier} || 1)."\n"; print $fh "// OS header\n"; print $fh "#include \"verilatedos.h\"\n"; @@ -1632,8 +1633,13 @@ sub _make_main { print $fh "$VM_PREFIX* topp;\n"; if (!$self->sc) { - print $fh "vluint64_t main_time = false;\n"; - print $fh "double sc_time_stamp() { return main_time; }\n"; + if ($self->{vl_time_stamp64}) { + print $fh "vluint64_t main_time = 0;\n"; + print $fh "vluint64_t vl_time_stamp() { return main_time; }\n"; + } else { + print $fh "double main_time = 0;\n"; + print $fh "double sc_time_stamp() { return main_time; }\n"; + } } if ($self->{savable}) { @@ -1663,7 +1669,8 @@ sub _make_main { print $fh "int sc_main(int argc, char** argv) {\n"; print $fh " sc_signal fastclk;\n" if $self->{inputs}{fastclk}; print $fh " sc_signal clk;\n" if $self->{inputs}{clk}; - print $fh " sc_time sim_time($self->{sim_time}, SC_NS);\n"; + print $fh " sc_set_time_resolution(1, $Self->{sc_time_resolution});\n"; + print $fh " sc_time sim_time($self->{sim_time}, $Self->{sc_time_resolution});\n"; } else { print $fh "int main(int argc, char** argv, char** env) {\n"; print $fh " double sim_time = $self->{sim_time};\n"; @@ -1719,7 +1726,8 @@ sub _make_main { _print_advance_time($self, $fh, 10); print $fh " }\n"; - print $fh " while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {\n"; + print $fh " while ((sc_time_stamp() < sim_time * MAIN_TIME_MULTIPLIER)\n"; + print $fh " && !Verilated::gotFinish()) {\n"; for (my $i=0; $i<5; $i++) { my $action = 0; if ($self->{inputs}{fastclk}) { @@ -1775,7 +1783,7 @@ sub _print_advance_time { if ($self->sc) { print $fh "#if (SYSTEMC_VERSION>=20070314)\n"; - print $fh " sc_start(${time}, SC_NS);\n"; + print $fh " sc_start(${time}, $Self->{sc_time_resolution});\n"; print $fh "#else\n"; print $fh " sc_start(${time});\n"; print $fh "#endif\n"; @@ -1788,7 +1796,7 @@ sub _print_advance_time { $fh->print("#endif // VM_TRACE\n"); } } - print $fh " main_time += ${time};\n"; + print $fh " main_time += ${time} * MAIN_TIME_MULTIPLIER;\n"; } } diff --git a/test_regress/t/t_clocker.out b/test_regress/t/t_clocker.out index 62637a38f..61a98ebaa 100644 --- a/test_regress/t/t_clocker.out +++ b/test_regress/t/t_clocker.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Fri Jun 22 19:23:24 2018 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 $ clk $end diff --git a/test_regress/t/t_cover_line_trace.out b/test_regress/t/t_cover_line_trace.out index 67983b6bd..d328b8b1b 100644 --- a/test_regress/t/t_cover_line_trace.out +++ b/test_regress/t/t_cover_line_trace.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Thu Mar 19 18:37:02 2020 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 5! clk $end diff --git a/test_regress/t/t_cover_sva_trace.out b/test_regress/t/t_cover_sva_trace.out index 948b88e77..b51a11853 100644 --- a/test_regress/t/t_cover_sva_trace.out +++ b/test_regress/t/t_cover_sva_trace.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Thu Oct 24 09:44:07 2019 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 ) clk $end diff --git a/test_regress/t/t_display_time.out b/test_regress/t/t_display_time.out index 04a719c8f..12f056d38 100644 --- a/test_regress/t/t_display_time.out +++ b/test_regress/t/t_display_time.out @@ -1,3 +1,3 @@ -default: [10.000] 0t time [ 10.000] No0 time p= 10000 0p='h2710 +default: [10] 0t time [ 10] No0 time p= 10 0p='ha *-* All Finished *-* diff --git a/test_regress/t/t_display_time.pl b/test_regress/t/t_display_time.pl index b0a9c5416..b4e259e0a 100755 --- a/test_regress/t/t_display_time.pl +++ b/test_regress/t/t_display_time.pl @@ -11,8 +11,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ['-DVL_TIME_MULTIPLER=1000'], - make_flags => 'CPPFLAGS_ADD=-DVL_TIME_MULTIPLIER=1000', ); execute( diff --git a/test_regress/t/t_display_wide.out b/test_regress/t/t_display_wide.out index 73da012fd..26d4c5c73 100644 --- a/test_regress/t/t_display_wide.out +++ b/test_regress/t/t_display_wide.out @@ -1,3 +1,3 @@ -[1000.000] cyc==99 crc=2961926edde3e5c6018be970cdbf327b72b5f3c5eab42995891005eec8767e5fdf03051edbe9d222ee756ee34d8d6c83ee877aad65c487140ac87d26c636a66214b4a69acad924c568cc8e8c79f97d07a6eedf91011919d0e3cdda5215ee58c942f6c4dea48b3f38abc77bf47e4f6d6a859fcc5b5d46ec9d2f6a5bf7b978b1ba7ca15d0713a2eb06ade1570c4e3a12db687625eef8dfebcb4095ab4bdffe79c1298f609307a5ef773a6432b855e3e54deb88ca342bf5a7fecc5f2f3e165a59cdb9179718a2d11c9d55f14d69f40b01e41fcb7335a8872a6ba7876ec684d6a3af0b82aa31cca6e26340a2589cf7bf886faa8d23844596dc71233c7025c5250a968b770ab72db90b03d8c045fb8848159df544a3a3bf063269be0aa11d5507f5c8b328b760a6df9e3fbe276faad8eadee126443ad3f99d595b12d0ae514b20693298a58642a07718f9ab7ea8c66575f7f8d0e3ba77d992235b3d5a4e015a7ff9b97a8c4f48ebdbfc2365e6bca4dd3ba6bfc7e850f7c8e2842c717a1d85a977a033f564fc -[1000.000] cyc==99 crc=001010010110000110010010011011101101110111100011111001011100011000000001100010111110100101110000110011011011111100110010011110110111001010110101111100111100010111101010101101000010100110010101100010010001000000000101111011101100100001110110011111100101111111011111000000110000010100011110110110111110100111010010001000101110111001110101011011101110001101001101100011010110110010000011111011101000011101111010101011010110010111000100100001110001010000001010110010000111110100100110110001100011011010100110011000100001010010110100101001101001101011001010110110010010010011000101011010001100110010001110100011000111100111111001011111010000011110100110111011101101111110010001000000010001100100011001110100001110001111001101110110100101001000010101111011100101100011001001010000101111011011000100110111101010010010001011001111110011100010101011110001110111101111110100011111100100111101101101011010101000010110011111110011000101101101011101010001101110110010011101001011110110101001011011111101111011100101111000101100011011101001111100101000010101110100000111000100111010001011101011000001101010110111100001010101110000110001001110001110100001001011011011011010000111011000100101111011101111100011011111111010111100101101000000100101011010101101001011110111111111111001111001110000010010100110001111011000001001001100000111101001011110111101110111001110100110010000110010101110000101010111100011111001010100110111101011100010001100101000110100001010111111010110100111111111101100110001011111001011110011111000010110010110100101100111001101101110010001011110010111000110001010001011010001000111001001110101010101111100010100110101101001111101000000101100000001111001000001111111001011011100110011010110101000100001110010101001101011101001111000011101101110110001101000010011010110101000111010111100001011100000101010101000110001110011001010011011100010011000110100000010100010010110001001110011110111101111111000100001101111101010101000110100100011100001000100010110010110110111000111000100100011001111000111000000100101110001010010010100001010100101101000101101110111000010101011011100101101101110010000101100000011110110001100000001000101111110111000100001001000000101011001110111110101010001001010001110100011101111110000011000110010011010011011111000001010101000010001110101010101000001111111010111001000101100110010100010110111011000001010011011011111100111100011111110111110001001110110111110101010110110001110101011011110111000010010011001000100001110101101001111111001100111010101100101011011000100101101000010101110010100010100101100100000011010010011001010011000101001011000011001000010101000000111011100011000111110011010101101111110101010001100011001100101011101011111011111111000110100001110001110111010011101111101100110010010001000110101101100111101010110100100111000000001010110100111111111111001101110010111101010001100010011110100100011101011110110111111110000100011011001011110011010111100101001001101110100111011101001101011111111000111111010000101000011110111110010001110001010000100001011000111000101111010000111011000010110101001011101111010000000110011111101010110010011111100 +[1000] cyc==99 crc=2961926edde3e5c6018be970cdbf327b72b5f3c5eab42995891005eec8767e5fdf03051edbe9d222ee756ee34d8d6c83ee877aad65c487140ac87d26c636a66214b4a69acad924c568cc8e8c79f97d07a6eedf91011919d0e3cdda5215ee58c942f6c4dea48b3f38abc77bf47e4f6d6a859fcc5b5d46ec9d2f6a5bf7b978b1ba7ca15d0713a2eb06ade1570c4e3a12db687625eef8dfebcb4095ab4bdffe79c1298f609307a5ef773a6432b855e3e54deb88ca342bf5a7fecc5f2f3e165a59cdb9179718a2d11c9d55f14d69f40b01e41fcb7335a8872a6ba7876ec684d6a3af0b82aa31cca6e26340a2589cf7bf886faa8d23844596dc71233c7025c5250a968b770ab72db90b03d8c045fb8848159df544a3a3bf063269be0aa11d5507f5c8b328b760a6df9e3fbe276faad8eadee126443ad3f99d595b12d0ae514b20693298a58642a07718f9ab7ea8c66575f7f8d0e3ba77d992235b3d5a4e015a7ff9b97a8c4f48ebdbfc2365e6bca4dd3ba6bfc7e850f7c8e2842c717a1d85a977a033f564fc +[1000] cyc==99 crc=001010010110000110010010011011101101110111100011111001011100011000000001100010111110100101110000110011011011111100110010011110110111001010110101111100111100010111101010101101000010100110010101100010010001000000000101111011101100100001110110011111100101111111011111000000110000010100011110110110111110100111010010001000101110111001110101011011101110001101001101100011010110110010000011111011101000011101111010101011010110010111000100100001110001010000001010110010000111110100100110110001100011011010100110011000100001010010110100101001101001101011001010110110010010010011000101011010001100110010001110100011000111100111111001011111010000011110100110111011101101111110010001000000010001100100011001110100001110001111001101110110100101001000010101111011100101100011001001010000101111011011000100110111101010010010001011001111110011100010101011110001110111101111110100011111100100111101101101011010101000010110011111110011000101101101011101010001101110110010011101001011110110101001011011111101111011100101111000101100011011101001111100101000010101110100000111000100111010001011101011000001101010110111100001010101110000110001001110001110100001001011011011011010000111011000100101111011101111100011011111111010111100101101000000100101011010101101001011110111111111111001111001110000010010100110001111011000001001001100000111101001011110111101110111001110100110010000110010101110000101010111100011111001010100110111101011100010001100101000110100001010111111010110100111111111101100110001011111001011110011111000010110010110100101100111001101101110010001011110010111000110001010001011010001000111001001110101010101111100010100110101101001111101000000101100000001111001000001111111001011011100110011010110101000100001110010101001101011101001111000011101101110110001101000010011010110101000111010111100001011100000101010101000110001110011001010011011100010011000110100000010100010010110001001110011110111101111111000100001101111101010101000110100100011100001000100010110010110110111000111000100100011001111000111000000100101110001010010010100001010100101101000101101110111000010101011011100101101101110010000101100000011110110001100000001000101111110111000100001001000000101011001110111110101010001001010001110100011101111110000011000110010011010011011111000001010101000010001110101010101000001111111010111001000101100110010100010110111011000001010011011011111100111100011111110111110001001110110111110101010110110001110101011011110111000010010011001000100001110101101001111111001100111010101100101011011000100101101000010101110010100010100101100100000011010010011001010011000101001011000011001000010101000000111011100011000111110011010101101111110101010001100011001100101011101011111011111111000110100001110001110111010011101111101100110010010001000110101101100111101010110100100111000000001010110100111111111111001101110010111101010001100010011110100100011101011110110111111110000100011011001011110011010111100101001001101110100111011101001101011111111000111111010000101000011110111110010001110001010000100001011000111000101111010000111011000010110101001011101111010000000110011111101010110010011111100 *-* All Finished *-* diff --git a/test_regress/t/t_display_wide.pl b/test_regress/t/t_display_wide.pl index 6c6caeae2..b4e259e0a 100755 --- a/test_regress/t/t_display_wide.pl +++ b/test_regress/t/t_display_wide.pl @@ -11,7 +11,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - make_flags => 'CPPFLAGS_ADD=-DVL_TIME_MULTIPLIER=1000', ); execute( diff --git a/test_regress/t/t_flag_timescale.out b/test_regress/t/t_flag_timescale.out new file mode 100644 index 000000000..b82ab0b9a --- /dev/null +++ b/test_regress/t/t_flag_timescale.out @@ -0,0 +1,2 @@ +Time scale of t is 1ms / 1us +*-* All Finished *-* diff --git a/test_regress/t/t_flag_timescale.pl b/test_regress/t/t_flag_timescale.pl new file mode 100755 index 000000000..ba5fd3fa2 --- /dev/null +++ b/test_regress/t/t_flag_timescale.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["-timescale 1ms/1us"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_flag_timescale.v b/test_regress/t/t_flag_timescale.v new file mode 100644 index 000000000..ed019c442 --- /dev/null +++ b/test_regress/t/t_flag_timescale.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial begin + $printtimescale; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_flag_timescale_override.out b/test_regress/t/t_flag_timescale_override.out new file mode 100644 index 000000000..b82ab0b9a --- /dev/null +++ b/test_regress/t/t_flag_timescale_override.out @@ -0,0 +1,2 @@ +Time scale of t is 1ms / 1us +*-* All Finished *-* diff --git a/test_regress/t/t_flag_timescale_override.pl b/test_regress/t/t_flag_timescale_override.pl new file mode 100755 index 000000000..b4f4fe235 --- /dev/null +++ b/test_regress/t/t_flag_timescale_override.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["-timescale-override 1ms/1us"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_flag_timescale_override.v b/test_regress/t/t_flag_timescale_override.v new file mode 100644 index 000000000..61ebcfd56 --- /dev/null +++ b/test_regress/t/t_flag_timescale_override.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`timescale 1s/1s + +module t; + initial begin + $printtimescale; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_flag_timescale_override2.out b/test_regress/t/t_flag_timescale_override2.out new file mode 100644 index 000000000..3a0d42216 --- /dev/null +++ b/test_regress/t/t_flag_timescale_override2.out @@ -0,0 +1,2 @@ +Time scale of t is 1s / 1us +*-* All Finished *-* diff --git a/test_regress/t/t_flag_timescale_override2.pl b/test_regress/t/t_flag_timescale_override2.pl new file mode 100755 index 000000000..458364b16 --- /dev/null +++ b/test_regress/t/t_flag_timescale_override2.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_flag_timescale_override.v"); + +compile( + verilator_flags2 => ["-timescale-override /1us"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_inst_sv.v b/test_regress/t/t_inst_sv.v index ebde35b38..c69208500 100644 --- a/test_regress/t/t_inst_sv.v +++ b/test_regress/t/t_inst_sv.v @@ -9,11 +9,6 @@ module t (/*AUTOARG*/ clk ); -`ifdef verilator // Otherwise need it in every module, including test, but that'll make a mess - timeunit 1ns; - timeprecision 1ns; -`endif - input clk; integer cyc; initial cyc=1; diff --git a/test_regress/t/t_interface_ref_trace.out b/test_regress/t/t_interface_ref_trace.out index be8ffdd44..75875933b 100644 --- a/test_regress/t/t_interface_ref_trace.out +++ b/test_regress/t/t_interface_ref_trace.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Wed Dec 4 07:47:51 2019 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 0 clk $end diff --git a/test_regress/t/t_math_real_public.v b/test_regress/t/t_math_real_public.v index 55ecd1d4b..8f5e46fd2 100644 --- a/test_regress/t/t_math_real_public.v +++ b/test_regress/t/t_math_real_public.v @@ -9,9 +9,6 @@ module t; endmodule module sub (); - timeunit 1ns; - timeprecision 1ps; - parameter REAL = 0.0; initial begin diff --git a/test_regress/t/t_order_clkinst.out b/test_regress/t/t_order_clkinst.out index a26ba0c26..2c1d5771e 100644 --- a/test_regress/t/t_order_clkinst.out +++ b/test_regress/t/t_order_clkinst.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Fri Jun 22 19:27:45 2018 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 / clk $end diff --git a/test_regress/t/t_split_var_2_trace.out b/test_regress/t/t_split_var_2_trace.out index b922cd557..6b7342255 100644 --- a/test_regress/t/t_split_var_2_trace.out +++ b/test_regress/t/t_split_var_2_trace.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Tue Feb 11 16:07:02 2020 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 o2 clk $end diff --git a/test_regress/t/t_time_literals.pl b/test_regress/t/t_time_literals.pl new file mode 100755 index 000000000..48c6bfa36 --- /dev/null +++ b/test_regress/t/t_time_literals.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_time_literals.v b/test_regress/t/t_time_literals.v new file mode 100644 index 000000000..c4de10979 --- /dev/null +++ b/test_regress/t/t_time_literals.v @@ -0,0 +1,32 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +`timescale 1ns/1ps + +module t; + time t; + + // realtime value scaled to timeunit, rounded to timeprecision + initial begin + // verilator lint_off REALCVT + t = 1s; `checkd(t, 64'd1000000000); + t = 2ms; `checkd(t, 2000000); + t = 1ms; `checkd(t, 1000000); + t = 1us; `checkd(t, 1000); + t = 1ns; `checkd(t, 1); + t = 1ps; `checkd(t, 0); // Below precision + t = 1fs; `checkd(t, 0); + + t = 2.3ps; `checkd(t, 0); + t = 2.4us; `checkd(t, 2400); + // verilator lint_on REALCVT + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_time_passed.out b/test_regress/t/t_time_passed.out new file mode 100644 index 000000000..c2bb36267 --- /dev/null +++ b/test_regress/t/t_time_passed.out @@ -0,0 +1,3 @@ +top.t.ps: Input time 5432109.877000ns 5432109877 +top.t.ns: Input time 5432109877.000000ns 5432109877 +*-* All Finished *-* diff --git a/test_regress/t/t_time_passed.pl b/test_regress/t/t_time_passed.pl new file mode 100755 index 000000000..2934909ea --- /dev/null +++ b/test_regress/t/t_time_passed.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_passed.v b/test_regress/t/t_time_passed.v new file mode 100644 index 000000000..ddc1b7185 --- /dev/null +++ b/test_regress/t/t_time_passed.v @@ -0,0 +1,64 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`timescale 1ns/1ps +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + + time in; + // verilator lint_off REALCVT + initial in = 5432109876.543210ns; // Will round to time units + // verilator lint_on REALCVT + + // This shows time changes when passed between modules with different units + // See also discussion in uvm_tlm2_time.svh + + ps ps (.*); + ns ns (.*); + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 60) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule + +`timescale 1ps/1ps + +module ps + (input clk, + input integer cyc, + input time in); + + always @ (posedge clk) begin + if (cyc == 10) begin + $timeformat(-9, 6, "ns", 16); + $write("%m: Input time %t %d\n", in, in); + end + end +endmodule + +`timescale 1ns/1ps + +module ns + (input clk, + input integer cyc, + input time in); + + always @ (posedge clk) begin + if (cyc == 20) begin + $timeformat(-9, 6, "ns", 16); + $write("%m: Input time %t %d\n", in, in); + end + end +endmodule diff --git a/test_regress/t/t_time_print.out b/test_regress/t/t_time_print.out new file mode 100644 index 000000000..57de4fd5b --- /dev/null +++ b/test_regress/t/t_time_print.out @@ -0,0 +1,10 @@ +[0] In top.t: Hi +Time scale of t is 1ns / 1ps +Time: ' 0' 10ns=10000 +Time: ' 0-my-ms' 10ns=0-my-ms +Time: ' 0.0-my-ms' 10ns=0.0-my-ms +Time: ' 0.00-my-us' 10ns=0.01-my-us +Time: ' 0.000-my-ns' 10ns=10.000-my-ns +Time: ' 0.000-my-ps' 10ns=10000.000-my-ps +Time: ' 0.0000-my-fs' 10ns=10000000.0000-my-fs +*-* All Finished *-* diff --git a/test_regress/t/t_time_print.pl b/test_regress/t/t_time_print.pl new file mode 100755 index 000000000..2934909ea --- /dev/null +++ b/test_regress/t/t_time_print.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_print.v b/test_regress/t/t_time_print.v new file mode 100644 index 000000000..cda0c811a --- /dev/null +++ b/test_regress/t/t_time_print.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + + timeunit 1ns; + timeprecision 1ps; + + time t; + + initial begin + t = 10ns; + + $write("[%0t] In %m: Hi\n", $time); + $printtimescale; + + $write("Time: '%t' 10ns=%0t\n", $time, t); + $timeformat(-3, 0, "-my-ms", 8); + $write("Time: '%t' 10ns=%0t\n", $time, t); + $timeformat(-3, 1, "-my-ms", 10); + $write("Time: '%t' 10ns=%0t\n", $time, t); + $timeformat(-6, 2, "-my-us", 12); + $write("Time: '%t' 10ns=%0t\n", $time, t); + $timeformat(-9, 3, "-my-ns", 13); + $write("Time: '%t' 10ns=%0t\n", $time, t); + $timeformat(-12, 3, "-my-ps", 13); + $write("Time: '%t' 10ns=%0t\n", $time, t); + $timeformat(-15, 4, "-my-fs", 14); + $write("Time: '%t' 10ns=%0t\n", $time, t); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_time_sc.v b/test_regress/t/t_time_sc.v new file mode 100644 index 000000000..50f48f359 --- /dev/null +++ b/test_regress/t/t_time_sc.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + + time texpect = `TEST_EXPECT; + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 1) begin + $printtimescale; + $write("[%0t] In %m: Hi - expect this is %0t\n", $time, texpect); + if ($time != texpect) begin + $write("[%0t] delta = %d\n", $time, $time - texpect); + $stop; + end + $write("*-* All Finished *-*\n"); + $finish; + end + + end +endmodule diff --git a/test_regress/t/t_time_sc_bad.out b/test_regress/t/t_time_sc_bad.out new file mode 100644 index 000000000..fb65dcdf0 --- /dev/null +++ b/test_regress/t/t_time_sc_bad.out @@ -0,0 +1,2 @@ +%Error: SystemC's sc_set_time_resolution is 10^-9, which does not match Verilog timeprecision 10^-12. Suggest use 'sc_set_time_resolution(1ps)', or Verilator '--timescale-override 1ns/1ns' +Aborting... diff --git a/test_regress/t/t_time_sc_bad.pl b/test_regress/t/t_time_sc_bad.pl new file mode 100755 index 000000000..3a854f25d --- /dev/null +++ b/test_regress/t/t_time_sc_bad.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_time_sc.v"); + +$Self->{sc_time_resolution} = 'SC_NS'; + +compile( + verilator_flags2 => ['-sc', '-timescale 1ps/1ps', # Mismatch w/sc_time_resolution + '+define+TEST_EXPECT=2us'], + ); + +execute( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_sc_fs.out b/test_regress/t/t_time_sc_fs.out new file mode 100644 index 000000000..2379bc68f --- /dev/null +++ b/test_regress/t/t_time_sc_fs.out @@ -0,0 +1,3 @@ +Time scale of t is 1fs / 1fs +[20] In top.t: Hi - expect this is 20 +*-* All Finished *-* diff --git a/test_regress/t/t_time_sc_fs.pl b/test_regress/t/t_time_sc_fs.pl new file mode 100755 index 000000000..7bb640bfe --- /dev/null +++ b/test_regress/t/t_time_sc_fs.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_time_sc.v"); + +$Self->{sc_time_resolution} = 'SC_FS'; + +compile( + verilator_flags2 => ['-sc', '-timescale 1fs/1fs', + '+define+TEST_EXPECT=20fs'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_sc_ms.out b/test_regress/t/t_time_sc_ms.out new file mode 100644 index 000000000..1c323b169 --- /dev/null +++ b/test_regress/t/t_time_sc_ms.out @@ -0,0 +1,6 @@ + +Warning: (W516) default time unit changed to time resolution +In file: /svaha/sicortex/eda/systemc/systemc-2.3.3/systemc-2.3.3/src/sysc/kernel/sc_time.cpp:412 +Time scale of t is 1ms / 1ms +[20] In top.t: Hi - expect this is 20 +*-* All Finished *-* diff --git a/test_regress/t/t_time_sc_ms.pl b/test_regress/t/t_time_sc_ms.pl new file mode 100755 index 000000000..12e800db8 --- /dev/null +++ b/test_regress/t/t_time_sc_ms.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_time_sc.v"); + +$Self->{sc_time_resolution} = 'SC_MS'; + +compile( + verilator_flags2 => ['-sc', '-timescale 1ms/1ms', + '+define+TEST_EXPECT=20ms'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_sc_ns.out b/test_regress/t/t_time_sc_ns.out new file mode 100644 index 000000000..6e03c9734 --- /dev/null +++ b/test_regress/t/t_time_sc_ns.out @@ -0,0 +1,3 @@ +Time scale of t is 1ns / 1ns +[20] In top.t: Hi - expect this is 20 +*-* All Finished *-* diff --git a/test_regress/t/t_time_sc_ns.pl b/test_regress/t/t_time_sc_ns.pl new file mode 100755 index 000000000..a9822649a --- /dev/null +++ b/test_regress/t/t_time_sc_ns.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_time_sc.v"); + +$Self->{sc_time_resolution} = 'SC_NS'; + +compile( + verilator_flags2 => ['-sc', '-timescale 1ns/1ns', + '+define+TEST_EXPECT=20ns'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_sc_sec.out b/test_regress/t/t_time_sc_sec.out new file mode 100644 index 000000000..545cd35d0 --- /dev/null +++ b/test_regress/t/t_time_sc_sec.out @@ -0,0 +1,6 @@ + +Warning: (W516) default time unit changed to time resolution +In file: /svaha/sicortex/eda/systemc/systemc-2.3.3/systemc-2.3.3/src/sysc/kernel/sc_time.cpp:412 +Time scale of t is 1s / 1s +[20] In top.t: Hi - expect this is 20 +*-* All Finished *-* diff --git a/test_regress/t/t_time_sc_sec.pl b/test_regress/t/t_time_sc_sec.pl new file mode 100755 index 000000000..bc1136ae2 --- /dev/null +++ b/test_regress/t/t_time_sc_sec.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_time_sc.v"); + +$Self->{sc_time_resolution} = 'SC_SEC'; + +compile( + verilator_flags2 => ['-sc', '-timescale 1s/1s', + '+define+TEST_EXPECT=20s'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_sc_us.out b/test_regress/t/t_time_sc_us.out new file mode 100644 index 000000000..bfcaa2024 --- /dev/null +++ b/test_regress/t/t_time_sc_us.out @@ -0,0 +1,6 @@ + +Warning: (W516) default time unit changed to time resolution +In file: /svaha/sicortex/eda/systemc/systemc-2.3.3/systemc-2.3.3/src/sysc/kernel/sc_time.cpp:412 +Time scale of t is 1us / 1us +[20] In top.t: Hi - expect this is 20 +*-* All Finished *-* diff --git a/test_regress/t/t_time_sc_us.pl b/test_regress/t/t_time_sc_us.pl new file mode 100755 index 000000000..7c3769370 --- /dev/null +++ b/test_regress/t/t_time_sc_us.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_time_sc.v"); + +$Self->{sc_time_resolution} = 'SC_US'; + +compile( + verilator_flags2 => ['-sc', '-timescale 1us/1us', + '+define+TEST_EXPECT=20us'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_stamp64.pl b/test_regress/t/t_time_stamp64.pl new file mode 100755 index 000000000..27bf74bb1 --- /dev/null +++ b/test_regress/t/t_time_stamp64.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +# Verilator before 4.033 had 'double sc_time_stamp()', make sure new form compiles +$self->{vl_time_stamp64} = 1; + +compile( + verilator_flags2 => ['-DVL_TIME_STAMP64=1'], + ); + +execute( + check_finished => 1, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_stamp64.v b/test_regress/t/t_time_stamp64.v new file mode 100644 index 000000000..2c965a83c --- /dev/null +++ b/test_regress/t/t_time_stamp64.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 1) begin + $write("[%0t] In %m: Hi\n", $time); + $printtimescale; + $write("*-* All Finished *-*\n"); + $finish; + end + + end +endmodule diff --git a/test_regress/t/t_time_stamp_double.pl b/test_regress/t/t_time_stamp_double.pl new file mode 100755 index 000000000..d86b6b3af --- /dev/null +++ b/test_regress/t/t_time_stamp_double.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +top_filename('t/t_time_stamp64.v'); + +# Verilator before 4.033 had 'double sc_time_stamp()', make sure this still compiles +$self->{vl_time_stamp64} = 0; + +compile( + verilator_flags2 => [], + ); + +execute( + check_finished => 1, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_vpi.v b/test_regress/t/t_time_vpi.v new file mode 100644 index 000000000..84496b256 --- /dev/null +++ b/test_regress/t/t_time_vpi.v @@ -0,0 +1,50 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`timescale `time_scale_units / `time_scale_prec + +import "DPI-C" function void dpii_check(); + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + // verilator lint_off REALCVT + time digits = 5432109876.543210ns; // Will round to time units + realtime rdigits = 5432109876.543210ns; // Will round to time precision + // verilator lint_on REALCVT + + always @ (posedge clk) begin + cyc <= cyc + 1; +`ifdef TEST_VERBOSE + $write("- [%0t] tick\n", $time); +`endif + if ($time >= 60) begin + $write(":: In %m\n"); + $printtimescale; + $write("[%0t] time%%0d=%0d 123%%0t=%0t\n", $time, $time, 123); + $write(" dig%%0t=%0t dig%%0d=%0d\n", digits, digits); + $write(" rdig%%0t=%0t rdig%%0f=%0f\n", rdigits, rdigits); + $timeformat(-9, 6, "ns", 16); + $write("[%0t] time%%0d=%0d 123%%0t=%0t\n", $time, $time, 123); + $write(" dig%%0t=%0t dig%%0d=%0d\n", digits, digits); + $write(" rdig%%0t=%0t rdig%%0f=%0f\n", rdigits, rdigits); + $write("[%0t] stime%%0t=%0t stime%%0d=%0d stime%%0f=%0f\n", + $time, $stime, $stime, $stime); + // verilator lint_off REALCVT + $write("[%0t] rtime%%0t=%0t rtime%%0d=%0d rtime%%0f=%0f\n", + $time, $realtime, $realtime, $realtime); + // verilator lint_on REALCVT + dpii_check(); + $write("*-* All Finished *-*\n"); + $finish; + end + + end +endmodule diff --git a/test_regress/t/t_time_vpi_10ms10ns.out b/test_regress/t/t_time_vpi_10ms10ns.out new file mode 100644 index 000000000..a561b40c3 --- /dev/null +++ b/test_regress/t/t_time_vpi_10ms10ns.out @@ -0,0 +1,15 @@ +:: In top.t +Time scale of t is 10ms / 10ns +[60000000] time%0d=60 123%0t=123000000 + dig%0t=543000000 dig%0d=543 + rdig%0t=543210987 rdig%0f=543.210988 +[600000000.000000ns] time%0d=60 123%0t=1230000000.000000ns + dig%0t=5430000000.000000ns dig%0d=543 + rdig%0t=5432109876.543210ns rdig%0f=543.210988 +[600000000.000000ns] stime%0t=600000000.000000ns stime%0d=60 stime%0f=60.000000 +[600000000.000000ns] rtime%0t=600000000.000000ns rtime%0d=60 rtime%0f=60.000000 +global vpiSimTime = 0,60000000 vpiScaledRealTime = 6e+07 +global vpiTimeUnit = -2 vpiTimePrecision = -8 +top.t vpiSimTime = 0,60000000 vpiScaledRealTime = 60 +top.t vpiTimeUnit = -2 vpiTimePrecision = -8 +*-* All Finished *-* diff --git a/test_regress/t/t_time_vpi_10ms10ns.pl b/test_regress/t/t_time_vpi_10ms10ns.pl new file mode 100755 index 000000000..6a32278b3 --- /dev/null +++ b/test_regress/t/t_time_vpi_10ms10ns.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator_st => 1); + +top_filename("t/t_time_vpi.v"); + +$Self->{main_time_multiplier} = 10e-3 / 10e-9; + +compile( + v_flags2 => ['+define+time_scale_units=10ms +define+time_scale_prec=10ns', + 't/t_time_vpi_c.cpp'], + verilator_flags2 => ['--vpi'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_vpi_1fs1fs.out b/test_regress/t/t_time_vpi_1fs1fs.out new file mode 100644 index 000000000..680d87168 --- /dev/null +++ b/test_regress/t/t_time_vpi_1fs1fs.out @@ -0,0 +1,15 @@ +:: In top.t +Time scale of t is 1fs / 1fs +[60] time%0d=60 123%0t=123 + dig%0t=5432109876543210 dig%0d=5432109876543210 + rdig%0t=5432109876543210 rdig%0f=5432109876543210.000000 +[0.000060ns] time%0d=60 123%0t=0.000123ns + dig%0t=5432109876.543210ns dig%0d=5432109876543210 + rdig%0t=5432109876.543210ns rdig%0f=5432109876543210.000000 +[0.000060ns] stime%0t=0.000060ns stime%0d=60 stime%0f=60.000000 +[0.000060ns] rtime%0t=0.000060ns rtime%0d=60 rtime%0f=60.000000 +global vpiSimTime = 0,60 vpiScaledRealTime = 60 +global vpiTimeUnit = -15 vpiTimePrecision = -15 +top.t vpiSimTime = 0,60 vpiScaledRealTime = 60 +top.t vpiTimeUnit = -15 vpiTimePrecision = -15 +*-* All Finished *-* diff --git a/test_regress/t/t_time_vpi_1fs1fs.pl b/test_regress/t/t_time_vpi_1fs1fs.pl new file mode 100755 index 000000000..7b8e47860 --- /dev/null +++ b/test_regress/t/t_time_vpi_1fs1fs.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator_st => 1); + +top_filename("t/t_time_vpi.v"); + +$Self->{main_time_multiplier} = 1e-15 / 1e-15; + +compile( + v_flags2 => ['+define+time_scale_units=1fs +define+time_scale_prec=1fs', + 't/t_time_vpi_c.cpp'], + verilator_flags2 => ['--vpi'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_vpi_1ms10ns.out b/test_regress/t/t_time_vpi_1ms10ns.out new file mode 100644 index 000000000..90ce5a0ed --- /dev/null +++ b/test_regress/t/t_time_vpi_1ms10ns.out @@ -0,0 +1,15 @@ +:: In top.t +Time scale of t is 1ms / 10ns +[6000000] time%0d=60 123%0t=12300000 + dig%0t=543200000 dig%0d=5432 + rdig%0t=543210987 rdig%0f=5432.109877 +[60000000.000000ns] time%0d=60 123%0t=123000000.000000ns + dig%0t=5432000000.000000ns dig%0d=5432 + rdig%0t=5432109876.543210ns rdig%0f=5432.109877 +[60000000.000000ns] stime%0t=60000000.000000ns stime%0d=60 stime%0f=60.000000 +[60000000.000000ns] rtime%0t=60000000.000000ns rtime%0d=60 rtime%0f=60.000000 +global vpiSimTime = 0,6000000 vpiScaledRealTime = 6e+06 +global vpiTimeUnit = -3 vpiTimePrecision = -8 +top.t vpiSimTime = 0,6000000 vpiScaledRealTime = 60 +top.t vpiTimeUnit = -3 vpiTimePrecision = -8 +*-* All Finished *-* diff --git a/test_regress/t/t_time_vpi_1ms10ns.pl b/test_regress/t/t_time_vpi_1ms10ns.pl new file mode 100755 index 000000000..05fc59263 --- /dev/null +++ b/test_regress/t/t_time_vpi_1ms10ns.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator_st => 1); + +top_filename("t/t_time_vpi.v"); + +$Self->{main_time_multiplier} = 1e-3 / 10e-9; + +compile( + v_flags2 => ['+define+time_scale_units=1ms +define+time_scale_prec=10ns', + 't/t_time_vpi_c.cpp'], + verilator_flags2 => ['--vpi --trace'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +file_grep("$Self->{obj_dir}/simx.vcd", qr!timescale +10ns!); + +ok(1); + +1; diff --git a/test_regress/t/t_time_vpi_1ns1ns.out b/test_regress/t/t_time_vpi_1ns1ns.out new file mode 100644 index 000000000..b6dad7274 --- /dev/null +++ b/test_regress/t/t_time_vpi_1ns1ns.out @@ -0,0 +1,15 @@ +:: In top.t +Time scale of t is 1ns / 1ns +[60] time%0d=60 123%0t=123 + dig%0t=5432109877 dig%0d=5432109877 + rdig%0t=5432109876 rdig%0f=5432109876.543210 +[60.000000ns] time%0d=60 123%0t=123.000000ns + dig%0t=5432109877.000000ns dig%0d=5432109877 + rdig%0t=5432109876.543210ns rdig%0f=5432109876.543210 +[60.000000ns] stime%0t=60.000000ns stime%0d=60 stime%0f=60.000000 +[60.000000ns] rtime%0t=60.000000ns rtime%0d=60 rtime%0f=60.000000 +global vpiSimTime = 0,60 vpiScaledRealTime = 60 +global vpiTimeUnit = -9 vpiTimePrecision = -9 +top.t vpiSimTime = 0,60 vpiScaledRealTime = 60 +top.t vpiTimeUnit = -9 vpiTimePrecision = -9 +*-* All Finished *-* diff --git a/test_regress/t/t_time_vpi_1ns1ns.pl b/test_regress/t/t_time_vpi_1ns1ns.pl new file mode 100755 index 000000000..215358c27 --- /dev/null +++ b/test_regress/t/t_time_vpi_1ns1ns.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator_st => 1); + +top_filename("t/t_time_vpi.v"); + +$Self->{main_time_multiplier} = 1e-9 / 1e-9; + +compile( + v_flags2 => ['+define+time_scale_units=1ns +define+time_scale_prec=1ns', + 't/t_time_vpi_c.cpp'], + verilator_flags2 => ['--vpi --trace'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +file_grep("$Self->{obj_dir}/simx.vcd", qr!timescale +1ns!); + +ok(1); + +1; diff --git a/test_regress/t/t_time_vpi_1ps1fs.out b/test_regress/t/t_time_vpi_1ps1fs.out new file mode 100644 index 000000000..c4935bc16 --- /dev/null +++ b/test_regress/t/t_time_vpi_1ps1fs.out @@ -0,0 +1,15 @@ +:: In top.t +Time scale of t is 1ps / 1fs +[60000] time%0d=60 123%0t=123000 + dig%0t=5432109876543000 dig%0d=5432109876543 + rdig%0t=5432109876543209 rdig%0f=5432109876543.209961 +[0.060000ns] time%0d=60 123%0t=0.123000ns + dig%0t=5432109876.543000ns dig%0d=5432109876543 + rdig%0t=5432109876.543209ns rdig%0f=5432109876543.209961 +[0.060000ns] stime%0t=0.060000ns stime%0d=60 stime%0f=60.000000 +[0.060000ns] rtime%0t=0.059999ns rtime%0d=60 rtime%0f=60.000000 +global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 +global vpiTimeUnit = -12 vpiTimePrecision = -15 +top.t vpiSimTime = 0,60000 vpiScaledRealTime = 60 +top.t vpiTimeUnit = -12 vpiTimePrecision = -15 +*-* All Finished *-* diff --git a/test_regress/t/t_time_vpi_1ps1fs.pl b/test_regress/t/t_time_vpi_1ps1fs.pl new file mode 100755 index 000000000..4d172aefe --- /dev/null +++ b/test_regress/t/t_time_vpi_1ps1fs.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator_st => 1); + +top_filename("t/t_time_vpi.v"); + +$Self->{main_time_multiplier} = 1e-12 / 10e-15; + +compile( + v_flags2 => ['+define+time_scale_units=1ps +define+time_scale_prec=1fs', + 't/t_time_vpi_c.cpp'], + verilator_flags2 => ['--vpi'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_vpi_1s10ns.out b/test_regress/t/t_time_vpi_1s10ns.out new file mode 100644 index 000000000..ba22c32bb --- /dev/null +++ b/test_regress/t/t_time_vpi_1s10ns.out @@ -0,0 +1,15 @@ +:: In top.t +Time scale of t is 1s / 10ns +[6000000000] time%0d=60 123%0t=12300000000 + dig%0t=500000000 dig%0d=5 + rdig%0t=543210987 rdig%0f=5.432110 +[60000000000.000000ns] time%0d=60 123%0t=123000000000.000000ns + dig%0t=5000000000.000000ns dig%0d=5 + rdig%0t=5432109876.543210ns rdig%0f=5.432110 +[60000000000.000000ns] stime%0t=60000000000.000000ns stime%0d=60 stime%0f=60.000000 +[60000000000.000000ns] rtime%0t=60000000000.000000ns rtime%0d=60 rtime%0f=60.000000 +global vpiSimTime = 1,1705032704 vpiScaledRealTime = 6e+09 +global vpiTimeUnit = 0 vpiTimePrecision = -8 +top.t vpiSimTime = 1,1705032704 vpiScaledRealTime = 60 +top.t vpiTimeUnit = 0 vpiTimePrecision = -8 +*-* All Finished *-* diff --git a/test_regress/t/t_time_vpi_1s10ns.pl b/test_regress/t/t_time_vpi_1s10ns.pl new file mode 100755 index 000000000..f98926d02 --- /dev/null +++ b/test_regress/t/t_time_vpi_1s10ns.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator_st => 1); + +top_filename("t/t_time_vpi.v"); + +$Self->{main_time_multiplier} = 1e0 / 10e-9; + +compile( + v_flags2 => ['+define+time_scale_units=1s +define+time_scale_prec=10ns', + 't/t_time_vpi_c.cpp'], + verilator_flags2 => ['--vpi'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_vpi_1us1ns.out b/test_regress/t/t_time_vpi_1us1ns.out new file mode 100644 index 000000000..182c19aa7 --- /dev/null +++ b/test_regress/t/t_time_vpi_1us1ns.out @@ -0,0 +1,15 @@ +:: In top.t +Time scale of t is 1us / 1ns +[60000] time%0d=60 123%0t=123000 + dig%0t=5432110000 dig%0d=5432110 + rdig%0t=5432109876 rdig%0f=5432109.876543 +[60000.000000ns] time%0d=60 123%0t=123000.000000ns + dig%0t=5432110000.000000ns dig%0d=5432110 + rdig%0t=5432109876.543209ns rdig%0f=5432109.876543 +[60000.000000ns] stime%0t=60000.000000ns stime%0d=60 stime%0f=60.000000 +[60000.000000ns] rtime%0t=59999.999999ns rtime%0d=60 rtime%0f=60.000000 +global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 +global vpiTimeUnit = -6 vpiTimePrecision = -9 +top.t vpiSimTime = 0,60000 vpiScaledRealTime = 60 +top.t vpiTimeUnit = -6 vpiTimePrecision = -9 +*-* All Finished *-* diff --git a/test_regress/t/t_time_vpi_1us1ns.pl b/test_regress/t/t_time_vpi_1us1ns.pl new file mode 100755 index 000000000..6a5205e42 --- /dev/null +++ b/test_regress/t/t_time_vpi_1us1ns.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator_st => 1); + +top_filename("t/t_time_vpi.v"); + +$Self->{main_time_multiplier} = 1e-6 / 1e-9; + +compile( + v_flags2 => ['+define+time_scale_units=1us +define+time_scale_prec=1ns', + 't/t_time_vpi_c.cpp'], + verilator_flags2 => ['--vpi'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_vpi_c.cpp b/test_regress/t/t_time_vpi_c.cpp new file mode 100644 index 000000000..da3eb7f98 --- /dev/null +++ b/test_regress/t/t_time_vpi_c.cpp @@ -0,0 +1,62 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2009-2011 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include +#include "svdpi.h" +#include "vpi_user.h" + +//====================================================================== + +#define NEED_EXTERNS + +#ifdef NEED_EXTERNS +extern "C" { +extern void dpii_check(); +} +#endif + +//====================================================================== + +void show(vpiHandle obj) { + const char* namep; + if (obj) { + namep = vpi_get_str(vpiName, obj); + } else { + namep = "global"; + } + + s_vpi_time t; + t.type = vpiSimTime; + vpi_get_time(obj, &t); + vpi_printf(const_cast("%s vpiSimTime = %d,%d"), namep, (int)t.high, (int)t.low); + + // Should be same value as vpiSimTime, just converted to real + t.type = vpiScaledRealTime; + vpi_get_time(obj, &t); + vpi_printf(const_cast(" vpiScaledRealTime = %g\n"), t.real); + + // These will both print the precision, because the 0 asks for global scope + int u = vpi_get(vpiTimeUnit, obj); + int p = vpi_get(vpiTimePrecision, obj); + vpi_printf(const_cast("%s vpiTimeUnit = %d"), namep, u); + vpi_printf(const_cast(" vpiTimePrecision = %d\n"), p); +} + +void dpii_check() { + show(0); + + vpiHandle mod = vpi_handle_by_name((PLI_BYTE8*)"top.t", NULL); + if (!mod) { + vpi_printf(const_cast("-- Cannot vpi_find module\n")); + } else { + show(mod); + } +} diff --git a/test_regress/t/t_timescale_default.out b/test_regress/t/t_timescale_default.out new file mode 100644 index 000000000..0eaea26f0 --- /dev/null +++ b/test_regress/t/t_timescale_default.out @@ -0,0 +1,2 @@ +Time scale of t is 1ps / 1ps +*-* All Finished *-* diff --git a/test_regress/t/t_timescale_default.pl b/test_regress/t/t_timescale_default.pl new file mode 100755 index 000000000..2934909ea --- /dev/null +++ b/test_regress/t/t_timescale_default.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_timescale_default.v b/test_regress/t/t_timescale_default.v new file mode 100644 index 000000000..507997cc9 --- /dev/null +++ b/test_regress/t/t_timescale_default.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Intentionally no timescale here, nor in driver file +module t; + initial begin + // Unspecified, but general consensus is 1s is default timeunit + $printtimescale; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timescale_lint_bad.out b/test_regress/t/t_timescale_lint_bad.out new file mode 100644 index 000000000..e397440d8 --- /dev/null +++ b/test_regress/t/t_timescale_lint_bad.out @@ -0,0 +1,5 @@ +%Error-TIMESCALEMOD: t/t_timescale_lint_bad.v:7:8: Timescale missing on this module as other modules have it (IEEE 1800-2017 3.14.2.2) + t/t_timescale_lint_bad.v:12:8: ... Location of module with timescale + 12 | module t; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_timescale_lint_bad.pl b/test_regress/t/t_timescale_lint_bad.pl new file mode 100755 index 000000000..6c66d6a67 --- /dev/null +++ b/test_regress/t/t_timescale_lint_bad.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +lint( + verilator_flags2 => ["--lint-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timescale_lint_bad.v b/test_regress/t/t_timescale_lint_bad.v new file mode 100644 index 000000000..ae23c49dc --- /dev/null +++ b/test_regress/t/t_timescale_lint_bad.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module pre_no_ts; +endmodule + +`timescale 1ns/1ns + +module t; + pre_no_ts pre_no_ts(); + post_no_ts pst_no_ts(); +endmodule + +module post_no_ts; +endmodule diff --git a/test_regress/t/t_timescale_parse.cpp b/test_regress/t/t_timescale_parse.cpp new file mode 100644 index 000000000..c77eebde1 --- /dev/null +++ b/test_regress/t/t_timescale_parse.cpp @@ -0,0 +1,22 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2019 by Wilson Snyder + +#include "Vt_timescale_parse.h" + +VM_PREFIX* tb = NULL; + +double sc_time_stamp() { + return 2 * 1e9; // e.g. 2 seconds in ns units +} + +int main() { + tb = new VM_PREFIX("tb"); + + tb->eval(); + tb->eval(); + tb->eval(); + + tb->final(); +} diff --git a/test_regress/t/t_timescale_parse.pl b/test_regress/t/t_timescale_parse.pl new file mode 100755 index 000000000..7b012fe8b --- /dev/null +++ b/test_regress/t/t_timescale_parse.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timescale_parse.v b/test_regress/t/t_timescale_parse.v new file mode 100644 index 000000000..63e5fbb1e --- /dev/null +++ b/test_regress/t/t_timescale_parse.v @@ -0,0 +1,103 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +//verilator lint_off REALCVT + +`define testmod(modname) \ +module modname; \ + time t; \ + task check; t = 1ns; $write("%m %0t\n", t); endtask \ +endmodule + +`timescale 1s/1fs +`testmod(s0) +`timescale 100ms/1fs +`testmod(s1) +`timescale 10ms/1fs +`testmod(s2) +`timescale 1ms/1fs +`testmod(s3) +`timescale 100us/1fs +`testmod(s4) +`timescale 10us/1fs +`testmod(s5) +`timescale 1us/1fs +`testmod(s6) +`timescale 100ns/1fs +`testmod(s7) +`timescale 10ns/1fs +`testmod(s8) +`timescale 1ns/1fs +`testmod(s9) +`timescale 100ps/1fs +`testmod(s10) +`timescale 10ps/1fs +`testmod(s11) +`timescale 1ps/1fs +`testmod(s12) +`timescale 100 fs/1fs +`testmod(s13) +`timescale 10fs/1 fs +`testmod(s14) +`timescale 1 fs / 1 fs // Comment +`testmod(s15) + + +module r0; + timeunit 10ns / 1ns; + task check; $write("%m %0t\n", $time); endtask +endmodule + +module r1; + timeunit 10ns; + timeprecision 1ns; + task check; $write("%m %0t\n", $time); endtask +endmodule + +module t; + s0 s0(); + s1 s1(); + s2 s2(); + s3 s3(); + s4 s4(); + s5 s5(); + s6 s6(); + s7 s7(); + s8 s8(); + s9 s9(); + s10 s10(); + s11 s11(); + s12 s12(); + s13 s13(); + s14 s14(); + s15 s15(); + + r0 r0(); + r1 r1(); + + final begin + s0.check(); + s1.check(); + s2.check(); + s3.check(); + s4.check(); + s5.check(); + s6.check(); + s7.check(); + s8.check(); + s9.check(); + s10.check(); + s11.check(); + s12.check(); + s13.check(); + s14.check(); + s15.check(); + r0.check(); + r1.check(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timescale_parse_bad.out b/test_regress/t/t_timescale_parse_bad.out new file mode 100644 index 000000000..8544ff3fc --- /dev/null +++ b/test_regress/t/t_timescale_parse_bad.out @@ -0,0 +1,25 @@ +%Error: t/t_timescale_parse_bad.v:8:1: `timescale timeunit '1ps' must be greater than or equal to timeprecision '1ns' + 8 | `timescale 1ps/1ns + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_timescale_parse_bad.v:11:1: `timescale timeunit syntax error: 'frump' + 11 | `timescale frump + | ^~~~~~~~~~~~~~~~ +%Error: t/t_timescale_parse_bad.v:12:1: `timescale timeunit syntax error: '1xs' + 12 | `timescale 1xs + | ^~~~~~~~~~~~~~ +%Error: t/t_timescale_parse_bad.v:13:1: `timescale timeunit syntax error: '2ps' + 13 | `timescale 2ps + | ^~~~~~~~~~~~~~ +%Error: t/t_timescale_parse_bad.v:14:1: `timescale timeprecision syntax error: 'frump' + 14 | `timescale 1ns / frump + | ^~~~~~~~~~~~~~~~~~~~~~ +%Error: t/t_timescale_parse_bad.v:15:1: `timescale syntax error: ' 1ns / 1ps /extra' + 15 | `timescale 1ns / 1ps /extra + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +%Error: t/t_timescale_parse_bad.v:18:13: timeunit illegal value + 18 | timeunit 2ps; + | ^~~ +%Error: t/t_timescale_parse_bad.v:19:18: timeprecision illegal value + 19 | timeprecision 2ps; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_timescale_parse_bad.pl b/test_regress/t/t_timescale_parse_bad.pl new file mode 100755 index 000000000..c1dba4c49 --- /dev/null +++ b/test_regress/t/t_timescale_parse_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timescale_parse_bad.v b/test_regress/t/t_timescale_parse_bad.v new file mode 100644 index 000000000..672cdbac9 --- /dev/null +++ b/test_regress/t/t_timescale_parse_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// units < precision +`timescale 1ps/1ns + +// Bad scale +`timescale frump +`timescale 1xs +`timescale 2ps +`timescale 1ns / frump +`timescale 1ns / 1ps /extra + +module t; + timeunit 2ps; // Bad + timeprecision 2ps; // Bad +endmodule diff --git a/test_regress/t/t_trace_cat.out b/test_regress/t/t_trace_cat.out index 8181ac5fa..729783918 100644 --- a/test_regress/t/t_trace_cat.out +++ b/test_regress/t/t_trace_cat.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Thu Aug 30 16:11:10 2018 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 $ clk $end diff --git a/test_regress/t/t_trace_cat_renew.out b/test_regress/t/t_trace_cat_renew.out index 127461f51..51fb48a1c 100644 --- a/test_regress/t/t_trace_cat_renew.out +++ b/test_regress/t/t_trace_cat_renew.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Sat Feb 23 20:18:07 2013 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 $ clk $end diff --git a/test_regress/t/t_trace_cat_renew_0000.out b/test_regress/t/t_trace_cat_renew_0000.out index 14efeeac2..c4408f6e9 100644 --- a/test_regress/t/t_trace_cat_renew_0000.out +++ b/test_regress/t/t_trace_cat_renew_0000.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Thu Aug 30 16:11:06 2018 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 $ clk $end diff --git a/test_regress/t/t_trace_cat_renew_0100.out b/test_regress/t/t_trace_cat_renew_0100.out index 94ba118e3..8222df3e2 100644 --- a/test_regress/t/t_trace_cat_renew_0100.out +++ b/test_regress/t/t_trace_cat_renew_0100.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Thu Aug 30 16:11:06 2018 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 $ clk $end diff --git a/test_regress/t/t_trace_cat_reopen.out b/test_regress/t/t_trace_cat_reopen.out index 127461f51..51fb48a1c 100644 --- a/test_regress/t/t_trace_cat_reopen.out +++ b/test_regress/t/t_trace_cat_reopen.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Sat Feb 23 20:18:07 2013 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 $ clk $end diff --git a/test_regress/t/t_trace_cat_reopen_0000.out b/test_regress/t/t_trace_cat_reopen_0000.out index 11edcfaad..5042b17c3 100644 --- a/test_regress/t/t_trace_cat_reopen_0000.out +++ b/test_regress/t/t_trace_cat_reopen_0000.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Thu Aug 30 16:10:58 2018 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 $ clk $end diff --git a/test_regress/t/t_trace_cat_reopen_0100.out b/test_regress/t/t_trace_cat_reopen_0100.out index 12d282b11..466b4c6d9 100644 --- a/test_regress/t/t_trace_cat_reopen_0100.out +++ b/test_regress/t/t_trace_cat_reopen_0100.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Thu Aug 30 16:10:58 2018 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 $ clk $end diff --git a/test_regress/t/t_trace_complex.out b/test_regress/t/t_trace_complex.out index 1c37ae59f..1372dbc2c 100644 --- a/test_regress/t/t_trace_complex.out +++ b/test_regress/t/t_trace_complex.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Tue Jan 21 18:15:27 2020 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 7" clk $end diff --git a/test_regress/t/t_trace_complex_params.out b/test_regress/t/t_trace_complex_params.out index aacfd2769..b328bd887 100644 --- a/test_regress/t/t_trace_complex_params.out +++ b/test_regress/t/t_trace_complex_params.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Tue Jan 21 18:15:28 2020 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 7" clk $end diff --git a/test_regress/t/t_trace_complex_structs.out b/test_regress/t/t_trace_complex_structs.out index 3344bd9e1..f22f6d3be 100644 --- a/test_regress/t/t_trace_complex_structs.out +++ b/test_regress/t/t_trace_complex_structs.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Tue Jan 21 18:55:13 2020 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 9# clk $end diff --git a/test_regress/t/t_trace_ena_cc.out b/test_regress/t/t_trace_ena_cc.out index e643c7e2b..32c437d8a 100644 --- a/test_regress/t/t_trace_ena_cc.out +++ b/test_regress/t/t_trace_ena_cc.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Sat Jan 27 15:03:24 2018 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 ' clk $end diff --git a/test_regress/t/t_trace_ena_sc.out b/test_regress/t/t_trace_ena_sc.out index 751645bdd..1553a9196 100644 --- a/test_regress/t/t_trace_ena_sc.out +++ b/test_regress/t/t_trace_ena_sc.out @@ -1,14 +1,14 @@ $version Generated by VerilatedVcd $end -$date Mon Jan 29 09:34:59 2018 +$date Tue Apr 7 19:56:41 2020 $end $timescale 1ps $end $scope module top $end $scope module t $end - $var wire 32 % c_trace_on [31:0] $end + $var wire 32 3 c_trace_on [31:0] $end $var wire 1 # clk $end - $var wire 32 $ cyc [31:0] $end - $var real 64 & r $end + $var wire 32 + cyc [31:0] $end + $var real 64 ; r $end $upscope $end $upscope $end $enddefinitions $end @@ -16,149 +16,149 @@ $enddefinitions $end #0 0# -b00000000000000000000000000000001 $ -b00000000000000000000000000000000 % -r0 & -#10000 +b00000000000000000000000000000001 + +b00000000000000000000000000000000 3 +r0 ; +#10 1# -b00000000000000000000000000000010 $ -r0.1 & -#11000 -#12000 -#13000 -#14000 -#15000 +b00000000000000000000000000000010 + +r0.1 ; +#11 +#12 +#13 +#14 +#15 0# -#16000 -#17000 -#18000 -#19000 -#20000 +#16 +#17 +#18 +#19 +#20 1# -b00000000000000000000000000000011 $ -b00000000000000000000000000000001 % -r0.2 & -#21000 -#22000 -#23000 -#24000 -#25000 +b00000000000000000000000000000011 + +b00000000000000000000000000000001 3 +r0.2 ; +#21 +#22 +#23 +#24 +#25 0# -#26000 -#27000 -#28000 -#29000 -#30000 +#26 +#27 +#28 +#29 +#30 1# -b00000000000000000000000000000100 $ -b00000000000000000000000000000010 % -r0.3 & -#31000 -#32000 -#33000 -#34000 -#35000 +b00000000000000000000000000000100 + +b00000000000000000000000000000010 3 +r0.3 ; +#31 +#32 +#33 +#34 +#35 0# -#36000 -#37000 -#38000 -#39000 -#40000 +#36 +#37 +#38 +#39 +#40 1# -b00000000000000000000000000000101 $ -b00000000000000000000000000000011 % -r0.4 & -#41000 -#42000 -#43000 -#44000 -#45000 +b00000000000000000000000000000101 + +b00000000000000000000000000000011 3 +r0.4 ; +#41 +#42 +#43 +#44 +#45 0# -#46000 -#47000 -#48000 -#49000 -#50000 +#46 +#47 +#48 +#49 +#50 1# -b00000000000000000000000000000110 $ -b00000000000000000000000000000100 % -r0.5 & -#51000 -#52000 -#53000 -#54000 -#55000 +b00000000000000000000000000000110 + +b00000000000000000000000000000100 3 +r0.5 ; +#51 +#52 +#53 +#54 +#55 0# -#56000 -#57000 -#58000 -#59000 -#60000 +#56 +#57 +#58 +#59 +#60 1# -b00000000000000000000000000000111 $ -b00000000000000000000000000000101 % -r0.6 & -#61000 -#62000 -#63000 -#64000 -#65000 +b00000000000000000000000000000111 + +b00000000000000000000000000000101 3 +r0.6 ; +#61 +#62 +#63 +#64 +#65 0# -#66000 -#67000 -#68000 -#69000 -#70000 +#66 +#67 +#68 +#69 +#70 1# -b00000000000000000000000000001000 $ -b00000000000000000000000000000110 % -r0.7 & -#71000 -#72000 -#73000 -#74000 -#75000 +b00000000000000000000000000001000 + +b00000000000000000000000000000110 3 +r0.7 ; +#71 +#72 +#73 +#74 +#75 0# -#76000 -#77000 -#78000 -#79000 -#80000 +#76 +#77 +#78 +#79 +#80 1# -b00000000000000000000000000001001 $ -b00000000000000000000000000000111 % -r0.7999999999999999 & -#81000 -#82000 -#83000 -#84000 -#85000 +b00000000000000000000000000001001 + +b00000000000000000000000000000111 3 +r0.7999999999999999 ; +#81 +#82 +#83 +#84 +#85 0# -#86000 -#87000 -#88000 -#89000 -#90000 +#86 +#87 +#88 +#89 +#90 1# -b00000000000000000000000000001010 $ -b00000000000000000000000000001000 % -r0.8999999999999999 & -#91000 -#92000 -#93000 -#94000 -#95000 +b00000000000000000000000000001010 + +b00000000000000000000000000001000 3 +r0.8999999999999999 ; +#91 +#92 +#93 +#94 +#95 0# -#96000 -#97000 -#98000 -#99000 -#100000 +#96 +#97 +#98 +#99 +#100 1# -b00000000000000000000000000001011 $ -b00000000000000000000000000001001 % -r0.9999999999999999 & -#101000 -#102000 -#103000 -#104000 +b00000000000000000000000000001011 + +b00000000000000000000000000001001 3 +r0.9999999999999999 ; +#101 +#102 +#103 +#104 diff --git a/test_regress/t/t_trace_public.out b/test_regress/t/t_trace_public.out index 0eb246678..01536b3b7 100644 --- a/test_regress/t/t_trace_public.out +++ b/test_regress/t/t_trace_public.out @@ -1,7 +1,7 @@ $version Generated by SpTraceVcd $end $date Tue Nov 3 09:34:23 2009 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 6 CLK $end diff --git a/test_regress/t/t_trace_timescale.cpp b/test_regress/t/t_trace_timescale.cpp deleted file mode 100644 index bac0d5179..000000000 --- a/test_regress/t/t_trace_timescale.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -// -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2008 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -#include -#include - -#include VM_PREFIX_INCLUDE - -unsigned long long main_time = 0; -double sc_time_stamp() { return ((double)main_time) / VL_TIME_MULTIPLIER; } - -int main(int argc, char** argv, char** env) { - VM_PREFIX* top = new VM_PREFIX("top"); - - Verilated::debug(0); - Verilated::traceEverOn(true); - - VerilatedVcdC* tfp = new VerilatedVcdC; - tfp->set_time_resolution("1ps"); - tfp->set_time_unit("1ns"); - - top->trace(tfp, 99); - - tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); - - top->clk = 0; - - while (main_time < 190 * VL_TIME_MULTIPLIER) { - top->clk = !top->clk; - top->eval(); - tfp->dump((unsigned int)(main_time)); - // Advance by 0.5 time units, to make sure our fractional - // time is working correctly - main_time += VL_TIME_MULTIPLIER / 2; - } - tfp->close(); - top->final(); - printf("*-* All Finished *-*\n"); - return 0; -} diff --git a/test_regress/t/t_trace_timescale.out b/test_regress/t/t_trace_timescale.out index 38d9e2168..208185cca 100644 --- a/test_regress/t/t_trace_timescale.out +++ b/test_regress/t/t_trace_timescale.out @@ -1,12 +1,12 @@ $version Generated by VerilatedVcd $end -$date Thu Aug 30 16:10:50 2018 +$date Tue Apr 7 21:19:07 2020 $end -$timescale 1ps $end +$timescale 1ms $end $scope module top $end - $var wire 1 $ clk $end + $var wire 1 + clk $end $scope module t $end - $var wire 1 $ clk $end + $var wire 1 + clk $end $var wire 32 # cyc [31:0] $end $upscope $end $upscope $end @@ -15,951 +15,57 @@ $enddefinitions $end #0 b00000000000000000000000000000000 # -1$ -#500 -0$ -#1000 +0+ +#10 b00000000000000000000000000000001 # -1$ -#1500 -0$ -#2000 +1+ +#15 +0+ +#20 b00000000000000000000000000000010 # -1$ -#2500 -0$ -#3000 +1+ +#25 +0+ +#30 b00000000000000000000000000000011 # -1$ -#3500 -0$ -#4000 +1+ +#35 +0+ +#40 b00000000000000000000000000000100 # -1$ -#4500 -0$ -#5000 +1+ +#45 +0+ +#50 b00000000000000000000000000000101 # -1$ -#5500 -0$ -#6000 +1+ +#55 +0+ +#60 b00000000000000000000000000000110 # -1$ -#6500 -0$ -#7000 +1+ +#65 +0+ +#70 b00000000000000000000000000000111 # -1$ -#7500 -0$ -#8000 +1+ +#75 +0+ +#80 b00000000000000000000000000001000 # -1$ -#8500 -0$ -#9000 +1+ +#85 +0+ +#90 b00000000000000000000000000001001 # -1$ -#9500 -0$ -#10000 +1+ +#95 +0+ +#100 b00000000000000000000000000001010 # -1$ -#10500 -0$ -#11000 +1+ +#105 +0+ +#110 b00000000000000000000000000001011 # -1$ -#11500 -0$ -#12000 -b00000000000000000000000000001100 # -1$ -#12500 -0$ -#13000 -b00000000000000000000000000001101 # -1$ -#13500 -0$ -#14000 -b00000000000000000000000000001110 # -1$ -#14500 -0$ -#15000 -b00000000000000000000000000001111 # -1$ -#15500 -0$ -#16000 -b00000000000000000000000000010000 # -1$ -#16500 -0$ -#17000 -b00000000000000000000000000010001 # -1$ -#17500 -0$ -#18000 -b00000000000000000000000000010010 # -1$ -#18500 -0$ -#19000 -b00000000000000000000000000010011 # -1$ -#19500 -0$ -#20000 -b00000000000000000000000000010100 # -1$ -#20500 -0$ -#21000 -b00000000000000000000000000010101 # -1$ -#21500 -0$ -#22000 -b00000000000000000000000000010110 # -1$ -#22500 -0$ -#23000 -b00000000000000000000000000010111 # -1$ -#23500 -0$ -#24000 -b00000000000000000000000000011000 # -1$ -#24500 -0$ -#25000 -b00000000000000000000000000011001 # -1$ -#25500 -0$ -#26000 -b00000000000000000000000000011010 # -1$ -#26500 -0$ -#27000 -b00000000000000000000000000011011 # -1$ -#27500 -0$ -#28000 -b00000000000000000000000000011100 # -1$ -#28500 -0$ -#29000 -b00000000000000000000000000011101 # -1$ -#29500 -0$ -#30000 -b00000000000000000000000000011110 # -1$ -#30500 -0$ -#31000 -b00000000000000000000000000011111 # -1$ -#31500 -0$ -#32000 -b00000000000000000000000000100000 # -1$ -#32500 -0$ -#33000 -b00000000000000000000000000100001 # -1$ -#33500 -0$ -#34000 -b00000000000000000000000000100010 # -1$ -#34500 -0$ -#35000 -b00000000000000000000000000100011 # -1$ -#35500 -0$ -#36000 -b00000000000000000000000000100100 # -1$ -#36500 -0$ -#37000 -b00000000000000000000000000100101 # -1$ -#37500 -0$ -#38000 -b00000000000000000000000000100110 # -1$ -#38500 -0$ -#39000 -b00000000000000000000000000100111 # -1$ -#39500 -0$ -#40000 -b00000000000000000000000000101000 # -1$ -#40500 -0$ -#41000 -b00000000000000000000000000101001 # -1$ -#41500 -0$ -#42000 -b00000000000000000000000000101010 # -1$ -#42500 -0$ -#43000 -b00000000000000000000000000101011 # -1$ -#43500 -0$ -#44000 -b00000000000000000000000000101100 # -1$ -#44500 -0$ -#45000 -b00000000000000000000000000101101 # -1$ -#45500 -0$ -#46000 -b00000000000000000000000000101110 # -1$ -#46500 -0$ -#47000 -b00000000000000000000000000101111 # -1$ -#47500 -0$ -#48000 -b00000000000000000000000000110000 # -1$ -#48500 -0$ -#49000 -b00000000000000000000000000110001 # -1$ -#49500 -0$ -#50000 -b00000000000000000000000000110010 # -1$ -#50500 -0$ -#51000 -b00000000000000000000000000110011 # -1$ -#51500 -0$ -#52000 -b00000000000000000000000000110100 # -1$ -#52500 -0$ -#53000 -b00000000000000000000000000110101 # -1$ -#53500 -0$ -#54000 -b00000000000000000000000000110110 # -1$ -#54500 -0$ -#55000 -b00000000000000000000000000110111 # -1$ -#55500 -0$ -#56000 -b00000000000000000000000000111000 # -1$ -#56500 -0$ -#57000 -b00000000000000000000000000111001 # -1$ -#57500 -0$ -#58000 -b00000000000000000000000000111010 # -1$ -#58500 -0$ -#59000 -b00000000000000000000000000111011 # -1$ -#59500 -0$ -#60000 -b00000000000000000000000000111100 # -1$ -#60500 -0$ -#61000 -b00000000000000000000000000111101 # -1$ -#61500 -0$ -#62000 -b00000000000000000000000000111110 # -1$ -#62500 -0$ -#63000 -b00000000000000000000000000111111 # -1$ -#63500 -0$ -#64000 -b00000000000000000000000001000000 # -1$ -#64500 -0$ -#65000 -b00000000000000000000000001000001 # -1$ -#65500 -0$ -#66000 -b00000000000000000000000001000010 # -1$ -#66500 -0$ -#67000 -b00000000000000000000000001000011 # -1$ -#67500 -0$ -#68000 -b00000000000000000000000001000100 # -1$ -#68500 -0$ -#69000 -b00000000000000000000000001000101 # -1$ -#69500 -0$ -#70000 -b00000000000000000000000001000110 # -1$ -#70500 -0$ -#71000 -b00000000000000000000000001000111 # -1$ -#71500 -0$ -#72000 -b00000000000000000000000001001000 # -1$ -#72500 -0$ -#73000 -b00000000000000000000000001001001 # -1$ -#73500 -0$ -#74000 -b00000000000000000000000001001010 # -1$ -#74500 -0$ -#75000 -b00000000000000000000000001001011 # -1$ -#75500 -0$ -#76000 -b00000000000000000000000001001100 # -1$ -#76500 -0$ -#77000 -b00000000000000000000000001001101 # -1$ -#77500 -0$ -#78000 -b00000000000000000000000001001110 # -1$ -#78500 -0$ -#79000 -b00000000000000000000000001001111 # -1$ -#79500 -0$ -#80000 -b00000000000000000000000001010000 # -1$ -#80500 -0$ -#81000 -b00000000000000000000000001010001 # -1$ -#81500 -0$ -#82000 -b00000000000000000000000001010010 # -1$ -#82500 -0$ -#83000 -b00000000000000000000000001010011 # -1$ -#83500 -0$ -#84000 -b00000000000000000000000001010100 # -1$ -#84500 -0$ -#85000 -b00000000000000000000000001010101 # -1$ -#85500 -0$ -#86000 -b00000000000000000000000001010110 # -1$ -#86500 -0$ -#87000 -b00000000000000000000000001010111 # -1$ -#87500 -0$ -#88000 -b00000000000000000000000001011000 # -1$ -#88500 -0$ -#89000 -b00000000000000000000000001011001 # -1$ -#89500 -0$ -#90000 -b00000000000000000000000001011010 # -1$ -#90500 -0$ -#91000 -b00000000000000000000000001011011 # -1$ -#91500 -0$ -#92000 -b00000000000000000000000001011100 # -1$ -#92500 -0$ -#93000 -b00000000000000000000000001011101 # -1$ -#93500 -0$ -#94000 -b00000000000000000000000001011110 # -1$ -#94500 -0$ -#95000 -b00000000000000000000000001011111 # -1$ -#95500 -0$ -#96000 -b00000000000000000000000001100000 # -1$ -#96500 -0$ -#97000 -b00000000000000000000000001100001 # -1$ -#97500 -0$ -#98000 -b00000000000000000000000001100010 # -1$ -#98500 -0$ -#99000 -b00000000000000000000000001100011 # -1$ -#99500 -0$ -#100000 -b00000000000000000000000001100100 # -1$ -#100500 -0$ -#101000 -b00000000000000000000000001100101 # -1$ -#101500 -0$ -#102000 -b00000000000000000000000001100110 # -1$ -#102500 -0$ -#103000 -b00000000000000000000000001100111 # -1$ -#103500 -0$ -#104000 -b00000000000000000000000001101000 # -1$ -#104500 -0$ -#105000 -b00000000000000000000000001101001 # -1$ -#105500 -0$ -#106000 -b00000000000000000000000001101010 # -1$ -#106500 -0$ -#107000 -b00000000000000000000000001101011 # -1$ -#107500 -0$ -#108000 -b00000000000000000000000001101100 # -1$ -#108500 -0$ -#109000 -b00000000000000000000000001101101 # -1$ -#109500 -0$ -#110000 -b00000000000000000000000001101110 # -1$ -#110500 -0$ -#111000 -b00000000000000000000000001101111 # -1$ -#111500 -0$ -#112000 -b00000000000000000000000001110000 # -1$ -#112500 -0$ -#113000 -b00000000000000000000000001110001 # -1$ -#113500 -0$ -#114000 -b00000000000000000000000001110010 # -1$ -#114500 -0$ -#115000 -b00000000000000000000000001110011 # -1$ -#115500 -0$ -#116000 -b00000000000000000000000001110100 # -1$ -#116500 -0$ -#117000 -b00000000000000000000000001110101 # -1$ -#117500 -0$ -#118000 -b00000000000000000000000001110110 # -1$ -#118500 -0$ -#119000 -b00000000000000000000000001110111 # -1$ -#119500 -0$ -#120000 -b00000000000000000000000001111000 # -1$ -#120500 -0$ -#121000 -b00000000000000000000000001111001 # -1$ -#121500 -0$ -#122000 -b00000000000000000000000001111010 # -1$ -#122500 -0$ -#123000 -b00000000000000000000000001111011 # -1$ -#123500 -0$ -#124000 -b00000000000000000000000001111100 # -1$ -#124500 -0$ -#125000 -b00000000000000000000000001111101 # -1$ -#125500 -0$ -#126000 -b00000000000000000000000001111110 # -1$ -#126500 -0$ -#127000 -b00000000000000000000000001111111 # -1$ -#127500 -0$ -#128000 -b00000000000000000000000010000000 # -1$ -#128500 -0$ -#129000 -b00000000000000000000000010000001 # -1$ -#129500 -0$ -#130000 -b00000000000000000000000010000010 # -1$ -#130500 -0$ -#131000 -b00000000000000000000000010000011 # -1$ -#131500 -0$ -#132000 -b00000000000000000000000010000100 # -1$ -#132500 -0$ -#133000 -b00000000000000000000000010000101 # -1$ -#133500 -0$ -#134000 -b00000000000000000000000010000110 # -1$ -#134500 -0$ -#135000 -b00000000000000000000000010000111 # -1$ -#135500 -0$ -#136000 -b00000000000000000000000010001000 # -1$ -#136500 -0$ -#137000 -b00000000000000000000000010001001 # -1$ -#137500 -0$ -#138000 -b00000000000000000000000010001010 # -1$ -#138500 -0$ -#139000 -b00000000000000000000000010001011 # -1$ -#139500 -0$ -#140000 -b00000000000000000000000010001100 # -1$ -#140500 -0$ -#141000 -b00000000000000000000000010001101 # -1$ -#141500 -0$ -#142000 -b00000000000000000000000010001110 # -1$ -#142500 -0$ -#143000 -b00000000000000000000000010001111 # -1$ -#143500 -0$ -#144000 -b00000000000000000000000010010000 # -1$ -#144500 -0$ -#145000 -b00000000000000000000000010010001 # -1$ -#145500 -0$ -#146000 -b00000000000000000000000010010010 # -1$ -#146500 -0$ -#147000 -b00000000000000000000000010010011 # -1$ -#147500 -0$ -#148000 -b00000000000000000000000010010100 # -1$ -#148500 -0$ -#149000 -b00000000000000000000000010010101 # -1$ -#149500 -0$ -#150000 -b00000000000000000000000010010110 # -1$ -#150500 -0$ -#151000 -b00000000000000000000000010010111 # -1$ -#151500 -0$ -#152000 -b00000000000000000000000010011000 # -1$ -#152500 -0$ -#153000 -b00000000000000000000000010011001 # -1$ -#153500 -0$ -#154000 -b00000000000000000000000010011010 # -1$ -#154500 -0$ -#155000 -b00000000000000000000000010011011 # -1$ -#155500 -0$ -#156000 -b00000000000000000000000010011100 # -1$ -#156500 -0$ -#157000 -b00000000000000000000000010011101 # -1$ -#157500 -0$ -#158000 -b00000000000000000000000010011110 # -1$ -#158500 -0$ -#159000 -b00000000000000000000000010011111 # -1$ -#159500 -0$ -#160000 -b00000000000000000000000010100000 # -1$ -#160500 -0$ -#161000 -b00000000000000000000000010100001 # -1$ -#161500 -0$ -#162000 -b00000000000000000000000010100010 # -1$ -#162500 -0$ -#163000 -b00000000000000000000000010100011 # -1$ -#163500 -0$ -#164000 -b00000000000000000000000010100100 # -1$ -#164500 -0$ -#165000 -b00000000000000000000000010100101 # -1$ -#165500 -0$ -#166000 -b00000000000000000000000010100110 # -1$ -#166500 -0$ -#167000 -b00000000000000000000000010100111 # -1$ -#167500 -0$ -#168000 -b00000000000000000000000010101000 # -1$ -#168500 -0$ -#169000 -b00000000000000000000000010101001 # -1$ -#169500 -0$ -#170000 -b00000000000000000000000010101010 # -1$ -#170500 -0$ -#171000 -b00000000000000000000000010101011 # -1$ -#171500 -0$ -#172000 -b00000000000000000000000010101100 # -1$ -#172500 -0$ -#173000 -b00000000000000000000000010101101 # -1$ -#173500 -0$ -#174000 -b00000000000000000000000010101110 # -1$ -#174500 -0$ -#175000 -b00000000000000000000000010101111 # -1$ -#175500 -0$ -#176000 -b00000000000000000000000010110000 # -1$ -#176500 -0$ -#177000 -b00000000000000000000000010110001 # -1$ -#177500 -0$ -#178000 -b00000000000000000000000010110010 # -1$ -#178500 -0$ -#179000 -b00000000000000000000000010110011 # -1$ -#179500 -0$ -#180000 -b00000000000000000000000010110100 # -1$ -#180500 -0$ -#181000 -b00000000000000000000000010110101 # -1$ -#181500 -0$ -#182000 -b00000000000000000000000010110110 # -1$ -#182500 -0$ -#183000 -b00000000000000000000000010110111 # -1$ -#183500 -0$ -#184000 -b00000000000000000000000010111000 # -1$ -#184500 -0$ -#185000 -b00000000000000000000000010111001 # -1$ -#185500 -0$ -#186000 -b00000000000000000000000010111010 # -1$ -#186500 -0$ -#187000 -b00000000000000000000000010111011 # -1$ -#187500 -0$ -#188000 -b00000000000000000000000010111100 # -1$ -#188500 -0$ -#189000 -b00000000000000000000000010111101 # -1$ -#189500 -0$ +1+ diff --git a/test_regress/t/t_trace_timescale.pl b/test_regress/t/t_trace_timescale.pl index 91e596a94..548304134 100755 --- a/test_regress/t/t_trace_timescale.pl +++ b/test_regress/t/t_trace_timescale.pl @@ -11,10 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt_all => 1); compile( - make_top_shell => 0, - make_main => 0, - v_flags2 => ["--trace --exe $Self->{t_dir}/t_trace_timescale.cpp"], - make_flags => 'CPPFLAGS_ADD=-DVL_TIME_MULTIPLIER=1000', + v_flags2 => ["--trace"], ); execute( diff --git a/test_regress/t/t_trace_timescale.v b/test_regress/t/t_trace_timescale.v index 7428682b5..206f7e601 100644 --- a/test_regress/t/t_trace_timescale.v +++ b/test_regress/t/t_trace_timescale.v @@ -4,14 +4,25 @@ // any use, without warranty, 2013 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +`timescale 1ms/1ms + +// See also t_time_sc_*.v/pl + module t - ( - input wire clk + (/*AUTOARG*/ + // Inputs + clk ); + input clk; + integer cyc; initial cyc = 0; always @ (posedge clk) begin cyc <= cyc + 1; + if (cyc == 10) begin + $write("*-* All Finished *-*\n"); + $finish; + end end endmodule diff --git a/test_regress/t/t_trace_two_dump_cc.out b/test_regress/t/t_trace_two_dump_cc.out index 3ed0dcca5..c452d0e3f 100644 --- a/test_regress/t/t_trace_two_dump_cc.out +++ b/test_regress/t/t_trace_two_dump_cc.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Sat Mar 7 18:39:02 2020 $end -$timescale 1ns $end +$timescale 1ps $end $scope module topa $end $var wire 1 3 clk $end diff --git a/test_regress/t/t_trace_two_hdr_cc.out b/test_regress/t/t_trace_two_hdr_cc.out index 7040fadaa..3d0809dda 100644 --- a/test_regress/t/t_trace_two_hdr_cc.out +++ b/test_regress/t/t_trace_two_hdr_cc.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Sat Feb 29 09:09:40 2020 $end -$timescale 1ns $end +$timescale 1ps $end $scope module topa $end $var wire 1 3 clk $end diff --git a/test_regress/t/t_trace_two_port_cc.out b/test_regress/t/t_trace_two_port_cc.out index cbe559eb8..4764562aa 100644 --- a/test_regress/t/t_trace_two_port_cc.out +++ b/test_regress/t/t_trace_two_port_cc.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Sat Mar 7 18:38:11 2020 $end -$timescale 1ns $end +$timescale 1ps $end $scope module topa $end $var wire 1 3 clk $end diff --git a/test_regress/t/t_var_escape.out b/test_regress/t/t_var_escape.out index 81c3ce6af..a4bcf2e13 100644 --- a/test_regress/t/t_var_escape.out +++ b/test_regress/t/t_var_escape.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Tue Jul 24 18:44:43 2012 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 * 9num $end diff --git a/test_regress/t/t_var_nonamebegin.out b/test_regress/t/t_var_nonamebegin.out index cad20277c..9e7795564 100644 --- a/test_regress/t/t_var_nonamebegin.out +++ b/test_regress/t/t_var_nonamebegin.out @@ -1,7 +1,7 @@ $version Generated by VerilatedVcd $end $date Tue Jul 24 18:46:01 2012 $end -$timescale 1ns $end +$timescale 1ps $end $scope module top $end $var wire 1 # clk $end From e6f345e45db64dab1a66cd9eb3b9a9ad084b874a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Apr 2020 21:47:37 -0400 Subject: [PATCH 060/127] Internal: clang-tidy fixes. No functional change. --- include/verilated_unordered_set_map.h | 2 +- src/V3AstNodes.cpp | 5 ++-- src/V3Config.cpp | 6 ++--- src/V3Config.h | 4 +-- src/V3EmitC.cpp | 37 ++++++++++++++------------- src/V3File.cpp | 3 ++- src/V3Gate.cpp | 2 +- src/V3Os.cpp | 4 +-- src/V3ParseImp.cpp | 2 +- src/V3ParseImp.h | 2 +- src/V3Partition.cpp | 2 +- src/V3PreProc.cpp | 14 +++++++--- src/V3SplitVar.cpp | 3 ++- src/V3TSP.cpp | 3 ++- src/V3Width.cpp | 4 +-- src/VlcOptions.h | 4 +-- 16 files changed, 54 insertions(+), 43 deletions(-) diff --git a/include/verilated_unordered_set_map.h b/include/verilated_unordered_set_map.h index ce5ee4357..7384e6aab 100644 --- a/include/verilated_unordered_set_map.h +++ b/include/verilated_unordered_set_map.h @@ -50,7 +50,7 @@ inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) { const vluint8_t* bufp = static_cast(vbufp); size_t hash = 0; for (size_t i = 0; i < nbytes; i++) { - hash = bufp[i] + 31u * hash; // the K&R classic! + hash = bufp[i] + 31U * hash; // the K&R classic! } return hash; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 86fa52c26..7c7c28e00 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -110,10 +110,11 @@ string AstNodeCCall::hiernameProtect() const { void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) { - if (lhs.isNeqZero()) + if (lhs.isNeqZero()) { out.opAssign(rhs); - else + } else { out.opAssign(ths); + } } int AstBasicDType::widthAlignBytes() const { diff --git a/src/V3Config.cpp b/src/V3Config.cpp index 7b89b4df7..757c8126f 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -250,7 +250,7 @@ public: return (m_on > rh.m_on); } }; -std::ostream& operator<<(std::ostream& os, V3ConfigIgnoresLine rhs) { +std::ostream& operator<<(std::ostream& os, const V3ConfigIgnoresLine& rhs) { return os << rhs.m_lineno << ", " << rhs.m_code << ", " << rhs.m_on; } @@ -456,8 +456,8 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas } } -void V3Config::addWaiver(V3ErrorCode code, const string& filename, const string& match) { - V3ConfigResolver::s().files().at(filename).addWaiver(code, match); +void V3Config::addWaiver(V3ErrorCode code, const string& filename, const string& message) { + V3ConfigResolver::s().files().at(filename).addWaiver(code, message); } void V3Config::applyCase(AstCase* nodep) { diff --git a/src/V3Config.h b/src/V3Config.h index fbf8b6413..96346c4f1 100644 --- a/src/V3Config.h +++ b/src/V3Config.h @@ -33,14 +33,14 @@ public: static void addCoverageBlockOff(const string& file, int lineno); static void addCoverageBlockOff(const string& module, const string& blockname); static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max); - static void addWaiver(V3ErrorCode code, const string& filename, const string& msg); + static void addWaiver(V3ErrorCode code, const string& filename, const string& message); static void addInline(FileLine* fl, const string& module, const string& ftask, bool on); static void addVarAttr(FileLine* fl, const string& module, const string& ftask, const string& signal, AstAttrType type, AstSenTree* nodep); static void applyCase(AstCase* nodep); static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep); static void applyIgnores(FileLine* filelinep); - static void applyModule(AstNodeModule* nodep); + static void applyModule(AstNodeModule* modulep); static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp); static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp); static bool waive(FileLine* filelinep, V3ErrorCode code, const string& match); diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 056f77d52..c39c8ecd6 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2924,9 +2924,10 @@ void EmitCImp::emitInt(AstNodeModule* modp) { string section; section = "\n// PORTS\n"; - if (modp->isTop()) + if (modp->isTop()) { section += ("// The application code writes and reads these signals to\n" "// propagate new values into/out from the Verilated model.\n"); + } emitVarList(modp->stmtsp(), EVL_CLASS_IO, "", section /*ref*/); section = "\n// LOCAL SIGNALS\n"; @@ -3452,24 +3453,24 @@ class EmitCTrace : EmitCStmts { } } // clang-format off - else if (vartype == AstVarType::GPARAM) fstvt = "FST_VT_VCD_PARAMETER"; - else if (vartype == AstVarType::LPARAM) fstvt = "FST_VT_VCD_PARAMETER"; - else if (vartype == AstVarType::SUPPLY0) fstvt = "FST_VT_VCD_SUPPLY0"; - else if (vartype == AstVarType::SUPPLY1) fstvt = "FST_VT_VCD_SUPPLY1"; - else if (vartype == AstVarType::TRI0) fstvt = "FST_VT_VCD_TRI0"; - else if (vartype == AstVarType::TRI1) fstvt = "FST_VT_VCD_TRI1"; - else if (vartype == AstVarType::TRIWIRE) fstvt = "FST_VT_VCD_TRI"; - else if (vartype == AstVarType::WIRE) fstvt = "FST_VT_VCD_WIRE"; - else if (vartype == AstVarType::PORT) fstvt = "FST_VT_VCD_WIRE"; + else if (vartype == AstVarType::GPARAM) { fstvt = "FST_VT_VCD_PARAMETER"; } + else if (vartype == AstVarType::LPARAM) { fstvt = "FST_VT_VCD_PARAMETER"; } + else if (vartype == AstVarType::SUPPLY0) { fstvt = "FST_VT_VCD_SUPPLY0"; } + else if (vartype == AstVarType::SUPPLY1) { fstvt = "FST_VT_VCD_SUPPLY1"; } + else if (vartype == AstVarType::TRI0) { fstvt = "FST_VT_VCD_TRI0"; } + else if (vartype == AstVarType::TRI1) { fstvt = "FST_VT_VCD_TRI1"; } + else if (vartype == AstVarType::TRIWIRE) { fstvt = "FST_VT_VCD_TRI"; } + else if (vartype == AstVarType::WIRE) { fstvt = "FST_VT_VCD_WIRE"; } + else if (vartype == AstVarType::PORT) { fstvt = "FST_VT_VCD_WIRE"; } // - else if (kwd == AstBasicDTypeKwd::INTEGER) fstvt = "FST_VT_VCD_INTEGER"; - else if (kwd == AstBasicDTypeKwd::BIT) fstvt = "FST_VT_SV_BIT"; - else if (kwd == AstBasicDTypeKwd::LOGIC) fstvt = "FST_VT_SV_LOGIC"; - else if (kwd == AstBasicDTypeKwd::INT) fstvt = "FST_VT_SV_INT"; - else if (kwd == AstBasicDTypeKwd::SHORTINT) fstvt = "FST_VT_SV_SHORTINT"; - else if (kwd == AstBasicDTypeKwd::LONGINT) fstvt = "FST_VT_SV_LONGINT"; - else if (kwd == AstBasicDTypeKwd::BYTE) fstvt = "FST_VT_SV_BYTE"; - else fstvt = "FST_VT_SV_BIT"; + else if (kwd == AstBasicDTypeKwd::INTEGER) { fstvt = "FST_VT_VCD_INTEGER"; } + else if (kwd == AstBasicDTypeKwd::BIT) { fstvt = "FST_VT_SV_BIT"; } + else if (kwd == AstBasicDTypeKwd::LOGIC) { fstvt = "FST_VT_SV_LOGIC"; } + else if (kwd == AstBasicDTypeKwd::INT) { fstvt = "FST_VT_SV_INT"; } + else if (kwd == AstBasicDTypeKwd::SHORTINT) { fstvt = "FST_VT_SV_SHORTINT"; } + else if (kwd == AstBasicDTypeKwd::LONGINT) { fstvt = "FST_VT_SV_LONGINT"; } + else if (kwd == AstBasicDTypeKwd::BYTE) { fstvt = "FST_VT_SV_BYTE"; } + else { fstvt = "FST_VT_SV_BIT"; } // clang-format on // // Not currently supported diff --git a/src/V3File.cpp b/src/V3File.cpp index 45527897e..a01457afd 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -496,7 +496,8 @@ private: void startFilter(const string& command) { if (command == "") {} // Prevent Unused #ifdef INFILTER_PIPE - int fd_stdin[2], fd_stdout[2]; + int fd_stdin[2]; + int fd_stdout[2]; static const int P_RD = 0; static const int P_WR = 1; diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 6f9128d94..1ff49ea4c 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -58,7 +58,7 @@ class GateVarVertex; class GateGraphBaseVisitor { public: V3Graph* m_graphp; // Graph this class is visiting - GateGraphBaseVisitor(V3Graph* graphp) + explicit GateGraphBaseVisitor(V3Graph* graphp) : m_graphp(graphp) {} virtual ~GateGraphBaseVisitor() {} virtual VNUser visit(GateLogicVertex* vertexp, VNUser vu = VNUser(0)) = 0; diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 86e5b266d..6fb2b9088 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -283,12 +283,12 @@ string V3Os::trueRandom(size_t size) { uint64_t V3Os::timeUsecs() { #if defined(_WIN32) || defined(__MINGW32__) // Microseconds between 1601-01-01 00:00:00 UTC and 1970-01-01 00:00:00 UTC - static const uint64_t EPOCH_DIFFERENCE_USECS = 11644473600000000ull; + static const uint64_t EPOCH_DIFFERENCE_USECS = 11644473600000000ULL; FILETIME ft; // contains number of 0.1us intervals since the beginning of 1601 UTC. GetSystemTimeAsFileTime(&ft); uint64_t us - = ((static_cast(ft.dwHighDateTime) << 32) + ft.dwLowDateTime + 5ull) / 10ull; + = ((static_cast(ft.dwHighDateTime) << 32) + ft.dwLowDateTime + 5ULL) / 10ULL; return us - EPOCH_DIFFERENCE_USECS; #else // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 390eff981..be019ff31 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -143,7 +143,7 @@ void V3ParseImp::verilatorCmtLint(const char* textp, bool warnOff) { while (*sp && isspace(*sp)) sp++; string msg = sp; string::size_type pos; - if ((pos = msg.find('*')) != string::npos) { msg.erase(pos); } + if ((pos = msg.find('*')) != string::npos) msg.erase(pos); if (!(parsep()->fileline()->warnOff(msg, warnOff))) { if (!parsep()->optFuture(msg)) { yyerrorf("Unknown verilator lint message code: %s, in %s", msg.c_str(), textp); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 05ceeb87d..e22688919 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -146,7 +146,7 @@ public: void ppline(const char* textp); void linenoInc() { fileline()->linenoInc(); } - void verilatorCmtLint(const char* textp, bool on); + void verilatorCmtLint(const char* textp, bool warnOff); void verilatorCmtLintSave(); void verilatorCmtLintRestore(); void verilatorCmtBad(const char* textp); diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index fda0bf411..e062e6e13 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -2356,7 +2356,7 @@ void V3Partition::hashGraphDebug(const V3Graph* graphp, const char* debugName) { for (const V3GraphVertex* vxp = graphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { for (const V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { const V3GraphVertex* top = edgep->top(); - hash = vx2Id[top] + 31u * hash; // The K&R hash function + hash = vx2Id[top] + 31U * hash; // The K&R hash function } } UINFO(0, "Hash of shape (not contents) of " << debugName << " = " << cvtToStr(hash) << endl); diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index d965f3ff6..466d3b209 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -1215,10 +1215,13 @@ int V3PreProcImp::getStateToken() { UINFO(5, "``-end-defarg Out:" << out << endl); statePop(); } - if (!m_off) unputDefrefString(out); + if (!m_off) { + unputDefrefString(out); + } // Prevent problem when EMPTY="" in `ifdef NEVER `define `EMPTY - else if (stateIsDefname()) + else if (stateIsDefname()) { unputDefrefString("__IF_OFF_IGNORED_DEFINE"); + } m_lexp->m_parenLevel = 0; } else { // Finished a defref inside a upper defref // Can't subst now, or @@ -1433,10 +1436,13 @@ int V3PreProcImp::getStateToken() { UINFO(5, "``-end-defref Out:" << out << endl); statePop(); } - if (!m_off) unputDefrefString(out); + if (!m_off) { + unputDefrefString(out); + } // Prevent problem when EMPTY="" in `ifdef NEVER `define `EMPTY - else if (stateIsDefname()) + else if (stateIsDefname()) { unputDefrefString("__IF_OFF_IGNORED_DEFINE"); + } } else { // Inside another define. // Can't subst now, or diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 51d96d6cf..f051ed1c8 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -949,7 +949,8 @@ public: points.push_back(std::make_pair(it->msb() + 1, true)); // End of a region } if (skipUnused && !m_rhs.empty()) { // Range to be read must be kept, so add points here - int lsb = m_basicp->msb() + 1, msb = m_basicp->lsb() - 1; + int lsb = m_basicp->msb() + 1; + int msb = m_basicp->lsb() - 1; for (size_t i = 0; i < m_rhs.size(); ++i) { lsb = std::min(lsb, m_rhs[i].lsb()); msb = std::max(msb, m_rhs[i].msb()); diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index 7ac74a154..57f22c16e 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -523,7 +523,8 @@ public: // For test purposes, each TspTestState is merely a point // on the Cartesian plane; cost is the linear distance // between two points. - unsigned xabs, yabs; + unsigned xabs; + unsigned yabs; xabs = diff(otherp->m_xpos, m_xpos); yabs = diff(otherp->m_ypos, m_ypos); return lround(sqrt(xabs * xabs + yabs * yabs)); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a21e85daf..a9b34a301 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2842,9 +2842,9 @@ private: patp->dtypep(vdtypep); AstNode* valuep = patternMemberValueIterate(patp); { // Packed. Convert to concat for now. - if (!newp) + if (!newp) { newp = valuep; - else { + } else { AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep); newp = concatp; newp->dtypeSetLogicSized(concatp->lhsp()->width() diff --git a/src/VlcOptions.h b/src/VlcOptions.h index e2af6e5e6..6d76dd99d 100644 --- a/src/VlcOptions.h +++ b/src/VlcOptions.h @@ -46,8 +46,8 @@ class VlcOptions { private: // METHODS - void showVersion(bool verbose); - bool onoff(const char* sw, const char* arg, bool& flag); + static void showVersion(bool verbose); + static bool onoff(const char* sw, const char* arg, bool& flag); public: // CONSTRUCTORS From 8f7e463656ff45dde534060c51ceb8c7197d9c3f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 16 Apr 2020 17:31:41 -0400 Subject: [PATCH 061/127] Tests: Fix makeflag test, was failing older makes. --- test_regress/t/t_flag_build_make.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/t/t_flag_build_make.pl b/test_regress/t/t_flag_build_make.pl index 400e3c51e..0084a0b55 100755 --- a/test_regress/t/t_flag_build_make.pl +++ b/test_regress/t/t_flag_build_make.pl @@ -17,7 +17,7 @@ compile( # Don't call cmake nor gmake from driver.pl verilator_make_gmake => 0, verilator_flags2 => ['--exe --cc --build -j 2 --make gmake', '../' . $Self->{main_filename}, - '-MAKEFLAGS --trace'], + '-MAKEFLAGS -p --trace'], ); execute( From 39d7cbf4123b855cba6af4e30f4e90aabf3dcb6b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 17 Apr 2020 19:30:53 -0400 Subject: [PATCH 062/127] Fix arrayed instances connecting to slices, #2263. --- Changes | 4 +- src/V3Inst.cpp | 16 ++++- test_regress/t/t_inst_dearray_slice.pl | 21 ++++++ test_regress/t/t_inst_dearray_slice.v | 90 ++++++++++++++++++++++++++ 4 files changed, 126 insertions(+), 5 deletions(-) create mode 100755 test_regress/t/t_inst_dearray_slice.pl create mode 100644 test_regress/t/t_inst_dearray_slice.v diff --git a/Changes b/Changes index 27a11f24c..8c68249c5 100644 --- a/Changes +++ b/Changes @@ -24,11 +24,11 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. -**** Greatly improve FST dump performance, #2244, #2250, #2257. [Geza Lore] +**** Greatly improve FST/VCD dump performance, #2244, #2246, #2250, #2257. [Geza Lore] **** Fix build of fast path tracing code to use OPT_FAST, #2245. [Geza Lore] -**** Improve VCD dump performance, #2246, #2250, #2257. [Geza Lore] +**** Fix arrayed instances connecting to slices, #2263. [Don/engr248] * Verilator 4.032 2020-04-04 diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index aa602b75e..fab5f9eac 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -371,10 +371,11 @@ private: } else { nodep->v3fatalSrc("Width mismatch; V3Width should have errored out."); } - } else if (AstArraySel* arrselp = VN_CAST(nodep->exprp(), ArraySel)) { + } // end expanding ranged cell + else if (AstArraySel* arrselp = VN_CAST(nodep->exprp(), ArraySel)) { if (AstUnpackArrayDType* arrp = VN_CAST(arrselp->lhsp()->dtypep(), UnpackArrayDType)) { if (!VN_IS(arrp->subDTypep(), IfaceRefDType)) return; - + // Interface pin attaches to one element of arrayed interface V3Const::constifyParamsEdit(arrselp->rhsp()); const AstConst* constp = VN_CAST(arrselp->rhsp(), Const); if (!constp) { @@ -395,6 +396,7 @@ private: AstVar* pinVarp = nodep->modVarp(); AstUnpackArrayDType* pinArrp = VN_CAST(pinVarp->dtypep(), UnpackArrayDType); if (!pinArrp || !VN_IS(pinArrp->subDTypep(), IfaceRefDType)) return; + // Arrayed pin/var attaches to arrayed submodule lower port/var, expand it AstNode* prevp = NULL; AstNode* prevPinp = NULL; // Clone the var referenced by the pin, and clone each var referenced by the varref @@ -432,8 +434,16 @@ private: newp->modVarp(varNewp); newp->name(newp->name() + "__BRA__" + cvtToStr(i) + "__KET__"); // And replace exprp with a new varxref + int offset = 0; const AstVarRef* varrefp = VN_CAST(newp->exprp(), VarRef); - string newname = varrefp->name() + "__BRA__" + cvtToStr(i) + "__KET__"; + if (varrefp) { + } else if (AstSliceSel* slicep = VN_CAST(newp->exprp(), SliceSel)) { + varrefp = VN_CAST(slicep->fromp(), VarRef); + UASSERT(VN_IS(slicep->rhsp(), Const), "Slices should be constant"); + offset = VN_CAST(slicep->rhsp(), Const)->toSInt(); + } + if (!varrefp) { newp->exprp()->v3error("Unexpected connection to arrayed port"); } + string newname = varrefp->name() + "__BRA__" + cvtToStr(i + offset) + "__KET__"; AstVarXRef* newVarXRefp = new AstVarXRef(nodep->fileline(), newname, "", true); newVarXRefp->varp(newp->modVarp()); newVarXRefp->dtypep(newp->modVarp()->dtypep()); diff --git a/test_regress/t/t_inst_dearray_slice.pl b/test_regress/t/t_inst_dearray_slice.pl new file mode 100755 index 000000000..e02817219 --- /dev/null +++ b/test_regress/t/t_inst_dearray_slice.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_inst_dearray_slice.v b/test_regress/t/t_inst_dearray_slice.v new file mode 100644 index 000000000..1cc17c8cb --- /dev/null +++ b/test_regress/t/t_inst_dearray_slice.v @@ -0,0 +1,90 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by engr248. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + wire [31:0] in = 0; + wire [31:0] out; + + Test test( + .out(out[31:0]), + .clk(clk), + .in (in[31:0]) + ); + + always @ (posedge clk) begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule + +interface Intf (); +endinterface + +module Select + #( + parameter int NUM_MASTER = 1 + ) + ( + Intf Upstream, + Intf Downstream[NUM_MASTER] + ); +endmodule + +module Crossbar + #( + parameter int NUM_MASTER = 1, + parameter int NUM_SLAVE = 1 + ) + ( + Intf Masters[NUM_MASTER] + ); + + Intf selectOut[(NUM_MASTER * (NUM_SLAVE+1))-1 : 0](); + + + genvar i; + + for (i = 0; i < NUM_MASTER; i = i + 1) begin + Select #( + .NUM_MASTER(NUM_SLAVE+1) + ) + select_inst ( + .Upstream(Masters[i]), + // Following line triggered the dearrayAll segfault + .Downstream(selectOut[(i+1)*(NUM_SLAVE+1) - 1 : i*(NUM_SLAVE+1)]) + ); + end + +endmodule + +module Test + ( + input clk, + input [31:0] in, + output reg [31:0] out + ); + + always @(posedge clk) begin + out <= in; + end + + Intf MST[2](); //MST must have >1 array size to trigger dearrayAll segfault + + Crossbar #( + .NUM_MASTER(2), + .NUM_SLAVE(1) + ) + xbar_inst ( + .Masters(MST) + ); + +endmodule From 74e16d85c547c3b6065deaf491776a5830d174ac Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 18 Apr 2020 23:54:02 +0100 Subject: [PATCH 063/127] Fix FST trace initial time stamp. (#2264) If the first dump was not at time zero, then the FST trace used to contain the initial values as if they were set at time zero. Now they only appear at the time the first dump call is actually made, and hence match the VCD trace exactly. --- include/verilated_fst_c.cpp | 2 +- test_regress/t/t_trace_two_dumpfst_cc.out | 11 ++++++----- test_regress/t/t_trace_two_portfst_cc.out | 11 ++++++----- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index afbf007ea..68f7becf4 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -230,6 +230,7 @@ void VerilatedFst::dump(vluint64_t timeui) { return; } m_minNextDumpTime = timeui + 1; + fstWriterEmitTimeChange(m_fst, timeui); if (VL_UNLIKELY(m_fullDump)) { m_fullDump = false; // No more need for next dump to be full for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { @@ -238,7 +239,6 @@ void VerilatedFst::dump(vluint64_t timeui) { } return; } - fstWriterEmitTimeChange(m_fst, timeui); for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { VerilatedFstCallInfo* cip = m_callbacks[ent]; (cip->m_changecb)(this, cip->m_userthis, cip->m_code); diff --git a/test_regress/t/t_trace_two_dumpfst_cc.out b/test_regress/t/t_trace_two_dumpfst_cc.out index b956e40cd..70134be06 100755 --- a/test_regress/t/t_trace_two_dumpfst_cc.out +++ b/test_regress/t/t_trace_two_dumpfst_cc.out @@ -1,5 +1,5 @@ $date - Mon Apr 6 08:10:23 2020 + Sat Apr 18 22:18:21 2020 $end $version @@ -21,10 +21,11 @@ $upscope $end $upscope $end $enddefinitions $end $dumpvars -1! -b00000000000000000000000000000001 " -b00000000000000000000000000000000 # +#10 b00000000000000000000000000000001 $ +b00000000000000000000000000000000 # +b00000000000000000000000000000001 " +1! #15 0! #20 @@ -83,5 +84,5 @@ b00000000000000000000000000001010 " 0! #110 1! -b00000000000000000000000000001011 " b00000000000000000000000000001100 # +b00000000000000000000000000001011 " diff --git a/test_regress/t/t_trace_two_portfst_cc.out b/test_regress/t/t_trace_two_portfst_cc.out index 60ff90a86..cb4a741f0 100755 --- a/test_regress/t/t_trace_two_portfst_cc.out +++ b/test_regress/t/t_trace_two_portfst_cc.out @@ -1,5 +1,5 @@ $date - Mon Apr 6 08:24:52 2020 + Sat Apr 18 22:19:21 2020 $end $version @@ -21,10 +21,11 @@ $upscope $end $upscope $end $enddefinitions $end $dumpvars -1! -b00000000000000000000000000000001 " -b00000000000000000000000000000000 # +#10 b00000000000000000000000000000001 $ +b00000000000000000000000000000000 # +b00000000000000000000000000000001 " +1! #15 0! #20 @@ -83,5 +84,5 @@ b00000000000000000000000000001010 " 0! #110 1! -b00000000000000000000000000001011 " b00000000000000000000000000001100 # +b00000000000000000000000000001011 " From efacac2e3dc70d145adf7ddc6b7f835def0ea038 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 18 Apr 2020 23:56:19 +0100 Subject: [PATCH 064/127] Tests: Ignore SystemC file paths in expected test results (#2265) --- test_regress/driver.pl | 1 + test_regress/t/t_time_sc_ms.out | 1 - test_regress/t/t_time_sc_sec.out | 1 - test_regress/t/t_time_sc_us.out | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 9ef588a21..65bb340f5 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2015,6 +2015,7 @@ sub files_identical { && !/^- [a-z.0-9]+:\d+:[^\n]+\n/ && !/^-node:/ && !/^dot [^\n]+\n/ + && !/^In file: \/.*\/systemc-\d\.\d\.\d\/.*:\d+/ } @l1; @l1 = map { s/(Internal Error: [^\n]+\.cpp):[0-9]+:/$1:#:/; diff --git a/test_regress/t/t_time_sc_ms.out b/test_regress/t/t_time_sc_ms.out index 1c323b169..14f456687 100644 --- a/test_regress/t/t_time_sc_ms.out +++ b/test_regress/t/t_time_sc_ms.out @@ -1,6 +1,5 @@ Warning: (W516) default time unit changed to time resolution -In file: /svaha/sicortex/eda/systemc/systemc-2.3.3/systemc-2.3.3/src/sysc/kernel/sc_time.cpp:412 Time scale of t is 1ms / 1ms [20] In top.t: Hi - expect this is 20 *-* All Finished *-* diff --git a/test_regress/t/t_time_sc_sec.out b/test_regress/t/t_time_sc_sec.out index 545cd35d0..74cdb5ba8 100644 --- a/test_regress/t/t_time_sc_sec.out +++ b/test_regress/t/t_time_sc_sec.out @@ -1,6 +1,5 @@ Warning: (W516) default time unit changed to time resolution -In file: /svaha/sicortex/eda/systemc/systemc-2.3.3/systemc-2.3.3/src/sysc/kernel/sc_time.cpp:412 Time scale of t is 1s / 1s [20] In top.t: Hi - expect this is 20 *-* All Finished *-* diff --git a/test_regress/t/t_time_sc_us.out b/test_regress/t/t_time_sc_us.out index bfcaa2024..a2680e350 100644 --- a/test_regress/t/t_time_sc_us.out +++ b/test_regress/t/t_time_sc_us.out @@ -1,6 +1,5 @@ Warning: (W516) default time unit changed to time resolution -In file: /svaha/sicortex/eda/systemc/systemc-2.3.3/systemc-2.3.3/src/sysc/kernel/sc_time.cpp:412 Time scale of t is 1us / 1us [20] In top.t: Hi - expect this is 20 *-* All Finished *-* From 466535abdcaf6da23812f26753ac67fd610422c8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 18 Apr 2020 20:20:17 -0400 Subject: [PATCH 065/127] Support direct class member init. --- bin/verilator | 5 ++-- src/V3LinkParse.cpp | 15 ++++++------ src/V3Task.cpp | 40 +++++++++++++++++++++++++++++--- test_regress/t/t_class_local.out | 7 ------ test_regress/t/t_class_local.pl | 8 +++---- 5 files changed, 49 insertions(+), 26 deletions(-) delete mode 100644 test_regress/t/t_class_local.out diff --git a/bin/verilator b/bin/verilator index fed1cb08d..2a2ea028b 100755 --- a/bin/verilator +++ b/bin/verilator @@ -3623,9 +3623,8 @@ path. =head2 Class Verilator class support is very limited and in active development. -Verilator supports members, and methods. Verilator doe not support initial -values on class members, class static members, class extend, or class -parameters. +Verilator supports members, and methods. Verilator doe not support class +static members, class extend, or class parameters. =head2 Dotted cross-hierarchy references diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 1d5e7a510..c5b1a89c7 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -221,17 +221,16 @@ private: if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) { // 1. Parameters and function inputs: It's a default to use if not overridden } else if (VN_IS(m_modp, Class)) { - // We make a AstVar initial value, but then do not set it in the constructor - // V3Emit::emitVarRecurse only does non-value inits. - // Perhaps these should still become a new form of - // AstInitial, and we propagate the initial to the class - // constructor - nodep->valuep()->v3error("Unsupported: initial value on member"); + // 2. Class member init become initials (as might call functions) + // later move into class constructor + nodep->addNextHere( + new AstInitial(fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), true), + nodep->valuep()->unlinkFrBack()))); } else if (!m_ftaskp && nodep->isNonOutput()) { nodep->v3error( "Unsupported: Default value on module input: " << nodep->prettyNameQ()); nodep->valuep()->unlinkFrBack()->deleteTree(); - } // 2. Under modules, it's an initial value to be loaded at time 0 via an AstInitial + } // 3. Under modules, it's an initial value to be loaded at time 0 via an AstInitial else if (m_valueModp) { // Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it FileLine* newfl = new FileLine(fl); @@ -239,7 +238,7 @@ private: nodep->addNextHere(new AstInitial( newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true), nodep->valuep()->unlinkFrBack()))); - } // 3. Under blocks, it's an initial value to be under an assign + } // 4. Under blocks, it's an initial value to be under an assign else { nodep->addNextHere(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true), nodep->valuep()->unlinkFrBack())); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 3ab819107..8fcd656ff 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -110,11 +110,14 @@ private: // TYPES typedef std::map, AstVarScope*> VarToScopeMap; + typedef std::vector Initials; // MEMBERS VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings AstAssignW* m_assignwp; // Current assignment + AstNodeFTask* m_ctorp; // Class constructor V3Graph m_callGraph; // Task call graph TaskBaseVertex* m_curVxp; // Current vertex we're adding to + Initials m_initialps; // Initial blocks to move public: // METHODS @@ -202,7 +205,10 @@ private: m_curVxp = getFTaskVertex(nodep); if (nodep->dpiImport()) m_curVxp->noInline(true); if (nodep->classMethod()) m_curVxp->noInline(true); // Until V3Task supports it - if (nodep->isConstructor()) m_curVxp->noInline(true); + if (nodep->isConstructor()) { + m_curVxp->noInline(true); + m_ctorp = nodep; + } iterateChildren(nodep); m_curVxp = lastVxp; } @@ -225,13 +231,41 @@ private: if (m_curVxp->pure() && !nodep->varp()->isXTemp()) m_curVxp->impure(nodep); } } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + // Move initial statements into the constructor + m_initialps.clear(); + m_ctorp = NULL; + { // Find m_initialps, m_ctor + iterateChildren(nodep); + } + UASSERT_OBJ(m_ctorp, nodep, "class constructor missing"); // LinkDot always makes it + for (Initials::iterator it = m_initialps.begin(); it != m_initialps.end(); ++it) { + AstInitial* initialp = *it; + if (AstNode* newp = initialp->bodysp()) { + newp->unlinkFrBackWithNext(); + if (!m_ctorp->stmtsp()) { + m_ctorp->addStmtsp(newp); + } else { + m_ctorp->stmtsp()->addHereThisAsNext(newp); + } + } + VL_DO_DANGLING(pushDeletep(initialp->unlinkFrBack()), initialp); + } + m_initialps.clear(); + m_ctorp = NULL; + } + virtual void visit(AstInitial* nodep) VL_OVERRIDE { + m_initialps.push_back(nodep); + iterateChildren(nodep); + } //-------------------- virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } public: // CONSTRUCTORS - explicit TaskStateVisitor(AstNetlist* nodep) { - m_assignwp = NULL; + explicit TaskStateVisitor(AstNetlist* nodep) + : m_assignwp(NULL) + , m_ctorp(NULL) { m_curVxp = new TaskCodeVertex(&m_callGraph); AstNode::user3ClearTree(); AstNode::user4ClearTree(); diff --git a/test_regress/t/t_class_local.out b/test_regress/t/t_class_local.out deleted file mode 100644 index 397a3ef37..000000000 --- a/test_regress/t/t_class_local.out +++ /dev/null @@ -1,7 +0,0 @@ -%Error: t/t_class_local.v:12:22: Unsupported: initial value on member - 12 | local int m_loc = 2; - | ^ -%Error: t/t_class_local.v:13:27: Unsupported: initial value on member - 13 | protected int m_prot = B; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_class_local.pl b/test_regress/t/t_class_local.pl index 64b3d2dde..27b3049d2 100755 --- a/test_regress/t/t_class_local.pl +++ b/test_regress/t/t_class_local.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ); ok(1); 1; From 6a54922044d96f601b5240ef9098ed67821499c1 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 19 Apr 2020 13:47:22 +0100 Subject: [PATCH 066/127] Set FST timescale correctly. (#2266) The FST trace timescale used to be set in the constructor via set_time_unit, but at that point we haven't normally opened the file yet so it was just dropped. On top of that, we actually want to use set_time_resolution... FST trace timescales now match the VCD. --- include/verilated_fst_c.cpp | 1 + include/verilated_fst_c.h | 8 +++++--- test_regress/t/t_interface_ref_trace_fst.out | 4 ++-- test_regress/t/t_trace_array_fst.out | 4 ++-- test_regress/t/t_trace_complex_fst.out | 4 ++-- test_regress/t/t_trace_complex_params_fst.out | 4 ++-- test_regress/t/t_trace_complex_structs_fst.out | 4 ++-- test_regress/t/t_trace_fst.out | 4 ++-- test_regress/t/t_trace_packed_struct_fst.out | 4 ++-- test_regress/t/t_trace_two_dumpfst_cc.out | 4 ++-- test_regress/t/t_trace_two_hdrfst_cc.out | 4 ++-- test_regress/t/t_trace_two_portfst_cc.out | 4 ++-- 12 files changed, 26 insertions(+), 23 deletions(-) diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 68f7becf4..7f4a763bc 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -100,6 +100,7 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { m_assertOne.check(); m_fst = fstWriterCreate(filename, 1); fstWriterSetPackType(m_fst, FST_WR_PT_LZ4); + fstWriterSetTimescaleFromString(m_fst, m_timeRes.c_str()); #ifdef VL_TRACE_THREADED fstWriterSetParallelMode(m_fst, 1); #endif diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index ed41eb031..b59b90a5b 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -65,6 +65,8 @@ private: // helpers std::vector m_valueStrBuffer; + std::string m_timeRes; + public: explicit VerilatedFst(void* fst = NULL); ~VerilatedFst(); @@ -77,11 +79,11 @@ public: fstWriterClose(m_fst); m_fst = NULL; } - void set_time_unit(const char* unitp) { fstWriterSetTimescaleFromString(m_fst, unitp); } + void set_time_unit(const char*) {} void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); } - void set_time_resolution(const char*) {} - void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); } + void set_time_resolution(const char* unitp) { m_timeRes = unitp; } + void set_time_resolution(const std::string& unit) { m_timeRes = unit; } // double timescaleToDouble(const char* unitp); // std::string doubleToTimescale(double value); diff --git a/test_regress/t/t_interface_ref_trace_fst.out b/test_regress/t/t_interface_ref_trace_fst.out index 0c3b36d2d..7ccec6303 100644 --- a/test_regress/t/t_interface_ref_trace_fst.out +++ b/test_regress/t/t_interface_ref_trace_fst.out @@ -1,12 +1,12 @@ $date - Wed Dec 4 07:48:29 2019 + Sun Apr 19 04:13:22 2020 $end $version fstWriter $end $timescale - 1ns + 1ps $end $scope module top $end $var wire 1 ! clk $end diff --git a/test_regress/t/t_trace_array_fst.out b/test_regress/t/t_trace_array_fst.out index 4bfede89b..52b55a782 100644 --- a/test_regress/t/t_trace_array_fst.out +++ b/test_regress/t/t_trace_array_fst.out @@ -1,12 +1,12 @@ $date - Sun Oct 21 21:57:08 2018 + Sun Apr 19 04:15:23 2020 $end $version fstWriter $end $timescale - 1ns + 1ps $end $scope module top $end $var wire 1 ! clk $end diff --git a/test_regress/t/t_trace_complex_fst.out b/test_regress/t/t_trace_complex_fst.out index 7ceb73591..8b05384c7 100644 --- a/test_regress/t/t_trace_complex_fst.out +++ b/test_regress/t/t_trace_complex_fst.out @@ -1,12 +1,12 @@ $date - Sun Apr 12 20:15:55 2020 + Sun Apr 19 04:15:26 2020 $end $version fstWriter $end $timescale - 1ns + 1ps $end $scope module top $end $var wire 1 ! clk $end diff --git a/test_regress/t/t_trace_complex_params_fst.out b/test_regress/t/t_trace_complex_params_fst.out index 63f837f52..c94200384 100644 --- a/test_regress/t/t_trace_complex_params_fst.out +++ b/test_regress/t/t_trace_complex_params_fst.out @@ -1,12 +1,12 @@ $date - Sun Apr 12 20:17:15 2020 + Sun Apr 19 04:15:31 2020 $end $version fstWriter $end $timescale - 1ns + 1ps $end $scope module top $end $var wire 1 ! clk $end diff --git a/test_regress/t/t_trace_complex_structs_fst.out b/test_regress/t/t_trace_complex_structs_fst.out index 8319f05a6..1cde8a16c 100644 --- a/test_regress/t/t_trace_complex_structs_fst.out +++ b/test_regress/t/t_trace_complex_structs_fst.out @@ -1,12 +1,12 @@ $date - Sun Apr 12 20:14:19 2020 + Sun Apr 19 04:15:33 2020 $end $version fstWriter $end $timescale - 1ns + 1ps $end $scope module top $end $var wire 1 ! clk $end diff --git a/test_regress/t/t_trace_fst.out b/test_regress/t/t_trace_fst.out index 0a3805543..dde4f07e0 100644 --- a/test_regress/t/t_trace_fst.out +++ b/test_regress/t/t_trace_fst.out @@ -1,12 +1,12 @@ $date - Sun Apr 12 20:17:58 2020 + Sun Apr 19 04:15:36 2020 $end $version fstWriter $end $timescale - 1ns + 1ps $end $scope module top $end $var wire 1 ! clk $end diff --git a/test_regress/t/t_trace_packed_struct_fst.out b/test_regress/t/t_trace_packed_struct_fst.out index 6335f7b24..ac5cfac00 100644 --- a/test_regress/t/t_trace_packed_struct_fst.out +++ b/test_regress/t/t_trace_packed_struct_fst.out @@ -1,12 +1,12 @@ $date - Sun Apr 12 20:19:35 2020 + Sun Apr 19 04:15:38 2020 $end $version fstWriter $end $timescale - 1ns + 1ps $end $scope module top $end $var wire 1 ! clk $end diff --git a/test_regress/t/t_trace_two_dumpfst_cc.out b/test_regress/t/t_trace_two_dumpfst_cc.out index 70134be06..c22d2b128 100755 --- a/test_regress/t/t_trace_two_dumpfst_cc.out +++ b/test_regress/t/t_trace_two_dumpfst_cc.out @@ -1,12 +1,12 @@ $date - Sat Apr 18 22:18:21 2020 + Sun Apr 19 04:15:48 2020 $end $version fstWriter $end $timescale - 1ns + 1ps $end $scope module topa $end $var wire 1 ! clk $end diff --git a/test_regress/t/t_trace_two_hdrfst_cc.out b/test_regress/t/t_trace_two_hdrfst_cc.out index 52aefd9cc..538f5e7e6 100755 --- a/test_regress/t/t_trace_two_hdrfst_cc.out +++ b/test_regress/t/t_trace_two_hdrfst_cc.out @@ -1,12 +1,12 @@ $date - Sat Mar 7 18:27:58 2020 + Sun Apr 19 04:15:51 2020 $end $version fstWriter $end $timescale - 1ns + 1ps $end $scope module topa $end $var wire 1 ! clk $end diff --git a/test_regress/t/t_trace_two_portfst_cc.out b/test_regress/t/t_trace_two_portfst_cc.out index cb4a741f0..a8a068954 100755 --- a/test_regress/t/t_trace_two_portfst_cc.out +++ b/test_regress/t/t_trace_two_portfst_cc.out @@ -1,12 +1,12 @@ $date - Sat Apr 18 22:19:21 2020 + Sun Apr 19 04:13:00 2020 $end $version fstWriter $end $timescale - 1ns + 1ps $end $scope module topa $end $var wire 1 ! clk $end From 4ae3d3af71486ba3b3e6800dee3c8c7ac0f50548 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 19 Apr 2020 12:43:20 -0400 Subject: [PATCH 067/127] Fix docker build error --- ci/docker/run/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/docker/run/Dockerfile b/ci/docker/run/Dockerfile index 315123203..83393fdbc 100644 --- a/ci/docker/run/Dockerfile +++ b/ci/docker/run/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update \ build-essential=12.4ubuntu1 \ ca-certificates=20180409 \ flex=2.6.4-6 \ - git=1:2.17.1-1ubuntu0.5 \ + git=1:2.17.1-1ubuntu0.6 \ libfl-dev=2.6.4-6 \ perl=5.26.1-6ubuntu0.3 \ python3=3.6.7-1~18.04 \ From 7b789fe02a847a444c407eae015b22d65643fbf1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 19 Apr 2020 12:59:38 -0400 Subject: [PATCH 068/127] Docker: Add ccache and libgoogle-perftools-dev --- ci/docker/run/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/docker/run/Dockerfile b/ci/docker/run/Dockerfile index 83393fdbc..83fb70a8e 100644 --- a/ci/docker/run/Dockerfile +++ b/ci/docker/run/Dockerfile @@ -15,9 +15,11 @@ RUN apt-get update \ bison=2:3.0.4.dfsg-1build1 \ build-essential=12.4ubuntu1 \ ca-certificates=20180409 \ + ccache \ flex=2.6.4-6 \ git=1:2.17.1-1ubuntu0.6 \ libfl-dev=2.6.4-6 \ + libgoogle-perftools-dev \ perl=5.26.1-6ubuntu0.3 \ python3=3.6.7-1~18.04 \ && apt-get clean \ From 9164eb03d557ed7f446610987ec8be4a0388c521 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 19 Apr 2020 18:36:55 -0400 Subject: [PATCH 069/127] Show that class parameters even if unused are unsupported. --- src/V3LinkResolve.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 904c4882e..35ea685db 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -100,7 +100,8 @@ private: } virtual void visit(AstVar* nodep) VL_OVERRIDE { iterateChildren(nodep); - if (m_classp) nodep->varType(AstVarType::MEMBER); + if (m_classp && !nodep->isParam()) nodep->varType(AstVarType::MEMBER); + if (m_classp && nodep->isParam()) nodep->v3error("Unsupported: class parameter"); if (m_ftaskp) nodep->funcLocal(true); if (nodep->isSigModPublic()) { nodep->sigModPublic(false); // We're done with this attribute From 39d903375b482d2add22f6e85e845cce80429f5e Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 19 Apr 2020 23:57:36 +0100 Subject: [PATCH 070/127] Factor out trace implementation common to all formats. (#2268) This patch de-duplicates common functionality between the VCD and FST trace implementation. It also enables adding new trace formats more easily and consistently. No functional nor performance change intended. --- include/verilated_fst_c.cpp | 144 +++++-------- include/verilated_fst_c.h | 186 +++++------------ include/verilated_trace.h | 184 +++++++++++++++++ include/verilated_trace_imp.cpp | 309 ++++++++++++++++++++++++++++ include/verilated_vcd_c.cpp | 351 ++++++-------------------------- include/verilated_vcd_c.h | 249 ++++++++-------------- 6 files changed, 752 insertions(+), 671 deletions(-) create mode 100644 include/verilated_trace.h create mode 100644 include/verilated_trace_imp.cpp diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 7f4a763bc..a128639ca 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -20,7 +20,6 @@ // clang-format off #define __STDC_LIMIT_MACROS // UINT64_MAX -#include "verilatedos.h" #include "verilated.h" #include "verilated_fst_c.h" @@ -54,65 +53,35 @@ // clang-format on //============================================================================= +// Specialization of the generics for this trace format -class VerilatedFstCallInfo { -protected: - friend class VerilatedFst; - VerilatedFstCallback_t m_initcb; ///< Initialization Callback function - VerilatedFstCallback_t m_fullcb; ///< Full Dumping Callback function - VerilatedFstCallback_t m_changecb; ///< Incremental Dumping Callback function - void* m_userthis; ///< Fake "this" for caller - vluint32_t m_code; ///< Starting code number - // CONSTRUCTORS - VerilatedFstCallInfo(VerilatedFstCallback_t icb, VerilatedFstCallback_t fcb, - VerilatedFstCallback_t changecb, void* ut) - : m_initcb(icb) - , m_fullcb(fcb) - , m_changecb(changecb) - , m_userthis(ut) - , m_code(1) {} - ~VerilatedFstCallInfo() {} -}; +#define VL_DERIVED_T VerilatedFst +#include "verilated_trace_imp.cpp" +#undef VL_DERIVED_T //============================================================================= // VerilatedFst VerilatedFst::VerilatedFst(void* fst) : m_fst(fst) - , m_fullDump(true) - , m_minNextDumpTime(0) - , m_nextCode(1) - , m_scopeEscape('.') - , m_symbolp(NULL) - , m_sigs_oldvalp(NULL) { - m_valueStrBuffer.reserve(64 + 1); // Need enough room for quad - set_time_unit(Verilated::timeunitString()); - set_time_resolution(Verilated::timeprecisionString()); -} + , m_symbolp(NULL) {} VerilatedFst::~VerilatedFst() { if (m_fst) fstWriterClose(m_fst); if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = NULL); - if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL); } void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { m_assertOne.check(); m_fst = fstWriterCreate(filename, 1); fstWriterSetPackType(m_fst, FST_WR_PT_LZ4); - fstWriterSetTimescaleFromString(m_fst, m_timeRes.c_str()); + fstWriterSetTimescaleFromString(m_fst, timeResStr().c_str()); // lintok-begin-on-ref #ifdef VL_TRACE_THREADED fstWriterSetParallelMode(m_fst, 1); #endif m_curScope.clear(); - m_nextCode = 1; - for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { - VerilatedFstCallInfo* cip = m_callbacks[ent]; - cip->m_code = m_nextCode; - // Initialize; callbacks will call decl* which update m_nextCode - (cip->m_initcb)(this, cip->m_userthis, cip->m_code); - } + VerilatedTrace::traceInit(); // Clear the scope stack std::list::iterator it = m_curScope.begin(); @@ -123,19 +92,16 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { // convert m_code2symbol into an array for fast lookup if (!m_symbolp) { - m_symbolp = new fstHandle[m_nextCode + 10]; + m_symbolp = new fstHandle[nextCode()]; for (Code2SymbolType::iterator it = m_code2symbol.begin(); it != m_code2symbol.end(); ++it) { m_symbolp[it->first] = it->second; } } m_code2symbol.clear(); - - // Allocate space now we know the number of codes - if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[m_nextCode + 10]; } -void VerilatedFst::module(const std::string& name) { m_module = name; } +void VerilatedFst::emitTimeChange(vluint64_t timeui) { fstWriterEmitTimeChange(m_fst, timeui); } //============================================================================= // Decl @@ -151,11 +117,7 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elem void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum, vluint32_t len, vluint32_t bits) { - - // Make sure deduplicate tracking increments for future declarations - int codesNeeded = 1 + int(bits / 32); - // Not supported: if (tri) codesNeeded *= 2; // Space in change array for __en signals - m_nextCode = std::max(m_nextCode, code + codesNeeded); + VerilatedTrace::declCode(code, bits, false); std::pair p = m_code2symbol.insert(std::make_pair(code, static_cast(NULL))); @@ -164,7 +126,7 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f std::list tokens(beg, end); // Split name std::string symbol_name(tokens.back()); tokens.pop_back(); // Remove symbol name from hierarchy - tokens.insert(tokens.begin(), m_module); // Add current module to the hierarchy + tokens.insert(tokens.begin(), moduleName()); // Add current module to the hierarchy // Find point where current and new scope diverge std::list::iterator cur_it = m_curScope.begin(); @@ -205,47 +167,49 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f } } -//============================================================================= -// Callbacks - -void VerilatedFst::addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb, - VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE { - m_assertOne.check(); - if (VL_UNLIKELY(isOpen())) { - std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__ - + " called with already open file"); - VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); - } - VerilatedFstCallInfo* cip = new VerilatedFstCallInfo(initcb, fullcb, changecb, userthis); - m_callbacks.push_back(cip); +void VerilatedFst::declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum) { + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1); +} +void VerilatedFst::declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum, int msb, int lsb) { + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, + msb - lsb + 1); +} +void VerilatedFst::declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum, int msb, int lsb) { + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, + msb - lsb + 1); +} +void VerilatedFst::declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum, int msb, int lsb) { + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, + msb - lsb + 1); +} +void VerilatedFst::declFloat(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum) { + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32); +} +void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, + fstVarType vartype, bool array, int arraynum) { + declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64); } -//============================================================================= -// Dumping - -void VerilatedFst::dump(vluint64_t timeui) { - if (!isOpen()) return; - if (timeui < m_minNextDumpTime) { - VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64 "u\n", - m_minNextDumpTime - 1, timeui); - return; - } - m_minNextDumpTime = timeui + 1; - fstWriterEmitTimeChange(m_fst, timeui); - if (VL_UNLIKELY(m_fullDump)) { - m_fullDump = false; // No more need for next dump to be full - for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { - VerilatedFstCallInfo* cip = m_callbacks[ent]; - (cip->m_fullcb)(this, cip->m_userthis, cip->m_code); - } - return; - } - for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { - VerilatedFstCallInfo* cip = m_callbacks[ent]; - (cip->m_changecb)(this, cip->m_userthis, cip->m_code); - } +void VerilatedFst::emitBit(vluint32_t code, vluint32_t newval) { + fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0"); +} +template void VerilatedFst::emitBus(vluint32_t code, vluint32_t newval) { + fstWriterEmitValueChange32(m_fst, m_symbolp[code], T_Bits, newval); +} +void VerilatedFst::emitQuad(vluint32_t code, vluint64_t newval, int bits) { + fstWriterEmitValueChange64(m_fst, m_symbolp[code], bits, newval); +} +void VerilatedFst::emitArray(vluint32_t code, const vluint32_t* newvalp, int bits) { + fstWriterEmitValueChangeVec32(m_fst, m_symbolp[code], bits, newvalp); +} +void VerilatedFst::emitFloat(vluint32_t code, float newval) { + fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval); +} +void VerilatedFst::emitDouble(vluint32_t code, double newval) { + fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval); } - -//******************************************************************** -// Local Variables: -// End: diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index b59b90a5b..9a8c7eb0e 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -20,8 +20,8 @@ #ifndef _VERILATED_FST_C_H_ #define _VERILATED_FST_C_H_ 1 -#include "verilatedos.h" #include "verilated.h" +#include "verilated_trace.h" #include "gtkwave/fstapi.h" @@ -30,176 +30,100 @@ #include #include -class VerilatedFst; -class VerilatedFstCallInfo; -typedef void (*VerilatedFstCallback_t)(VerilatedFst* vcdp, void* userthis, vluint32_t code); - //============================================================================= // VerilatedFst /// Base class to create a Verilator FST dump /// This is an internally used class - see VerilatedFstC for what to call from applications -class VerilatedFst { +class VerilatedFst : public VerilatedTrace { +private: + // Give the superclass access to private bits (to avoid virtual functions) + friend class VerilatedTrace; + + //========================================================================= + // FST specific internals + typedef std::map Code2SymbolType; typedef std::map Local2FstDtype; - typedef std::vector CallbackVec; -private: void* m_fst; - VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread - bool m_fullDump; - vluint64_t m_minNextDumpTime; - vluint32_t m_nextCode; ///< Next code number to assign - char m_scopeEscape; - std::string m_module; - CallbackVec m_callbacks; ///< Routines to perform dumping Code2SymbolType m_code2symbol; Local2FstDtype m_local2fstdtype; std::list m_curScope; fstHandle* m_symbolp; ///< same as m_code2symbol, but as an array - vluint32_t* m_sigs_oldvalp; // CONSTRUCTORS VL_UNCOPYABLE(VerilatedFst); void declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum, vluint32_t len, vluint32_t bits); - // helpers - std::vector m_valueStrBuffer; - std::string m_timeRes; +protected: + //========================================================================= + // Implementation of VerilatedTrace interface + + // Implementations of protected virtual methods for VerilatedTrace + void emitTimeChange(vluint64_t timeui) VL_OVERRIDE; + + // Hooks called from VerilatedTrace + bool preFullDump() VL_OVERRIDE { return isOpen(); } + bool preChangeDump() VL_OVERRIDE { return isOpen(); } + + // Implementations of duck-typed methods for VerilatedTrace + void emitBit(vluint32_t code, vluint32_t newval); + template void emitBus(vluint32_t code, vluint32_t newval); + void emitQuad(vluint32_t code, vluint64_t newval, int bits); + void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits); + void emitFloat(vluint32_t code, float newval); + void emitDouble(vluint32_t code, double newval); public: + //========================================================================= + // External interface to client code + explicit VerilatedFst(void* fst = NULL); ~VerilatedFst(); - void changeThread() { m_assertOne.changeThread(); } - bool isOpen() const { return m_fst != NULL; } + + /// Open the file; call isOpen() to see if errors void open(const char* filename) VL_MT_UNSAFE; - void flush() VL_MT_UNSAFE { fstWriterFlushContext(m_fst); } + /// Close the file void close() VL_MT_UNSAFE { m_assertOne.check(); fstWriterClose(m_fst); m_fst = NULL; } - void set_time_unit(const char*) {} - void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); } + /// Flush any remaining data to this file + void flush() VL_MT_UNSAFE { fstWriterFlushContext(m_fst); } + /// Is file open? + bool isOpen() const { return m_fst != NULL; } - void set_time_resolution(const char* unitp) { m_timeRes = unitp; } - void set_time_resolution(const std::string& unit) { m_timeRes = unit; } + //========================================================================= + // Internal interface to Verilator generated code - // double timescaleToDouble(const char* unitp); - // std::string doubleToTimescale(double value); - - /// Change character that splits scopes. Note whitespace are ALWAYS escapes. - void scopeEscape(char flag) { m_scopeEscape = flag; } - /// Is this an escape? - bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; } - /// Inside dumping routines, called each cycle to make the dump - void dump(vluint64_t timeui); - /// Inside dumping routines, declare callbacks for tracings - void addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb, - VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE; - - /// Inside dumping routines, declare a module - void module(const std::string& name); /// Inside dumping routines, declare a data type void declDTypeEnum(int dtypenum, const char* name, vluint32_t elements, unsigned int minValbits, const char** itemNamesp, const char** itemValuesp); + /// Inside dumping routines, declare a signal void declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1); - } + fstVarType vartype, bool array, int arraynum); void declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum, int msb, int lsb) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, - msb - lsb + 1); - } + fstVarType vartype, bool array, int arraynum, int msb, int lsb); void declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum, int msb, int lsb) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, - msb - lsb + 1); - } + fstVarType vartype, bool array, int arraynum, int msb, int lsb); void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum, int msb, int lsb) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, - msb - lsb + 1); - } + fstVarType vartype, bool array, int arraynum, int msb, int lsb); void declFloat(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32); - } + fstVarType vartype, bool array, int arraynum); void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum) { - declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64); - } - - //========================================================================= - // Inside dumping routines used by Verilator - - vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; } - - //========================================================================= - // Write back to previous value buffer value and emit - - void fullBit(vluint32_t* oldp, vluint32_t newval) { - *oldp = newval; - fstWriterEmitValueChange(m_fst, m_symbolp[oldp - m_sigs_oldvalp], newval ? "1" : "0"); - } - template void fullBus(vluint32_t* oldp, vluint32_t newval) { - *oldp = newval; - fstWriterEmitValueChange32(m_fst, m_symbolp[oldp - m_sigs_oldvalp], T_Bits, newval); - } - void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { - *reinterpret_cast(oldp) = newval; - fstWriterEmitValueChange64(m_fst, m_symbolp[oldp - m_sigs_oldvalp], bits, newval); - } - void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { - for (int i = 0; i < (bits + 31) / 32; ++i) oldp[i] = newvalp[i]; - fstWriterEmitValueChangeVec32(m_fst, m_symbolp[oldp - m_sigs_oldvalp], bits, newvalp); - } - void fullFloat(vluint32_t* oldp, float newval) { - // cppcheck-suppress invalidPointerCast - *reinterpret_cast(oldp) = newval; - fstWriterEmitValueChange(m_fst, m_symbolp[oldp - m_sigs_oldvalp], oldp); - } - void fullDouble(vluint32_t* oldp, double newval) { - // cppcheck-suppress invalidPointerCast - *reinterpret_cast(oldp) = newval; - fstWriterEmitValueChange(m_fst, m_symbolp[oldp - m_sigs_oldvalp], oldp); - } - - //========================================================================= - // Check previous value and emit if changed - - inline void chgBit(vluint32_t* oldp, vluint32_t newval) { - const vluint32_t diff = *oldp ^ newval; - if (VL_UNLIKELY(diff)) fullBit(oldp, newval); - } - template inline void chgBus(vluint32_t* oldp, vluint32_t newval) { - const vluint32_t diff = *oldp ^ newval; - if (VL_UNLIKELY(diff)) fullBus(oldp, newval); - } - inline void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { - const vluint64_t diff = *reinterpret_cast(oldp) ^ newval; - if (VL_UNLIKELY(diff)) fullQuad(oldp, newval, bits); - } - inline void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { - for (int i = 0; i < (bits + 31) / 32; ++i) { - if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) { - fullArray(oldp, newvalp, bits); - return; - } - } - } - inline void chgFloat(vluint32_t* oldp, float newval) { - // cppcheck-suppress invalidPointerCast - if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullFloat(oldp, newval); - } - inline void chgDouble(vluint32_t* oldp, double newval) { - // cppcheck-suppress invalidPointerCast - if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullDouble(oldp, newval); - } + fstVarType vartype, bool array, int arraynum); }; +// Declare specialization here as it's used in VerilatedFstC just below +template <> void VerilatedTrace::dump(vluint64_t timeui); +template <> void VerilatedTrace::set_time_unit(const char* unitp); +template <> void VerilatedTrace::set_time_unit(const std::string& unit); +template <> void VerilatedTrace::set_time_resolution(const char* unitp); +template <> void VerilatedTrace::set_time_resolution(const std::string& unit); + //============================================================================= // VerilatedFstC /// Create a FST dump file in C standalone (no SystemC) simulations. @@ -239,11 +163,11 @@ public: /// Set time units (s/ms, defaults to ns) /// For Verilated models, these propage from the Verilated default --timeunit void set_time_unit(const char* unitp) { m_sptrace.set_time_unit(unitp); } - void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); } + void set_time_unit(const std::string& unit) { m_sptrace.set_time_unit(unit); } /// Set time resolution (s/ms, defaults to ns) /// For Verilated models, these propage from the Verilated default --timeunit void set_time_resolution(const char* unitp) { m_sptrace.set_time_resolution(unitp); } - void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); } + void set_time_resolution(const std::string& unit) { m_sptrace.set_time_resolution(unit); } /// Internal class access inline VerilatedFst* spTrace() { return &m_sptrace; }; diff --git a/include/verilated_trace.h b/include/verilated_trace.h new file mode 100644 index 000000000..8be887734 --- /dev/null +++ b/include/verilated_trace.h @@ -0,0 +1,184 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//============================================================================= +// +// THIS MODULE IS PUBLICLY LICENSED +// +// Copyright 2001-2020 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//============================================================================= +/// +/// \file +/// \brief Tracing functionality common to all formats +/// +//============================================================================= +// SPDIFF_OFF + +#ifndef _VERILATED_TRACE_H_ +#define _VERILATED_TRACE_H_ 1 + +#include "verilated.h" + +#include +#include + +class VerilatedTraceCallInfo; + +//============================================================================= +// VerilatedTrace + +// VerilatedTrace uses F-bounded polymorphism to access duck-typed +// implementations in the format specific derived class, which must be passed +// as the type parameter T_Derived +template class VerilatedTrace { +private: + //========================================================================= + // Generic tracing internals + + vluint32_t* m_sigs_oldvalp; ///< Old value store + vluint64_t m_timeLastDump; ///< Last time we did a dump + std::vector m_callbacks; ///< Routines to perform dumping + bool m_fullDump; ///< Whether a full dump is required on the next call to 'dump' + vluint32_t m_nextCode; ///< Next code number to assign + std::string m_moduleName; ///< Name of module being trace initialized now + char m_scopeEscape; + double m_timeRes; ///< Time resolution (ns/ms etc) + double m_timeUnit; ///< Time units (ns/ms etc) + + // Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->' + // to access duck-typed functions to avoid a virtual function call. + T_Derived* self() { return static_cast(this); } + + // CONSTRUCTORS + VL_UNCOPYABLE(VerilatedTrace); + +protected: + //========================================================================= + // Internals available to format specific implementations + + VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread + + vluint32_t nextCode() const { return m_nextCode; } + const std::string& moduleName() const { return m_moduleName; } + void fullDump(bool value) { m_fullDump = value; } + vluint64_t timeLastDump() { return m_timeLastDump; } + + double timeRes() const { return m_timeRes; } + double timeUnit() const { return m_timeUnit; } + std::string timeResStr() const; + std::string timeUnitStr() const; + + void traceInit() VL_MT_UNSAFE; + + void declCode(vluint32_t code, vluint32_t bits, bool tri); + + /// Is this an escape? + bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; } + /// Character that splits scopes. Note whitespace are ALWAYS escapes. + char scopeEscape() { return m_scopeEscape; } + + //========================================================================= + // Virtual functions to be provided by the format specific implementation + + // Called when the trace moves forward to a new time point + virtual void emitTimeChange(vluint64_t timeui) = 0; + + // These hooks are called before a full or change based dump is produced. + // The return value indicates whether to proceed with the dump. + virtual bool preFullDump() { return true; } + virtual bool preChangeDump() { return true; } + +public: + //========================================================================= + // External interface to client code + + explicit VerilatedTrace(); + ~VerilatedTrace(); + + // Set time units (s/ms, defaults to ns) + void set_time_unit(const char* unitp); + void set_time_unit(const std::string& unit); + // Set time resolution (s/ms, defaults to ns) + void set_time_resolution(const char* unitp); + void set_time_resolution(const std::string& unit); + + // Call + void dump(vluint64_t timeui); + + //========================================================================= + // Non-hot path internal interface to Verilator generated code + + typedef void (*callback_t)(T_Derived* tracep, void* userthis, vluint32_t code); + + void changeThread() { m_assertOne.changeThread(); } + + void addCallback(callback_t initcb, callback_t fullcb, callback_t changecb, + void* userthis) VL_MT_UNSAFE_ONE; + + void module(const std::string& name) VL_MT_UNSAFE_ONE { + m_assertOne.check(); + m_moduleName = name; + } + + void scopeEscape(char flag) { m_scopeEscape = flag; } + + //========================================================================= + // Hot path internal interface to Verilator generated code + + // Implementation note: We rely on the following duck-typed implementations + // in the derived class T_Derived. These emit* functions record a format + // specific trace entry. Normally one would use pure virtual functions for + // these here, but we cannot afford dynamic dispatch for calling these as + // this is very hot code during tracing. + + // duck-typed void emitBit(vluint32_t code, vluint32_t newval) = 0; + // duck-typed template void emitBus(vluint32_t code, vluint32_t newval) = 0; + // duck-typed void emitQuad(vluint32_t code, vluint64_t newval, int bits) = 0; + // duck-typed void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits) = 0; + // duck-typed void emitFloat(vluint32_t code, float newval) = 0; + // duck-typed void emitDouble(vluint32_t code, double newval) = 0; + + vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; } + + // Write to previous value buffer value and emit trace entry. + void fullBit(vluint32_t* oldp, vluint32_t newval); + template void fullBus(vluint32_t* oldp, vluint32_t newval); + void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits); + void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits); + void fullFloat(vluint32_t* oldp, float newval); + void fullDouble(vluint32_t* oldp, double newval); + + // Check previous dumped value of signal. If changed, then emit trace entry + inline void chgBit(vluint32_t* oldp, vluint32_t newval) { + const vluint32_t diff = *oldp ^ newval; + if (VL_UNLIKELY(diff)) fullBit(oldp, newval); + } + template inline void chgBus(vluint32_t* oldp, vluint32_t newval) { + const vluint32_t diff = *oldp ^ newval; + if (VL_UNLIKELY(diff)) fullBus(oldp, newval); + } + inline void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + const vluint64_t diff = *reinterpret_cast(oldp) ^ newval; + if (VL_UNLIKELY(diff)) fullQuad(oldp, newval, bits); + } + inline void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + for (int i = 0; i < (bits + 31) / 32; ++i) { + if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) { + fullArray(oldp, newvalp, bits); + return; + } + } + } + inline void chgFloat(vluint32_t* oldp, float newval) { + // cppcheck-suppress invalidPointerCast + if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullFloat(oldp, newval); + } + inline void chgDouble(vluint32_t* oldp, double newval) { + // cppcheck-suppress invalidPointerCast + if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullDouble(oldp, newval); + } +}; +#endif // guard diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp new file mode 100644 index 000000000..537b687dd --- /dev/null +++ b/include/verilated_trace_imp.cpp @@ -0,0 +1,309 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//============================================================================= +// +// THIS MODULE IS PUBLICLY LICENSED +// +// Copyright 2001-2020 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//============================================================================= +/// +/// \file +/// \brief Implementation of tracing functionality common to all trace formats +/// +//============================================================================= +// SPDIFF_OFF + +// clang-format off + +#ifndef VL_DERIVED_T +# error "This file should be included in trace format implementations" +#endif + +#include "verilated_trace.h" + +// clang-format on + +//============================================================================= +// Static utility functions + +static double timescaleToDouble(const char* unitp) { + char* endp; + double value = strtod(unitp, &endp); + // On error so we allow just "ns" to return 1e-9. + if (value == 0.0 && endp == unitp) value = 1; + unitp = endp; + for (; *unitp && isspace(*unitp); unitp++) {} + switch (*unitp) { + case 's': value *= 1e1; break; + case 'm': value *= 1e-3; break; + case 'u': value *= 1e-6; break; + case 'n': value *= 1e-9; break; + case 'p': value *= 1e-12; break; + case 'f': value *= 1e-15; break; + case 'a': value *= 1e-18; break; + } + return value; +} + +static std::string doubleToTimescale(double value) { + const char* suffixp = "s"; + // clang-format off + if (value >= 1e0) { suffixp = "s"; value *= 1e0; } + else if (value >= 1e-3 ) { suffixp = "ms"; value *= 1e3; } + else if (value >= 1e-6 ) { suffixp = "us"; value *= 1e6; } + else if (value >= 1e-9 ) { suffixp = "ns"; value *= 1e9; } + else if (value >= 1e-12) { suffixp = "ps"; value *= 1e12; } + else if (value >= 1e-15) { suffixp = "fs"; value *= 1e15; } + else if (value >= 1e-18) { suffixp = "as"; value *= 1e18; } + // clang-format on + char valuestr[100]; + sprintf(valuestr, "%3.0f%s", value, suffixp); + return valuestr; // Gets converted to string, so no ref to stack +} + +//============================================================================= +// Internal callback routines for each module being traced. + +// Each module that wishes to be traced registers a set of callbacks stored in +// this class. When the trace file is being constructed, this class provides +// the callback routines to be executed. +class VerilatedTraceCallInfo { +public: // This is in .cpp file so is not widely visible + typedef VerilatedTrace::callback_t callback_t; + + callback_t m_initcb; ///< Initialization Callback function + callback_t m_fullcb; ///< Full Dumping Callback function + callback_t m_changecb; ///< Incremental Dumping Callback function + void* m_userthis; ///< User data pointer for callback + vluint32_t m_code; ///< Starting code number (set later by traceInit) + // CONSTRUCTORS + VerilatedTraceCallInfo(callback_t icb, callback_t fcb, callback_t changecb, void* ut) + : m_initcb(icb) + , m_fullcb(fcb) + , m_changecb(changecb) + , m_userthis(ut) + , m_code(1) {} + ~VerilatedTraceCallInfo() {} +}; + +//============================================================================= +// VerilatedTrace + +template <> +VerilatedTrace::VerilatedTrace() + : m_sigs_oldvalp(NULL) + , m_timeLastDump(0) + , m_fullDump(true) + , m_nextCode(0) + , m_scopeEscape('.') + , m_timeRes(1e-9) + , m_timeUnit(1e-9) { + set_time_unit(Verilated::timeunitString()); + set_time_resolution(Verilated::timeprecisionString()); +} + +template <> VerilatedTrace::~VerilatedTrace() { + if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL); + while (!m_callbacks.empty()) { + delete m_callbacks.back(); + m_callbacks.pop_back(); + } +} + +//========================================================================= +// Internals available to format specific implementations + +template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { + m_assertOne.check(); + + // Note: It is possible to re-open a trace file (VCD in particular), + // so we must reset the next code here, but it must have the same number + // of codes on re-open + const vluint32_t expectedCodes = nextCode(); + m_nextCode = 1; + + // Call all initialize callbacks, which will call decl* for each signal. + for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { + VerilatedTraceCallInfo* cip = m_callbacks[ent]; + cip->m_code = nextCode(); + (cip->m_initcb)(self(), cip->m_userthis, cip->m_code); + } + + if (expectedCodes && nextCode() != expectedCodes) { + VL_FATAL_MT(__FILE__, __LINE__, "", + "Reopening trace file with different number of signals"); + } + + // Now that we know the number of codes, allocate space for the buffer + // holding previous signal values. + if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()]; +} + +template <> +void VerilatedTrace::declCode(vluint32_t code, vluint32_t bits, bool tri) { + if (!code) { + VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal"); + } + // Note: The tri-state flag is not used by Verilator, but is here for + // compatibility with some foreign code. + int codesNeeded = (bits + 31) / 32; + if (tri) codesNeeded *= 2; + m_nextCode = std::max(m_nextCode, code + codesNeeded); +} + +//========================================================================= +// Internals available to format specific implementations + +template <> std::string VerilatedTrace::timeResStr() const { + return doubleToTimescale(m_timeRes); +} + +template <> std::string VerilatedTrace::timeUnitStr() const { + return doubleToTimescale(m_timeUnit); +} + +//========================================================================= +// External interface to client code + +template <> void VerilatedTrace::set_time_unit(const char* unitp) { + m_timeUnit = timescaleToDouble(unitp); +} + +template <> void VerilatedTrace::set_time_unit(const std::string& unit) { + set_time_unit(unit.c_str()); +} + +template <> void VerilatedTrace::set_time_resolution(const char* unitp) { + m_timeRes = timescaleToDouble(unitp); +} + +template <> void VerilatedTrace::set_time_resolution(const std::string& unit) { + set_time_resolution(unit.c_str()); +} + +template <> void VerilatedTrace::dump(vluint64_t timeui) { + m_assertOne.check(); + if (VL_UNLIKELY(m_timeLastDump && timeui <= m_timeLastDump)) { + VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64 + "u, dump call ignored\n", + m_timeLastDump, timeui); + return; + } + m_timeLastDump = timeui; + Verilated::quiesce(); + if (VL_UNLIKELY(m_fullDump)) { + if (!preFullDump()) return; + emitTimeChange(timeui); + m_fullDump = false; // No more need for next dump to be full + for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) { + VerilatedTraceCallInfo* cip = m_callbacks[ent]; + (cip->m_fullcb)(self(), cip->m_userthis, cip->m_code); + } + } else { + if (!preChangeDump()) return; + emitTimeChange(timeui); + for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { + VerilatedTraceCallInfo* cip = m_callbacks[ent]; + (cip->m_changecb)(self(), cip->m_userthis, cip->m_code); + } + } +} + +//============================================================================= +// Non-hot path internal interface to Verilator generated code + +template <> +void VerilatedTrace::addCallback(callback_t initcb, callback_t fullcb, + callback_t changecb, + void* userthis) VL_MT_UNSAFE_ONE { + m_assertOne.check(); + if (VL_UNLIKELY(timeLastDump() != 0)) { + std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__ + + " called with already open file"); + VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); + } + VerilatedTraceCallInfo* cip = new VerilatedTraceCallInfo(initcb, fullcb, changecb, userthis); + m_callbacks.push_back(cip); +} + +//========================================================================= +// Hot path internal interface to Verilator generated code + +// These functions must write the new value back into the old value store, +// and subsequently call the format specific emit* implementations. Note +// that this file must be included in the format specific implementation, so +// the emit* functions can be inlined for performance. + +template <> void VerilatedTrace::fullBit(vluint32_t* oldp, vluint32_t newval) { + *oldp = newval; + self()->emitBit(oldp - m_sigs_oldvalp, newval); +} + +// We want these functions specialized for sizes to avoid hard to predict +// branches, but we don't want them inlined, so we explicitly instantiate the +// template for each size used by Verilator. +template <> +template +void VerilatedTrace::fullBus(vluint32_t* oldp, vluint32_t newval) { + *oldp = newval; + self()->emitBus(oldp - m_sigs_oldvalp, newval); +} + +// Note: No specialization for width 1, covered by 'fullBit' +template void VerilatedTrace::fullBus<2>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<3>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<4>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<5>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<6>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<7>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<8>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<9>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<10>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<11>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<12>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<13>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<14>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<15>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<16>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<17>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<18>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<19>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<20>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<21>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<22>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<23>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<24>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<25>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<26>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<27>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<28>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<29>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<30>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<31>(vluint32_t* oldp, vluint32_t newval); +template void VerilatedTrace::fullBus<32>(vluint32_t* oldp, vluint32_t newval); + +template <> +void VerilatedTrace::fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + *reinterpret_cast(oldp) = newval; + self()->emitQuad(oldp - m_sigs_oldvalp, newval, bits); +} +template <> +void VerilatedTrace::fullArray(vluint32_t* oldp, const vluint32_t* newvalp, + int bits) { + for (int i = 0; i < (bits + 31) / 32; ++i) oldp[i] = newvalp[i]; + self()->emitArray(oldp - m_sigs_oldvalp, newvalp, bits); +} +template <> void VerilatedTrace::fullFloat(vluint32_t* oldp, float newval) { + // cppcheck-suppress invalidPointerCast + *reinterpret_cast(oldp) = newval; + self()->emitFloat(oldp - m_sigs_oldvalp, newval); +} +template <> void VerilatedTrace::fullDouble(vluint32_t* oldp, double newval) { + // cppcheck-suppress invalidPointerCast + *reinterpret_cast(oldp) = newval; + self()->emitDouble(oldp - m_sigs_oldvalp, newval); +} diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 21ce58cd5..af8bb2a15 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -60,6 +60,13 @@ // cache-lines. #define VL_TRACE_SUFFIX_ENTRY_SIZE 8 ///< Size of a suffix entry +//============================================================================= +// Specialization of the generics for this trace format + +#define VL_DERIVED_T VerilatedVcd +#include "verilated_trace_imp.cpp" +#undef VL_DERIVED_T + //============================================================================= // VerilatedVcdImp /// Base class to hold some static state @@ -101,33 +108,6 @@ public: } }; -//============================================================================= -// VerilatedVcdCallInfo -/// Internal callback routines for each module being traced. -//// -/// Each module that wishes to be traced registers a set of -/// callbacks stored in this class. When the trace file is being -/// constructed, this class provides the callback routines to be executed. - -class VerilatedVcdCallInfo { -protected: - friend class VerilatedVcd; - VerilatedVcdCallback_t m_initcb; ///< Initialization Callback function - VerilatedVcdCallback_t m_fullcb; ///< Full Dumping Callback function - VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function - void* m_userthis; ///< Fake "this" for caller - vluint32_t m_code; ///< Starting code number (set later by traceInit) - // CONSTRUCTORS - VerilatedVcdCallInfo(VerilatedVcdCallback_t icb, VerilatedVcdCallback_t fcb, - VerilatedVcdCallback_t changecb, void* ut) - : m_initcb(icb) - , m_fullcb(fcb) - , m_changecb(changecb) - , m_userthis(ut) - , m_code(1) {} - ~VerilatedVcdCallInfo() {} -}; - //============================================================================= //============================================================================= //============================================================================= @@ -153,26 +133,18 @@ ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) VL_MT_UNSAFE { VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) : m_isOpen(false) , m_rolloverMB(0) - , m_modDepth(0) - , m_nextCode(1) { + , m_modDepth(0) { // Not in header to avoid link issue if header is included without this .cpp file m_fileNewed = (filep == NULL); m_filep = m_fileNewed ? new VerilatedVcdFile : filep; m_namemapp = NULL; - m_timeLastDump = 0; - m_sigs_oldvalp = NULL; m_evcd = false; - m_scopeEscape = '.'; // Backward compatibility - m_fullDump = true; m_wrChunkSize = 8 * 1024; m_wrBufp = new char[m_wrChunkSize * 8]; m_wrFlushp = m_wrBufp + m_wrChunkSize * 6; m_writep = m_wrBufp; m_wroteBytes = 0; m_suffixesp = NULL; - m_timeRes = m_timeUnit = 1e-9; - set_time_unit(Verilated::timeunitString()); - set_time_resolution(Verilated::timeprecisionString()); } void VerilatedVcd::open(const char* filename) { @@ -193,16 +165,11 @@ void VerilatedVcd::open(const char* filename) { dumpHeader(); - // Allocate space now we know the number of codes - if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[m_nextCode + 10]; - // Get the direct access pointer to the code strings m_suffixesp = &m_suffixes[0]; // Note: C++11 m_suffixes.data(); - if (m_rolloverMB) { - openNext(true); - if (!isOpen()) return; - } + // When using rollover, the first chunk contains the header only. + if (m_rolloverMB) openNext(true); } void VerilatedVcd::openNext(bool incFilename) { @@ -245,21 +212,27 @@ void VerilatedVcd::openNext(bool incFilename) { } } m_isOpen = true; - m_fullDump = true; // First dump must be full + fullDump(true); // First dump must be full m_wroteBytes = 0; } +bool VerilatedVcd::preChangeDump() { + if (VL_UNLIKELY(m_rolloverMB && m_wroteBytes > m_rolloverMB)) { openNext(true); } + return isOpen(); +} + +void VerilatedVcd::emitTimeChange(vluint64_t timeui) { + printStr("#"); + printQuad(timeui); + printStr("\n"); +} + void VerilatedVcd::makeNameMap() { // Take signal information from each module and build m_namemapp deleteNameMap(); - m_nextCode = 1; m_namemapp = new NameMap; - for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) { - VerilatedVcdCallInfo* cip = m_callbacks[ent]; - cip->m_code = m_nextCode; - // Initialize; callbacks will call decl* which update m_nextCode - (cip->m_initcb)(this, cip->m_userthis, cip->m_code); - } + + VerilatedTrace::traceInit(); // Though not speced, it's illegal to generate a vcd with signals // not under any module - it crashes at least two viewers. @@ -292,13 +265,8 @@ void VerilatedVcd::deleteNameMap() { VerilatedVcd::~VerilatedVcd() { close(); if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = NULL); - if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL); deleteNameMap(); if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = NULL); - for (CallbackVec::const_iterator it = m_callbacks.begin(); it != m_callbacks.end(); ++it) { - delete *it; - } - m_callbacks.clear(); VerilatedVcdSingleton::removeVcd(this); } @@ -328,7 +296,7 @@ void VerilatedVcd::close() { if (!isOpen()) return; if (m_evcd) { printStr("$vcdclose "); - printTime(m_timeLastDump); + printQuad(timeLastDump()); printStr(" $end\n"); } closePrev(); @@ -348,21 +316,6 @@ void VerilatedVcd::printQuad(vluint64_t n) { printStr(buf); } -void VerilatedVcd::printTime(vluint64_t timeui) { - // VCD file format specification does not allow non-integers for timestamps - // Dinotrace doesn't mind, but Cadence Vision seems to choke - if (VL_UNLIKELY(timeui < m_timeLastDump)) { - timeui = m_timeLastDump; - static VL_THREAD_LOCAL bool backTime = false; - if (!backTime) { - backTime = true; - VL_PRINTF_MT("%%Warning: VCD time is moving backwards, wave file may be incorrect.\n"); - } - } - m_timeLastDump = timeui; - printQuad(timeui); -} - void VerilatedVcd::bufferResize(vluint64_t minsize) { // minsize is size of largest write. We buffer at least 8 times as much data, // writing when we are 3/4 full (with thus 2*minsize remaining free) @@ -408,56 +361,6 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE { m_writep = m_wrBufp; } -//============================================================================= -// Simple methods - -void VerilatedVcd::set_time_unit(const char* unitp) { - // cout<<" set_time_unit("<= 1e0) { suffixp = "s"; value *= 1e0; } - else if (value >= 1e-3 ) { suffixp = "ms"; value *= 1e3; } - else if (value >= 1e-6 ) { suffixp = "us"; value *= 1e6; } - else if (value >= 1e-9 ) { suffixp = "ns"; value *= 1e9; } - else if (value >= 1e-12) { suffixp = "ps"; value *= 1e12; } - else if (value >= 1e-15) { suffixp = "fs"; value *= 1e15; } - else if (value >= 1e-18) { suffixp = "as"; value *= 1e18; } - // clang-format on - char valuestr[100]; - sprintf(valuestr, "%3.0f%s", value, suffixp); - return valuestr; // Gets converted to string, so no ref to stack -} - //============================================================================= // VCD string code @@ -490,8 +393,7 @@ void VerilatedVcd::dumpHeader() { printStr(" $end\n"); printStr("$timescale "); - const std::string& timeResStr = doubleToTimescale(m_timeRes); - printStr(timeResStr.c_str()); + printStr(timeResStr().c_str()); // lintok-begin-on-ref printStr(" $end\n"); makeNameMap(); @@ -571,37 +473,19 @@ void VerilatedVcd::dumpHeader() { deleteNameMap(); } -void VerilatedVcd::module(const std::string& name) { - m_assertOne.check(); - m_modName = name; -} - void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, bool array, int arraynum, bool tri, bool bussed, int msb, int lsb) { - if (!code) { - VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal"); - } + const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1; - int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1; - int codesNeeded = 1 + int(bits / 32); - if (tri) codesNeeded *= 2; // Space in change array for __en signals + VerilatedTrace::declCode(code, bits, tri); - // Make sure array is large enough - m_nextCode = std::max(m_nextCode, code + codesNeeded); - if (m_sigs.capacity() <= m_nextCode) { - m_sigs.reserve(m_nextCode * 2); // Power-of-2 allocation speeds things up - } - if (m_suffixes.size() <= m_nextCode * VL_TRACE_SUFFIX_ENTRY_SIZE) { - m_suffixes.resize(m_nextCode * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0); + if (m_suffixes.size() <= nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE) { + m_suffixes.resize(nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0); } // Make sure write buffer is large enough (one character per bit), plus header bufferResize(bits + 1024); - // Save declaration info - VerilatedVcdSig sig = VerilatedVcdSig(code, bits); - m_sigs.push_back(sig); - // Split name into basename // Spaces and tabs aren't legal in VCD signal names, so: // Space separates each level of scope @@ -609,8 +493,8 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, // Tab sorts before spaces, so signals nicely will print before scopes // Note the hiername may be nothing, if so we'll add "\t{name}" std::string nameasstr = name; - if (!m_modName.empty()) { - nameasstr = m_modName + m_scopeEscape + nameasstr; // Optional ->module prefix + if (!moduleName().empty()) { + nameasstr = moduleName() + scopeEscape() + nameasstr; // Optional ->module prefix } std::string hiername; std::string basename; @@ -693,7 +577,7 @@ void VerilatedVcd::declFloat(vluint32_t code, const char* name, bool array, int void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int arraynum) { declare(code, name, "real", array, arraynum, false, false, 63, 0); } -#ifndef VL_TRACE_VCD_OLD_API +#ifdef VL_TRACE_VCD_OLD_API void VerilatedVcd::declTriBit(vluint32_t code, const char* name, bool array, int arraynum) { declare(code, name, "wire", array, arraynum, true, false, 0, 0); } @@ -714,14 +598,11 @@ void VerilatedVcd::declTriArray(vluint32_t code, const char* name, bool array, i //============================================================================= // Trace recording routines -#ifndef VL_TRACE_VCD_OLD_API - //============================================================================= -// Pointer based variants used by Verilator +// Emit trace entries // Emit suffix, write back write pointer, check buffer -void VerilatedVcd::finishLine(vluint32_t* oldp, char* writep) { - const vluint32_t code = oldp - m_sigs_oldvalp; +void VerilatedVcd::finishLine(vluint32_t code, char* writep) { const char* const suffixp = m_suffixesp + code * VL_TRACE_SUFFIX_ENTRY_SIZE; // Copy the whole suffix (this avoid having hard to predict branches which // helps a lot). Note suffixp could be aligned, so could load it in one go, @@ -742,20 +623,13 @@ void VerilatedVcd::finishLine(vluint32_t* oldp, char* writep) { bufferCheck(); } -void VerilatedVcd::fullBit(vluint32_t* oldp, vluint32_t newval) { - *oldp = newval; +void VerilatedVcd::emitBit(vluint32_t code, vluint32_t newval) { char* wp = m_writep; *wp++ = '0' | static_cast(newval); - finishLine(oldp, wp); + finishLine(code, wp); } -// We do want these functions specialized for sizes to avoid hard to predict -// branches, but we don't want them inlined, so we explicitly create one -// specialization for each size used here here. - -// T_Bits is the number of used bits in the value -template void VerilatedVcd::fullBus(vluint32_t* oldp, vluint32_t newval) { - *oldp = newval; +template void VerilatedVcd::emitBus(vluint32_t code, vluint32_t newval) { char* wp = m_writep; *wp++ = 'b'; newval <<= 32 - T_Bits; @@ -764,44 +638,10 @@ template void VerilatedVcd::fullBus(vluint32_t* oldp, vluint32_t ne *wp++ = '0' | static_cast(newval >> 31); newval <<= 1; } while (--bits); - finishLine(oldp, wp); + finishLine(code, wp); } -// Note: No specialization for width 1, covered by 'fullBit' -template void VerilatedVcd::fullBus<2>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<3>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<4>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<5>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<6>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<7>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<8>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<9>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<10>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<11>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<12>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<13>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<14>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<15>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<16>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<17>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<18>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<19>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<20>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<21>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<22>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<23>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<24>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<25>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<26>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<27>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<28>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<29>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<30>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<31>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedVcd::fullBus<32>(vluint32_t* oldp, vluint32_t newval); -// T_Bits is the number of used bits in the value -void VerilatedVcd::fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { - *reinterpret_cast(oldp) = newval; +void VerilatedVcd::emitQuad(vluint32_t code, vluint64_t newval, int bits) { char* wp = m_writep; *wp++ = 'b'; newval <<= 64 - bits; @@ -850,12 +690,11 @@ void VerilatedVcd::fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { *wp++ = '0' | static_cast(newval >> 63); newval <<= 1; } while (--remaining); - finishLine(oldp, wp); + finishLine(code, wp); } -void VerilatedVcd::fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { +void VerilatedVcd::emitArray(vluint32_t code, const vluint32_t* newvalp, int bits) { int words = (bits + 31) / 32; - for (int i = 0; i < words; ++i) oldp[i] = newvalp[i]; char* wp = m_writep; *wp++ = 'b'; // Handle the most significant word @@ -907,41 +746,37 @@ void VerilatedVcd::fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bi val <<= 1; } while (--bits); } - finishLine(oldp, wp); + finishLine(code, wp); } -void VerilatedVcd::fullFloat(vluint32_t* oldp, float newval) { - // cppcheck-suppress invalidPointerCast - *reinterpret_cast(oldp) = newval; +void VerilatedVcd::emitFloat(vluint32_t code, float newval) { char* wp = m_writep; // Buffer can't overflow before sprintf; we sized during declaration sprintf(wp, "r%.16g", static_cast(newval)); wp += strlen(wp); - finishLine(oldp, wp); + finishLine(code, wp); } -void VerilatedVcd::fullDouble(vluint32_t* oldp, double newval) { - // cppcheck-suppress invalidPointerCast - *reinterpret_cast(oldp) = newval; +void VerilatedVcd::emitDouble(vluint32_t code, double newval) { char* wp = m_writep; // Buffer can't overflow before sprintf; we sized during declaration sprintf(wp, "r%.16g", newval); wp += strlen(wp); - finishLine(oldp, wp); + finishLine(code, wp); } -#else // VL_TRACE_VCD_OLD_API +#ifdef VL_TRACE_VCD_OLD_API void VerilatedVcd::fullBit(vluint32_t code, const vluint32_t newval) { // Note the &1, so we don't require clean input -- makes more common no change case faster - m_sigs_oldvalp[code] = newval; + *oldp(code) = newval; *m_writep++ = ('0' + static_cast(newval & 1)); m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } void VerilatedVcd::fullBus(vluint32_t code, const vluint32_t newval, int bits) { - m_sigs_oldvalp[code] = newval; + *oldp(code) = newval; *m_writep++ = 'b'; for (int bit = bits - 1; bit >= 0; --bit) { *m_writep++ = ((newval & (1L << bit)) ? '1' : '0'); @@ -952,7 +787,7 @@ void VerilatedVcd::fullBus(vluint32_t code, const vluint32_t newval, int bits) { bufferCheck(); } void VerilatedVcd::fullQuad(vluint32_t code, const vluint64_t newval, int bits) { - (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; + (*(reinterpret_cast(oldp(code)))) = newval; *m_writep++ = 'b'; for (int bit = bits - 1; bit >= 0; --bit) { *m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0'); @@ -963,9 +798,7 @@ void VerilatedVcd::fullQuad(vluint32_t code, const vluint64_t newval, int bits) bufferCheck(); } void VerilatedVcd::fullArray(vluint32_t code, const vluint32_t* newval, int bits) { - for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { - m_sigs_oldvalp[code + word] = newval[word]; - } + for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { oldp(code)[word] = newval[word]; } *m_writep++ = 'b'; for (int bit = bits - 1; bit >= 0; --bit) { *m_writep++ = ((newval[(bit / 32)] & (1L << (bit & 0x1f))) ? '1' : '0'); @@ -976,9 +809,7 @@ void VerilatedVcd::fullArray(vluint32_t code, const vluint32_t* newval, int bits bufferCheck(); } void VerilatedVcd::fullArray(vluint32_t code, const vluint64_t* newval, int bits) { - for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { - m_sigs_oldvalp[code + word] = newval[word]; - } + for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { oldp(code)[word] = newval[word]; } *m_writep++ = 'b'; for (int bit = bits - 1; bit >= 0; --bit) { *m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0'); @@ -989,17 +820,17 @@ void VerilatedVcd::fullArray(vluint32_t code, const vluint64_t* newval, int bits bufferCheck(); } void VerilatedVcd::fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) { - m_sigs_oldvalp[code] = newval; - m_sigs_oldvalp[code + 1] = newtri; - *m_writep++ = "01zz"[m_sigs_oldvalp[code] | (m_sigs_oldvalp[code + 1] << 1)]; + oldp(code)[0] = newval; + oldp(code)[1] = newtri; + *m_writep++ = "01zz"[newval | (newtri << 1)]; m_writep = writeCode(m_writep, code); *m_writep++ = '\n'; bufferCheck(); } void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) { - m_sigs_oldvalp[code] = newval; - m_sigs_oldvalp[code + 1] = newtri; + oldp(code)[0] = newval; + oldp(code)[1] = newtri; *m_writep++ = 'b'; for (int bit = bits - 1; bit >= 0; --bit) { *m_writep++ = "01zz"[((newval >> bit) & 1) | (((newtri >> bit) & 1) << 1)]; @@ -1011,8 +842,8 @@ void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vl } void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) { - (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; - (*(reinterpret_cast(&m_sigs_oldvalp[code + 1]))) = newtri; + (*(reinterpret_cast(oldp(code)))) = newval; + (*(reinterpret_cast(oldp(code + 1)))) = newtri; *m_writep++ = 'b'; for (int bit = bits - 1; bit >= 0; --bit) { *m_writep++ @@ -1026,8 +857,8 @@ void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const v void VerilatedVcd::fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits) { for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { - m_sigs_oldvalp[code + word * 2] = newvalp[word]; - m_sigs_oldvalp[code + word * 2 + 1] = newtrip[word]; + oldp(code)[word * 2] = newvalp[word]; + oldp(code)[word * 2 + 1] = newtrip[word]; } *m_writep++ = 'b'; for (int bit = bits - 1; bit >= 0; --bit) { @@ -1042,7 +873,7 @@ void VerilatedVcd::fullTriArray(vluint32_t code, const vluint32_t* newvalp, } void VerilatedVcd::fullDouble(vluint32_t code, const double newval) { // cppcheck-suppress invalidPointerCast - (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; + (*(reinterpret_cast(oldp(code)))) = newval; // Buffer can't overflow before sprintf; we sized during declaration sprintf(m_writep, "r%.16g", newval); m_writep += strlen(m_writep); @@ -1053,7 +884,7 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) { } void VerilatedVcd::fullFloat(vluint32_t code, const float newval) { // cppcheck-suppress invalidPointerCast - (*(reinterpret_cast(&m_sigs_oldvalp[code]))) = newval; + (*(reinterpret_cast(oldp(code)))) = newval; // Buffer can't overflow before sprintf; we sized during declaration sprintf(m_writep, "r%.16g", static_cast(newval)); m_writep += strlen(m_writep); @@ -1081,60 +912,6 @@ void VerilatedVcd::fullArrayX(vluint32_t code, int bits) { fullBusX(code, bits); #endif // VL_TRACE_VCD_OLD_API -//============================================================================= -// Callbacks - -void VerilatedVcd::addCallback(VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, - VerilatedVcdCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE { - m_assertOne.check(); - if (VL_UNLIKELY(isOpen())) { - std::string msg = std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__ - + " called with already open file"; - VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); - } - VerilatedVcdCallInfo* cip = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis); - m_callbacks.push_back(cip); -} - -//============================================================================= -// Dumping - -void VerilatedVcd::dumpFull(vluint64_t timeui) { - m_assertOne.check(); - dumpPrep(timeui); - Verilated::quiesce(); - for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) { - VerilatedVcdCallInfo* cip = m_callbacks[ent]; - (cip->m_fullcb)(this, cip->m_userthis, cip->m_code); - } -} - -void VerilatedVcd::dump(vluint64_t timeui) { - m_assertOne.check(); - if (!isOpen()) return; - if (VL_UNLIKELY(m_fullDump)) { - m_fullDump = false; // No more need for next dump to be full - dumpFull(timeui); - return; - } - if (VL_UNLIKELY(m_rolloverMB && m_wroteBytes > this->m_rolloverMB)) { - openNext(true); - if (!isOpen()) return; - } - dumpPrep(timeui); - Verilated::quiesce(); - for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { - VerilatedVcdCallInfo* cip = m_callbacks[ent]; - (cip->m_changecb)(this, cip->m_userthis, cip->m_code); - } -} - -void VerilatedVcd::dumpPrep(vluint64_t timeui) { - printStr("#"); - printTime(timeui); - printStr("\n"); -} - //====================================================================== // Static members diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 7e5dd2860..0ee8084c8 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -20,15 +20,14 @@ #ifndef _VERILATED_VCD_C_H_ #define _VERILATED_VCD_C_H_ 1 -#include "verilatedos.h" #include "verilated.h" +#include "verilated_trace.h" #include #include #include class VerilatedVcd; -class VerilatedVcdCallInfo; // SPDIFF_ON //============================================================================= @@ -48,48 +47,26 @@ public: virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE; }; -//============================================================================= -// VerilatedVcdSig -/// Internal data on one signal being traced. - -class VerilatedVcdSig { -protected: - friend class VerilatedVcd; - vluint32_t m_code; ///< VCD file code number - int m_bits; ///< Size of value in bits - VerilatedVcdSig(vluint32_t code, int bits) - : m_code(code) - , m_bits(bits) {} - -public: - ~VerilatedVcdSig() {} -}; - -//============================================================================= - -typedef void (*VerilatedVcdCallback_t)(VerilatedVcd* vcdp, void* userthis, vluint32_t code); - //============================================================================= // VerilatedVcd /// Base class to create a Verilator VCD dump /// This is an internally used class - see VerilatedVcdC for what to call from applications -class VerilatedVcd { +class VerilatedVcd : public VerilatedTrace { private: + // Give the superclass access to private bits (to avoid virtual functions) + friend class VerilatedTrace; + + //========================================================================= + // VCD specific internals + VerilatedVcdFile* m_filep; ///< File we're writing to bool m_fileNewed; ///< m_filep needs destruction bool m_isOpen; ///< True indicates open file bool m_evcd; ///< True for evcd format std::string m_filename; ///< Filename we're writing to (if open) vluint64_t m_rolloverMB; ///< MB of file size to rollover at - char m_scopeEscape; ///< Character to separate scope components int m_modDepth; ///< Depth of module hierarchy - bool m_fullDump; ///< True indicates dump ignoring if changed - vluint32_t m_nextCode; ///< Next code number to assign - std::string m_modName; ///< Module name being traced now - double m_timeRes; ///< Time resolution (ns/ms etc) - double m_timeUnit; ///< Time units (ns/ms etc) - vluint64_t m_timeLastDump; ///< Last time we did a dump char* m_wrBufp; ///< Output buffer char* m_wrFlushp; ///< Output buffer flush trigger location @@ -100,16 +77,9 @@ private: std::vector m_suffixes; ///< VCD line end string codes + metadata const char* m_suffixesp; ///< Pointer to first element of above - vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values - typedef std::vector SigVec; - SigVec m_sigs; ///< Pointer to signal information - typedef std::vector CallbackVec; - CallbackVec m_callbacks; ///< Routines to perform dumping typedef std::map NameMap; NameMap* m_namemapp; ///< List of names for the header - VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread - void bufferResize(vluint64_t minsize); void bufferFlush() VL_MT_UNSAFE_ONE; inline void bufferCheck() { @@ -130,165 +100,112 @@ private: bool tri, bool bussed, int msb, int lsb); void dumpHeader(); - void dumpPrep(vluint64_t timeui); - void dumpFull(vluint64_t timeui); - // cppcheck-suppress functionConst - void dumpDone(); + char* writeCode(char* writep, vluint32_t code); - void finishLine(vluint32_t* oldp, char* writep); + void finishLine(vluint32_t code, char* writep); + + /// Flush any remaining data from all files + static void flush_all() VL_MT_UNSAFE_ONE; // CONSTRUCTORS VL_UNCOPYABLE(VerilatedVcd); +protected: + //========================================================================= + // Implementation of VerilatedTrace interface + + // Implementations of protected virtual methods for VerilatedTrace + void emitTimeChange(vluint64_t timeui) VL_OVERRIDE; + + // Hooks called from VerilatedTrace + bool preFullDump() VL_OVERRIDE { return isOpen(); } + bool preChangeDump() VL_OVERRIDE; + + // Implementations of duck-typed methods for VerilatedTrace + void emitBit(vluint32_t code, vluint32_t newval); + template void emitBus(vluint32_t code, vluint32_t newval); + void emitQuad(vluint32_t code, vluint64_t newval, int bits); + void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits); + void emitFloat(vluint32_t code, float newval); + void emitDouble(vluint32_t code, double newval); + public: + //========================================================================= + // External interface to client code + explicit VerilatedVcd(VerilatedVcdFile* filep = NULL); ~VerilatedVcd(); - /// Routines can only be called from one thread; allow next call from different thread - void changeThread() { m_assertOne.changeThread(); } // ACCESSORS /// Set size in megabytes after which new file should be created void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB = rolloverMB; } - /// Is file open? - bool isOpen() const { return m_isOpen; } - /// Change character that splits scopes. Note whitespace are ALWAYS escapes. - void scopeEscape(char flag) { m_scopeEscape = flag; } - /// Is this an escape? - inline bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; } // METHODS /// Open the file; call isOpen() to see if errors void open(const char* filename) VL_MT_UNSAFE_ONE; - void openNext(bool incFilename); ///< Open next data-only file - void close() VL_MT_UNSAFE_ONE; ///< Close the file + /// Open next data-only file + void openNext(bool incFilename) VL_MT_UNSAFE_ONE; + /// Close the file + void close() VL_MT_UNSAFE_ONE; /// Flush any remaining data to this file void flush() VL_MT_UNSAFE_ONE { bufferFlush(); } - /// Flush any remaining data from all files - static void flush_all() VL_MT_UNSAFE_ONE; + /// Is file open? + bool isOpen() const { return m_isOpen; } - void set_time_unit(const char* unitp); ///< Set time units (s/ms, defaults to ns) - void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); } + //========================================================================= + // Internal interface to Verilator generated code - void set_time_resolution(const char* unitp); ///< Set time resolution (s/ms, defaults to ns) - void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); } - - double timescaleToDouble(const char* unitp); - std::string doubleToTimescale(double value); - - /// Inside dumping routines, called each cycle to make the dump - void dump(vluint64_t timeui); - /// Call dump with a absolute unscaled time in seconds - void dumpSeconds(double secs) { dump(static_cast(secs * m_timeRes)); } - - /// Inside dumping routines, declare callbacks for tracings - void addCallback(VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, - VerilatedVcdCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE; - - /// Inside dumping routines, declare a module - void module(const std::string& name); - /// Inside dumping routines, declare a signal void declBit(vluint32_t code, const char* name, bool array, int arraynum); void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declFloat(vluint32_t code, const char* name, bool array, int arraynum); void declDouble(vluint32_t code, const char* name, bool array, int arraynum); -#ifndef VL_TRACE_VCD_OLD_API + +#ifdef VL_TRACE_VCD_OLD_API + //========================================================================= + // Note: These are only for testing for backward compatibility with foreign + // code and is not used by Verilator. Do not use these as there is no + // guarantee of functionality. + void declTriBit(vluint32_t code, const char* name, bool array, int arraynum); void declTriBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declTriQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); -#endif // VL_TRACE_VCD_OLD_API - // ... other module_start for submodules (based on cell name) - - //========================================================================= - // Inside dumping routines used by Verilator - - vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; } - -#ifndef VL_TRACE_VCD_OLD_API - //========================================================================= // Write back to previous value buffer value and emit - void fullBit(vluint32_t* oldp, vluint32_t newval); - template void fullBus(vluint32_t* oldp, vluint32_t newval); - void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits); - void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits); - void fullFloat(vluint32_t* oldp, float newval); - void fullDouble(vluint32_t* oldp, double newval); - - //========================================================================= - // Check previous value and emit if changed - - inline void chgBit(vluint32_t* oldp, vluint32_t newval) { - const vluint32_t diff = *oldp ^ newval; - if (VL_UNLIKELY(diff)) fullBit(oldp, newval); - } - template inline void chgBus(vluint32_t* oldp, vluint32_t newval) { - const vluint32_t diff = *oldp ^ newval; - if (VL_UNLIKELY(diff)) fullBus(oldp, newval); - } - inline void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { - const vluint64_t diff = *reinterpret_cast(oldp) ^ newval; - if (VL_UNLIKELY(diff)) fullQuad(oldp, newval, bits); - } - inline void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { - for (int i = 0; i < (bits + 31) / 32; ++i) { - if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) { - fullArray(oldp, newvalp, bits); - return; - } - } - } - inline void chgFloat(vluint32_t* oldp, float newval) { - // cppcheck-suppress invalidPointerCast - if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullFloat(oldp, newval); - } - inline void chgDouble(vluint32_t* oldp, double newval) { - // cppcheck-suppress invalidPointerCast - if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullDouble(oldp, newval); - } - -#else // VL_TRACE_VCD_OLD_API - - // Note: These are only for testing for backward compatibility. Verilator - // should use the more efficient versions above. - - //========================================================================= - // Write back to previous value buffer value and emit - - void fullBit(vluint32_t* oldp, vluint32_t newval) { fullBit(oldp - m_sigs_oldvalp, newval); } + void fullBit(vluint32_t* oldp, vluint32_t newval) { fullBit(oldp - this->oldp(0), newval); } template void fullBus(vluint32_t* oldp, vluint32_t newval) { - fullBus(oldp - m_sigs_oldvalp, newval, T_Bits); + fullBus(oldp - this->oldp(0), newval, T_Bits); } void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { - fullQuad(oldp - m_sigs_oldvalp, newval, bits); + fullQuad(oldp - this->oldp(0), newval, bits); } void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { - fullArray(oldp - m_sigs_oldvalp, newvalp, bits); + fullArray(oldp - this->oldp(0), newvalp, bits); } - void fullFloat(vluint32_t* oldp, float newval) { fullFloat(oldp - m_sigs_oldvalp, newval); } - void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - m_sigs_oldvalp, newval); } + void fullFloat(vluint32_t* oldp, float newval) { fullFloat(oldp - this->oldp(0), newval); } + void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); } //========================================================================= // Check previous value and emit if changed - void chgBit(vluint32_t* oldp, vluint32_t newval) { chgBit(oldp - m_sigs_oldvalp, newval); } + void chgBit(vluint32_t* oldp, vluint32_t newval) { chgBit(oldp - this->oldp(0), newval); } template void chgBus(vluint32_t* oldp, vluint32_t newval) { - chgBus(oldp - m_sigs_oldvalp, newval, T_Bits); + chgBus(oldp - this->oldp(0), newval, T_Bits); } void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { - chgQuad(oldp - m_sigs_oldvalp, newval, bits); + chgQuad(oldp - this->oldp(0), newval, bits); } void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { - chgArray(oldp - m_sigs_oldvalp, newvalp, bits); + chgArray(oldp - this->oldp(0), newvalp, bits); } - void chgFloat(vluint32_t* oldp, float newval) { chgFloat(oldp - m_sigs_oldvalp, newval); } - void chgDouble(vluint32_t* oldp, double newval) { chgDouble(oldp - m_sigs_oldvalp, newval); } + void chgFloat(vluint32_t* oldp, float newval) { chgFloat(oldp - this->oldp(0), newval); } + void chgDouble(vluint32_t* oldp, double newval) { chgDouble(oldp - this->oldp(0), newval); } /// Inside dumping routines, dump one signal, faster when not inlined /// due to code size reduction. @@ -317,11 +234,11 @@ public: /// Inside dumping routines, dump one signal if it has changed. /// We do want to inline these to avoid calls when the value did not change. inline void chgBit(vluint32_t code, const vluint32_t newval) { - vluint32_t diff = m_sigs_oldvalp[code] ^ newval; + vluint32_t diff = oldp(code)[0] ^ newval; if (VL_UNLIKELY(diff)) fullBit(code, newval); } inline void chgBus(vluint32_t code, const vluint32_t newval, int bits) { - vluint32_t diff = m_sigs_oldvalp[code] ^ newval; + vluint32_t diff = oldp(code)[0] ^ newval; if (VL_UNLIKELY(diff)) { if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) { fullBus(code, newval, bits); @@ -329,7 +246,7 @@ public: } } inline void chgQuad(vluint32_t code, const vluint64_t newval, int bits) { - vluint64_t diff = (*(reinterpret_cast(&m_sigs_oldvalp[code]))) ^ newval; + vluint64_t diff = (*(reinterpret_cast(oldp(code)))) ^ newval; if (VL_UNLIKELY(diff)) { if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) { fullQuad(code, newval, bits); @@ -338,7 +255,7 @@ public: } inline void chgArray(vluint32_t code, const vluint32_t* newvalp, int bits) { for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { - if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newvalp[word])) { + if (VL_UNLIKELY(oldp(code)[word] ^ newvalp[word])) { fullArray(code, newvalp, bits); return; } @@ -346,14 +263,15 @@ public: } inline void chgArray(vluint32_t code, const vluint64_t* newvalp, int bits) { for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { - if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newvalp[word])) { + if (VL_UNLIKELY(*(reinterpret_cast(oldp(code + 2 * word))) + ^ newvalp[word])) { fullArray(code, newvalp, bits); return; } } } inline void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) { - vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval) | (m_sigs_oldvalp[code + 1] ^ newtri)); + vluint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri)); if (VL_UNLIKELY(diff)) { // Verilator 3.510 and newer provide clean input, so the below // is only for back compatibility @@ -364,7 +282,7 @@ public: } inline void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) { - vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval) | (m_sigs_oldvalp[code + 1] ^ newtri)); + vluint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri)); if (VL_UNLIKELY(diff)) { if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) { fullTriBus(code, newval, newtri, bits); @@ -373,9 +291,8 @@ public: } inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) { - vluint64_t diff - = (((*(reinterpret_cast(&m_sigs_oldvalp[code]))) ^ newval) - | ((*(reinterpret_cast(&m_sigs_oldvalp[code + 1]))) ^ newtri)); + vluint64_t diff = (((*(reinterpret_cast(oldp(code)))) ^ newval) + | ((*(reinterpret_cast(oldp(code + 1)))) ^ newtri)); if (VL_UNLIKELY(diff)) { if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) { fullTriQuad(code, newval, newtri, bits); @@ -385,8 +302,8 @@ public: inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits) { for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { - if (VL_UNLIKELY((m_sigs_oldvalp[code + word * 2] ^ newvalp[word]) - | (m_sigs_oldvalp[code + word * 2 + 1] ^ newtrip[word]))) { + if (VL_UNLIKELY((oldp(code)[word * 2] ^ newvalp[word]) + | (oldp(code)[word * 2 + 1] ^ newtrip[word]))) { fullTriArray(code, newvalp, newtrip, bits); return; } @@ -394,24 +311,30 @@ public: } inline void chgDouble(vluint32_t code, const double newval) { // cppcheck-suppress invalidPointerCast - if (VL_UNLIKELY((*(reinterpret_cast(&m_sigs_oldvalp[code]))) != newval)) { + if (VL_UNLIKELY((*(reinterpret_cast(oldp(code)))) != newval)) { fullDouble(code, newval); } } inline void chgFloat(vluint32_t code, const float newval) { // cppcheck-suppress invalidPointerCast - if (VL_UNLIKELY((*(reinterpret_cast(&m_sigs_oldvalp[code]))) != newval)) { + if (VL_UNLIKELY((*(reinterpret_cast(oldp(code)))) != newval)) { fullFloat(code, newval); } } -#endif // VL_TRACE_VCD_OLD_API - protected: // METHODS void evcd(bool flag) { m_evcd = flag; } +#endif // VL_TRACE_VCD_OLD_API }; +// Declare specializations here they are used in VerilatedVcdC just below +template <> void VerilatedTrace::dump(vluint64_t timeui); +template <> void VerilatedTrace::set_time_unit(const char* unitp); +template <> void VerilatedTrace::set_time_unit(const std::string& unit); +template <> void VerilatedTrace::set_time_resolution(const char* unitp); +template <> void VerilatedTrace::set_time_resolution(const std::string& unit); + //============================================================================= // VerilatedVcdC /// Create a VCD dump file in C standalone (no SystemC) simulations. @@ -460,11 +383,11 @@ public: /// Set time units (s/ms, defaults to ns) /// For Verilated models, these propage from the Verilated default --timeunit void set_time_unit(const char* unit) { m_sptrace.set_time_unit(unit); } - void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); } + void set_time_unit(const std::string& unit) { m_sptrace.set_time_unit(unit); } /// Set time resolution (s/ms, defaults to ns) /// For Verilated models, these propage from the Verilated default --timeunit void set_time_resolution(const char* unit) { m_sptrace.set_time_resolution(unit); } - void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); } + void set_time_resolution(const std::string& unit) { m_sptrace.set_time_resolution(unit); } /// Internal class access inline VerilatedVcd* spTrace() { return &m_sptrace; } From 4272f2116e7f56003932c11e2d716f76877a3ba6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 19 Apr 2020 20:10:07 -0400 Subject: [PATCH 071/127] Tests: Update static test. --- test_regress/t/t_var_static.v | 69 +++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/test_regress/t/t_var_static.v b/test_regress/t/t_var_static.v index 48a94b7dc..9290a4c5c 100644 --- a/test_regress/t/t_var_static.v +++ b/test_regress/t/t_var_static.v @@ -4,6 +4,8 @@ // any use, without warranty, 2014 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + module t (/*AUTOARG*/ // Inputs clk @@ -42,29 +44,56 @@ module t (/*AUTOARG*/ endfunction initial begin - if (f_no_no() != 3) $stop; - if (f_no_no() != 4) $stop; - if (f_no_st() != 3) $stop; - if (f_no_st() != 4) $stop; - if (f_no_au() != 3) $stop; - if (f_no_au() != 3) $stop; + `checkh(f_no_no(), 3); + `checkh(f_no_no(), 4); + `checkh(f_no_st(), 3); + `checkh(f_no_st(), 4); + `checkh(f_no_au(), 3); + `checkh(f_no_au(), 3); // - if (f_st_no() != 3) $stop; - if (f_st_no() != 4) $stop; - if (f_st_st() != 3) $stop; - if (f_st_st() != 4) $stop; - if (f_st_au() != 3) $stop; - if (f_st_au() != 3) $stop; + `checkh(f_st_no(), 3); + `checkh(f_st_no(), 4); + `checkh(f_st_st(), 3); + `checkh(f_st_st(), 4); + `checkh(f_st_au(), 3); + `checkh(f_st_au(), 3); // - if (f_au_no() != 3) $stop; - if (f_au_no() != 3) $stop; - if (f_au_st() != 3) $stop; - if (f_au_st() != 4) $stop; - if (f_au_au() != 3) $stop; - if (f_au_au() != 3) $stop; + `checkh(f_au_no(), 3); + `checkh(f_au_no(), 3); + `checkh(f_au_st(), 3); + `checkh(f_au_st(), 4); + `checkh(f_au_au(), 3); + `checkh(f_au_au(), 3); // - $write("*-* All Finished *-*\n"); - $finish; + end + + int cyc = 0; + always @ (posedge clk) begin + int ist1; + static int ist2; + automatic int iau3; + + cyc <= cyc + 1; + if (cyc == 0) begin + ist1 = 10; + ist2 = 20; + iau3 = 30; + `checkh(ist1, 10); + `checkh(ist2, 20); + `checkh(iau3, 30); + ++ist1; + ++ist2; + ++iau3; + end + else if (cyc == 1) begin + `checkh(ist1, 11); + `checkh(ist2, 21); + `checkh(iau3, 30); + end + else if (cyc == 5) begin + $write("*-* All Finished *-*\n"); + $finish; + end end endmodule From fceedd9f4d8ca6034ddb5f10da0ac7fb8d52f603 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 19 Apr 2020 21:18:57 -0400 Subject: [PATCH 072/127] Tests: Update static test. --- test_regress/t/t_var_static.v | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test_regress/t/t_var_static.v b/test_regress/t/t_var_static.v index 9290a4c5c..67f772591 100644 --- a/test_regress/t/t_var_static.v +++ b/test_regress/t/t_var_static.v @@ -20,7 +20,7 @@ module t (/*AUTOARG*/ static int st = 2; st++; return st; endfunction function int f_no_au (); - automatic int st = 2; st++; return st; + automatic int au = 2; au++; return au; endfunction function static int f_st_no (); @@ -30,17 +30,17 @@ module t (/*AUTOARG*/ static int st = 2; st++; return st; endfunction function static int f_st_au (); - automatic int st = 2; st++; return st; + automatic int au = 2; au++; return au; endfunction function automatic int f_au_no (); - int st = 2; st++; return st; + int au = 2; au++; return au; endfunction function automatic int f_au_st (); static int st = 2; st++; return st; endfunction function automatic int f_au_au (); - automatic int st = 2; st++; return st; + automatic int au = 2; au++; return au; endfunction initial begin @@ -66,7 +66,7 @@ module t (/*AUTOARG*/ `checkh(f_au_au(), 3); // end - + int cyc = 0; always @ (posedge clk) begin int ist1; @@ -88,7 +88,7 @@ module t (/*AUTOARG*/ else if (cyc == 1) begin `checkh(ist1, 11); `checkh(ist2, 21); - `checkh(iau3, 30); + `checkh(iau3, 0); end else if (cyc == 5) begin $write("*-* All Finished *-*\n"); From def40fab9ba256f945f6eaf1175f338239737e63 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 19 Apr 2020 21:19:09 -0400 Subject: [PATCH 073/127] Internals: Rename VSigning --- src/V3Ast.cpp | 12 +++---- src/V3Ast.h | 78 ++++++++++++++++--------------------------- src/V3AstNodes.cpp | 4 +-- src/V3AstNodes.h | 81 ++++++++++++++++++++++----------------------- src/V3Const.cpp | 6 ++-- src/V3Expand.cpp | 8 ++--- src/V3Gate.cpp | 2 +- src/V3ParseImp.h | 2 +- src/V3Table.cpp | 2 +- src/V3Width.cpp | 68 ++++++++++++++++++------------------- src/V3WidthCommit.h | 2 +- src/verilog.y | 12 +++---- 12 files changed, 127 insertions(+), 150 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 8f0a5373e..dbd8e8779 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1210,7 +1210,7 @@ void AstNode::v3errorEnd(std::ostringstream& str) const { void AstNode::dtypeChgSigned(bool flag) { UASSERT_OBJ(dtypep(), this, "No dtype when changing to (un)signed"); - dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(), AstNumeric::fromBool(flag)); + dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(), VSigning::fromBool(flag)); } void AstNode::dtypeChgWidth(int width, int widthMin) { UASSERT_OBJ(dtypep(), this, @@ -1218,7 +1218,7 @@ void AstNode::dtypeChgWidth(int width, int widthMin) { dtypeChgWidthSigned(width, widthMin, dtypep()->numeric()); } -void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) { +void AstNode::dtypeChgWidthSigned(int width, int widthMin, VSigning numeric) { if (!dtypep()) { // We allow dtypep() to be null, as before/during widthing dtypes are not resolved dtypeSetLogicUnsized(width, widthMin, numeric); @@ -1240,21 +1240,21 @@ AstNodeDType* AstNode::findBasicDType(AstBasicDTypeKwd kwd) const { // More advanced types land under the module/task/etc return v3Global.rootp()->typeTablep()->findBasicDType(fileline(), kwd); } -AstNodeDType* AstNode::findBitDType(int width, int widthMin, AstNumeric numeric) const { +AstNodeDType* AstNode::findBitDType(int width, int widthMin, VSigning numeric) const { return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, width, widthMin, numeric); } -AstNodeDType* AstNode::findLogicDType(int width, int widthMin, AstNumeric numeric) const { +AstNodeDType* AstNode::findLogicDType(int width, int widthMin, VSigning numeric) const { return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, width, widthMin, numeric); } AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin, - AstNumeric numeric) const { + VSigning numeric) const { return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, range, widthMin, numeric); } AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin, - AstNumeric numeric) const { + VSigning numeric) const { return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, range, widthMin, numeric); } diff --git a/src/V3Ast.h b/src/V3Ast.h index 2b227bb60..295f30783 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -94,16 +94,7 @@ inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return o //###################################################################### -enum VSignedState { - // This can't be in the fancy class as the lexer union will get upset - signedst_UNSIGNED = 0, - signedst_SIGNED = 1, - signedst_NOSIGN = 2 -}; - -//###################################################################### - -class AstNumeric { +class VSigning { public: enum en { UNSIGNED, @@ -116,35 +107,25 @@ public: static const char* const names[] = {"UNSIGNED", "SIGNED", "NOSIGN"}; return names[m_e]; } - inline AstNumeric() + inline VSigning() : m_e(UNSIGNED) {} // cppcheck-suppress noExplicitConstructor - inline AstNumeric(en _e) + inline VSigning(en _e) : m_e(_e) {} - // cppcheck-suppress noExplicitConstructor - inline AstNumeric(VSignedState signst) { - if (signst == signedst_UNSIGNED) { - m_e = UNSIGNED; - } else if (signst == signedst_SIGNED) { - m_e = SIGNED; - } else { - m_e = NOSIGN; - } + static inline VSigning fromBool(bool isSigned) { // Factory method + return isSigned ? VSigning(SIGNED) : VSigning(UNSIGNED); } - static inline AstNumeric fromBool(bool isSigned) { // Factory method - return isSigned ? AstNumeric(SIGNED) : AstNumeric(UNSIGNED); - } - explicit inline AstNumeric(int _e) + explicit inline VSigning(int _e) : m_e(static_cast(_e)) {} operator en() const { return m_e; } inline bool isSigned() const { return m_e == SIGNED; } inline bool isNosign() const { return m_e == NOSIGN; } // No isUnsigned() as it's ambiguous if NOSIGN should be included or not. }; -inline bool operator==(const AstNumeric& lhs, const AstNumeric& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const AstNumeric& lhs, AstNumeric::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(AstNumeric::en lhs, const AstNumeric& rhs) { return lhs == rhs.m_e; } -inline std::ostream& operator<<(std::ostream& os, const AstNumeric& rhs) { +inline bool operator==(const VSigning& lhs, const VSigning& rhs) { return lhs.m_e == rhs.m_e; } +inline bool operator==(const VSigning& lhs, VSigning::en rhs) { return lhs.m_e == rhs; } +inline bool operator==(VSigning::en lhs, const VSigning& rhs) { return lhs == rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VSigning& rhs) { return os << rhs.ascii(); } @@ -998,7 +979,7 @@ class VBasicTypeKey { public: int m_width; // From AstNodeDType: Bit width of operation int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation - AstNumeric m_numeric; // From AstNodeDType: Node is signed + VSigning m_numeric; // From AstNodeDType: Node is signed AstBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword) inline bool operator==(const VBasicTypeKey& rhs) const { @@ -1018,7 +999,7 @@ public: if (!(m_nrange == rhs.m_nrange)) return false; // lhs > rhs return false; } - VBasicTypeKey(int width, int widthMin, AstNumeric numeric, AstBasicDTypeKwd kwd, + VBasicTypeKey(int width, int widthMin, VSigning numeric, AstBasicDTypeKwd kwd, const VNumRange& nrange) : m_width(width) , m_widthMin(widthMin) @@ -1638,17 +1619,17 @@ public: } void dtypeChgSigned(bool flag = true); void dtypeChgWidth(int width, int widthMin); - void dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric); - void dtypeSetBitUnsized(int width, int widthMin, AstNumeric numeric) { + void dtypeChgWidthSigned(int width, int widthMin, VSigning numeric); + void dtypeSetBitUnsized(int width, int widthMin, VSigning numeric) { dtypep(findBitDType(width, widthMin, numeric)); } - void dtypeSetBitSized(int width, AstNumeric numeric) { + void dtypeSetBitSized(int width, VSigning numeric) { dtypep(findBitDType(width, width, numeric)); // Since sized, widthMin is width } - void dtypeSetLogicUnsized(int width, int widthMin, AstNumeric numeric) { + void dtypeSetLogicUnsized(int width, int widthMin, VSigning numeric) { dtypep(findLogicDType(width, widthMin, numeric)); } - void dtypeSetLogicSized(int width, AstNumeric numeric) { + void dtypeSetLogicSized(int width, VSigning numeric) { dtypep(findLogicDType(width, width, numeric)); // Since sized, widthMin is width } void dtypeSetLogicBool() { dtypep(findLogicBoolDType()); } @@ -1667,12 +1648,11 @@ public: AstNodeDType* findUInt32DType() { return findBasicDType(AstBasicDTypeKwd::UINT32); } AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); } AstNodeDType* findVoidDType() const; - AstNodeDType* findBitDType(int width, int widthMin, AstNumeric numeric) const; - AstNodeDType* findLogicDType(int width, int widthMin, AstNumeric numeric) const; + AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const; + AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const; AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin, - AstNumeric numeric) const; - AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin, - AstNumeric numeric) const; + VSigning numeric) const; + AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin, VSigning numeric) const; AstNodeDType* findBasicDType(AstBasicDTypeKwd kwd) const; AstBasicDType* findInsertSameDType(AstBasicDType* nodep); @@ -2224,7 +2204,7 @@ class AstNodeDType : public AstNode { private: int m_width; // (also in AstTypeTable::Key) Bit width of operation int m_widthMin; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation - AstNumeric m_numeric; // (also in AstTypeTable::Key) Node is signed + VSigning m_numeric; // (also in AstTypeTable::Key) Node is signed // Other members bool m_generic; // Simple globally referenced type, don't garbage collect // Unique number assigned to each dtype during creation for IEEE matching @@ -2287,10 +2267,10 @@ public: } // int width() const { return m_width; } - void numeric(AstNumeric flag) { m_numeric = flag; } + void numeric(VSigning flag) { m_numeric = flag; } bool isSigned() const { return m_numeric.isSigned(); } bool isNosign() const { return m_numeric.isNosign(); } - AstNumeric numeric() const { return m_numeric; } + VSigning numeric() const { return m_numeric; } int widthWords() const { return VL_WORDS_I(width()); } int widthMin() const { // If sized, the size, if unsized the min digits to represent it return m_widthMin ? m_widthMin : m_width; @@ -2321,12 +2301,12 @@ private: MemberNameMap m_members; public: - AstNodeUOrStructDType(AstType t, FileLine* fl, AstNumeric numericUnpack) + AstNodeUOrStructDType(AstType t, FileLine* fl, VSigning numericUnpack) : AstNodeDType(t, fl) { - // AstNumeric::NOSIGN overloaded to indicate not packed - m_packed = (numericUnpack != AstNumeric::NOSIGN); + // VSigning::NOSIGN overloaded to indicate not packed + m_packed = (numericUnpack != VSigning::NOSIGN); m_isFourstate = false; // V3Width computes - numeric(AstNumeric::fromBool(numericUnpack.isSigned())); + numeric(VSigning::fromBool(numericUnpack.isSigned())); } ASTNODE_BASE_FUNCS(NodeUOrStructDType) virtual const char* broken() const; @@ -2458,7 +2438,7 @@ class AstNodeStream : public AstNodeBiop { public: AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(t, fl, lhsp, rhsp) { - if (lhsp->dtypep()) { dtypeSetLogicSized(lhsp->dtypep()->width(), AstNumeric::UNSIGNED); } + if (lhsp->dtypep()) { dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED); } } ASTNODE_BASE_FUNCS(NodeStream) }; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 7c7c28e00..3f6fb3dfd 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -875,7 +875,7 @@ AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) } AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width, - int widthMin, AstNumeric numeric) { + int widthMin, VSigning numeric) { AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin); AstBasicDType* newp = findInsertSameDType(new1p); if (newp != new1p) { @@ -887,7 +887,7 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw } AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, VNumRange range, - int widthMin, AstNumeric numeric) { + int widthMin, VSigning numeric) { AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin); AstBasicDType* newp = findInsertSameDType(new1p); if (newp != new1p) { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index bfca78855..4c8c098a6 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -59,7 +59,7 @@ private: dtypeSetString(); } else { dtypeSetLogicUnsized(m_num.width(), (m_num.sized() ? 0 : m_num.widthMin()), - AstNumeric::fromBool(m_num.isSigned())); + VSigning::fromBool(m_num.isSigned())); } m_num.nodep(this); } @@ -97,35 +97,35 @@ public: AstConst(FileLine* fl, uint32_t num) : ASTGEN_SUPER(fl) , m_num(this, 32, num) { - dtypeSetLogicUnsized(m_num.width(), 0, AstNumeric::UNSIGNED); + dtypeSetLogicUnsized(m_num.width(), 0, VSigning::UNSIGNED); } class Unsized32 {}; // for creator type-overload selection AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value : ASTGEN_SUPER(fl) , m_num(this, 32, num) { m_num.width(32, false); - dtypeSetLogicUnsized(32, m_num.widthMin(), AstNumeric::UNSIGNED); + dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::UNSIGNED); } class Signed32 {}; // for creator type-overload selection AstConst(FileLine* fl, Signed32, int32_t num) // Signed 32-bit integer of specified value : ASTGEN_SUPER(fl) , m_num(this, 32, num) { m_num.width(32, true); - dtypeSetLogicUnsized(32, m_num.widthMin(), AstNumeric::SIGNED); + dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::SIGNED); } class Unsized64 {}; // for creator type-overload selection AstConst(FileLine* fl, Unsized64, vluint64_t num) : ASTGEN_SUPER(fl) , m_num(this, 64, 0) { m_num.setQuad(num); - dtypeSetLogicSized(64, AstNumeric::UNSIGNED); + dtypeSetLogicSized(64, VSigning::UNSIGNED); } class SizedEData {}; // for creator type-overload selection AstConst(FileLine* fl, SizedEData, vluint64_t num) : ASTGEN_SUPER(fl) , m_num(this, VL_EDATASIZE, 0) { m_num.setQuad(num); - dtypeSetLogicSized(VL_EDATASIZE, AstNumeric::UNSIGNED); + dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED); } class RealDouble {}; // for creator type-overload selection AstConst(FileLine* fl, RealDouble, double num) @@ -735,24 +735,23 @@ private: } m; // See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned) public: - AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, VSignedState signst = signedst_NOSIGN) + AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, const VSigning& signst = VSigning::NOSIGN) : ASTGEN_SUPER(fl) { - init(kwd, AstNumeric(signst), 0, -1, NULL); + init(kwd, signst, 0, -1, NULL); } AstBasicDType(FileLine* fl, VFlagLogicPacked, int wantwidth) : ASTGEN_SUPER(fl) { - init(AstBasicDTypeKwd::LOGIC, AstNumeric::NOSIGN, wantwidth, -1, NULL); + init(AstBasicDTypeKwd::LOGIC, VSigning::NOSIGN, wantwidth, -1, NULL); } AstBasicDType(FileLine* fl, VFlagBitPacked, int wantwidth) : ASTGEN_SUPER(fl) { - init(AstBasicDTypeKwd::BIT, AstNumeric::NOSIGN, wantwidth, -1, NULL); + init(AstBasicDTypeKwd::BIT, VSigning::NOSIGN, wantwidth, -1, NULL); } - AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstNumeric numer, int wantwidth, - int widthmin) + AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, VSigning numer, int wantwidth, int widthmin) : ASTGEN_SUPER(fl) { init(kwd, numer, wantwidth, widthmin, NULL); } - AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstNumeric numer, VNumRange range, + AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, VSigning numer, VNumRange range, int widthmin) : ASTGEN_SUPER(fl) { init(kwd, numer, range.elements(), widthmin, NULL); @@ -760,7 +759,7 @@ public: } // See also addRange in verilog.y private: - void init(AstBasicDTypeKwd kwd, AstNumeric numer, int wantwidth, int wantwidthmin, + void init(AstBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin, AstRange* rangep) { // wantwidth=0 means figure it out, but if a widthmin is >=0 // we allow width 0 so that {{0{x}},y} works properly @@ -771,11 +770,11 @@ private: if (keyword() == AstBasicDTypeKwd::LOGIC_IMPLICIT) { if (rangep || wantwidth) m.m_keyword = AstBasicDTypeKwd::LOGIC; } - if (numer == AstNumeric::NOSIGN) { + if (numer == VSigning::NOSIGN) { if (keyword().isSigned()) { - numer = AstNumeric::SIGNED; + numer = VSigning::SIGNED; } else if (keyword().isUnsigned()) { - numer = AstNumeric::UNSIGNED; + numer = VSigning::UNSIGNED; } } numeric(numer); @@ -818,11 +817,11 @@ public: } AstRange* rangep() const { return VN_CAST(op1p(), Range); } // op1 = Range of variable void rangep(AstRange* nodep) { setNOp1p(nodep); } - void setSignedState(VSignedState signst) { + void setSignedState(const VSigning& signst) { // Note NOSIGN does NOT change the state; this is required by the parser - if (signst == signedst_UNSIGNED) { + if (signst == VSigning::UNSIGNED) { numeric(signst); - } else if (signst == signedst_SIGNED) { + } else if (signst == VSigning::SIGNED) { numeric(signst); } } @@ -1187,8 +1186,8 @@ public: class AstStructDType : public AstNodeUOrStructDType { public: - // AstNumeric below is mispurposed to indicate if packed or not - AstStructDType(FileLine* fl, AstNumeric numericUnpack) + // VSigning below is mispurposed to indicate if packed or not + AstStructDType(FileLine* fl, VSigning numericUnpack) : ASTGEN_SUPER(fl, numericUnpack) {} ASTNODE_NODE_FUNCS(StructDType) virtual string verilogKwd() const { return "struct"; } @@ -1197,8 +1196,8 @@ public: class AstUnionDType : public AstNodeUOrStructDType { public: // UNSUP: bool isTagged; - // AstNumeric below is mispurposed to indicate if packed or not - AstUnionDType(FileLine* fl, AstNumeric numericUnpack) + // VSigning below is mispurposed to indicate if packed or not + AstUnionDType(FileLine* fl, VSigning numericUnpack) : ASTGEN_SUPER(fl, numericUnpack) {} ASTNODE_NODE_FUNCS(UnionDType) virtual string verilogKwd() const { return "union"; } @@ -1592,13 +1591,13 @@ public: : ASTGEN_SUPER(fl, fromp, lsbp, widthp) { m_declElWidth = 1; if (VN_IS(widthp, Const)) { - dtypeSetLogicSized(VN_CAST(widthp, Const)->toUInt(), AstNumeric::UNSIGNED); + dtypeSetLogicSized(VN_CAST(widthp, Const)->toUInt(), VSigning::UNSIGNED); } } AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth) : ASTGEN_SUPER(fl, fromp, new AstConst(fl, lsb), new AstConst(fl, bitwidth)) { m_declElWidth = 1; - dtypeSetLogicSized(bitwidth, AstNumeric::UNSIGNED); + dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(Sel) virtual void dump(std::ostream& str) const; @@ -1861,7 +1860,7 @@ public: , m_origName(name) { init(); combineType(type); - dtypeSetLogicSized(wantwidth, AstNumeric::UNSIGNED); + dtypeSetLogicSized(wantwidth, VSigning::UNSIGNED); m_declKwd = AstBasicDTypeKwd::LOGIC; } AstVar(FileLine* fl, AstVarType type, const string& name, VFlagBitPacked, int wantwidth) @@ -1870,7 +1869,7 @@ public: , m_origName(name) { init(); combineType(type); - dtypeSetBitSized(wantwidth, AstNumeric::UNSIGNED); + dtypeSetBitSized(wantwidth, VSigning::UNSIGNED); m_declKwd = AstBasicDTypeKwd::BIT; } AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep) @@ -5204,7 +5203,7 @@ public: : ASTGEN_SUPER(fl, lhsp) {} AstExtend(FileLine* fl, AstNode* lhsp, int width) : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicSized(width, AstNumeric::UNSIGNED); + dtypeSetLogicSized(width, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(Extend) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); } @@ -5225,7 +5224,7 @@ public: AstExtendS(FileLine* fl, AstNode* lhsp, int width) // Important that widthMin be correct, as opExtend requires it after V3Expand : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicSized(width, AstNumeric::UNSIGNED); + dtypeSetLogicSized(width, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(ExtendS) virtual void numberOperate(V3Number& out, const V3Number& lhs) { @@ -5503,7 +5502,7 @@ public: m_size = setwidth; if (setwidth) { if (minwidth == -1) minwidth = setwidth; - dtypeSetLogicUnsized(setwidth, minwidth, AstNumeric::UNSIGNED); + dtypeSetLogicUnsized(setwidth, minwidth, VSigning::UNSIGNED); } } AstCCast(FileLine* fl, AstNode* lhsp, AstNode* typeFromp) @@ -6650,7 +6649,7 @@ class AstShiftL : public AstNodeBiop { public: AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { - if (setwidth) { dtypeSetLogicSized(setwidth, AstNumeric::UNSIGNED); } + if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } } ASTNODE_NODE_FUNCS(ShiftL) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { @@ -6672,7 +6671,7 @@ class AstShiftR : public AstNodeBiop { public: AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { - if (setwidth) { dtypeSetLogicSized(setwidth, AstNumeric::UNSIGNED); } + if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } } ASTNODE_NODE_FUNCS(ShiftR) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { @@ -6698,7 +6697,7 @@ public: AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { // Important that widthMin be correct, as opExtend requires it after V3Expand - if (setwidth) { dtypeSetLogicSized(setwidth, AstNumeric::SIGNED); } + if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::SIGNED); } } ASTNODE_NODE_FUNCS(ShiftRS) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { @@ -7206,7 +7205,7 @@ public: : ASTGEN_SUPER(fl, lhsp, rhsp) { if (lhsp->dtypep() && rhsp->dtypep()) { dtypeSetLogicSized(lhsp->dtypep()->width() + rhsp->dtypep()->width(), - AstNumeric::UNSIGNED); + VSigning::UNSIGNED); } } ASTNODE_NODE_FUNCS(Concat) @@ -7256,7 +7255,7 @@ private: void init() { if (lhsp()) { if (const AstConst* constp = VN_CAST(rhsp(), Const)) { - dtypeSetLogicSized(lhsp()->width() * constp->toUInt(), AstNumeric::UNSIGNED); + dtypeSetLogicSized(lhsp()->width() * constp->toUInt(), VSigning::UNSIGNED); } } } @@ -7482,7 +7481,7 @@ class AstGetcN : public AstNodeBiop { public: AstGetcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetBitSized(8, AstNumeric::UNSIGNED); + dtypeSetBitSized(8, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(GetcN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { @@ -7508,7 +7507,7 @@ class AstGetcRefN : public AstNodeBiop { public: AstGetcRefN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetBitSized(8, AstNumeric::UNSIGNED); + dtypeSetBitSized(8, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(GetcRefN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { @@ -8193,7 +8192,7 @@ public: , m_cleanOut(cleanOut) , m_pure(true) { addNOp1p(new AstText(fl, textStmt, true)); - if (setwidth) { dtypeSetLogicSized(setwidth, AstNumeric::UNSIGNED); } + if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } } ASTNODE_NODE_FUNCS(CMath) virtual bool isGateOptimizable() const { return m_pure; } @@ -8340,9 +8339,9 @@ public: AstVoidDType* findVoidDType(FileLine* fl); AstBasicDType* findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd); AstBasicDType* findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width, int widthMin, - AstNumeric numeric); + VSigning numeric); AstBasicDType* findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, VNumRange range, - int widthMin, AstNumeric numeric); + int widthMin, VSigning numeric); AstBasicDType* findInsertSameDType(AstBasicDType* nodep); void clearCache(); void repairCache(); diff --git a/src/V3Const.cpp b/src/V3Const.cpp index dcaec4787..c36ae1f9d 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -839,7 +839,7 @@ private: // use the lhs to replace the parent concat lp->lhsp()->replaceWith(newlp); lp->rhsp()->replaceWith(newrp); - lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), AstNumeric::UNSIGNED); + lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), VSigning::UNSIGNED); UINFO(5, "merged " << nodep << endl); VL_DO_DANGLING(rp->unlinkFrBack()->deleteTree(), rp); nodep->replaceWith(lp->unlinkFrBack()); @@ -1179,7 +1179,7 @@ private: AstNode* srcp = nodep->rhsp()->unlinkFrBack(); // Connect the rhs to the stream operator and update its width VN_CAST(streamp, StreamL)->lhsp(srcp); - streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), AstNumeric::UNSIGNED); + streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), VSigning::UNSIGNED); // Shrink the RHS if necessary if (sWidth > dWidth) { streamp = new AstSel(streamp->fileline(), streamp, sWidth - dWidth, dWidth); @@ -1239,7 +1239,7 @@ private: val.opShiftL(andConstp->num(), shiftConstp->num()); AstAnd* newp = new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), val), fromp); // widthMin no longer applicable if different C-expanded width - newp->dtypeSetLogicSized(nodep->width(), AstNumeric::UNSIGNED); + newp->dtypeSetLogicSized(nodep->width(), VSigning::UNSIGNED); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); if (debug() >= 9) newp->dumpTree(cout, " _new: "); diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index fad150a05..cbc2ccfe9 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -112,13 +112,11 @@ private: new AstConst(nodep->fileline(), word)); } else if (nodep->isQuad() && word == 0) { AstNode* quadfromp = nodep->cloneTree(true); - quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(), - AstNumeric::UNSIGNED); + quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(), VSigning::UNSIGNED); return new AstCCast(nodep->fileline(), quadfromp, VL_EDATASIZE); } else if (nodep->isQuad() && word == 1) { AstNode* quadfromp = nodep->cloneTree(true); - quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(), - AstNumeric::UNSIGNED); + quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(), VSigning::UNSIGNED); return new AstCCast(nodep->fileline(), new AstShiftR(nodep->fileline(), quadfromp, new AstConst(nodep->fileline(), VL_EDATASIZE), @@ -698,7 +696,7 @@ private: if (lhswidth == 1) { newp = new AstNegate(nodep->fileline(), lhsp->cloneTree(true)); newp->dtypeSetLogicSized(VL_EDATASIZE, - AstNumeric::UNSIGNED); // Replicate always unsigned + VSigning::UNSIGNED); // Replicate always unsigned } else { newp = newAstWordSelClone(lhsp, w); for (unsigned repnum = 1; repnum < times; repnum++) { diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 1ff49ea4c..e296c8bf0 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -1340,7 +1340,7 @@ private: VL_DO_DANGLING(oldrhsp->deleteTree(), oldrhsp); m_assignp->dtypeChgWidthSigned(m_assignp->width() + assignp->width(), m_assignp->width() + assignp->width(), - AstNumeric::SIGNED); + VSigning::SIGNED); // don't need to delete, will be handled // assignp->unlinkFrBack(); VL_DO_DANGLING(assignp->deleteTree(), // assignp); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index e22688919..6c8fdafc0 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -55,8 +55,8 @@ struct V3ParseBisonYYSType { double cdouble; bool cbool; V3UniqState uniqstate; - VSignedState signstate; V3ImportProperty iprop; + VSigning::en signstate; V3ErrorCode::en errcodeen; AstAttrType::en attrtypeen; diff --git a/src/V3Table.cpp b/src/V3Table.cpp index 624b9eac8..9c1754e57 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -182,7 +182,7 @@ private: // Change it variable FileLine* fl = nodep->fileline(); AstNodeArrayDType* dtypep = new AstUnpackArrayDType( - fl, nodep->findBitDType(m_outVarps.size(), m_outVarps.size(), AstNumeric::UNSIGNED), + fl, nodep->findBitDType(m_outVarps.size(), m_outVarps.size(), VSigning::UNSIGNED), new AstRange(fl, VL_MASK_I(m_inWidth), 0)); v3Global.rootp()->typeTablep()->addTypesp(dtypep); AstVar* chgVarp = new AstVar(fl, AstVarType::MODULETEMP, diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a9b34a301..49762c4c1 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -317,10 +317,10 @@ private: // Widths: out signed/unsigned width = lhs width, input un|signed virtual void visit(AstSigned* nodep) VL_OVERRIDE { - visit_signed_unsigned(nodep, AstNumeric::SIGNED); + visit_signed_unsigned(nodep, VSigning::SIGNED); } virtual void visit(AstUnsigned* nodep) VL_OVERRIDE { - visit_signed_unsigned(nodep, AstNumeric::UNSIGNED); + visit_signed_unsigned(nodep, VSigning::UNSIGNED); } // Widths: Output width from lhs, rhs<33 bits @@ -369,7 +369,7 @@ private: // See similar handling in visit_cmp_eq_gt where created iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH); - nodep->dtypeSetBitSized(8, AstNumeric::UNSIGNED); + nodep->dtypeSetBitSized(8, VSigning::UNSIGNED); } } virtual void visit(AstGetcRefN* nodep) VL_OVERRIDE { @@ -379,7 +379,7 @@ private: // See similar handling in visit_cmp_eq_gt where created iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH); - nodep->dtypeSetBitSized(8, AstNumeric::UNSIGNED); + nodep->dtypeSetBitSized(8, VSigning::UNSIGNED); } } virtual void visit(AstSubstrN* nodep) VL_OVERRIDE { @@ -454,7 +454,7 @@ private: int width = std::max(nodep->expr1p()->width(), nodep->expr2p()->width()); int mwidth = std::max(nodep->expr1p()->widthMin(), nodep->expr2p()->widthMin()); bool issigned = nodep->expr1p()->isSigned() && nodep->expr2p()->isSigned(); - nodep->dtypeSetLogicUnsized(width, mwidth, AstNumeric::fromBool(issigned)); + nodep->dtypeSetLogicUnsized(width, mwidth, VSigning::fromBool(issigned)); } } if (m_vup->final()) { @@ -489,7 +489,7 @@ private: iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); nodep->dtypeSetLogicUnsized(nodep->lhsp()->width() + nodep->rhsp()->width(), nodep->lhsp()->widthMin() + nodep->rhsp()->widthMin(), - AstNumeric::UNSIGNED); + VSigning::UNSIGNED); // Cleanup zero width Verilog2001 {x,{0{foo}}} now, // otherwise having width(0) will cause later assertions to fire if (AstReplicate* repp = VN_CAST(nodep->lhsp(), Replicate)) { @@ -586,7 +586,7 @@ private: } else { nodep->dtypeSetLogicUnsized((nodep->lhsp()->width() * times), (nodep->lhsp()->widthMin() * times), - AstNumeric::UNSIGNED); + VSigning::UNSIGNED); } } if (m_vup->final()) { @@ -647,7 +647,7 @@ private: } } nodep->dtypeSetLogicUnsized(nodep->lhsp()->width(), nodep->lhsp()->widthMin(), - AstNumeric::UNSIGNED); + VSigning::UNSIGNED); } if (m_vup->final()) { if (!nodep->dtypep()->widthSized()) { @@ -719,7 +719,7 @@ private: nodep->v3error("Unsupported: MSB < LSB of bit extract: " << nodep->msbConst() << "<" << nodep->lsbConst()); width = (nodep->lsbConst() - nodep->msbConst() + 1); - nodep->dtypeSetLogicSized(width, AstNumeric::UNSIGNED); + nodep->dtypeSetLogicSized(width, VSigning::UNSIGNED); nodep->widthp()->replaceWith(new AstConst(nodep->widthp()->fileline(), width)); nodep->lsbp()->replaceWith(new AstConst(nodep->lsbp()->fileline(), 0)); } @@ -1035,7 +1035,7 @@ private: virtual void visit(AstUCFunc* nodep) VL_OVERRIDE { // Give it the size the user wants. if (m_vup && m_vup->prelim()) { - nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::UNSIGNED); // We don't care + nodep->dtypeSetLogicUnsized(32, 1, VSigning::UNSIGNED); // We don't care // All arguments seek their natural sizes userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); } @@ -1120,8 +1120,8 @@ private: iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); // If it's a 32 bit number, we need a 6 bit number as we need to return '32'. int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1; - nodep->dtypeSetLogicSized( - selwidth, AstNumeric::UNSIGNED); // Spec doesn't indicate if an integer + nodep->dtypeSetLogicSized(selwidth, + VSigning::UNSIGNED); // Spec doesn't indicate if an integer } } virtual void visit(AstCvtPackString* nodep) VL_OVERRIDE { @@ -1261,7 +1261,7 @@ private: } default: { // Everything else resolved earlier - nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::UNSIGNED); // Approximation, unsized 32 + nodep->dtypeSetLogicUnsized(32, 1, VSigning::UNSIGNED); // Approximation, unsized 32 UINFO(1, "Missing ATTR type case node: " << nodep << endl); nodep->v3fatalSrc("Missing ATTR type case"); break; @@ -1596,13 +1596,13 @@ private: // not "parameter logic foo" as you can extract // "foo[0]" from a parameter but not a wire nodep->dtypeChgWidthSigned(width, nodep->valuep()->widthMin(), - AstNumeric::fromBool(issigned)); + VSigning::fromBool(issigned)); nodep->dtypep(nodep->findLogicRangeDType(VNumRange(0, 0, false), nodep->valuep()->widthMin(), - AstNumeric::fromBool(issigned))); + VSigning::fromBool(issigned))); } else { nodep->dtypeChgWidthSigned(width, nodep->valuep()->widthMin(), - AstNumeric::fromBool(issigned)); + VSigning::fromBool(issigned)); } didchk = true; } @@ -2958,7 +2958,7 @@ private: int mwidth = std::max(subDTypep->widthMin(), condp->widthMin()); bool issigned = subDTypep->isSigned() && condp->isSigned(); subDTypep - = nodep->findLogicDType(width, mwidth, AstNumeric::fromBool(issigned)); + = nodep->findLogicDType(width, mwidth, VSigning::fromBool(issigned)); } } } @@ -3245,13 +3245,13 @@ private: iterateCheckFileDesc(nodep, nodep->filep(), BOTH); // We only support string types, not packed array iterateCheckString(nodep, "$ferror string result", nodep->strp(), BOTH); - nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::SIGNED); // Spec says integer return + nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } } virtual void visit(AstFEof* nodep) VL_OVERRIDE { if (m_vup->prelim()) { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); - nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::SIGNED); // Spec says integer return + nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } } virtual void visit(AstFFlush* nodep) VL_OVERRIDE { @@ -3260,22 +3260,22 @@ private: } virtual void visit(AstFRewind* nodep) VL_OVERRIDE { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); - nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::SIGNED); // Spec says integer return + nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } virtual void visit(AstFTell* nodep) VL_OVERRIDE { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); - nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::SIGNED); // Spec says integer return + nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } virtual void visit(AstFSeek* nodep) VL_OVERRIDE { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); iterateCheckSigned32(nodep, "$fseek offset", nodep->offset(), BOTH); iterateCheckSigned32(nodep, "$fseek operation", nodep->operation(), BOTH); - nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::SIGNED); // Spec says integer return + nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } virtual void visit(AstFGetC* nodep) VL_OVERRIDE { if (m_vup->prelim()) { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); - nodep->dtypeSetLogicUnsized(32, 8, AstNumeric::SIGNED); // Spec says integer return + nodep->dtypeSetLogicUnsized(32, 8, VSigning::SIGNED); // Spec says integer return } } virtual void visit(AstFGetS* nodep) VL_OVERRIDE { @@ -3289,7 +3289,7 @@ private: if (m_vup->prelim()) { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); iterateCheckSigned32(nodep, "$fungetc character", nodep->charp(), BOTH); - nodep->dtypeSetLogicUnsized(32, 8, AstNumeric::SIGNED); // Spec says integer return + nodep->dtypeSetLogicUnsized(32, 8, VSigning::SIGNED); // Spec says integer return } } virtual void visit(AstFRead* nodep) VL_OVERRIDE { @@ -3370,7 +3370,7 @@ private: if (m_vup->prelim()) { userIterateAndNext(nodep->searchp(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->outp(), WidthVP(SELF, BOTH).p()); - nodep->dtypeChgWidthSigned(32, 1, AstNumeric::SIGNED); // Spec says integer return + nodep->dtypeChgWidthSigned(32, 1, VSigning::SIGNED); // Spec says integer return } } virtual void visit(AstTimeFormat* nodep) VL_OVERRIDE { @@ -3775,7 +3775,7 @@ private: // LHS presumed self-determined, then coerced to real if (m_vup->prelim()) { // First stage evaluation nodep->dtypeSetDouble(); - AstNodeDType* subDTypep = nodep->findLogicDType(64, 64, AstNumeric::UNSIGNED); + AstNodeDType* subDTypep = nodep->findLogicDType(64, 64, VSigning::UNSIGNED); // Self-determined operand userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p()); iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP); @@ -3787,7 +3787,7 @@ private: // LHS presumed self-determined, then coerced to real if (m_vup->prelim()) { // First stage evaluation nodep->dtypeSetDouble(); - AstNodeDType* subDTypep = nodep->findLogicDType(32, 32, AstNumeric::SIGNED); + AstNodeDType* subDTypep = nodep->findLogicDType(32, 32, VSigning::SIGNED); // Self-determined operand userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p()); iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP); @@ -3906,7 +3906,7 @@ private: int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width()); int ewidth = std::max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin()); AstNodeDType* subDTypep - = nodep->findLogicDType(width, ewidth, AstNumeric::fromBool(signedFl)); + = nodep->findLogicDType(width, ewidth, VSigning::fromBool(signedFl)); bool warnOn = true; if (!signedFl && width == 32) { // Waive on unsigned < or <= if RHS is narrower, since can't give wrong answer @@ -4001,7 +4001,7 @@ private: } } - void visit_signed_unsigned(AstNodeUniop* nodep, AstNumeric rs_out) { + void visit_signed_unsigned(AstNodeUniop* nodep, VSigning rs_out) { // CALLER: Signed, Unsigned // Width: lhs is self determined width // See IEEE-2012 6.24.1: @@ -4096,7 +4096,7 @@ private: int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width()); int mwidth = std::max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin()); bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()); - nodep->dtypeChgWidthSigned(width, mwidth, AstNumeric::fromBool(expSigned)); + nodep->dtypeChgWidthSigned(width, mwidth, VSigning::fromBool(expSigned)); } if (m_vup->final()) { AstNodeDType* expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); @@ -4144,7 +4144,7 @@ private: int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width()); int mwidth = std::max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin()); bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()); - nodep->dtypeChgWidthSigned(width, mwidth, AstNumeric::fromBool(expSigned)); + nodep->dtypeChgWidthSigned(width, mwidth, VSigning::fromBool(expSigned)); } } if (m_vup->final()) { @@ -4304,7 +4304,7 @@ private: linker.relink(newp); nodep = newp; } - nodep->dtypeChgWidthSigned(expWidth, expWidth, AstNumeric::fromBool(expSigned)); + nodep->dtypeChgWidthSigned(expWidth, expWidth, VSigning::fromBool(expSigned)); UINFO(4, " _new: " << nodep << endl); } @@ -4529,7 +4529,7 @@ private: subDTypep = nodep->findLogicDType( std::max(subDTypep->width(), underp->width()), std::max(subDTypep->widthMin(), underp->widthMin()), - AstNumeric::fromBool(underp->isSigned())); + VSigning::fromBool(underp->isSigned())); UINFO(9, "Assignment of opposite-signed RHS to LHS: " << nodep << endl); } underp = userIterateSubtreeReturnEdits(underp, WidthVP(subDTypep, FINAL).p()); @@ -4674,7 +4674,7 @@ private: if (warnOn) nodep->v3warn(REALCVT, "Implicit conversion of real to integer"); AstNode* newp = new AstRToIRoundS(nodep->fileline(), nodep); linker.relink(newp); - newp->dtypeSetBitSized(width, AstNumeric::SIGNED); + newp->dtypeSetBitSized(width, VSigning::SIGNED); return newp; } else { return nodep; diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index 04320bffb..72436b9d1 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -148,7 +148,7 @@ private: if (nodep->user1SetOnce()) return; // Process once nodep->widthMinFromWidth(); // Too late to any unspecified sign to be anything but unsigned - if (nodep->numeric().isNosign()) nodep->numeric(AstNumeric::UNSIGNED); + if (nodep->numeric().isNosign()) nodep->numeric(VSigning::UNSIGNED); iterateChildren(nodep); nodep->virtRefDTypep(editOneDType(nodep->virtRefDTypep())); nodep->virtRefDType2p(editOneDType(nodep->virtRefDType2p())); diff --git a/src/verilog.y b/src/verilog.y index 42eee81cf..0c261d185 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1549,13 +1549,13 @@ non_integer_type: // ==IEEE: non_integer_type ; signingE: // IEEE: signing - plus empty - /*empty*/ { $$ = signedst_NOSIGN; } + /*empty*/ { $$ = VSigning::NOSIGN; } | signing { $$ = $1; } ; signing: // ==IEEE: signing - ySIGNED { $$ = $1; $$ = signedst_SIGNED; } - | yUNSIGNED { $$ = $1; $$ = signedst_UNSIGNED; } + ySIGNED { $$ = $1; $$ = VSigning::SIGNED; } + | yUNSIGNED { $$ = $1; $$ = VSigning::UNSIGNED; } ; //************************************************ @@ -1784,9 +1784,9 @@ taggedE: ; packedSigningE: - // // AstNumeric::NOSIGN overloaded to indicate not packed - /*empty*/ { $$ = signedst_NOSIGN; } - | yPACKED signingE { $$ = $2; if ($$ == signedst_NOSIGN) $$ = signedst_UNSIGNED; } + // // VSigning::NOSIGN overloaded to indicate not packed + /*empty*/ { $$ = VSigning::NOSIGN; } + | yPACKED signingE { $$ = $2; if ($$ == VSigning::NOSIGN) $$ = VSigning::UNSIGNED; } ; //************************************************ From 7d6668a3bd96456ba1d8bab94bf8c864777d2866 Mon Sep 17 00:00:00 2001 From: Veripool API Bot Date: Mon, 20 Apr 2020 19:38:21 -0400 Subject: [PATCH 074/127] Commentary commit for Codacity. --- docs/CONTRIBUTORS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 09209bf36..89f59cf22 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -2,8 +2,7 @@ The contributors listed below have certified their Verilator contributions under the Developer Certificate of Origin (https://developercertificate.org/). -Please see the Verilator manual for 200+ additional contributors. Thanks to -all. +Please see the Verilator manual for 200+ additional contributors. Thanks to all. Ahmed El-Mahmoudy Alex Chadwick From 03bc8b7480fcc6253724c1f4cf07fea43914a09c Mon Sep 17 00:00:00 2001 From: Veripool API Bot Date: Mon, 20 Apr 2020 19:54:07 -0400 Subject: [PATCH 075/127] Commentary commit for Codacity. --- docs/CONTRIBUTORS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 89f59cf22..447e57f23 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -1,6 +1,5 @@ The contributors listed below have certified their Verilator contributions -under the Developer Certificate of Origin -(https://developercertificate.org/). +under the Developer Certificate of Origin (https://developercertificate.org/). Please see the Verilator manual for 200+ additional contributors. Thanks to all. From 1cacb1deab403bf6d8c54974be9e33892749a445 Mon Sep 17 00:00:00 2001 From: Veripool API Bot Date: Mon, 20 Apr 2020 20:01:59 -0400 Subject: [PATCH 076/127] Commentary commit for Codacity. --- docs/CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 447e57f23..b9ea6e795 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -3,6 +3,7 @@ under the Developer Certificate of Origin (https://developercertificate.org/). Please see the Verilator manual for 200+ additional contributors. Thanks to all. + Ahmed El-Mahmoudy Alex Chadwick Chris Randall From 83c6e9e8214c5407402add30642330c916d02d79 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 20 Apr 2020 21:13:43 -0400 Subject: [PATCH 077/127] Commentary commit for Codacity. --- docs/CONTRIBUTORS | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index b9ea6e795..447e57f23 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -3,7 +3,6 @@ under the Developer Certificate of Origin (https://developercertificate.org/). Please see the Verilator manual for 200+ additional contributors. Thanks to all. - Ahmed El-Mahmoudy Alex Chadwick Chris Randall From 15f768575570cc95732338b33bb2c10b8ee5df46 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 20 Apr 2020 21:43:05 -0400 Subject: [PATCH 078/127] Codacity cleanups. No functional change intended. --- src/V3CCtors.cpp | 2 +- src/V3Task.cpp | 2 +- test_regress/t/t_dpi_arg_inout_type.cpp | 12 ++++++------ test_regress/t/t_dpi_arg_input_type.cpp | 8 ++++---- test_regress/t/t_dpi_arg_output_type.cpp | 20 ++++++++++---------- test_regress/t/t_dpi_result_type.cpp | 22 +++++++++++----------- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index c4c1cc713..962b382f9 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -145,8 +145,8 @@ void V3CCtors::cctorsAll() { for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp = VN_CAST(modp->nextp(), NodeModule)) { // Process each module in turn - AstCFunc* varResetFuncp; { + AstCFunc* varResetFuncp; V3CCtorsVisitor var_reset( modp, "_ctor_var_reset", (VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""), diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 8fcd656ff..bdb75e68d 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -512,7 +512,7 @@ private: AstNode* beginp = new AstComment(refp->fileline(), string("Function: ") + refp->name(), true); AstNodeCCall* ccallp; - if (AstNew* mrefp = VN_CAST(refp, New)) { + if (VN_IS(refp, New)) { AstCNew* cnewp = new AstCNew(refp->fileline(), cfuncp); cnewp->dtypep(refp->dtypep()); ccallp = cnewp; diff --git a/test_regress/t/t_dpi_arg_inout_type.cpp b/test_regress/t/t_dpi_arg_inout_type.cpp index 5cec53ba8..04b8165de 100644 --- a/test_regress/t/t_dpi_arg_inout_type.cpp +++ b/test_regress/t/t_dpi_arg_inout_type.cpp @@ -160,7 +160,7 @@ void i_chandle(void** x) { static int n = 0; printf("i_chandle %d\n", n); if (*x != NULL) stop(); - *x = n % 2 ? reinterpret_cast(&i_chandle) : 0; + *x = (n % 2) ? reinterpret_cast(&i_chandle) : 0; n++; } @@ -288,7 +288,7 @@ void i_chandle_t(void** x) { static int n = 0; printf("i_chandle_t %d\n", n); if (*x != NULL) stop(); - *x = n % 2 ? 0 : reinterpret_cast(&i_chandle_t); + *x = (n % 2) ? 0 : reinterpret_cast(&i_chandle_t); n++; } @@ -951,7 +951,7 @@ void check_exports() { if (x_shortreal != 200.0f + 1.0f * n + 0.25f) stop(); #endif - if (n % 2 == 0) { + if ((n % 2) == 0) { x_chandle = reinterpret_cast(&e_chandle); x_string = "Good"; } else { @@ -960,7 +960,7 @@ void check_exports() { } e_chandle(&x_chandle); e_string(&x_string); - if (n % 2 == 0) { + if ((n % 2) == 0) { if (x_chandle != NULL) stop(); if (strcmp(x_string, "Hello") != 0) stop(); } else { @@ -1034,7 +1034,7 @@ void check_exports() { if (x_shortreal_t != 222.0f + 1.0f * (2 * n) + 0.25f) stop(); #endif - if (n % 2 == 0) { + if ((n % 2) == 0) { x_chandle_t = NULL; x_string_t = "Bye"; } else { @@ -1043,7 +1043,7 @@ void check_exports() { } e_chandle_t(&x_chandle_t); e_string_t(&x_string_t); - if (n % 2 == 0) { + if ((n % 2) == 0) { if (x_chandle_t != NULL) stop(); if (strcmp(x_string_t, "World") != 0) stop(); } else { diff --git a/test_regress/t/t_dpi_arg_input_type.cpp b/test_regress/t/t_dpi_arg_input_type.cpp index 730740cb3..e794bd745 100644 --- a/test_regress/t/t_dpi_arg_input_type.cpp +++ b/test_regress/t/t_dpi_arg_input_type.cpp @@ -618,8 +618,8 @@ void check_exports() { #ifndef NO_SHORTREAL e_shortreal(1.0f * n + 0.25f); #endif - e_chandle(n % 2 ? reinterpret_cast(&e_chandle) : NULL); - e_string(n % 2 ? "World" : "Hello"); + e_chandle((n % 2) ? reinterpret_cast(&e_chandle) : NULL); + e_string((n % 2) ? "World" : "Hello"); e_bit(n % 2); e_logic(!(n % 2)); @@ -645,8 +645,8 @@ void check_exports() { #ifndef NO_SHORTREAL e_shortreal_t(1.0f * (2 * n) + 0.25f); #endif - e_chandle_t(n % 2 ? NULL : reinterpret_cast(&e_chandle_t)); - e_string_t(n % 2 ? "Hello" : "World"); + e_chandle_t((n % 2) ? NULL : reinterpret_cast(&e_chandle_t)); + e_string_t((n % 2) ? "Hello" : "World"); e_bit_t(n % 2); e_logic_t(!(n % 2)); diff --git a/test_regress/t/t_dpi_arg_output_type.cpp b/test_regress/t/t_dpi_arg_output_type.cpp index e23375e6c..931f3775a 100644 --- a/test_regress/t/t_dpi_arg_output_type.cpp +++ b/test_regress/t/t_dpi_arg_output_type.cpp @@ -710,14 +710,14 @@ void check_exports() { if (x_chandle != NULL) stop(); e_string(&x_string); - if (n % 2 == 0) { + if ((n % 2) == 0) { if (strcmp(x_string, "Hello") != 0) stop(); } else { if (strcmp(x_string, "World") != 0) stop(); } e_bit(&x_bit); - if (x_bit != n % 2) stop(); + if (x_bit != (n % 2)) stop(); e_logic(&x_logic); if (x_logic != !(n % 2)) stop(); @@ -771,14 +771,14 @@ void check_exports() { if (x_chandle_t != NULL) stop(); e_string_t(&x_string_t); - if (n % 2 == 0) { + if ((n % 2) == 0) { if (strcmp(x_string_t, "Hello") != 0) stop(); } else { if (strcmp(x_string_t, "World") != 0) stop(); } e_bit_t(&x_bit_t); - if (x_bit_t != n % 2) stop(); + if (x_bit_t != (n % 2)) stop(); e_logic_t(&x_logic_t); if (x_logic_t != !(n % 2)) stop(); @@ -787,7 +787,7 @@ void check_exports() { // 2-state packed arrays e_array_2_state_1(x_array_2_state_1); - if (x_array_2_state_1[0] != n % 2) stop(); + if (x_array_2_state_1[0] != (n % 2)) stop(); e_array_2_state_32(x_array_2_state_32); if (x_array_2_state_32[0] != 0xffffffff >> n) stop(); @@ -813,7 +813,7 @@ void check_exports() { // 2-state packed structures e_struct_2_state_1(x_struct_2_state_1); - if (x_struct_2_state_1[0] != n % 2) stop(); + if (x_struct_2_state_1[0] != (n % 2)) stop(); e_struct_2_state_32(x_struct_2_state_32); if (x_struct_2_state_32[0] != 0xffffffff >> n) stop(); @@ -839,7 +839,7 @@ void check_exports() { // 2-state packed unions e_union_2_state_1(x_union_2_state_1); - if (x_union_2_state_1[0] != n % 2) stop(); + if (x_union_2_state_1[0] != (n % 2)) stop(); e_union_2_state_32(x_union_2_state_32); if (x_union_2_state_32[0] != 0xffffffff >> n) stop(); @@ -865,7 +865,7 @@ void check_exports() { // 4-state packed arrays e_array_4_state_1(x_array_4_state_1); - if (x_array_4_state_1[0].aval != n % 2) stop(); + if (x_array_4_state_1[0].aval != (n % 2)) stop(); e_array_4_state_32(x_array_4_state_32); if (x_array_4_state_32[0].aval != 0xffffffff >> n) stop(); @@ -898,7 +898,7 @@ void check_exports() { // 4-state packed structures e_struct_4_state_1(x_struct_4_state_1); - if (x_struct_4_state_1[0].aval != n % 2) stop(); + if (x_struct_4_state_1[0].aval != (n % 2)) stop(); e_struct_4_state_32(x_struct_4_state_32); if (x_struct_4_state_32[0].aval != 0xffffffff >> n) stop(); @@ -931,7 +931,7 @@ void check_exports() { // 4-state packed unions e_union_4_state_1(x_union_4_state_1); - if (x_union_4_state_1[0].aval != n % 2) stop(); + if (x_union_4_state_1[0].aval != (n % 2)) stop(); e_union_4_state_32(x_union_4_state_32); if (x_union_4_state_32[0].aval != 0xffffffff >> n) stop(); diff --git a/test_regress/t/t_dpi_result_type.cpp b/test_regress/t/t_dpi_result_type.cpp index 27bffe8c5..2f5bbe7f5 100644 --- a/test_regress/t/t_dpi_result_type.cpp +++ b/test_regress/t/t_dpi_result_type.cpp @@ -108,13 +108,13 @@ float i_shortreal() { void* i_chandle() { static int n = 0; printf("i_chandle %d\n", n); - return n++ % 2 ? reinterpret_cast(&i_chandle) : NULL; + return (n++ % 2) ? reinterpret_cast(&i_chandle) : NULL; } const char* i_string() { static int n = 0; printf("i_string %d\n", n); - return n++ % 2 ? "Hello" : "World"; + return (n++ % 2) ? "Hello" : "World"; } svBit i_bit() { @@ -205,13 +205,13 @@ float i_shortreal_t() { void* i_chandle_t() { static int n = 0; printf("i_chandle_t %d\n", n); - return n++ % 2 ? reinterpret_cast(&i_chandle) : NULL; + return (n++ % 2) ? reinterpret_cast(&i_chandle) : NULL; } const char* i_string_t() { static int n = 0; printf("i_string_t %d\n", n); - return n++ % 2 ? "Hello" : "World"; + return (n++ % 2) ? "Hello" : "World"; } svBit i_bit_t() { @@ -300,12 +300,12 @@ void check_exports() { if (e_shortreal() != 1.0f * n + 0.25f) stop(); #endif if (e_chandle() != NULL) stop(); - if (n % 2 == 0) { + if ((n % 2) == 0) { if (strcmp(e_string(), "Hello") != 0) stop(); } else { if (strcmp(e_string(), "World") != 0) stop(); } - if (e_bit() != n % 2) stop(); + if (e_bit() != (n % 2)) stop(); if (e_logic() != !(n % 2)) stop(); // Basic types via tyepdef @@ -324,27 +324,27 @@ void check_exports() { if (e_shortreal_t() != 1.0f * (2 * n) + 0.25f) stop(); #endif if (e_chandle_t() != NULL) stop(); - if (n % 2 == 0) { + if ((n % 2) == 0) { if (strcmp(e_string_t(), "Hello") != 0) stop(); } else { if (strcmp(e_string_t(), "World") != 0) stop(); } - if (e_bit_t() != n % 2) stop(); + if (e_bit_t() != (n % 2)) stop(); if (e_logic_t() != !(n % 2)) stop(); #ifndef NO_ARRAY // 2-state packed arrays of width <= 32 - if (e_array_2_state_1() != n % 2) stop(); + if (e_array_2_state_1() != (n % 2)) stop(); if (e_array_2_state_32() != 0xffffffff >> n) stop(); #endif #ifndef NO_STRUCT_OR_UNION // 2-state packed structures of width <= 32 - if (e_struct_2_state_1() != n % 2) stop(); + if (e_struct_2_state_1() != (n % 2)) stop(); if (e_struct_2_state_32() != 0xffffffff >> n) stop(); // 2-state packed unions of width <= 32 - if (e_union_2_state_1() != n % 2) stop(); + if (e_union_2_state_1() != (n % 2)) stop(); if (e_union_2_state_32() != 0xffffffff >> n) stop(); #endif From 7709130d93982bbbba98fdb6c1f8758efa1cb2bb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 20 Apr 2020 21:52:29 -0400 Subject: [PATCH 079/127] Fix Codacy badge --- README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index 5fd864f76..45f2c7409 100644 --- a/README.adoc +++ b/README.adoc @@ -4,7 +4,7 @@ ifdef::env-github[] image:https://img.shields.io/badge/License-LGPL%20v3-blue.svg[license LGPLv3,link=https://www.gnu.org/licenses/lgpl-3.0] image:https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg[license Artistic-2.0,link=https://opensource.org/licenses/Artistic-2.0] -image:https://api.codacy.com/project/badge/Grade/48478c986f13400682ffe4a5e0939b3a[Code Quality,link=https://www.codacy.com/gh/verilator/verilator] +image:https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f[Code Quality,link=https://www.codacy.com/gh/verilator/verilator] image:https://travis-ci.com/verilator/verilator.svg?branch=master[Build Status (Travis CI),link=https://travis-ci.com/verilator/verilator] endif::[] From b12413e42f4ead946b6d1d48dd763b381ed2958a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 20 Apr 2020 21:55:23 -0400 Subject: [PATCH 080/127] Tests: Reenable some tests incorrectly marked unsupported. --- test_regress/t/t_display_time.out | 4 ++++ test_regress/t/t_display_time.v | 2 -- test_regress/t/t_enum_type_pins.pl | 2 -- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test_regress/t/t_display_time.out b/test_regress/t/t_display_time.out index 12f056d38..9f28e2cd5 100644 --- a/test_regress/t/t_display_time.out +++ b/test_regress/t/t_display_time.out @@ -1,3 +1,7 @@ default: [10] 0t time [ 10] No0 time p= 10 0p='ha +-9,0,,0: [10] 0t time [10] No0 time p= 10 0p='ha +-9,0,,10: [10] 0t time [ 10] No0 time p= 10 0p='ha +-9,0,ns,5: [10ns] 0t time [ 10ns] No0 time p= 10 0p='ha +-9,3,ns,8: [10.000ns] 0t time [10.000ns] No0 time p= 10 0p='ha *-* All Finished *-* diff --git a/test_regress/t/t_display_time.v b/test_regress/t/t_display_time.v index c68b89829..72b84a94c 100644 --- a/test_regress/t/t_display_time.v +++ b/test_regress/t/t_display_time.v @@ -18,7 +18,6 @@ module t (/*AUTOARG*/ $write; // Check missing arguments work $write("default: [%0t] 0t time [%t] No0 time p=%p 0p=%0p\n", $time, $time, $time, $time); -`ifndef verilator // Unsupported $timeformat(-9, 0, "", 0); $write("-9,0,,0: [%0t] 0t time [%t] No0 time p=%p 0p=%0p\n", $time, $time, $time, $time); @@ -31,7 +30,6 @@ module t (/*AUTOARG*/ $timeformat(-9, 3, "ns", 8); $write("-9,3,ns,8: [%0t] 0t time [%t] No0 time p=%p 0p=%0p\n", $time, $time, $time, $time); -`endif $write("\n"); $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_enum_type_pins.pl b/test_regress/t/t_enum_type_pins.pl index 340f9836d..1d046ed3f 100755 --- a/test_regress/t/t_enum_type_pins.pl +++ b/test_regress/t/t_enum_type_pins.pl @@ -9,8 +9,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 scenarios(simulator => 1); -# Not yet working on Verilator -$Self->{vlt_all} and unsupported("Verilator unsupported"); compile( ); From 174fd1bf0ed5256cf62aa1cebf0774aafb4ff1cc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 20 Apr 2020 22:01:47 -0400 Subject: [PATCH 081/127] Codacy cleanups. No functional change. --- include/verilated.h | 1 + test_regress/t/t_dpi_arg_output_type.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index c49226ce4..c2bc2bfad 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -46,6 +46,7 @@ // Allow user to specify their own include file #ifdef VL_VERILATED_INCLUDE +// cppcheck-suppress preprocessorErrorDirective # include VL_VERILATED_INCLUDE #endif // clang-format on diff --git a/test_regress/t/t_dpi_arg_output_type.cpp b/test_regress/t/t_dpi_arg_output_type.cpp index 931f3775a..c257f53ff 100644 --- a/test_regress/t/t_dpi_arg_output_type.cpp +++ b/test_regress/t/t_dpi_arg_output_type.cpp @@ -131,13 +131,13 @@ void i_shortreal(float* o) { void i_chandle(void** o) { static int n = 0; printf("i_chandle %d\n", n); - *o = n++ % 2 ? reinterpret_cast(&i_chandle) : NULL; + *o = (n++ % 2) ? reinterpret_cast(&i_chandle) : NULL; } void i_string(const char** o) { static int n = 0; printf("i_string %d\n", n); - *o = n++ % 2 ? "Hello" : "World"; + *o = (n++ % 2) ? "Hello" : "World"; } void i_bit(svBit* o) { @@ -247,13 +247,13 @@ void i_shortreal_t(float* o) { void i_chandle_t(void** o) { static int n = 0; printf("i_chandle_t %d\n", n); - *o = n++ % 2 ? reinterpret_cast(&i_chandle) : NULL; + *o = (n++ % 2) ? reinterpret_cast(&i_chandle) : NULL; } void i_string_t(const char** o) { static int n = 0; printf("i_string_t %d\n", n); - *o = n++ % 2 ? "Hello" : "World"; + *o = (n++ % 2) ? "Hello" : "World"; } void i_bit_t(svBit* o) { From 65cd4f6047d9f27e55263059bbf3f31cd548b8d0 Mon Sep 17 00:00:00 2001 From: James Hanlon Date: Tue, 21 Apr 2020 18:11:53 -0400 Subject: [PATCH 082/127] Fix comment and add to CONTRIBUTORS (#2270). --- docs/CONTRIBUTORS | 1 + src/V3Options.cpp | 2 +- src/V3Options.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 447e57f23..dedbf3726 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -14,6 +14,7 @@ Geza Lore Gianfranco Costamagna Howard Su Iztok Jeras +James Hanlon Jeremy Bennett John Coiner Julien Margetts diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 51a889cb6..641424df8 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -883,7 +883,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if ( onoff (sw, "-vpi", flag/*ref*/)) { m_vpi = flag; } else if ( onoff (sw, "-Wpedantic", flag/*ref*/)) { m_pedantic = flag; } else if ( onoff (sw, "-x-initial-edge", flag/*ref*/)) { m_xInitialEdge = flag; } - else if ( onoff (sw, "-xml-only", flag/*ref*/)) { m_xmlOnly = flag; } // Undocumented, still experimental + else if ( onoff (sw, "-xml-only", flag/*ref*/)) { m_xmlOnly = flag; } else { hadSwitchPart1 = false; } // clang-format on diff --git a/src/V3Options.h b/src/V3Options.h index c5ef514ed..32745c8d6 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -268,7 +268,7 @@ private: bool m_verilate; // main swith: --verilate bool m_vpi; // main switch: --vpi bool m_xInitialEdge; // main switch: --x-initial-edge - bool m_xmlOnly; // main switch: --xml-netlist + bool m_xmlOnly; // main switch: --xml-only int m_buildJobs; // main switch: -j int m_convergeLimit;// main switch: --converge-limit From 97cbc10925787fc6bd364ffc8ecfb0198737f4b7 Mon Sep 17 00:00:00 2001 From: James Hanlon Date: Tue, 21 Apr 2020 18:14:08 -0400 Subject: [PATCH 083/127] Add --flaten for use with --xml-only (#2270). --- Changes | 2 + bin/verilator | 7 +++ docs/xml.adoc | 2 +- src/V3Inline.cpp | 8 ++- src/V3Options.cpp | 2 + src/V3Options.h | 2 + src/Verilator.cpp | 14 +++-- test_regress/t/t_xml_flat.out | 114 ++++++++++++++++++++++++++++++++++ test_regress/t/t_xml_flat.pl | 27 ++++++++ 9 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 test_regress/t/t_xml_flat.out create mode 100755 test_regress/t/t_xml_flat.pl diff --git a/Changes b/Changes index 8c68249c5..cefd3e574 100644 --- a/Changes +++ b/Changes @@ -20,6 +20,8 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Fix DPI import/export to be standard compliant, #2236. [Geza Lore] +*** Add --flatten for use with --xml-only, #2270. [James Hanlon] + **** Support $ferror, and $fflush without arguments, #1638. **** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. diff --git a/bin/verilator b/bin/verilator index 2a2ea028b..3fa55b771 100755 --- a/bin/verilator +++ b/bin/verilator @@ -303,6 +303,7 @@ detailed descriptions in L for more information. -F Parse options from a file, relatively -f Parse options from a file -FI Force include of a file + --flatten Force inlining of all modules, tasks and functions -G= Overwrite toplevel parameter --gdb Run Verilator under GDB interactively --gdbbt Run Verilator under GDB for backtrace @@ -847,6 +848,12 @@ specified file might be used to contain define prototypes of custom VL_VPRINTF functions, and may need to include verilatedos.h as this file is included before any other standard includes. +=item --flatten + +Force flattening of the design's hierarchy, with all modules, tasks and +functions inlined. Typically used with C<--xml-only>. Note flattening +large designs may require significant CPU time, memory and storage. + =item -GI=I Overwrites the given parameter of the toplevel module. The value is limited diff --git a/docs/xml.adoc b/docs/xml.adoc index 3dabedc02..0189b44cf 100644 --- a/docs/xml.adoc +++ b/docs/xml.adoc @@ -21,7 +21,7 @@ parser. == Structure -The XML document is consists of 4 sections within the top level `verilator_xml` +The XML document consists of 4 sections within the top level `verilator_xml` element: ``...``:: diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index dce048684..49c795669 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -194,13 +194,15 @@ private: int refs = modp->user3(); // Should we automatically inline this module? + // If --flatten is specified, then force everything to be inlined that can be. // inlineMult = 2000 by default. // If a mod*#refs is < this # nodes, can inline it bool doit = ((allowed == CIL_USER) || ((allowed == CIL_MAYBE) - && (refs == 1 || statements < INLINE_MODS_SMALLER - || v3Global.opt.inlineMult() < 1 - || refs * statements < v3Global.opt.inlineMult()))); + && (v3Global.opt.flatten() + || (refs == 1 || statements < INLINE_MODS_SMALLER + || v3Global.opt.inlineMult() < 1 + || refs * statements < v3Global.opt.inlineMult())))); // Packages aren't really "under" anything so they confuse this algorithm if (VN_IS(modp, Package)) doit = false; UINFO(4, " Inline=" << doit << " Possible=" << allowed << " Refs=" << refs diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 641424df8..1f0b30f15 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -842,6 +842,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if ( onoff (sw, "-dump-defines", flag/*ref*/)) { m_dumpDefines = flag; } else if ( onoff (sw, "-dump-tree", flag/*ref*/)) { m_dumpTree = flag ? 3 : 0; } // Also see --dump-treei else if ( onoff (sw, "-exe", flag/*ref*/)) { m_exe = flag; } + else if ( onoff (sw, "-flatten", flag/*ref*/)) { m_flatten = flag; } else if ( onoff (sw, "-ignc", flag/*ref*/)) { m_ignc = flag; } else if ( onoff (sw, "-inhibit-sim", flag/*ref*/)) { m_inhibitSim = flag; } else if ( onoff (sw, "-lint-only", flag/*ref*/)) { m_lintOnly = flag; } @@ -1525,6 +1526,7 @@ V3Options::V3Options() { m_dpiHdrOnly = false; m_dumpDefines = false; m_exe = false; + m_flatten = false; m_ignc = false; m_inhibitSim = false; m_lintOnly = false; diff --git a/src/V3Options.h b/src/V3Options.h index 32745c8d6..d8d233112 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -230,6 +230,7 @@ private: bool m_dpiHdrOnly; // main switch: --dpi-hdr-only bool m_dumpDefines; // main switch: --dump-defines bool m_exe; // main switch: --exe + bool m_flatten; // main switch: --flatten bool m_ignc; // main switch: --ignc bool m_inhibitSim; // main switch: --inhibit-sim bool m_lintOnly; // main switch: --lint-only @@ -424,6 +425,7 @@ public: bool dpiHdrOnly() const { return m_dpiHdrOnly; } bool dumpDefines() const { return m_dumpDefines; } bool exe() const { return m_exe; } + bool flatten() const { return m_flatten; } bool gmake() const { return m_gmake; } bool threadsDpiPure() const { return m_threadsDpiPure; } bool threadsDpiUnpure() const { return m_threadsDpiUnpure; } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 23471fe7e..31a499e28 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -160,7 +160,7 @@ static void process() { // V3Assert::assertAll(v3Global.rootp()); - if (!v3Global.opt.xmlOnly()) { + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { // Add top level wrapper with instance pointing to old top // Move packages to under new top // Must do this after we know parameters and dtypes (as don't clone dtype decls) @@ -170,7 +170,7 @@ static void process() { // Propagate constants into expressions V3Const::constifyAllLint(v3Global.rootp()); - if (!v3Global.opt.xmlOnly()) { + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { // Split packed variables into multiple pieces to resolve UNOPTFLAT. // should be after constifyAllLint() which flattens to 1D bit vector V3SplitVar::splitVariable(v3Global.rootp()); @@ -214,7 +214,7 @@ static void process() { //--FLATTENING--------------- - if (!v3Global.opt.xmlOnly()) { + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { // We're going to flatten the hierarchy, so as many optimizations that // can be done as possible should be before this.... @@ -234,19 +234,25 @@ static void process() { //--SCOPE BASED OPTIMIZATIONS-------------- - if (!v3Global.opt.xmlOnly()) { + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { // Cleanup V3Const::constifyAll(v3Global.rootp()); V3Dead::deadifyDTypesScoped(v3Global.rootp()); v3Global.checkTree(); + } + if (!v3Global.opt.xmlOnly()) { // Convert case statements to if() blocks. Must be after V3Unknown // Must be before V3Task so don't need to deal with task in case value compares V3Case::caseAll(v3Global.rootp()); + } + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { // Inline all tasks V3Task::taskAll(v3Global.rootp()); + } + if (!v3Global.opt.xmlOnly()) { // Add __PVT's // After V3Task so task internal variables will get renamed V3Name::nameAll(v3Global.rootp()); diff --git a/test_regress/t/t_xml_flat.out b/test_regress/t/t_xml_flat.out new file mode 100644 index 000000000..4ba3a085a --- /dev/null +++ b/test_regress/t/t_xml_flat.out @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test_regress/t/t_xml_flat.pl b/test_regress/t/t_xml_flat.pl new file mode 100755 index 000000000..f8062ce2d --- /dev/null +++ b/test_regress/t/t_xml_flat.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2012 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; + +top_filename("t/t_xml_first.v"); + +compile( + verilator_flags2 => ['--xml-only', '--flatten'], + verilator_make_gmake => 0, + make_top_shell => 0, + make_main => 0, + ); + +files_identical("$out_filename", $Self->{golden_filename}); + +ok(1); +1; From 6ab51de96d5d0295b90e228d2c8a5bc166289c35 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 21 Apr 2020 18:37:53 -0400 Subject: [PATCH 084/127] Fix dockerfile --- ci/docker/run/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/docker/run/Dockerfile b/ci/docker/run/Dockerfile index 83fb70a8e..e5e063a13 100644 --- a/ci/docker/run/Dockerfile +++ b/ci/docker/run/Dockerfile @@ -17,11 +17,11 @@ RUN apt-get update \ ca-certificates=20180409 \ ccache \ flex=2.6.4-6 \ - git=1:2.17.1-1ubuntu0.6 \ + git \ libfl-dev=2.6.4-6 \ libgoogle-perftools-dev \ - perl=5.26.1-6ubuntu0.3 \ - python3=3.6.7-1~18.04 \ + perl \ + python3 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* From c52f3349d1e473426115c35ba2edccaf02c4b55a Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 21 Apr 2020 23:49:07 +0100 Subject: [PATCH 085/127] Initial implementation of generic multithreaded tracing (#2269) The --trace-threads option can now be used to perform tracing on a thread separate from the main thread when using VCD tracing (with --trace-threads 1). For FST tracing --trace-threads can be 1 or 2, and --trace-fst --trace-threads 1 is the same a what --trace-fst-threads used to be (which is now deprecated). Performance numbers on SweRV EH1 CoreMark, clang 6.0.0, Intel i7-3770 @ 3.40GHz, IO to ramdisk, with numactl set to schedule threads on different physical cores. Relative speedup: --trace -> --trace --trace-threads 1 +22% --trace-fst -> --trace-fst --trace-threads 1 +38% (as --trace-fst-thread) --trace-fst -> --trace-fst --trace-threads 2 +93% Speed relative to --trace with no threaded tracing: --trace 1.00 x --trace --trace-threads 1 0.82 x --trace-fst 1.79 x --trace-fst --trace-threads 1 1.23 x --trace-fst --trace-threads 2 0.87 x This means FST tracing with 2 extra threads is now faster than single threaded VCD tracing, and is on par with threaded VCD tracing. You do pay for it in total compute though as --trace-fst --trace-threads 2 uses about 240% CPU vs 150% for --trace-fst --trace-threads 1, and 155% for --trace --trace threads 1. Still for interactive use it should be helpful with large designs. --- Changes | 2 + bin/verilator | 50 +++- include/verilated.mk.in | 16 +- include/verilated_fst_c.cpp | 17 +- include/verilated_fst_c.h | 8 +- include/verilated_trace.h | 197 +++++++++++- include/verilated_trace_imp.cpp | 281 +++++++++++++++++- include/verilated_vcd_c.cpp | 6 + include/verilated_vcd_c.h | 2 +- src/V3EmitC.cpp | 4 +- src/V3EmitMk.cpp | 21 +- src/V3Options.cpp | 14 +- src/V3Options.h | 11 +- test_regress/driver.pl | 6 +- test_regress/t/t_trace_array_fst_threads_1.pl | 27 ++ test_regress/t/t_trace_array_fst_threads_2.pl | 27 ++ test_regress/t/t_trace_array_threads_1.pl | 26 ++ ...ad.pl => t_trace_complex_fst_threads_1.pl} | 2 +- .../t/t_trace_complex_fst_threads_2.pl | 27 ++ test_regress/t/t_trace_complex_old_api.pl | 2 +- test_regress/t/t_trace_complex_threads_1.pl | 37 +++ test_regress/t/t_trace_two_dumpfst_cc.pl | 4 +- test_regress/t/t_trace_two_hdrfst_cc.pl | 4 +- test_regress/t/t_trace_two_portfst_cc.pl | 4 +- test_regress/t/t_verilated_all.pl | 2 + 25 files changed, 735 insertions(+), 62 deletions(-) create mode 100755 test_regress/t/t_trace_array_fst_threads_1.pl create mode 100755 test_regress/t/t_trace_array_fst_threads_2.pl create mode 100755 test_regress/t/t_trace_array_threads_1.pl rename test_regress/t/{t_trace_complex_fst_thread.pl => t_trace_complex_fst_threads_1.pl} (91%) create mode 100755 test_regress/t/t_trace_complex_fst_threads_2.pl create mode 100755 test_regress/t/t_trace_complex_threads_1.pl diff --git a/Changes b/Changes index cefd3e574..483d49ecd 100644 --- a/Changes +++ b/Changes @@ -20,6 +20,8 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Fix DPI import/export to be standard compliant, #2236. [Geza Lore] +** Add --trace-threads for general multithreaded tracing, #2269. [Geza Lore] + *** Add --flatten for use with --xml-only, #2270. [James Hanlon] **** Support $ferror, and $fflush without arguments, #1638. diff --git a/bin/verilator b/bin/verilator index 3fa55b771..7d0b2c5c0 100755 --- a/bin/verilator +++ b/bin/verilator @@ -377,14 +377,14 @@ detailed descriptions in L for more information. --timescale-override Overrides all timescales --top-module Name of top level input module --trace Enable waveform creation - --trace-depth Depth of tracing --trace-coverage Enable tracing of coverage + --trace-depth Depth of tracing --trace-fst Enable FST waveform creation - --trace-fst-thread Enable FST threaded waveform creation --trace-max-array Maximum bit width for tracing --trace-max-width Maximum array depth for tracing --trace-params Enable tracing of parameters --trace-structs Enable tracing structure names + --trace-threads Enable waveform creation on separate threads --trace-underscore Enable tracing of _signals -U Undefine preprocessor define --unroll-count Tune maximum loop iterations @@ -1477,6 +1477,8 @@ need to add these to your Makefile manually. Having tracing compiled in may result in some small performance losses, even when waveforms are not turned on during model execution. +See also C<--trace-threads>. + =item --trace-coverage With --trace and --coverage-*, enable tracing to include a traced signal @@ -1498,14 +1500,8 @@ improve simulation runtime and trace file size. =item --trace-fst -Enable FST waveform tracing in the model. This overrides C<--trace> and -C<--trace-fst-thread>. See also C<--trace-fst-thread>. - -=item --trace-fst-thread - -Enable FST waveform tracing in the model, using a separate thread. This is -typically faster in simulation runtime but slower in total computes than -C<--trace-fst>. This overrides C<--trace> and C<--trace-fst>. +Enable FST waveform tracing in the model. This overrides C<--trace>. +See also C<--trace-threads>. =item --trace-max-array I @@ -1530,6 +1526,15 @@ array fields, rather than a single combined packed bus. Due to VCD file format constraints this may result in significantly slower trace times and larger trace files. +=item --trace-threads I + +Enable waveform tracing using separate threads. This is typically faster in +simulation runtime but uses more total compute. This option is independend of, +and works with, both C<--trace> and C<--trace-fst>. Different trace formats can +take advantage of more trace threads to varying degrees. Currently VCD tracing +can utilize at most --trace-threads 1, and FST tracing can utilize at most +--trace-threads 2. This overrides C<--no-threads>. + =item --trace-underscore Enable tracing of signals that start with an underscore. Normally, these @@ -2773,7 +2778,7 @@ performance. With --threads 1, the generated model is single threaded, however the support libraries are multithread safe. This allows different instantiations of model(s) to potentially each be run under a different -thread. All threading is the responsibility of the user's C++ testbench. +thread. All threading is the responsibility of the user's C++ testbench. With --threads N, where N is at least 2, the generated model will be designed to run in parallel on N threads. The thread calling eval() @@ -2784,9 +2789,6 @@ Verilated model should not livelock nor deadlock, however, you can expect performance to be far worse than it would be with proper ratio of threads and CPU cores. -With --trace-fst-thread, tracing occurs in a separate thread from the main -simulation thread(s). This option is orthogonal to --threads. - The remainder of this section describe behavior with --threads 1 or --threads N (not --no-threads). @@ -2800,12 +2802,28 @@ be done by a "main thread". In most cases the eval thread and main thread are the same thread (i.e. the user's top C++ testbench runs on a single thread), but this is not required. +The --trace-threads options can be used to produce trace dumps using multiple +threads. If --trace-threads is set without --threads, then --trace-threads will +imply --threads 1, i.e.: the support libraries will be thread safe. + +With --trace-threads 0, trace dumps are produced on the main thread. This again +gives the highest single thread performance. + +With --trace-threads N, where N is at least 1, N additional threads will be +created and managed by the trace files (e.g.: VerilatedVcdC or VerilatedFstC), +to generate the trace dump. The main thread will be released to proceed with +execution as soon as possible, though some blocking of the main thread is still +necessary while capturing the trace. Different trace formats can utilize a +various number of threads. See the --trace-threads option. + When running a multithreaded model, the default Linux task scheduler often works against the model, by assuming threads are short lived, and thus often schedules threads using multiple hyperthreads within the same physical core. For best performance use the C program to (when the -threading count fits) select unique physical cores on the same socket. For -example, if a model was Verilated with "--threads 4", we consult +threading count fits) select unique physical cores on the same socket. The +same applies for --trace-threads as well. + +As an example, if a model was Verilated with "--threads 4", we consult egrep 'processor|physical id|core id' /proc/cpuinfo diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 833d185c1..1966bf956 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -129,14 +129,26 @@ ifneq ($(VM_THREADS),0) endif endif -ifneq ($(VM_TRACE_THREADED),0) - ifneq ($(VM_TRACE_THREADED),) +ifneq ($(VM_TRACE_THREADS),0) + ifneq ($(VM_TRACE_THREADS),) + ifeq ($(findstring -DVL_THREADED,$(CPPFLAGS)),) + $(error VM_TRACE_THREADS requires VM_THREADS) + endif CPPFLAGS += -DVL_TRACE_THREADED VK_C11=1 VK_LIBS_THREADED=1 endif endif + +ifneq ($(VM_TRACE_FST_WRITER_THREAD),0) + ifneq ($(VM_TRACE_FST_WRITER_THREAD),) + CPPFLAGS += -DVL_TRACE_FST_WRITER_THREAD + VK_C11=1 + VK_LIBS_THREADED=1 + endif +endif + ifneq ($(VK_C11),0) ifneq ($(VK_C11),) # Need C++11 at least, so always default to newest diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index a128639ca..1e1d44434 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -24,7 +24,7 @@ #include "verilated_fst_c.h" // GTKWave configuration -#ifdef VL_TRACE_THREADED +#ifdef VL_TRACE_FST_WRITER_THREAD # define HAVE_LIBPTHREAD # define FST_WRITER_PARALLEL #endif @@ -76,9 +76,10 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { m_fst = fstWriterCreate(filename, 1); fstWriterSetPackType(m_fst, FST_WR_PT_LZ4); fstWriterSetTimescaleFromString(m_fst, timeResStr().c_str()); // lintok-begin-on-ref -#ifdef VL_TRACE_THREADED +#ifdef VL_TRACE_FST_WRITER_THREAD fstWriterSetParallelMode(m_fst, 1); #endif + m_curScope.clear(); VerilatedTrace::traceInit(); @@ -101,6 +102,18 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { m_code2symbol.clear(); } +void VerilatedFst::close() { + m_assertOne.check(); + VerilatedTrace::close(); + fstWriterClose(m_fst); + m_fst = NULL; +} + +void VerilatedFst::flush() { + VerilatedTrace::flush(); + fstWriterFlushContext(m_fst); +} + void VerilatedFst::emitTimeChange(vluint64_t timeui) { fstWriterEmitTimeChange(m_fst, timeui); } //============================================================================= diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 9a8c7eb0e..8572a0f5f 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -85,13 +85,9 @@ public: /// Open the file; call isOpen() to see if errors void open(const char* filename) VL_MT_UNSAFE; /// Close the file - void close() VL_MT_UNSAFE { - m_assertOne.check(); - fstWriterClose(m_fst); - m_fst = NULL; - } + void close() VL_MT_UNSAFE; /// Flush any remaining data to this file - void flush() VL_MT_UNSAFE { fstWriterFlushContext(m_fst); } + void flush() VL_MT_UNSAFE; /// Is file open? bool isOpen() const { return m_fst != NULL; } diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 8be887734..a611a436c 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -20,11 +20,99 @@ #ifndef _VERILATED_TRACE_H_ #define _VERILATED_TRACE_H_ 1 +// clang-format off + #include "verilated.h" #include #include +#ifdef VL_TRACE_THREADED +# include +# include +# include +#endif + +// clang-format on + +#ifdef VL_TRACE_THREADED +//============================================================================= +// Threaded tracing + +// A simple synchronized first in first out queue +template class VerilatedThreadQueue { +private: + VerilatedMutex m_mutex; // Protects m_queue + std::condition_variable_any m_cv; + std::deque m_queue VL_GUARDED_BY(m_mutex); + +public: + // Put an element at the back of the queue + void put(T value) { + VerilatedLockGuard lock(m_mutex); + m_queue.push_back(value); + m_cv.notify_one(); + } + + // Put an element at the front of the queue + void put_front(T value) { + VerilatedLockGuard lock(m_mutex); + m_queue.push_front(value); + m_cv.notify_one(); + } + + // Get an element from the front of the queue. Blocks if none available + T get() { + VerilatedLockGuard lock(m_mutex); + m_cv.wait(lock, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); }); + assert(!m_queue.empty()); + T value = m_queue.front(); + m_queue.pop_front(); + return value; + } + + // Non blocking get + bool tryGet(T& result) { + VerilatedLockGuard lockGuard(m_mutex); + if (m_queue.empty()) { return false; } + result = m_queue.front(); + m_queue.pop_front(); + return true; + } +}; + +// Commands used by thread tracing. Note that the bottom 8 bits of all these +// values are empty and are used to store small amounts of additional command +// parameters. Anonymous enum in class, as we want it scoped, but we also +// want the automatic conversion to integer types. +class VerilatedTraceCommand { +public: + enum { + CHG_BIT = 0x0000, + CHG_BUS = 0x0100, + CHG_QUAD = 0x0200, + CHG_ARRAY = 0x0300, + CHG_FLOAT = 0x0400, + CHG_DOUBLE = 0x0500, + TIME_CHANGE = 0x8000, + END = 0xf000, // End of buffer + SHUTDOWN = 0xf200 // Shutdown worker thread, also marks end of buffer + }; +}; + +typedef union { + vluint32_t cmd; // Command code + params in bottom 8 bits + vluint32_t* oldp; // Pointer to previous value buffer to consult/update + // Note: These are 64-bit wide, as this union already has a pointer type in it. + vluint64_t params; // Command parameter + // New signal value in various forms + vluint64_t newBits; + float newFloat; + double newDouble; + vluint64_t timeui; +} VerilatedTraceEntry; +#endif + class VerilatedTraceCallInfo; //============================================================================= @@ -43,6 +131,7 @@ private: std::vector m_callbacks; ///< Routines to perform dumping bool m_fullDump; ///< Whether a full dump is required on the next call to 'dump' vluint32_t m_nextCode; ///< Next code number to assign + vluint32_t m_numSignals; ///< Number of distinct signals std::string m_moduleName; ///< Name of module being trace initialized now char m_scopeEscape; double m_timeRes; ///< Time resolution (ns/ms etc) @@ -52,6 +141,40 @@ private: // to access duck-typed functions to avoid a virtual function call. T_Derived* self() { return static_cast(this); } +#ifdef VL_TRACE_THREADED + // Number of total trace buffers that have been allocated + vluint32_t m_numTraceBuffers; + + // Size of trace buffers + size_t m_traceBufferSize; + + // Buffers handed to worker for processing + VerilatedThreadQueue m_buffersToWorker; + // Buffers returned from worker after processing + VerilatedThreadQueue m_buffersFromWorker; + + // Get a new trace buffer that can be populated. May block if none available + VerilatedTraceEntry* getTraceBuffer(); + + // Write pointer into current buffer + VerilatedTraceEntry* m_traceBufferWritep; + + // End of trace buffer + VerilatedTraceEntry* m_traceBufferEndp; + + // The worker thread itself + std::unique_ptr m_workerThread; + + // The function executed by the worker thread + void workerThreadMain(); + + // Wait until given buffer is placed in m_buffersFromWorker + void waitForBuffer(const VerilatedTraceEntry* bufferp); + + // Shut down and join worker, if it's running, otherwise do nothing + void shutdownWorker(); +#endif + // CONSTRUCTORS VL_UNCOPYABLE(VerilatedTrace); @@ -62,6 +185,7 @@ protected: VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread vluint32_t nextCode() const { return m_nextCode; } + vluint32_t numSignals() const { return m_numSignals; } const std::string& moduleName() const { return m_moduleName; } void fullDump(bool value) { m_fullDump = value; } vluint64_t timeLastDump() { return m_timeLastDump; } @@ -80,6 +204,9 @@ protected: /// Character that splits scopes. Note whitespace are ALWAYS escapes. char scopeEscape() { return m_scopeEscape; } + void close(); + void flush(); + //========================================================================= // Virtual functions to be provided by the format specific implementation @@ -151,20 +278,76 @@ public: void fullFloat(vluint32_t* oldp, float newval); void fullDouble(vluint32_t* oldp, double newval); - // Check previous dumped value of signal. If changed, then emit trace entry +#ifdef VL_TRACE_THREADED + // Threaded tracing. Just dump everything in the trace buffer inline void chgBit(vluint32_t* oldp, vluint32_t newval) { + m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_BIT | newval; + m_traceBufferWritep[1].oldp = oldp; + m_traceBufferWritep += 2; + VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + } + template inline void chgBus(vluint32_t* oldp, vluint32_t newval) { + m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_BUS | T_Bits; + m_traceBufferWritep[1].oldp = oldp; + m_traceBufferWritep[2].newBits = newval; + m_traceBufferWritep += 3; + VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + } + inline void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_QUAD | bits; + m_traceBufferWritep[1].oldp = oldp; + m_traceBufferWritep[2].newBits = newval; + m_traceBufferWritep += 3; + VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + } + inline void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_ARRAY; + m_traceBufferWritep[1].oldp = oldp; + m_traceBufferWritep[2].params = bits; + m_traceBufferWritep += 3; + vluint32_t* const wp = reinterpret_cast(m_traceBufferWritep); + for (int i = 0; i < (bits + 31) / 32; ++i) { wp[i] = newvalp[i]; } + m_traceBufferWritep += (bits + 63) / 64; + VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + } + inline void chgFloat(vluint32_t* oldp, float newval) { + m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_FLOAT; + m_traceBufferWritep[1].oldp = oldp; + m_traceBufferWritep[2].newFloat = newval; + m_traceBufferWritep += 3; + VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + } + inline void chgDouble(vluint32_t* oldp, double newval) { + m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_DOUBLE; + m_traceBufferWritep[1].oldp = oldp; + m_traceBufferWritep[2].newDouble = newval; + m_traceBufferWritep += 3; + VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + } + +#define CHG(name) chg##name##Impl +#else +#define CHG(name) chg##name +#endif + + // In non-threaded mode, these are called directly by the trace callbacks, + // and are called chg*. In threaded mode, they are called by the worker + // thread and are called chg*Impl + + // Check previous dumped value of signal. If changed, then emit trace entry + inline void CHG(Bit)(vluint32_t* oldp, vluint32_t newval) { const vluint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullBit(oldp, newval); } - template inline void chgBus(vluint32_t* oldp, vluint32_t newval) { + template inline void CHG(Bus)(vluint32_t* oldp, vluint32_t newval) { const vluint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullBus(oldp, newval); } - inline void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + inline void CHG(Quad)(vluint32_t* oldp, vluint64_t newval, int bits) { const vluint64_t diff = *reinterpret_cast(oldp) ^ newval; if (VL_UNLIKELY(diff)) fullQuad(oldp, newval, bits); } - inline void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + inline void CHG(Array)(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { for (int i = 0; i < (bits + 31) / 32; ++i) { if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) { fullArray(oldp, newvalp, bits); @@ -172,13 +355,15 @@ public: } } } - inline void chgFloat(vluint32_t* oldp, float newval) { + inline void CHG(Float)(vluint32_t* oldp, float newval) { // cppcheck-suppress invalidPointerCast if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullFloat(oldp, newval); } - inline void chgDouble(vluint32_t* oldp, double newval) { + inline void CHG(Double)(vluint32_t* oldp, double newval) { // cppcheck-suppress invalidPointerCast if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullDouble(oldp, newval); } + +#undef CHG }; #endif // guard diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp index 537b687dd..b5b6fc924 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.cpp @@ -25,6 +25,13 @@ #include "verilated_trace.h" +#if 0 +# include +# define VL_TRACE_THREAD_DEBUG(msg) std::cout << "TRACE THREAD: " << msg << std::endl +#else +# define VL_TRACE_THREAD_DEBUG(msg) +#endif + // clang-format on //============================================================================= @@ -90,6 +97,213 @@ public: // This is in .cpp file so is not widely visible ~VerilatedTraceCallInfo() {} }; +#ifdef VL_TRACE_THREADED +//========================================================================= +// Buffer management + +template <> VerilatedTraceEntry* VerilatedTrace::getTraceBuffer() { + VerilatedTraceEntry* bufferp; + // Some jitter is expected, so some number of alternative trace buffers are + // required, but don't allocate more than 8 buffers. + if (m_numTraceBuffers < 8) { + // Allocate a new buffer if none is available + if (!m_buffersFromWorker.tryGet(bufferp)) { + ++m_numTraceBuffers; + // Note: over allocate a bit so pointer comparison is well defined + // if we overflow only by a small amount + bufferp = new VerilatedTraceEntry[m_traceBufferSize + 16]; + } + } else { + // Block until a buffer becomes available + bufferp = m_buffersFromWorker.get(); + } + return bufferp; +} + +template <> void VerilatedTrace::waitForBuffer(const VerilatedTraceEntry* buffp) { + // Slow path code only called on flush/shutdown, so use a simple algorithm. + // Collect buffers from worker and stash them until we get the one we want. + std::deque stash; + do { stash.push_back(m_buffersFromWorker.get()); } while (stash.back() != buffp); + // Now put them back in the queue, in the original order. + while (!stash.empty()) { + m_buffersFromWorker.put_front(stash.back()); + stash.pop_back(); + } +} + +//========================================================================= +// Worker thread + +template <> void VerilatedTrace::workerThreadMain() { + while (true) { + VerilatedTraceEntry* const bufferp = m_buffersToWorker.get(); + + VL_TRACE_THREAD_DEBUG(""); + VL_TRACE_THREAD_DEBUG("Got buffer"); + + const VerilatedTraceEntry* readp = bufferp; + + vluint32_t cmd; + unsigned bits; + vluint32_t* oldp; + vluint64_t newBits; + + while (true) { + cmd = (readp++)->cmd; + + switch (cmd & ~0xFFU) { + //=== + // CHG_* commands + case VerilatedTraceCommand::CHG_BIT: + VL_TRACE_THREAD_DEBUG("Command CHG_BIT"); + chgBitImpl((readp++)->oldp, cmd & 1); + continue; + case VerilatedTraceCommand::CHG_BUS: + VL_TRACE_THREAD_DEBUG("Command CHG_BUS"); + + oldp = (readp++)->oldp; + newBits = (readp++)->newBits; + + // Bits stored in bottom byte of command + switch (cmd & 0xFFU) { + case 2: chgBusImpl<2>(oldp, newBits); continue; + case 3: chgBusImpl<3>(oldp, newBits); continue; + case 4: chgBusImpl<4>(oldp, newBits); continue; + case 5: chgBusImpl<5>(oldp, newBits); continue; + case 6: chgBusImpl<6>(oldp, newBits); continue; + case 7: chgBusImpl<7>(oldp, newBits); continue; + case 8: chgBusImpl<8>(oldp, newBits); continue; + case 9: chgBusImpl<9>(oldp, newBits); continue; + case 10: chgBusImpl<10>(oldp, newBits); continue; + case 11: chgBusImpl<11>(oldp, newBits); continue; + case 12: chgBusImpl<12>(oldp, newBits); continue; + case 13: chgBusImpl<13>(oldp, newBits); continue; + case 14: chgBusImpl<14>(oldp, newBits); continue; + case 15: chgBusImpl<15>(oldp, newBits); continue; + case 16: chgBusImpl<16>(oldp, newBits); continue; + case 17: chgBusImpl<17>(oldp, newBits); continue; + case 18: chgBusImpl<18>(oldp, newBits); continue; + case 19: chgBusImpl<19>(oldp, newBits); continue; + case 20: chgBusImpl<20>(oldp, newBits); continue; + case 21: chgBusImpl<21>(oldp, newBits); continue; + case 22: chgBusImpl<22>(oldp, newBits); continue; + case 23: chgBusImpl<23>(oldp, newBits); continue; + case 24: chgBusImpl<24>(oldp, newBits); continue; + case 25: chgBusImpl<25>(oldp, newBits); continue; + case 26: chgBusImpl<26>(oldp, newBits); continue; + case 27: chgBusImpl<27>(oldp, newBits); continue; + case 28: chgBusImpl<28>(oldp, newBits); continue; + case 29: chgBusImpl<29>(oldp, newBits); continue; + case 30: chgBusImpl<30>(oldp, newBits); continue; + case 31: chgBusImpl<31>(oldp, newBits); continue; + case 32: chgBusImpl<32>(oldp, newBits); continue; + } + VL_FATAL_MT(__FILE__, __LINE__, "", "Bad number of bits in CHG_BUS command"); + break; + case VerilatedTraceCommand::CHG_QUAD: + VL_TRACE_THREAD_DEBUG("Command CHG_QUAD"); + // Bits stored in bottom byte of command + chgQuadImpl(readp[0].oldp, readp[1].newBits, cmd & 0xFF); + readp += 2; + continue; + case VerilatedTraceCommand::CHG_ARRAY: + VL_TRACE_THREAD_DEBUG("Command CHG_CHG_ARRAY"); + oldp = (readp++)->oldp; + bits = (readp++)->params; + chgArrayImpl(oldp, reinterpret_cast(readp), bits); + readp += (bits + 63) / 64; + continue; + case VerilatedTraceCommand::CHG_FLOAT: + VL_TRACE_THREAD_DEBUG("Command CHG_FLOAT"); + chgFloatImpl(readp[0].oldp, readp[1].newFloat); + readp += 2; + continue; + case VerilatedTraceCommand::CHG_DOUBLE: + VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE"); + chgDoubleImpl(readp[0].oldp, readp[1].newDouble); + readp += 2; + continue; + + //=== + // Rare commands + case VerilatedTraceCommand::TIME_CHANGE: + VL_TRACE_THREAD_DEBUG("Command TIME_CHANGE"); + emitTimeChange((readp++)->timeui); + continue; + + //=== + // Commands ending this buffer + case VerilatedTraceCommand::END: VL_TRACE_THREAD_DEBUG("Command END"); break; + case VerilatedTraceCommand::SHUTDOWN: + VL_TRACE_THREAD_DEBUG("Command SHUTDOWN"); + break; + + //=== + // Unknown command + default: + VL_PRINTF_MT("Trace command: 0x%08x\n", cmd); + VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command"); + break; + } + + // The above switch will execute 'continue' when necessary, + // so if we ever reach here, we are done with the buffer. + break; + } + + VL_TRACE_THREAD_DEBUG("Returning buffer"); + + // Return buffer + m_buffersFromWorker.put(bufferp); + + // Shut down if required + if (VL_UNLIKELY(cmd == VerilatedTraceCommand::SHUTDOWN)) return; + } +} + +template <> void VerilatedTrace::shutdownWorker() { + // If the worker thread is not running, done.. + if (!m_workerThread) return; + + // Hand an buffer with a shutdown command to the worker thread + VerilatedTraceEntry* const bufferp = getTraceBuffer(); + bufferp[0].cmd = VerilatedTraceCommand::SHUTDOWN; + m_buffersToWorker.put(bufferp); + // Wait for it to return + waitForBuffer(bufferp); + // Join the thread and delete it + m_workerThread->join(); + m_workerThread.reset(nullptr); +} + +#endif + +//============================================================================= +// Life cycle + +template <> void VerilatedTrace::close() { +#ifdef VL_TRACE_THREADED + shutdownWorker(); + while (m_numTraceBuffers) { + delete[] m_buffersFromWorker.get(); + m_numTraceBuffers--; + } +#endif +} + +template <> void VerilatedTrace::flush() { +#ifdef VL_TRACE_THREADED + // Hand an empty buffer to the worker thread + VerilatedTraceEntry* const bufferp = getTraceBuffer(); + bufferp[0].cmd = VerilatedTraceCommand::END; + m_buffersToWorker.put(bufferp); + // Wait for it to be returned. As the processing is in-order, + // this ensures all previous buffers have been processed. + waitForBuffer(bufferp); +#endif +} + //============================================================================= // VerilatedTrace @@ -99,9 +313,14 @@ VerilatedTrace::VerilatedTrace() , m_timeLastDump(0) , m_fullDump(true) , m_nextCode(0) + , m_numSignals(0) , m_scopeEscape('.') , m_timeRes(1e-9) - , m_timeUnit(1e-9) { + , m_timeUnit(1e-9) +#ifdef VL_TRACE_THREADED + , m_numTraceBuffers(0) +#endif +{ set_time_unit(Verilated::timeunitString()); set_time_resolution(Verilated::timeprecisionString()); } @@ -112,6 +331,9 @@ template <> VerilatedTrace::~VerilatedTrace() { delete m_callbacks.back(); m_callbacks.pop_back(); } +#ifdef VL_TRACE_THREADED + close(); +#endif } //========================================================================= @@ -125,6 +347,7 @@ template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { // of codes on re-open const vluint32_t expectedCodes = nextCode(); m_nextCode = 1; + m_numSignals = 0; // Call all initialize callbacks, which will call decl* for each signal. for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { @@ -141,6 +364,18 @@ template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { // Now that we know the number of codes, allocate space for the buffer // holding previous signal values. if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()]; + +#ifdef VL_TRACE_THREADED + // Compute trace buffer size. we need to be able to store a new value for + // each signal, which is 'nextCode()' entries after the init callbacks + // above have been run, plus up to 3 more words of metadata per signal, + // plus fixed overhead of 1 for a termination flag and 2 for a time stamp + // update. + m_traceBufferSize = nextCode() + numSignals() * 3 + 3; + + // Start the worker thread + m_workerThread.reset(new std::thread(&VerilatedTrace::workerThreadMain, this)); +#endif } template <> @@ -153,6 +388,7 @@ void VerilatedTrace::declCode(vluint32_t code, vluint32_t bits, bo int codesNeeded = (bits + 31) / 32; if (tri) codesNeeded *= 2; m_nextCode = std::max(m_nextCode, code + codesNeeded); + ++m_numSignals; } //========================================================================= @@ -194,23 +430,60 @@ template <> void VerilatedTrace::dump(vluint64_t timeui) { return; } m_timeLastDump = timeui; + Verilated::quiesce(); + + // Call hook for format specific behaviour if (VL_UNLIKELY(m_fullDump)) { if (!preFullDump()) return; + } else { + if (!preChangeDump()) return; + } + +#ifdef VL_TRACE_THREADED + // Get the trace buffer we are about to fill + VerilatedTraceEntry* const bufferp = getTraceBuffer(); + m_traceBufferWritep = bufferp; + m_traceBufferEndp = bufferp + m_traceBufferSize; + + // Currently only incremental dumps run on the worker thread + if (VL_LIKELY(!m_fullDump)) { + // Tell worker to update time point + (m_traceBufferWritep++)->cmd = VerilatedTraceCommand::TIME_CHANGE; + (m_traceBufferWritep++)->timeui = timeui; + } else { + // Update time point emitTimeChange(timeui); + } +#else + // Update time point + emitTimeChange(timeui); +#endif + + // Run the callbacks + if (VL_UNLIKELY(m_fullDump)) { m_fullDump = false; // No more need for next dump to be full - for (vluint32_t ent = 0; ent < m_callbacks.size(); ent++) { + for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { VerilatedTraceCallInfo* cip = m_callbacks[ent]; (cip->m_fullcb)(self(), cip->m_userthis, cip->m_code); } } else { - if (!preChangeDump()) return; - emitTimeChange(timeui); for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { VerilatedTraceCallInfo* cip = m_callbacks[ent]; (cip->m_changecb)(self(), cip->m_userthis, cip->m_code); } } + +#ifdef VL_TRACE_THREADED + // Mark end of the trace buffer we just filled + (m_traceBufferWritep++)->cmd = VerilatedTraceCommand::END; + + // Assert no buffer overflow + assert(m_traceBufferWritep - bufferp <= m_traceBufferSize); + + // Pass it to the worker thread + m_buffersToWorker.put(bufferp); +#endif } //============================================================================= diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index af8bb2a15..c5ad6f7bb 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -294,6 +294,7 @@ void VerilatedVcd::close() { // This function is on the flush() call path m_assertOne.check(); if (!isOpen()) return; + VerilatedTrace::close(); if (m_evcd) { printStr("$vcdclose "); printQuad(timeLastDump()); @@ -302,6 +303,11 @@ void VerilatedVcd::close() { closePrev(); } +void VerilatedVcd::flush() { + VerilatedTrace::flush(); + bufferFlush(); +} + void VerilatedVcd::printStr(const char* str) { // Not fast... while (*str) { diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 0ee8084c8..e9838c15b 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -149,7 +149,7 @@ public: /// Close the file void close() VL_MT_UNSAFE_ONE; /// Flush any remaining data to this file - void flush() VL_MT_UNSAFE_ONE { bufferFlush(); } + void flush() VL_MT_UNSAFE_ONE; /// Is file open? bool isOpen() const { return m_isOpen; } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index c39c8ecd6..89053334c 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3427,7 +3427,7 @@ class EmitCTrace : EmitCStmts { putsQuoted(VIdProtect::protectWordsIf(nodep->showname(), nodep->protect())); if (nodep->isScoped()) puts(",\" \")"); // Direction - if (v3Global.opt.traceFormat().fstFlavor()) { + if (v3Global.opt.traceFormat().fst()) { puts("," + cvtToStr(enumNum)); // fstVarDir if (nodep->declDirection().isInoutish()) { @@ -3503,7 +3503,7 @@ class EmitCTrace : EmitCStmts { int emitTraceDeclDType(AstNodeDType* nodep) { // Return enum number or -1 for none - if (v3Global.opt.traceFormat().fstFlavor()) { + if (v3Global.opt.traceFormat().fst()) { // Skip over refs-to-refs, but stop before final ref so can get data type name // Alternatively back in V3Width we could push enum names from upper typedefs if (AstEnumDType* enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) { diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index cb4443037..a2710f70a 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -46,8 +46,11 @@ public: of.puts("# See " + v3Global.opt.prefix() + ".mk" + " for the caller.\n"); of.puts("\n### Switches...\n"); - of.puts("# C11 constructs required? 0/1 (from --threads or use of classes)\n"); - of.puts("VM_C11 = " + cvtToStr(v3Global.needC11() || v3Global.opt.threads()) + "\n"); + of.puts("# C11 constructs required? 0/1 (from --threads, " + "--trace-threads or use of classes)\n"); + of.puts("VM_C11 = "); + of.puts(v3Global.needC11() || v3Global.opt.threads() ? "1" : "0"); + of.puts("\n"); of.puts("# Coverage output mode? 0/1 (from --coverage)\n"); of.puts("VM_COVERAGE = "); of.puts(v3Global.opt.coverage() ? "1" : "0"); @@ -60,13 +63,19 @@ public: of.puts("VM_THREADS = "); of.puts(cvtToStr(v3Global.opt.threads())); of.puts("\n"); - of.puts("# Tracing output mode? 0/1 (from --trace)\n"); + of.puts("# Tracing output mode? 0/1 (from --trace/--trace-fst)\n"); of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace() ? "1" : "0"); of.puts("\n"); - of.puts("# Tracing threaded output mode? 0/1 (from --trace-fst-thread)\n"); - of.puts("VM_TRACE_THREADED = "); - of.puts(v3Global.opt.traceFormat().threaded() ? "1" : "0"); + of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n"); + of.puts("VM_TRACE_THREADS = "); + of.puts(!v3Global.opt.traceThreads() + ? "0" + : cvtToStr(v3Global.opt.traceThreads() - v3Global.opt.traceFormat().fst())); + of.puts("\n"); + of.puts("# Separate FST writer thread? 0/1 (from --trace-fst with --trace-thread > 0)\n"); + of.puts("VM_TRACE_FST_WRITER_THREAD = "); + of.puts(v3Global.opt.traceThreads() && v3Global.opt.traceFormat().fst() ? "1" : "0"); of.puts("\n"); of.puts("\n### Object file lists...\n"); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 1f0b30f15..c836bffc6 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -631,6 +631,9 @@ void V3Options::notify() { && !v3Global.opt.preprocOnly() // && !v3Global.opt.xmlOnly()); } + + // --trace-threads implies --threads 1 unless explicitly specified + if (traceThreads() && !threads()) { m_threads = 1; } } //###################################################################### @@ -1062,8 +1065,16 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char addLdLibs("-lz"); } else if (!strcmp(sw, "-trace-fst-thread")) { m_trace = true; - m_traceFormat = TraceFormat::FST_THREAD; + m_traceFormat = TraceFormat::FST; addLdLibs("-lz"); + fl->v3warn(DEPRECATED, "Option --trace-fst-thread is deprecated. " + "Use --trace-fst with --trace-threads > 0."); + if (m_traceThreads == 0) m_traceThreads = 1; + } else if (!strcmp(sw, "-trace-threads")) { + shift; + m_trace = true; + m_traceThreads = atoi(argv[i]); + if (m_traceThreads < 0) fl->v3fatal("--trace-threads must be >= 0: " << argv[i]); } else if (!strcmp(sw, "-trace-depth") && (i + 1) < argc) { shift; m_traceDepth = atoi(argv[i]); @@ -1568,6 +1579,7 @@ V3Options::V3Options() { m_traceParams = true; m_traceStructs = false; m_traceUnderscore = false; + m_traceThreads = 0; m_underlineZero = false; m_verilate = true; m_vpi = false; diff --git a/src/V3Options.h b/src/V3Options.h index d8d233112..2e48eda40 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -150,21 +150,20 @@ inline std::ostream& operator<<(std::ostream& os, const VTimescale& rhs) { class TraceFormat { public: - enum en { VCD = 0, FST, FST_THREAD } m_e; + enum en { VCD = 0, FST } m_e; // cppcheck-suppress noExplicitConstructor inline TraceFormat(en _e = VCD) : m_e(_e) {} explicit inline TraceFormat(int _e) : m_e(static_cast(_e)) {} operator en() const { return m_e; } - bool fstFlavor() const { return m_e == FST || m_e == FST_THREAD; } - bool threaded() const { return m_e == FST_THREAD; } + bool fst() const { return m_e == FST; } string classBase() const { - static const char* const names[] = {"VerilatedVcd", "VerilatedFst", "VerilatedFst"}; + static const char* const names[] = {"VerilatedVcd", "VerilatedFst"}; return names[m_e]; } string sourceName() const { - static const char* const names[] = {"verilated_vcd", "verilated_fst", "verilated_fst"}; + static const char* const names[] = {"verilated_vcd", "verilated_fst"}; return names[m_e]; } }; @@ -295,6 +294,7 @@ private: TraceFormat m_traceFormat; // main switch: --trace or --trace-fst int m_traceMaxArray;// main switch: --trace-max-array int m_traceMaxWidth;// main switch: --trace-max-width + int m_traceThreads; // main switch: --trace-threads int m_unrollCount; // main switch: --unroll-count int m_unrollStmts; // main switch: --unroll-stmts @@ -487,6 +487,7 @@ public: TraceFormat traceFormat() const { return m_traceFormat; } int traceMaxArray() const { return m_traceMaxArray; } int traceMaxWidth() const { return m_traceMaxWidth; } + int traceThreads() const { return m_traceThreads; } int unrollCount() const { return m_unrollCount; } int unrollStmts() const { return m_unrollStmts; } diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 65bb340f5..d523aac45 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -833,8 +833,7 @@ sub compile_vlt_flags { @{$param{verilator_flags3}}); $self->{sc} = 1 if ($checkflags =~ /-sc\b/); $self->{trace} = ($opt_trace || $checkflags =~ /-trace\b/ - || $checkflags =~ /-trace-fst\b/ - || $checkflags =~ /-trace-fst-thread\b/); + || $checkflags =~ /-trace-fst\b/); $self->{trace_format} = (($checkflags =~ /-trace-fst/ && 'fst-c') || ($self->{sc} && 'vcd-sc') || (!$self->{sc} && 'vcd-c')); @@ -849,7 +848,8 @@ sub compile_vlt_flags { unshift @verilator_flags, "--trace" if $opt_trace; my $threads = ::calc_threads($Vltmt_threads); unshift @verilator_flags, "--threads $threads" if $param{vltmt} && $checkflags !~ /-threads /; - unshift @verilator_flags, "--trace-fst-thread" if $param{vltmt} && $checkflags =~ /-trace-fst/; + unshift @verilator_flags, "--trace-threads 1" if $param{vltmt} && $checkflags =~ /-trace /; + unshift @verilator_flags, "--trace-threads 2" if $param{vltmt} && $checkflags =~ /-trace-fst /; unshift @verilator_flags, "--debug-partition" if $param{vltmt}; unshift @verilator_flags, "--make gmake" if $param{verilator_make_gmake}; unshift @verilator_flags, "--make cmake" if $param{verilator_make_cmake}; diff --git a/test_regress/t/t_trace_array_fst_threads_1.pl b/test_regress/t/t_trace_array_fst_threads_1.pl new file mode 100755 index 000000000..487c4b474 --- /dev/null +++ b/test_regress/t/t_trace_array_fst_threads_1.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_trace_array.v"); +$Self->{golden_filename} = "t/t_trace_array_fst.out"; + +compile( + verilator_flags2 => ['--cc --trace-fst --trace-threads 1 --trace-structs'], + ); + +execute( + check_finished => 1, + ); + +fst_identical($Self->trace_filename, $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_trace_array_fst_threads_2.pl b/test_regress/t/t_trace_array_fst_threads_2.pl new file mode 100755 index 000000000..170baffe6 --- /dev/null +++ b/test_regress/t/t_trace_array_fst_threads_2.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_trace_array.v"); +$Self->{golden_filename} = "t/t_trace_array_fst.out"; + +compile( + verilator_flags2 => ['--cc --trace-fst --trace-threads 2 --trace-structs'], + ); + +execute( + check_finished => 1, + ); + +fst_identical($Self->trace_filename, $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_trace_array_threads_1.pl b/test_regress/t/t_trace_array_threads_1.pl new file mode 100755 index 000000000..00d9d4789 --- /dev/null +++ b/test_regress/t/t_trace_array_threads_1.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_trace_array.v"); + +compile( + verilator_flags2 => ['--cc --trace --trace-threads 1 --trace-structs'], + ); + +execute( + check_finished => 1, + ); + +file_grep("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); + +ok(1); +1; diff --git a/test_regress/t/t_trace_complex_fst_thread.pl b/test_regress/t/t_trace_complex_fst_threads_1.pl similarity index 91% rename from test_regress/t/t_trace_complex_fst_thread.pl rename to test_regress/t/t_trace_complex_fst_threads_1.pl index 59ffac304..5e9707bf6 100755 --- a/test_regress/t/t_trace_complex_fst_thread.pl +++ b/test_regress/t/t_trace_complex_fst_threads_1.pl @@ -14,7 +14,7 @@ top_filename("t/t_trace_complex.v"); $Self->{golden_filename} = "t/t_trace_complex_fst.out"; compile( - verilator_flags2 => ['--cc --trace-fst-thread'], + verilator_flags2 => ['--cc --trace-fst --trace-threads 1'], ); execute( diff --git a/test_regress/t/t_trace_complex_fst_threads_2.pl b/test_regress/t/t_trace_complex_fst_threads_2.pl new file mode 100755 index 000000000..7cbdebcbb --- /dev/null +++ b/test_regress/t/t_trace_complex_fst_threads_2.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +top_filename("t/t_trace_complex.v"); +$Self->{golden_filename} = "t/t_trace_complex_fst.out"; + +compile( + verilator_flags2 => ['--cc --trace-fst --trace-threads 2'], + ); + +execute( + check_finished => 1, + ); + +fst_identical($Self->trace_filename, $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_trace_complex_old_api.pl b/test_regress/t/t_trace_complex_old_api.pl index 6041f09c2..730aa1e76 100755 --- a/test_regress/t/t_trace_complex_old_api.pl +++ b/test_regress/t/t_trace_complex_old_api.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Same test as t_trace_complex, but exercising the old VCD tracing API -scenarios(simulator => 1); +scenarios(vlt => 1); top_filename("t/t_trace_complex.v"); diff --git a/test_regress/t/t_trace_complex_threads_1.pl b/test_regress/t/t_trace_complex_threads_1.pl new file mode 100755 index 000000000..0999ed679 --- /dev/null +++ b/test_regress/t/t_trace_complex_threads_1.pl @@ -0,0 +1,37 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +top_filename("t/t_trace_complex.v"); +$Self->{golden_filename} = "t/t_trace_complex.out"; + +compile( + verilator_flags2 => ['--cc --trace --trace-threads 1'] + ); + +execute( + check_finished => 1, + ); + +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_strp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_strp_strp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp_arrp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp_strp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru\(/); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arru\(/); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arrp\(/); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_strp\(/); + +vcd_identical ("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_trace_two_dumpfst_cc.pl b/test_regress/t/t_trace_two_dumpfst_cc.pl index d2288c696..6a1fae915 100755 --- a/test_regress/t/t_trace_two_dumpfst_cc.pl +++ b/test_regress/t/t_trace_two_dumpfst_cc.pl @@ -18,13 +18,13 @@ compile( verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', VM_PREFIX => 'Vt_trace_two_b', - verilator_flags2 => ['--trace-fst-thread -DTEST_FST'], + verilator_flags2 => ['--trace-fst --trace-threads 1 -DTEST_FST'], ); compile( make_main => 0, top_filename => 't_trace_two_a.v', - verilator_flags2 => ['-exe', '--trace-fst-thread', + verilator_flags2 => ['-exe', '--trace-fst --trace-threads 1', '-DTEST_FST', "$Self->{t_dir}/t_trace_two_cc.cpp"], v_flags2 => ['+define+TEST_DUMP'], diff --git a/test_regress/t/t_trace_two_hdrfst_cc.pl b/test_regress/t/t_trace_two_hdrfst_cc.pl index dd4712626..653776ccc 100755 --- a/test_regress/t/t_trace_two_hdrfst_cc.pl +++ b/test_regress/t/t_trace_two_hdrfst_cc.pl @@ -18,14 +18,14 @@ compile( verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', VM_PREFIX => 'Vt_trace_two_b', - verilator_flags2 => ['--trace-fst-thread'], + verilator_flags2 => ['--trace-fst --trace-threads 1'], ); compile( make_main => 0, top_filename => 't_trace_two_a.v', make_flags => 'CPPFLAGS_ADD="-DTEST_HDR_TRACE=1 -DTEST_FST=1"', - verilator_flags2 => ['-exe', '--trace-fst-thread', + verilator_flags2 => ['-exe', '--trace-fst --trace-threads 1', '-DTEST_FST', "$Self->{t_dir}/t_trace_two_cc.cpp"], ); diff --git a/test_regress/t/t_trace_two_portfst_cc.pl b/test_regress/t/t_trace_two_portfst_cc.pl index acb6176b9..299b3cefb 100755 --- a/test_regress/t/t_trace_two_portfst_cc.pl +++ b/test_regress/t/t_trace_two_portfst_cc.pl @@ -18,13 +18,13 @@ compile( verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', VM_PREFIX => 'Vt_trace_two_b', - verilator_flags2 => ['--trace-fst-thread'], + verilator_flags2 => ['--trace-fst --trace-threads 1'], ); compile( make_main => 0, top_filename => 't_trace_two_a.v', - verilator_flags2 => ['-exe', '--trace-fst-thread', + verilator_flags2 => ['-exe', '--trace-fst --trace-threads 1', '-DTEST_FST', "$Self->{t_dir}/t_trace_two_cc.cpp"], v_flags2 => ['+define+TEST_DUMPPORTS'], diff --git a/test_regress/t/t_verilated_all.pl b/test_regress/t/t_verilated_all.pl index d3b70bac5..0bd51a322 100755 --- a/test_regress/t/t_verilated_all.pl +++ b/test_regress/t/t_verilated_all.pl @@ -19,6 +19,8 @@ compile( "--trace --vpi ", ($Self->cfg_with_threaded ? "--threads 2 $root/include/verilated_threads.cpp" : ""), + ($Self->cfg_with_threaded + ? "--trace-threads 1" : ""), "$root/include/verilated_save.cpp"], ); From 77915f78db5ec8b0e8ab8a52ff8aa9b374fc646a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 21 Apr 2020 20:45:23 -0400 Subject: [PATCH 086/127] Add experimental-only option. --- src/Makefile_obj.in | 1 + src/V3EmitCMain.cpp | 100 ++++++++++++++++++++++++++++++++++ src/V3EmitCMain.h | 30 ++++++++++ src/V3Options.cpp | 11 +++- src/V3Options.h | 2 + src/Verilator.cpp | 10 ++-- test_regress/t/t_flag_main.pl | 26 +++++++++ test_regress/t/t_flag_main.v | 13 +++++ 8 files changed, 185 insertions(+), 8 deletions(-) create mode 100644 src/V3EmitCMain.cpp create mode 100644 src/V3EmitCMain.h create mode 100755 test_regress/t/t_flag_main.pl create mode 100644 test_regress/t/t_flag_main.v diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index f35bb2103..911f97e1f 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -185,6 +185,7 @@ RAW_OBJS = \ V3EmitCInlines.o \ V3EmitCSyms.o \ V3EmitCMake.o \ + V3EmitCMain.o \ V3EmitMk.o \ V3EmitV.o \ V3EmitXml.o \ diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp new file mode 100644 index 000000000..14e67ed2a --- /dev/null +++ b/src/V3EmitCMain.cpp @@ -0,0 +1,100 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Emit C++ for tree +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2020 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Global.h" +#include "V3EmitC.h" +#include "V3EmitCBase.h" +#include "V3EmitCMain.h" + +#include +#include +#include +#include + +//###################################################################### + +class EmitCMain : EmitCBaseVisitor { + // METHODS + + // VISITORS + virtual void visit(AstNode* nodep) { iterateChildren(nodep); } + +public: + // CONSTRUCTORS + explicit EmitCMain(AstNetlist* nodep) { emitInt(); } + +private: + // MAIN METHOD + void emitInt() { + string filename = v3Global.opt.makeDir() + "/" + topClassName() + "__main.cpp"; + newCFile(filename, false /*slow*/, true /*source*/); + V3OutCFile cf(filename); + m_ofp = &cf; + + // Heavly commented output, as users are likely to look at or copy this code + ofp()->putsHeader(); + puts("// DESCRIPTION: main() calling loop, created with Verilator --main\n"); + puts("\n"); + + puts("#include \"verilated.h\"\n"); + puts("#include \"" + topClassName() + ".h\"\n"); + + puts("\n//======================\n\n"); + + puts(topClassName() + "* topp;\n"); + puts("\n"); + puts("// Requires -DVL_TIME_STAMP64\n"); + v3Global.opt.addCFlags("-DVL_TIME_STAMP64"); + puts("vluint64_t main_time = 0;\n"); + puts("vluint64_t vl_time_stamp64() { return main_time; }\n"); + puts("\n"); + + puts("int main(int argc, char** argv, char**) {\n"); + puts("// Setup defaults and parse command line\n"); + puts("Verilated::debug(0);\n"); + puts("Verilated::commandArgs(argc, argv);\n"); + puts("// Construct the Verilated model, from Vtop.h generated from Verilating\n"); + puts("topp = new " + topClassName() + "(\"top\");\n"); + puts("// Evaluate initials\n"); + puts("topp->eval(); // Evaluate\n"); + + puts("// Simulate until $finish\n"); + puts("while (!Verilated::gotFinish()) {\n"); + /**/ puts("// Evaluate model\n"); + /**/ puts("topp->eval();\n"); + /**/ puts("// Advance time\n"); + /**/ puts("++main_time;\n"); + puts("}\n"); + puts("\n"); + + puts("// Final model cleanup\n"); + puts("topp->final();\n"); + puts("VL_DO_DANGLING(delete topp, topp);\n"); + puts("exit(0);\n"); + puts("}\n"); + } +}; + +//###################################################################### +// EmitC class functions + +void V3EmitCMain::emit() { + UINFO(2, __FUNCTION__ << ": " << endl); + EmitCMain(v3Global.rootp()); +} diff --git a/src/V3EmitCMain.h b/src/V3EmitCMain.h new file mode 100644 index 000000000..04df088a2 --- /dev/null +++ b/src/V3EmitCMain.h @@ -0,0 +1,30 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Emit C main() +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2020 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#ifndef _V3EMITCMAIN_H_ +#define _V3EMITCMAIN_H_ 1 + +#include "config_build.h" +#include "verilatedos.h" + +//============================================================================ + +class V3EmitCMain { +public: + static void emit(); +}; + +#endif // Guard diff --git a/src/V3Options.cpp b/src/V3Options.cpp index c836bffc6..1d4000b87 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -585,6 +585,8 @@ string V3Options::getenvVERILATOR_ROOT() { // V3 Options notification methods void V3Options::notify() { + FileLine* cmdfl = new FileLine(FileLine::commandLineFilename()); + // Notify that all arguments have been passed and final modification can be made. if (!outFormatOk() && !cdc() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !xmlOnly()) { v3fatal("verilator: Need --cc, --sc, --cdc, --dpi-hdr-only, --lint-only, " @@ -595,7 +597,6 @@ void V3Options::notify() { if (!m_gmake && !m_cmake) m_gmake = true; if (protectIds()) { - FileLine* cmdfl = new FileLine(FileLine::commandLineFilename()); if (allPublic()) { // We always call protect() on names, we don't check if public or not // Hence any external references wouldn't be able to find the refed public object. @@ -633,7 +634,11 @@ void V3Options::notify() { } // --trace-threads implies --threads 1 unless explicitly specified - if (traceThreads() && !threads()) { m_threads = 1; } + if (traceThreads() && !threads()) m_threads = 1; + + if (v3Global.opt.main() && v3Global.opt.systemC()) { + cmdfl->v3error("--main not usable with SystemC. Suggest see examples for sc_main()."); + } } //###################################################################### @@ -849,6 +854,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if ( onoff (sw, "-ignc", flag/*ref*/)) { m_ignc = flag; } else if ( onoff (sw, "-inhibit-sim", flag/*ref*/)) { m_inhibitSim = flag; } else if ( onoff (sw, "-lint-only", flag/*ref*/)) { m_lintOnly = flag; } + else if ( onoff (sw, "-main", flag/*ref*/)) { m_main = flag; } // Undocumented future else if (!strcmp(sw, "-no-pins64")) { m_pinsBv = 33; } else if ( onoff (sw, "-order-clock-delay", flag/*ref*/)) { m_orderClockDly = flag; } else if (!strcmp(sw, "-pins64")) { m_pinsBv = 65; } @@ -1543,6 +1549,7 @@ V3Options::V3Options() { m_lintOnly = false; m_gmake = false; m_makePhony = false; + m_main = false; m_orderClockDly = true; m_outFormatOk = false; m_pedantic = false; diff --git a/src/V3Options.h b/src/V3Options.h index 2e48eda40..6e4941ba8 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -234,6 +234,7 @@ private: bool m_inhibitSim; // main switch: --inhibit-sim bool m_lintOnly; // main switch: --lint-only bool m_gmake; // main switch: --make gmake + bool m_main; // main swithc: --main bool m_orderClockDly;// main switch: --order-clock-delay bool m_outFormatOk; // main switch: --cc, --sc or --sp was specified bool m_pedantic; // main switch: --Wpedantic @@ -436,6 +437,7 @@ public: bool traceParams() const { return m_traceParams; } bool traceStructs() const { return m_traceStructs; } bool traceUnderscore() const { return m_traceUnderscore; } + bool main() const { return m_main; } bool orderClockDly() const { return m_orderClockDly; } bool outFormatOk() const { return m_outFormatOk; } bool keepTempFiles() const { return (V3Error::debugDefault() != 0); } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 31a499e28..c34bd6b6a 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -42,6 +42,7 @@ #include "V3Descope.h" #include "V3EmitC.h" #include "V3EmitCMake.h" +#include "V3EmitCMain.h" #include "V3EmitMk.h" #include "V3EmitV.h" #include "V3EmitXml.h" @@ -487,12 +488,9 @@ static void process() { if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { // Makefile must be after all other emitters - if (v3Global.opt.cmake()) { // - V3EmitCMake::emit(); - } - if (v3Global.opt.gmake()) { // - V3EmitMk::emitmk(); - } + if (v3Global.opt.main()) V3EmitCMain::emit(); + if (v3Global.opt.cmake()) V3EmitCMake::emit(); + if (v3Global.opt.gmake()) V3EmitMk::emitmk(); } // Note early return above when opt.cdc() diff --git a/test_regress/t/t_flag_main.pl b/test_regress/t/t_flag_main.pl new file mode 100755 index 000000000..e68010553 --- /dev/null +++ b/test_regress/t/t_flag_main.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ['--exe --build --main'], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + make_top => 1, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_main.v b/test_regress/t/t_flag_main.v new file mode 100644 index 000000000..ef63ab8ca --- /dev/null +++ b/test_regress/t/t_flag_main.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by engr248. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + initial begin + $write("[%0t] Hello", $time); // Check timestamp works + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From c96a43b4520c4312def7c110dfebe66a31eaf6f0 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 22 Apr 2020 22:25:35 +0100 Subject: [PATCH 087/127] Fix unused variable in VL_READMEM_N (#2274) --- include/verilated.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 43fa648c9..490c0d501 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1901,7 +1901,6 @@ void VL_READMEM_N(bool hex, // Hex format, else binary QData start, // First array row address to read QData end // Last row address to read ) VL_MT_SAFE { - QData addr_max = array_lsb + depth - 1; if (start < static_cast(array_lsb)) start = array_lsb; VlReadMem rmem(hex, bits, filename, start, end); From 7176aee852303843d8deee42b7d0dd9cef5c65e6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 22 Apr 2020 21:31:40 -0400 Subject: [PATCH 088/127] Internals: Parse fork and delays, but then still report unsupported. --- src/V3Ast.h | 58 ++++++++++++++++++++++ src/V3AstNodes.cpp | 9 +++- src/V3AstNodes.h | 47 +++++++++++++----- src/V3Config.cpp | 4 +- src/V3EmitV.cpp | 10 ++++ src/V3LinkDot.cpp | 68 +++++++++++++------------- src/V3LinkJump.cpp | 30 ++++++------ src/V3LinkParse.cpp | 11 +++++ src/V3ParseImp.h | 1 + src/V3Width.cpp | 4 ++ src/verilog.y | 58 ++++++++++++---------- test_regress/t/t_delay_stmtdly_bad.out | 17 ++++--- test_regress/t/t_fork.out | 4 ++ test_regress/t/t_fork.pl | 19 +++++++ test_regress/t/t_fork.v | 18 +++++++ test_regress/t/t_fork_bbox.pl | 18 +++++++ test_regress/t/t_fork_bbox.v | 18 +++++++ 17 files changed, 296 insertions(+), 98 deletions(-) create mode 100644 test_regress/t/t_fork.out create mode 100755 test_regress/t/t_fork.pl create mode 100644 test_regress/t/t_fork.v create mode 100755 test_regress/t/t_fork_bbox.pl create mode 100644 test_regress/t/t_fork_bbox.v diff --git a/src/V3Ast.h b/src/V3Ast.h index 295f30783..2fd9c30ce 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -578,6 +578,40 @@ inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) { //###################################################################### +/// Join type +class VJoinType { +public: + enum en { JOIN = 0, JOIN_ANY = 1, JOIN_NONE = 2 }; + enum en m_e; + // CONSTRUCTOR - note defaults to *UNKNOWN* + inline VJoinType() + : m_e(JOIN) {} + // cppcheck-suppress noExplicitConstructor + inline VJoinType(en _e) + : m_e(_e) {} + explicit inline VJoinType(int _e) + : m_e(static_cast(_e)) {} + const char* ascii() const { + static const char* const names[] = {"JOIN", "JOIN_ANY", "JOIN_NONE"}; + return names[m_e]; + } + const char* verilogKwd() const { + static const char* const names[] = {"join", "join_any", "join_none"}; + return names[m_e]; + } + bool join() const { return m_e == JOIN; } + bool joinAny() const { return m_e == JOIN_ANY; } + bool joinNone() const { return m_e == JOIN_NONE; } +}; +inline bool operator==(const VJoinType& lhs, const VJoinType& rhs) { return lhs.m_e == rhs.m_e; } +inline bool operator==(const VJoinType& lhs, VJoinType::en rhs) { return lhs.m_e == rhs; } +inline bool operator==(VJoinType::en lhs, const VJoinType& rhs) { return lhs == rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VJoinType& rhs) { + return os << rhs.ascii(); +} + +//###################################################################### + class AstVarType { public: enum en { @@ -1975,6 +2009,30 @@ public: virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) = 0; }; +class AstNodeBlock : public AstNode { + // A Begin/fork block + // Parents: statement + // Children: statements +private: + string m_name; // Name of block + bool m_unnamed; // Originally unnamed (name change does not affect this) +public: + AstNodeBlock(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) + : AstNode(t, fl) + , m_name(name) { + addNOp1p(stmtsp); + m_unnamed = (name == ""); + } + ASTNODE_BASE_FUNCS(NodeBlock) + virtual void dump(std::ostream& str) const; + virtual string name() const { return m_name; } // * = Block name + virtual void name(const string& name) { m_name = name; } + // op1 = Statements + AstNode* stmtsp() const { return op1p(); } // op1 = List of statements + void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } + bool unnamed() const { return m_unnamed; } +}; + class AstNodePreSel : public AstNode { // Something that becomes an AstSel public: diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 3f6fb3dfd..8cb89dc5e 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1493,9 +1493,12 @@ void AstNodeFTask::dump(std::ostream& str) const { if (dpiOpenParent()) str << " [DPIOPENPARENT]"; if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]"; } -void AstBegin::dump(std::ostream& str) const { +void AstNodeBlock::dump(std::ostream& str) const { this->AstNode::dump(str); if (unnamed()) str << " [UNNAMED]"; +} +void AstBegin::dump(std::ostream& str) const { + this->AstNode::dump(str); if (generate()) str << " [GEN]"; if (genforp()) str << " [GENFOR]"; if (implied()) str << " [IMPLIED]"; @@ -1518,6 +1521,10 @@ void AstCoverInc::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +void AstFork::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (!joinType().join()) str << " [" << joinType() << "]"; +} void AstTraceInc::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> "; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 4c8c098a6..97014185a 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3402,6 +3402,21 @@ public: AstNode* changep() const { return op3p(); } }; +class AstDelay : public AstNodeStmt { + // Delay statement +public: + AstDelay(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER(fl) { + setOp1p(lhsp); + } + ASTNODE_NODE_FUNCS(Delay) + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { return true; } + // + AstNode* lhsp() const { return op1p(); } // op2 = Statements to evaluate + void lhsp(AstNode* nodep) { setOp1p(nodep); } +}; + class AstGenCase : public AstNodeCase { // Generate Case statement // Parents: {statement list} @@ -4372,42 +4387,48 @@ public: virtual bool same(const AstNode* samep) const { return true; } }; -class AstBegin : public AstNode { +class AstBegin : public AstNodeBlock { // A Begin/end named block, only exists shortly after parsing until linking // Parents: statement // Children: statements private: - string m_name; // Name of block - bool m_unnamed; // Originally unnamed (name change does not affect this) bool m_generate; // Underneath a generate bool m_implied; // Not inserted by user public: // Node that simply puts name into the output stream AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false, bool implied = false) - : ASTGEN_SUPER(fl) - , m_name(name) { - addNOp1p(stmtsp); - m_unnamed = (name == ""); + : ASTGEN_SUPER(fl, name, stmtsp) { m_generate = generate; m_implied = implied; } ASTNODE_NODE_FUNCS(Begin) virtual void dump(std::ostream& str) const; - virtual string name() const { return m_name; } // * = Block name - virtual void name(const string& name) { m_name = name; } - // op1 = Statements - AstNode* stmtsp() const { return op1p(); } // op1 = List of statements - void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } + // op1p is statements in NodeBlock AstNode* genforp() const { return op2p(); } // op2 = GENFOR, if applicable, // might NOT be a GenFor, as loop unrolling replaces with Begin void addGenforp(AstGenFor* nodep) { addOp2p(nodep); } - bool unnamed() const { return m_unnamed; } void generate(bool flag) { m_generate = flag; } bool generate() const { return m_generate; } bool implied() const { return m_implied; } }; +class AstFork : public AstNodeBlock { + // A fork named block + // Parents: statement + // Children: statements +private: + VJoinType m_joinType; // Join keyword type +public: + // Node that simply puts name into the output stream + AstFork(FileLine* fl, const string& name, AstNode* stmtsp) + : ASTGEN_SUPER(fl, name, stmtsp) {} + ASTNODE_NODE_FUNCS(Fork) + virtual void dump(std::ostream& str) const; + VJoinType joinType() const { return m_joinType; } + void joinType(const VJoinType& flag) { m_joinType = flag; } +}; + class AstInitial : public AstNode { public: AstInitial(FileLine* fl, AstNode* bodysp) diff --git a/src/V3Config.cpp b/src/V3Config.cpp index 757c8126f..eca233a8d 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -209,7 +209,7 @@ public: } } - void applyBlock(AstBegin* nodep) { + void applyBlock(AstNodeBlock* nodep) { AstPragmaType pragma = AstPragmaType::COVERAGE_BLOCK_OFF; if (!nodep->unnamed()) { for (StringSet::const_iterator it = m_coverageOffBlocks.begin(); @@ -311,7 +311,7 @@ public: m_waivers.push_back(make_pair(code, match)); } - void applyBlock(AstBegin* nodep) { + void applyBlock(AstNodeBlock* nodep) { // Apply to block at this line AstPragmaType pragma = AstPragmaType::COVERAGE_BLOCK_OFF; if (lineMatch(nodep->fileline()->lineno(), pragma)) { diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index dd7f12b0a..5b28dec41 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -79,6 +79,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { iterateChildren(nodep); puts("end\n"); } + virtual void visit(AstFork* nodep) VL_OVERRIDE { + if (nodep->name() == "") { + putbs("fork\n"); + } else { + putbs("fork : " + nodep->name() + "\n"); + } + iterateChildren(nodep); + puts(nodep->joinType().verilogKwd()); + puts("\n"); + } virtual void visit(AstFinal* nodep) VL_OVERRIDE { putfs(nodep, "final begin\n"); iterateChildren(nodep); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d5df411c5..0f0aa5ad2 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -127,7 +127,7 @@ private: // AstVar::user2p() // AstFTask*. If a function variable, the task // that links to the variable // AstVar::user4() // bool. True if port set for this variable - // AstBegin::user4() // bool. Did name processing + // AstNodeBlock::user4() // bool. Did name processing // AstNodeModule::user4() // bool. Live module AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; @@ -689,13 +689,13 @@ class LinkDotFindVisitor : public AstNVisitor { VSymEnt* m_modSymp; // Symbol Entry for current module VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert string m_scope; // Scope text - AstBegin* m_beginp; // Current Begin/end block + AstNodeBlock* m_blockp; // Current Begin/end block AstNodeFTask* m_ftaskp; // Current function/task bool m_inRecursion; // Inside a recursive module int m_paramNum; // Parameter number, for position based connection - int m_beginNum; // Begin block number, 0=none seen + int m_blockNum; // Begin block number, 0=none seen bool m_explicitNew; // Hit a "new" function - int m_modBeginNum; // Begin block number in module, 0=none seen + int m_modBlockNum; // Begin block number in module, 0=none seen // METHODS int debug() { return LinkDotState::debug(); } @@ -780,8 +780,8 @@ class LinkDotFindVisitor : public AstNVisitor { VSymEnt* oldModSymp = m_modSymp; VSymEnt* oldCurSymp = m_curSymp; int oldParamNum = m_paramNum; - int oldBeginNum = m_beginNum; - int oldModBeginNum = m_modBeginNum; + int oldBlockNum = m_blockNum; + int oldModBlockNum = m_modBlockNum; if (doit && nodep->user2()) { nodep->v3error("Unsupported: Identically recursive module (module instantiates " "itself, without changing parameters): " @@ -805,8 +805,8 @@ class LinkDotFindVisitor : public AstNVisitor { } // m_paramNum = 0; - m_beginNum = 0; - m_modBeginNum = 0; + m_blockNum = 0; + m_modBlockNum = 0; // m_modSymp/m_curSymp for non-packages set by AstCell above this module // Iterate nodep->user2(true); @@ -826,8 +826,8 @@ class LinkDotFindVisitor : public AstNVisitor { m_modSymp = oldModSymp; m_curSymp = oldCurSymp; m_paramNum = oldParamNum; - m_beginNum = oldBeginNum; - m_modBeginNum = oldModBeginNum; + m_blockNum = oldBlockNum; + m_modBlockNum = oldModBlockNum; // Prep for next m_packagep = NULL; } @@ -838,8 +838,8 @@ class LinkDotFindVisitor : public AstNVisitor { VSymEnt* oldModSymp = m_modSymp; VSymEnt* oldCurSymp = m_curSymp; int oldParamNum = m_paramNum; - int oldBeginNum = m_beginNum; - int oldModBeginNum = m_modBeginNum; + int oldBlockNum = m_blockNum; + int oldModBlockNum = m_modBlockNum; { UINFO(4, " Link Class: " << nodep << endl); VSymEnt* upperSymp = m_curSymp; @@ -850,8 +850,8 @@ class LinkDotFindVisitor : public AstNVisitor { UINFO(9, "New module scope " << m_curSymp << endl); // m_paramNum = 0; - m_beginNum = 0; - m_modBeginNum = 0; + m_blockNum = 0; + m_modBlockNum = 0; m_explicitNew = false; // m_modSymp/m_curSymp for non-packages set by AstCell above this module // Iterate @@ -864,8 +864,8 @@ class LinkDotFindVisitor : public AstNVisitor { m_modSymp = oldModSymp; m_curSymp = oldCurSymp; m_paramNum = oldParamNum; - m_beginNum = oldBeginNum; - m_modBeginNum = oldModBeginNum; + m_blockNum = oldBlockNum; + m_modBlockNum = oldModBlockNum; } virtual void visit(AstScope* nodep) VL_OVERRIDE { UASSERT_OBJ(m_statep->forScopeCreation(), nodep, @@ -879,7 +879,7 @@ class LinkDotFindVisitor : public AstNVisitor { iterateChildren(nodep); // Recurse in, preserving state string oldscope = m_scope; - AstBegin* oldbeginp = m_beginp; + AstNodeBlock* oldblockp = m_blockp; VSymEnt* oldModSymp = m_modSymp; VSymEnt* oldCurSymp = m_curSymp; int oldParamNum = m_paramNum; @@ -901,13 +901,13 @@ class LinkDotFindVisitor : public AstNVisitor { { m_scope = m_scope + "." + nodep->name(); m_curSymp = m_modSymp = m_statep->insertCell(aboveSymp, m_modSymp, nodep, m_scope); - m_beginp = NULL; + m_blockp = NULL; m_inRecursion = nodep->recursive(); // We don't report NotFoundModule, as may be a unused module in a generate if (nodep->modp()) iterate(nodep->modp()); } m_scope = oldscope; - m_beginp = oldbeginp; + m_blockp = oldblockp; m_modSymp = oldModSymp; m_curSymp = oldCurSymp; m_paramNum = oldParamNum; @@ -937,13 +937,13 @@ class LinkDotFindVisitor : public AstNVisitor { nodep->user1p(m_curSymp); iterateChildren(nodep); } - virtual void visit(AstBegin* nodep) VL_OVERRIDE { + virtual void visit(AstNodeBlock* nodep) VL_OVERRIDE { UINFO(5, " " << nodep << endl); // Rename "genblk"s to include a number if (m_statep->forPrimary() && !nodep->user4SetOnce()) { if (nodep->name() == "genblk") { - ++m_beginNum; - nodep->name(nodep->name() + cvtToStr(m_beginNum)); + ++m_blockNum; + nodep->name(nodep->name() + cvtToStr(m_blockNum)); } } // All blocks are numbered in the standard, IE we start with "genblk1" even if only one. @@ -955,8 +955,8 @@ class LinkDotFindVisitor : public AstNVisitor { // are common. for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (VN_IS(stmtp, Var)) { - ++m_modBeginNum; - nodep->name("unnamedblk" + cvtToStr(m_modBeginNum)); + ++m_modBlockNum; + nodep->name("unnamedblk" + cvtToStr(m_modBlockNum)); break; } } @@ -964,20 +964,20 @@ class LinkDotFindVisitor : public AstNVisitor { if (nodep->name() == "") { iterateChildren(nodep); } else { - int oldNum = m_beginNum; - AstBegin* oldbegin = m_beginp; + int oldNum = m_blockNum; + AstNodeBlock* oldblockp = m_blockp; VSymEnt* oldCurSymp = m_curSymp; { - m_beginNum = 0; - m_beginp = nodep; + m_blockNum = 0; + m_blockp = nodep; m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_packagep); m_curSymp->fallbackp(oldCurSymp); // Iterate iterateChildren(nodep); } m_curSymp = oldCurSymp; - m_beginp = oldbegin; - m_beginNum = oldNum; + m_blockp = oldblockp; + m_blockNum = oldNum; } } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { @@ -1249,13 +1249,13 @@ public: m_packagep = NULL; m_curSymp = m_modSymp = NULL; m_statep = statep; - m_beginp = NULL; + m_blockp = NULL; m_ftaskp = NULL; m_inRecursion = false; m_paramNum = 0; - m_beginNum = 0; + m_blockNum = 0; m_explicitNew = false; - m_modBeginNum = 0; + m_modBlockNum = 0; // iterate(rootp); } @@ -2546,7 +2546,7 @@ private: // checkNoDot not appropriate, can be under a dot iterateChildren(nodep); } - virtual void visit(AstBegin* nodep) VL_OVERRIDE { + virtual void visit(AstNodeBlock* nodep) VL_OVERRIDE { UINFO(5, " " << nodep << endl); checkNoDot(nodep); VSymEnt* oldCurSymp = m_curSymp; diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 4cbb97210..097cdbc9a 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -38,7 +38,7 @@ class LinkJumpVisitor : public AstNVisitor { private: // TYPES - typedef std::vector BeginStack; + typedef std::vector BlockStack; // STATE AstNodeModule* m_modp; // Current module @@ -46,7 +46,7 @@ private: AstWhile* m_loopp; // Current loop bool m_loopInc; // In loop increment int m_modRepeatNum; // Repeat counter - BeginStack m_beginStack; // All begin blocks above current node + BlockStack m_blockStack; // All begin blocks above current node // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -58,8 +58,8 @@ private: AstNode* underp = NULL; bool under_and_next = true; - if (VN_IS(nodep, Begin)) { - underp = VN_CAST(nodep, Begin)->stmtsp(); + if (VN_IS(nodep, NodeBlock)) { + underp = VN_CAST(nodep, NodeBlock)->stmtsp(); } else if (VN_IS(nodep, NodeFTask)) { underp = VN_CAST(nodep, NodeFTask)->stmtsp(); } else if (VN_IS(nodep, While)) { @@ -123,11 +123,11 @@ private: iterateChildren(nodep); m_ftaskp = NULL; } - virtual void visit(AstBegin* nodep) VL_OVERRIDE { + virtual void visit(AstNodeBlock* nodep) VL_OVERRIDE { UINFO(8, " " << nodep << endl); - m_beginStack.push_back(nodep); + m_blockStack.push_back(nodep); iterateChildren(nodep); - m_beginStack.pop_back(); + m_blockStack.pop_back(); } virtual void visit(AstRepeat* nodep) VL_OVERRIDE { // So later optimizations don't need to deal with them, @@ -223,22 +223,24 @@ private: virtual void visit(AstDisable* nodep) VL_OVERRIDE { UINFO(8, " DISABLE " << nodep << endl); iterateChildren(nodep); - AstBegin* beginp = NULL; - for (BeginStack::reverse_iterator it = m_beginStack.rbegin(); it != m_beginStack.rend(); + AstNodeBlock* blockp = NULL; + for (BlockStack::reverse_iterator it = m_blockStack.rbegin(); it != m_blockStack.rend(); ++it) { UINFO(9, " UNDERBLK " << *it << endl); if ((*it)->name() == nodep->name()) { - beginp = *it; + blockp = *it; break; } } - // if (debug() >= 9) { UINFO(0, "\n"); beginp->dumpTree(cout, " labeli: "); } - if (!beginp) { + // if (debug() >= 9) { UINFO(0, "\n"); blockp->dumpTree(cout, " labeli: "); } + if (!blockp) { nodep->v3error("disable isn't underneath a begin with name: " << nodep->prettyNameQ()); - } else { - // Jump to the end of the named begin + } else if (AstBegin* beginp = VN_CAST(blockp, Begin)) { + // Jump to the end of the named block AstJumpLabel* labelp = findAddLabel(beginp, false); nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp)); + } else { + nodep->v3error("Unsupported: disable fork"); } nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index c5b1a89c7..ad875a432 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -491,6 +491,17 @@ private: } iterateChildren(nodep); } + virtual void visit(AstFork* nodep) VL_OVERRIDE { + if (v3Global.opt.bboxUnsup()) { + AstBegin* newp + = new AstBegin(nodep->fileline(), nodep->name(), nodep->stmtsp()->unlinkFrBack()); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else { + nodep->v3error("Unsupported: fork statements"); + // TBD might support only normal join, if so complain about other join flavors + } + } virtual void visit(AstCase* nodep) VL_OVERRIDE { V3Config::applyCase(nodep); cleanFileline(nodep); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 6c8fdafc0..1a079b604 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -69,6 +69,7 @@ struct V3ParseBisonYYSType { AstCell* cellp; AstClass* classp; AstConst* constp; + AstFork* forkp; AstMemberDType* memberp; AstNodeModule* modulep; AstNodeUOrStructDType* uorstructp; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 49762c4c1..36ff94be0 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -538,6 +538,10 @@ private: } } } + virtual void visit(AstDelay* nodep) VL_OVERRIDE { + nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement."); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + } virtual void visit(AstToLowerN* nodep) VL_OVERRIDE { if (m_vup->prelim()) { iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); diff --git a/src/verilog.y b/src/verilog.y index 0c261d185..4f6d2bd43 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -790,6 +790,10 @@ class AstSenTree; // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion +// Blank lines for type insertion +// Blank lines for type insertion +// Blank lines for type insertion +// Blank lines for type insertion %start source_text @@ -2274,31 +2278,31 @@ assignOne: delayE: /* empty */ { } - | delay_control { $1->v3warn(ASSIGNDLY,"Unsupported: Ignoring delay on this assignment/primitive."); } /* ignored */ + | delay_control { $1->v3warn(ASSIGNDLY,"Unsupported: Ignoring delay on this assignment/primitive."); DEL($1); } /* ignored */ ; -delay_control: //== IEEE: delay_control - '#' delay_value { $$ = $1; } /* ignored */ - | '#' '(' minTypMax ')' { $$ = $1; } /* ignored */ - | '#' '(' minTypMax ',' minTypMax ')' { $$ = $1; } /* ignored */ - | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { $$ = $1; } /* ignored */ +delay_control: //== IEEE: delay_control + '#' delay_value { $$ = $2; } + | '#' '(' minTypMax ')' { $$ = $3; } + | '#' '(' minTypMax ',' minTypMax ')' { $$ = $3; DEL($5); } + | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { $$ = $3; DEL($5); DEL($7); } ; -delay_value: // ==IEEE:delay_value +delay_value: // ==IEEE:delay_value // // IEEE: ps_identifier - ps_id_etc { } - | yaINTNUM { } - | yaFLOATNUM { } - | timeNumAdjusted { DEL($1); } + ps_id_etc { $$ = $1; } + | yaINTNUM { $$ = new AstConst($1, *$1); } + | yaFLOATNUM { $$ = new AstConst($1, AstConst::RealDouble(), $1); } + | timeNumAdjusted { $$ = $1; } ; -delayExpr: - expr { DEL($1); } +delayExpr: + expr { $$ = $1; } ; -minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression - delayExpr { } - | delayExpr ':' delayExpr ':' delayExpr { } +minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression + delayExpr { $$ = $1; } + | delayExpr ':' delayExpr ':' delayExpr { $$ = $1; DEL($3); DEL($5); } ; netSigList: // IEEE: list_of_port_identifiers @@ -2657,21 +2661,27 @@ seq_block: // ==IEEE: seq_block par_block: // ==IEEE: par_block par_blockFront blockDeclStmtList yJOIN endLabelE { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } | par_blockFront /**/ yJOIN endLabelE { $$ = $1; + $1->joinType(VJoinType::JOIN); SYMP->popScope($1); GRAMMARP->endLabel($3, $1, $3); } | par_blockFront blockDeclStmtList yJOIN_ANY endLabelE { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN_ANY); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } | par_blockFront /**/ yJOIN_ANY endLabelE { $$ = $1; + $1->joinType(VJoinType::JOIN_ANY); SYMP->popScope($1); GRAMMARP->endLabel($3, $1, $3); } | par_blockFront blockDeclStmtList yJOIN_NONE endLabelE { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN_NONE); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } | par_blockFront /**/ yJOIN_NONE endLabelE { $$ = $1; + $1->joinType(VJoinType::JOIN_NONE); SYMP->popScope($1); GRAMMARP->endLabel($3, $1, $3); } ; @@ -2680,13 +2690,9 @@ seq_blockFront: // IEEE: part of seq_block | yBEGIN ':' idAny/*new-block_identifier*/ { $$ = new AstBegin($3, *$3, NULL); SYMP->pushNew($$); } ; -par_blockFront: // IEEE: part of par_block - yFORK { $$ = new AstBegin($1, "", NULL); SYMP->pushNew($$); - BBUNSUP($1, "Unsupported: fork statements"); - // When support, record or BBUNSUP yJOIN_ANY/yJOIN_NONE - } - | yFORK ':' idAny/*new-block_identifier*/ { $$ = new AstBegin($3, *$3, NULL); SYMP->pushNew($$); - BBUNSUP($1, "Unsupported: fork statements"); } +par_blockFront: // IEEE: part of par_block + yFORK { $$ = new AstFork($1, "", NULL); SYMP->pushNew($$); } + | yFORK ':' idAny/*new-block_identifier*/ { $$ = new AstFork($3, *$3, NULL); SYMP->pushNew($$); } ; blockDeclStmtList: // IEEE: { block_item_declaration } { statement or null } @@ -2831,7 +2837,7 @@ statement_item: // IEEE: statement_item // | par_block { $$ = $1; } // // IEEE: procedural_timing_control_statement + procedural_timing_control - | delay_control stmtBlock { $$ = $2; $1->v3warn(STMTDLY,"Unsupported: Ignoring delay on this delayed statement."); } + | delay_control stmtBlock { $$ = new AstDelay($1->fileline(), $1); $$->addNextNull($2); } //UNSUP event_control stmtBlock { UNSUP } //UNSUP cycle_delay stmtBlock { UNSUP } // @@ -5521,8 +5527,8 @@ classImplementsList: // IEEE: part of class_declaration // must be included in the rules below. // Each of these must end with {symsPackageDone | symsClassDone} -ps_id_etc: // package_scope + general id - package_scopeIdFollowsE id { } +ps_id_etc: // package_scope + general id + package_scopeIdFollowsE varRefBase { $$ = $2; $2->packagep($1); } ; ps_type: // IEEE: ps_parameter_identifier | ps_type_identifier diff --git a/test_regress/t/t_delay_stmtdly_bad.out b/test_regress/t/t_delay_stmtdly_bad.out index 5e1f99423..f52d97869 100644 --- a/test_regress/t/t_delay_stmtdly_bad.out +++ b/test_regress/t/t_delay_stmtdly_bad.out @@ -1,14 +1,15 @@ -%Warning-ASSIGNDLY: t/t_delay.v:20:11: Unsupported: Ignoring delay on this assignment/primitive. +%Warning-ASSIGNDLY: t/t_delay.v:20:13: Unsupported: Ignoring delay on this assignment/primitive. 20 | assign #(1.2000000000000000) dly1 = dly0 + 32'h1; - | ^ + | ^~~~~~~~~~~~~~~~~~ ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. -%Warning-ASSIGNDLY: t/t_delay.v:25:18: Unsupported: Ignoring delay on this assignment/primitive. +%Warning-ASSIGNDLY: t/t_delay.v:25:19: Unsupported: Ignoring delay on this assignment/primitive. 25 | dly0 <= #0 32'h11; - | ^ -%Warning-ASSIGNDLY: t/t_delay.v:28:18: Unsupported: Ignoring delay on this assignment/primitive. + | ^ +%Warning-ASSIGNDLY: t/t_delay.v:28:19: Unsupported: Ignoring delay on this assignment/primitive. 28 | dly0 <= #0.12 dly0 + 32'h12; - | ^ -%Warning-STMTDLY: t/t_delay.v:34:10: Unsupported: Ignoring delay on this delayed statement. + | ^~~~ +%Warning-STMTDLY: t/t_delay.v:34:11: Unsupported: Ignoring delay on this delayed statement. + : ... In instance t 34 | #100 $finish; - | ^ + | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_fork.out b/test_regress/t/t_fork.out new file mode 100644 index 000000000..1f9b98a83 --- /dev/null +++ b/test_regress/t/t_fork.out @@ -0,0 +1,4 @@ +%Error: t/t_fork.v:10:14: Unsupported: fork statements + 10 | fork : fblk + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_fork.pl b/test_regress/t/t_fork.pl new file mode 100755 index 000000000..ac387c7d9 --- /dev/null +++ b/test_regress/t/t_fork.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_fork.v b/test_regress/t/t_fork.v new file mode 100644 index 000000000..06f9ed036 --- /dev/null +++ b/test_regress/t/t_fork.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2003 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + initial begin + fork : fblk + begin + $write("*-* All Finished *-*\n"); + $finish; + end + join : fblk + end + +endmodule diff --git a/test_regress/t/t_fork_bbox.pl b/test_regress/t/t_fork_bbox.pl new file mode 100755 index 000000000..4bf13ff24 --- /dev/null +++ b/test_regress/t/t_fork_bbox.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + verilator_flags2 => ['--lint-only --bbox-unsup'], + ); + +ok(1); +1; diff --git a/test_regress/t/t_fork_bbox.v b/test_regress/t/t_fork_bbox.v new file mode 100644 index 000000000..06f9ed036 --- /dev/null +++ b/test_regress/t/t_fork_bbox.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2003 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + initial begin + fork : fblk + begin + $write("*-* All Finished *-*\n"); + $finish; + end + join : fblk + end + +endmodule From 14643643c979c3dea1869b951af8a2bd938ca10b Mon Sep 17 00:00:00 2001 From: Qingyao Sun Date: Thu, 23 Apr 2020 05:14:20 -0600 Subject: [PATCH 089/127] Fix compatibility problem with CMake policy CMP0025 (#2277) Signed-off-by: Qingyao Sun --- docs/CONTRIBUTORS | 1 + verilator-config.cmake.in | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index dedbf3726..7c70a0722 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -33,6 +33,7 @@ Patrick Stewart Peter Monsson Philipp Wagner Pieter Kapsenberg +Qingyao Sun Richard Myers Sean Cross Sebastien Van Cauwenberghe diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in index 458b74c49..50edfdcd9 100644 --- a/verilator-config.cmake.in +++ b/verilator-config.cmake.in @@ -163,7 +163,9 @@ function(verilate TARGET) endforeach() string(TOLOWER ${CMAKE_CXX_COMPILER_ID} COMPILER) - if (NOT COMPILER MATCHES "msvc|clang") + if (COMPILER STREQUAL "appleclang") + set(COMPILER clang) + elseif (NOT COMPILER MATCHES "^msvc$|^clang$") set(COMPILER gcc) endif() From 2b58e834ee32daf19c27408d2f9679865ccc3ec7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 23 Apr 2020 07:42:05 -0400 Subject: [PATCH 090/127] Tests: Rename IVERILOG define for consistency. No functional change. --- test_regress/driver.pl | 2 +- test_regress/t/t_mem_packed.v | 2 +- test_regress/t/t_vpi_get.v | 4 ++-- test_regress/t/t_vpi_memory.v | 2 +- test_regress/t/t_vpi_module.v | 2 +- test_regress/t/t_vpi_time_cb.pl | 2 +- test_regress/t/t_vpi_time_cb.v | 2 +- test_regress/t/t_vpi_var.v | 4 ++-- test_regress/t/t_vpi_zero_time_cb.pl | 2 +- test_regress/t/t_vpi_zero_time_cb.v | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index d523aac45..0010e3971 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -585,7 +585,7 @@ sub new { ghdl_run_flags => [], # IV iv => 0, - iv_flags => [split(/\s+/,"+define+iverilog -g2012 -o $self->{obj_dir}/simiv")], + iv_flags => [split(/\s+/,"+define+IVERILOG -g2012 -o $self->{obj_dir}/simiv")], iv_flags2 => [], # Overridden in some sim files iv_pli => 0, # need to use pli iv_run_flags => [], diff --git a/test_regress/t/t_mem_packed.v b/test_regress/t/t_mem_packed.v index 55ec2deca..52a38bf9d 100644 --- a/test_regress/t/t_mem_packed.v +++ b/test_regress/t/t_mem_packed.v @@ -18,7 +18,7 @@ module t (/*AUTOARG*/ //logic [3:3] [2:2] [1:1] log_p; //14 integer cyc; initial cyc = 0; -`ifdef iverilog +`ifdef IVERILOG reg [7:0] arr [3:0]; wire [7:0] arr_w [3:0]; `else diff --git a/test_regress/t/t_vpi_get.v b/test_regress/t/t_vpi_get.v index d6b120790..de893386b 100644 --- a/test_regress/t/t_vpi_get.v +++ b/test_regress/t/t_vpi_get.v @@ -43,7 +43,7 @@ extern "C" int mon_check(); integer status; -`ifdef iverilog +`ifdef IVERILOG // stop icarus optimizing signals away wire redundant = onebit | onetwo[1] | twoone | fourthreetwoone[3]; `endif @@ -57,7 +57,7 @@ extern "C" int mon_check(); `ifdef VERILATOR status = $c32("mon_check()"); `endif -`ifdef iverilog +`ifdef IVERILOG status = $mon_check(); `endif `ifndef USE_VPI_NOT_DPI diff --git a/test_regress/t/t_vpi_memory.v b/test_regress/t/t_vpi_memory.v index f140f12e0..de2d2b4a7 100644 --- a/test_regress/t/t_vpi_memory.v +++ b/test_regress/t/t_vpi_memory.v @@ -33,7 +33,7 @@ extern "C" int mon_check(); `ifdef VERILATOR status = $c32("mon_check()"); `endif -`ifdef iverilog +`ifdef IVERILOG status = $mon_check(); `endif `ifndef USE_VPI_NOT_DPI diff --git a/test_regress/t/t_vpi_module.v b/test_regress/t/t_vpi_module.v index f411143fd..e3490e5a4 100644 --- a/test_regress/t/t_vpi_module.v +++ b/test_regress/t/t_vpi_module.v @@ -42,7 +42,7 @@ extern "C" int mon_check(); `ifdef VERILATOR status = $c32("mon_check()"); `endif -`ifdef iverilog +`ifdef IVERILOG status = $mon_check(); `endif `ifndef USE_VPI_NOT_DPI diff --git a/test_regress/t/t_vpi_time_cb.pl b/test_regress/t/t_vpi_time_cb.pl index 94c01d0cb..512dbb1b7 100755 --- a/test_regress/t/t_vpi_time_cb.pl +++ b/test_regress/t/t_vpi_time_cb.pl @@ -15,7 +15,7 @@ compile( make_main => 0, make_pli => 1, sim_time => 2100, - iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -DWAVES -Diverilog"], + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -DWAVES -DIVERILOG"], v_flags2 => ["+define+USE_VPI_NOT_DPI"], verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_time_cb.cpp -LDFLAGS '-ldl -rdynamic'"], ); diff --git a/test_regress/t/t_vpi_time_cb.v b/test_regress/t/t_vpi_time_cb.v index 96f5ba107..a2410c7c5 100644 --- a/test_regress/t/t_vpi_time_cb.v +++ b/test_regress/t/t_vpi_time_cb.v @@ -87,7 +87,7 @@ endmodule : t module sub; reg subsig1 /*verilator public_flat_rd*/; reg subsig2 /*verilator public_flat_rd*/; -`ifdef iverilog +`ifdef IVERILOG // stop icarus optimizing signals away wire redundant = subsig1 | subsig2; `endif diff --git a/test_regress/t/t_vpi_var.v b/test_regress/t/t_vpi_var.v index 74119a4dc..206b38584 100644 --- a/test_regress/t/t_vpi_var.v +++ b/test_regress/t/t_vpi_var.v @@ -57,7 +57,7 @@ extern "C" int mon_check(); `ifdef VERILATOR status = $c32("mon_check()"); `endif -`ifdef iverilog +`ifdef IVERILOG status = $mon_check(); `endif `ifndef USE_VPI_NOT_DPI @@ -100,7 +100,7 @@ endmodule : t module sub; reg subsig1 /*verilator public_flat_rd*/; reg subsig2 /*verilator public_flat_rd*/; -`ifdef iverilog +`ifdef IVERILOG // stop icarus optimizing signals away wire redundant = subsig1 | subsig2; `endif diff --git a/test_regress/t/t_vpi_zero_time_cb.pl b/test_regress/t/t_vpi_zero_time_cb.pl index 58239f1a7..717592491 100755 --- a/test_regress/t/t_vpi_zero_time_cb.pl +++ b/test_regress/t/t_vpi_zero_time_cb.pl @@ -15,7 +15,7 @@ compile( make_main => 0, make_pli => 1, sim_time => 2100, - iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -DWAVES -Diverilog"], + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -DWAVES -DIVERILOG"], v_flags2 => ["+define+USE_VPI_NOT_DPI"], verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_zero_time_cb.cpp -LDFLAGS '-ldl -rdynamic'"], ); diff --git a/test_regress/t/t_vpi_zero_time_cb.v b/test_regress/t/t_vpi_zero_time_cb.v index 052b9f4ba..f88aa8e8c 100644 --- a/test_regress/t/t_vpi_zero_time_cb.v +++ b/test_regress/t/t_vpi_zero_time_cb.v @@ -87,7 +87,7 @@ endmodule : t module sub; reg subsig1 /*verilator public_flat_rd*/; reg subsig2 /*verilator public_flat_rd*/; -`ifdef iverilog +`ifdef IVERILOG // stop icarus optimizing signals away wire redundant = subsig1 | subsig2; `endif From ace35b3e81657b12b320957b8d88da601cf8cb75 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 23 Apr 2020 08:04:15 -0400 Subject: [PATCH 091/127] Tests: Add -G test. --- test_regress/t/t_flag_parameter_hier.pl | 33 ++++++++++ test_regress/t/t_flag_parameter_hier.v | 83 +++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100755 test_regress/t/t_flag_parameter_hier.pl create mode 100644 test_regress/t/t_flag_parameter_hier.v diff --git a/test_regress/t/t_flag_parameter_hier.pl b/test_regress/t/t_flag_parameter_hier.pl new file mode 100755 index 000000000..0bf458d34 --- /dev/null +++ b/test_regress/t/t_flag_parameter_hier.pl @@ -0,0 +1,33 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + # For Verilator, all PARAMs at all levels are overwridden + # Error if parameter not found + #verilator_flags2 => ['-GPARAM=10 -Gtop.t.x.HIER=20'], # HIER would error + verilator_flags2 => ['-GPARAM=10'], + # For NC, always implies a hierarchy, only HIER will be set + # Warns if sets nothing + nc_flags2 => ['+defparam+PARAM=10 +defparam+top.t.x.HIER=20'], + # For VCS, all PARAMs at all levels are overridden. Hierarchy not allowed. + # Informational on all overrides + vcs_flags2 => ['-pvalue+PARAM=10 -px.HIER=20'], + # For icarus -P without hierarchy does nothing, only can ref into top + iv_flags2 => ['-PPARAM=10', '-Ptop.HIER=30', '-Ptop.t.x.HIER=20'], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_parameter_hier.v b/test_regress/t/t_flag_parameter_hier.v new file mode 100644 index 000000000..e5ee4a84a --- /dev/null +++ b/test_regress/t/t_flag_parameter_hier.v @@ -0,0 +1,83 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2016 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define check(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: %m: Wrong parameter value\n", `__FILE__,`__LINE__); $stop; end while(0); + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + u u (); + tx x (); + + parameter PARAM = 0; + parameter HIER = 0; + initial begin + $display("%m PARAM=%0d HIER=%0d", PARAM, HIER); +`ifdef IVERILOG + `check(PARAM, 0); +`elsif NC + `check(PARAM, 0); +`elsif VCS + `check(PARAM, 10); +`else + `check(PARAM, 10); +`endif + + `check(HIER, 0); + end + always @ (posedge clk) begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule + +module u; + ux x(); +endmodule + +module ux; + parameter PARAM = 0; + parameter HIER = 0; + initial begin + $display("%m PARAM=%0d HIER=%0d", PARAM, HIER); +`ifdef IVERILOG + `check(PARAM, 0); +`elsif NC + `check(PARAM, 0); +`elsif VCS + `check(PARAM, 10); +`else + `check(PARAM, 0); +`endif + `check(HIER, 0); + end +endmodule + +module tx; + parameter PARAM = 0; + parameter HIER = 0; + initial begin + $display("%m PARAM=%0d HIER=%0d", PARAM, HIER); +`ifdef IVERILOG + `check(PARAM, 0); +`elsif NC + `check(PARAM, 10); +`elsif VCS + `check(PARAM, 10); +`else + `check(PARAM, 0); +`endif +`ifdef NC + `check(HIER, 20); +`else + `check(HIER, 0); +`endif + end +endmodule From 8208fe8a0e529415b3fc33f6557ef9b179f2c709 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 23 Apr 2020 22:29:37 +0100 Subject: [PATCH 092/127] Fix test failures on Ubuntu 20.04 (#2278) - Packaged SystemC lives in /usr so needed to update regex in test driver - Clang 10 complains about mixed named and positional initializers in struct definitions. --- test_regress/driver.pl | 2 +- test_regress/t/t_vpi_get.cpp | 2 +- test_regress/t/t_vpi_memory.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 0010e3971..c5878a27e 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2015,7 +2015,7 @@ sub files_identical { && !/^- [a-z.0-9]+:\d+:[^\n]+\n/ && !/^-node:/ && !/^dot [^\n]+\n/ - && !/^In file: \/.*\/systemc-\d\.\d\.\d\/.*:\d+/ + && !/^In file: .*\/sc_.*:\d+/ } @l1; @l1 = map { s/(Internal Error: [^\n]+\.cpp):[0-9]+:/$1:#:/; diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index 3f66a7f10..0dd2e7541 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -82,7 +82,7 @@ unsigned int main_time = 0; #define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp) static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int scalar, int type) { - s_vpi_value value = {vpiIntVal, .value = {.integer = 0}}; + s_vpi_value value = {.format = vpiIntVal, .value = {.integer = 0}}; // check size of object int vpisize = vpi_get(vpiSize, handle); CHECK_RESULT(vpisize, size); diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index 74ace580f..5b229b78b 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -83,7 +83,7 @@ unsigned int main_time = 0; int _mon_check_range(TestVpiHandle& handle, int size, int left, int right) { TestVpiHandle iter_h, left_h, right_h; - s_vpi_value value = {vpiIntVal, .value = {.integer = 0}}; + s_vpi_value value = {.format = vpiIntVal, .value = {.integer = 0}}; // check size of object int vpisize = vpi_get(vpiSize, handle); CHECK_RESULT(vpisize, size); @@ -112,7 +112,7 @@ int _mon_check_memory() { int cnt; TestVpiHandle mem_h, lcl_h; vpiHandle iter_h; // Icarus does not like auto free of iterator handles - s_vpi_value value = {vpiIntVal, .value = {.integer = 0}}; + s_vpi_value value = {.format = vpiIntVal, .value = {.integer = 0}}; vpi_printf((PLI_BYTE8*)"Check memory vpi ...\n"); mem_h = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted("mem0"), NULL); CHECK_RESULT_NZ(mem_h); From 6ed10b7fde1f2194c22345055f63294420b142d0 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 23 Apr 2020 22:30:23 +0100 Subject: [PATCH 093/127] Fix --protect-lib generated library link rules (#2279) We used to include a .cpp file on the link line for the shared library, which was ignored, but generated a .d file for the .so which contained the header files required by the .cpp file. This then caused a rebuild where we included the .d in verilated.mk to included in the .h headers among the prerequisites of the .so, yielding a clang error about treating .h files as c++-header rather than c-header... Long story short, we don't do that anymore. This used t cause t_a4_examples to fail on occasion. Note there is no need for a separate compilation rule for the <--protect-lib>.cpp, as it will jsut pick up the standard OPT_FAST rule. --- src/V3EmitMk.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index a2710f70a..af8be2aa9 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -241,19 +241,14 @@ public: } if (!v3Global.opt.protectLib().empty()) { - of.puts("\n### Library rules... (from --protect-lib)\n"); - of.puts("# Using -fPIC objects for both static and dynamic libraries " - "(which appears to work)\n"); - of.puts(v3Global.opt.protectLibName(false) + ": $(VK_OBJS) $(VK_GLOBAL_OBJS)\n"); - of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o " - + v3Global.opt.protectLib() + ".o " + v3Global.opt.protectLib() + ".cpp\n"); - of.puts("\tar rc $@ $^ " + v3Global.opt.protectLib() + ".o\n"); + const string protectLibDeps + = "$(VK_OBJS) $(VK_GLOBAL_OBJS) " + v3Global.opt.protectLib() + ".o"; + of.puts("\n### Library rules from --protect-lib\n"); + of.puts(v3Global.opt.protectLibName(false) + ": " + protectLibDeps + "\n"); + of.puts("\tar rc $@ $^\n"); of.puts("\n"); - - of.puts(v3Global.opt.protectLibName(true) - + ": $(VM_PREFIX)__ALL.a $(VK_GLOBAL_OBJS)\n"); - of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ " - + v3Global.opt.protectLib() + ".cpp $^\n"); + of.puts(v3Global.opt.protectLibName(true) + ": " + protectLibDeps + "\n"); + of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ $^\n"); of.puts("\n"); of.puts("lib" + v3Global.opt.protectLib() + ": " + v3Global.opt.protectLibName(false) From f93ae707e0ad11cf751798348d44f97b6349e7c5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 23 Apr 2020 19:56:02 -0400 Subject: [PATCH 094/127] Tests: Add bad option test. --- src/V3Options.cpp | 4 ++-- test_regress/t/t_flag_invalid2_bad.out | 1 + test_regress/t/t_flag_invalid2_bad.pl | 21 +++++++++++++++++++++ test_regress/t/t_flag_invalid_bad.out | 1 + test_regress/t/t_flag_invalid_bad.pl | 21 +++++++++++++++++++++ 5 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 test_regress/t/t_flag_invalid2_bad.out create mode 100755 test_regress/t/t_flag_invalid2_bad.pl create mode 100644 test_regress/t/t_flag_invalid_bad.out create mode 100755 test_regress/t/t_flag_invalid_bad.pl diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 1d4000b87..a39b2387b 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -804,7 +804,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char } else if (!strcmp(sw, "+librescan")) { // NOP } else if (!strcmp(sw, "+notimingchecks")) { // NOP } else { - fl->v3fatal("Invalid Option: " << argv[i]); + fl->v3fatal("Invalid option: " << argv[i]); } shift; } @@ -1293,7 +1293,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char shift; addIncDirUser(parseFileArg(optdir, string(argv[i]))); } else { - fl->v3fatal("Invalid Option: " << argv[i]); + fl->v3fatal("Invalid option: " << argv[i]); } shift; } // - options diff --git a/test_regress/t/t_flag_invalid2_bad.out b/test_regress/t/t_flag_invalid2_bad.out new file mode 100644 index 000000000..e84f9a0d8 --- /dev/null +++ b/test_regress/t/t_flag_invalid2_bad.out @@ -0,0 +1 @@ +%Error: Invalid option: +invalid-plus diff --git a/test_regress/t/t_flag_invalid2_bad.pl b/test_regress/t/t_flag_invalid2_bad.pl new file mode 100755 index 000000000..42e60b698 --- /dev/null +++ b/test_regress/t/t_flag_invalid2_bad.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + fails => 1, + verilator_flags2 => ['+invalid-plus'], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_flag_invalid_bad.out b/test_regress/t/t_flag_invalid_bad.out new file mode 100644 index 000000000..54d2f3d73 --- /dev/null +++ b/test_regress/t/t_flag_invalid_bad.out @@ -0,0 +1 @@ +%Error: Invalid option: --invalid-dash diff --git a/test_regress/t/t_flag_invalid_bad.pl b/test_regress/t/t_flag_invalid_bad.pl new file mode 100755 index 000000000..71aee1a28 --- /dev/null +++ b/test_regress/t/t_flag_invalid_bad.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + fails => 1, + verilator_flags2 => ['--invalid-dash'], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; From df52e481fb5b03338d45cc881270e75ba8c02108 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 23 Apr 2020 21:22:47 -0400 Subject: [PATCH 095/127] Collected minor output code cleanups. --- include/verilated.h | 8 ++++++-- include/verilatedos.h | 2 ++ src/V3EmitC.cpp | 8 +++++--- src/V3EmitCMain.cpp | 13 +++++++++---- src/V3Options.cpp | 4 ++++ 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index c2bc2bfad..086838c47 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -853,9 +853,13 @@ double vl_time_multiplier(int scale); /// Evaluate expression if debug enabled #ifdef VL_DEBUG -# define VL_DEBUG_IF(text) {if (VL_UNLIKELY(Verilated::debug())) {text}} +# define VL_DEBUG_IF(text) \ + do { \ + if (VL_UNLIKELY(Verilated::debug())) {text} \ + } while (false) #else -# define VL_DEBUG_IF(text) +// We intentionally do not compile the text to improve compile speed +# define VL_DEBUG_IF(text) do {} while (false) #endif /// Collect coverage analysis for this line diff --git a/include/verilatedos.h b/include/verilatedos.h index ae2f14048..8f689190b 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -205,6 +205,7 @@ # define VL_INCLUDE_UNORDERED_SET # endif # define VL_FINAL final +# define VL_MUTABLE mutable # define VL_OVERRIDE override #else # define VL_EQ_DELETE @@ -212,6 +213,7 @@ # define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h" # define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h" # define VL_FINAL +# define VL_MUTABLE # define VL_OVERRIDE #endif diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 89053334c..28c3ace73 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2334,7 +2334,9 @@ void EmitCImp::emitDestructorImp(AstNodeModule* modp) { puts("\n"); puts(prefixNameProtect(modp) + "::~" + prefixNameProtect(modp) + "() {\n"); if (modp->isTop()) { - if (v3Global.opt.mtasks()) puts("delete __Vm_threadPoolp; __Vm_threadPoolp = NULL;\n"); + if (v3Global.opt.mtasks()) { + puts("VL_DO_CLEAR(delete __Vm_threadPoolp, __Vm_threadPoolp = NULL);\n"); + } // Call via function in __Trace.cpp as this .cpp file does not have trace header if (v3Global.needTraceDumper()) { puts("#ifdef VM_TRACE\n"); @@ -2343,7 +2345,7 @@ void EmitCImp::emitDestructorImp(AstNodeModule* modp) { } } emitTextSection(AstType::atScDtor); - if (modp->isTop()) puts("delete __VlSymsp; __VlSymsp=NULL;\n"); + if (modp->isTop()) puts("VL_DO_CLEAR(delete __VlSymsp, __VlSymsp = NULL);\n"); puts("}\n"); splitSizeInc(10); } @@ -3326,7 +3328,7 @@ class EmitCTrace : EmitCStmts { puts("void " + topClassName() + "::_traceDumpClose() {\n"); puts("VerilatedLockGuard lock(__VlSymsp->__Vm_dumperMutex);\n"); puts("__VlSymsp->__Vm_dumping = false;\n"); - puts("delete __VlSymsp->__Vm_dumperp; __VlSymsp->__Vm_dumperp = NULL;\n"); + puts("VL_DO_CLEAR(delete __VlSymsp->__Vm_dumperp, __VlSymsp->__Vm_dumperp = NULL);\n"); puts("}\n"); splitSizeInc(10); } diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index 14e67ed2a..f74bae3b0 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -76,10 +76,15 @@ private: puts("// Simulate until $finish\n"); puts("while (!Verilated::gotFinish()) {\n"); - /**/ puts("// Evaluate model\n"); - /**/ puts("topp->eval();\n"); - /**/ puts("// Advance time\n"); - /**/ puts("++main_time;\n"); + puts(/**/ "// Evaluate model\n"); + puts(/**/ "topp->eval();\n"); + puts(/**/ "// Advance time\n"); + puts(/**/ "++main_time;\n"); + puts("}\n"); + puts("\n"); + + puts("if (!Verilated::gotFinish()) {\n"); + puts(/**/ "VL_DEBUG_IF(VL_PRINTF(\"+ Exiting without $finish; no events left\\n\"););\n"); puts("}\n"); puts("\n"); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index a39b2387b..29b058b72 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -633,6 +633,10 @@ void V3Options::notify() { && !v3Global.opt.xmlOnly()); } + if (v3Global.opt.main() && v3Global.opt.systemC()) { + cmdfl->v3error("--main not usable with SystemC. Suggest see examples for sc_main()."); + } + // --trace-threads implies --threads 1 unless explicitly specified if (traceThreads() && !threads()) m_threads = 1; From 27f4399c31c10e4c6981ee0e6124435995c5ada7 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 24 Apr 2020 02:27:06 +0100 Subject: [PATCH 096/127] Fix tests failing on rerun after passing from clean. (#2281) --- test_regress/driver.pl | 5 +++++ test_regress/t/t_flag_build_cmake.pl | 5 +++++ test_regress/t/t_flag_verilate.pl | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index c5878a27e..9e3733dfa 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -806,6 +806,11 @@ sub clean { } } +sub clean_objs { + my $self = (ref $_[0] ? shift : $Self); + system("rm", "-rf", glob("$self->{obj_dir}/*")); +} + sub compile_vlt_cmd { my $self = (ref $_[0]? shift : $Self); my %param = (%{$self}, @_); # Default arguments are from $self diff --git a/test_regress/t/t_flag_build_cmake.pl b/test_regress/t/t_flag_build_cmake.pl index a58be70f6..1c189d3c3 100755 --- a/test_regress/t/t_flag_build_cmake.pl +++ b/test_regress/t/t_flag_build_cmake.pl @@ -12,6 +12,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_flag_make_cmake.v"); +# This test seems broken as the CMake build invoked by Verilator itself +# invokes Verilator.. (See #2280). Strangely though it passes when built +# from clean, so nuke it: +clean_objs(); + compile( # Don't call cmake nor gmake from driver.pl verilator_make_cmake => 0, verilator_make_gmake => 0, diff --git a/test_regress/t/t_flag_verilate.pl b/test_regress/t/t_flag_verilate.pl index c28d235b6..b523b77e3 100755 --- a/test_regress/t/t_flag_verilate.pl +++ b/test_regress/t/t_flag_verilate.pl @@ -12,6 +12,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_flag_make_cmake.v"); +# We expect below that Vt_flag_verilate.mk and others are not in the build +# tree already when doing --no-verilate, so we must remove them when +# re-running the test. +clean_objs(); + compile( # Don't call cmake nor gmake from driver.pl. Nothing should be done here. verilator_make_cmake => 0, verilator_make_gmake => 0, From c1665818b955c4730896315a580d0bbaffb3d95a Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 24 Apr 2020 03:09:26 +0100 Subject: [PATCH 097/127] Fix missing flush with threaded VCD tracing. (#2282) VerilatedVcdC::openNext() failed to flush the tracing thread before opening the next output file, which caused t_trace_cat.pl to fail with --vltmt on occasion. --- include/verilated_vcd_c.cpp | 12 ++++++------ include/verilated_vcd_c.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index c5ad6f7bb..9f5befff3 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -294,18 +294,17 @@ void VerilatedVcd::close() { // This function is on the flush() call path m_assertOne.check(); if (!isOpen()) return; - VerilatedTrace::close(); if (m_evcd) { printStr("$vcdclose "); printQuad(timeLastDump()); printStr(" $end\n"); } closePrev(); -} - -void VerilatedVcd::flush() { - VerilatedTrace::flush(); - bufferFlush(); + // closePrev() already called VerilatedTrace::flush() via + // bufferFlush(), and there were no opportunities to enqueue further + // buffers as this close() is running on the main thread the same as dump() + // so just shutting down the trace thread will suffice. + VerilatedTrace::close(); } void VerilatedVcd::printStr(const char* str) { @@ -343,6 +342,7 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE { // This is much faster than using buffered I/O m_assertOne.check(); if (VL_UNLIKELY(!isOpen())) return; + VerilatedTrace::flush(); char* wp = m_wrBufp; while (true) { ssize_t remaining = (m_writep - wp); diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index e9838c15b..0ee8084c8 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -149,7 +149,7 @@ public: /// Close the file void close() VL_MT_UNSAFE_ONE; /// Flush any remaining data to this file - void flush() VL_MT_UNSAFE_ONE; + void flush() VL_MT_UNSAFE_ONE { bufferFlush(); } /// Is file open? bool isOpen() const { return m_isOpen; } From 10b4678ee6b307ed44e40204302d2838600bade9 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 24 Apr 2020 04:53:22 +0100 Subject: [PATCH 098/127] Make vgen.pl deterministic --- test_regress/vgen.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/vgen.pl b/test_regress/vgen.pl index 03bd0b6f1..112e083ba 100755 --- a/test_regress/vgen.pl +++ b/test_regress/vgen.pl @@ -322,7 +322,7 @@ sub rnd_op { } my $chooseweight = rnd($totweight); $totweight = 0; - foreach my $opref (values %Ops) { + foreach my $opref (sort {$a->{name} cmp $b->{name}} values %Ops) { if (_rnd_op_ok($opref,$paramref)) { $totweight += $opref->{weight}; if ($chooseweight < $totweight) { From 3b37b5b92d050a8f14c705002618d63b522c7ce8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 24 Apr 2020 08:22:19 -0400 Subject: [PATCH 099/127] Tests: Check output from some unsupported tests. --- test_regress/t/t_array_packed_write_read.v | 2 +- test_regress/t/t_iff.out | 7 ++++++ test_regress/t/t_iff.pl | 9 ++++---- test_regress/t/t_param_avec.out | 5 +++++ test_regress/t/t_param_avec.pl | 9 ++++---- test_regress/t/t_sv_bus_mux_demux.v | 2 +- .../sv_bus_mux_demux_mux.sv | 2 +- test_regress/t/t_udp_noname.out | 4 ++++ test_regress/t/t_udp_noname.pl | 9 ++++---- test_regress/t/t_var_static.out | 22 +++++++++++++++++++ test_regress/t/t_var_static.pl | 9 ++++---- 11 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 test_regress/t/t_iff.out create mode 100644 test_regress/t/t_param_avec.out create mode 100644 test_regress/t/t_udp_noname.out create mode 100644 test_regress/t/t_var_static.out diff --git a/test_regress/t/t_array_packed_write_read.v b/test_regress/t/t_array_packed_write_read.v index 99aae9117..0da8351b4 100644 --- a/test_regress/t/t_array_packed_write_read.v +++ b/test_regress/t/t_array_packed_write_read.v @@ -27,7 +27,7 @@ module t (/*AUTOARG*/ // msg926 logic [3:0][31:0] packedArray; - initial packedArray <= '0; + initial packedArray = '0; // event counter always @ (posedge clk) begin diff --git a/test_regress/t/t_iff.out b/test_regress/t/t_iff.out new file mode 100644 index 000000000..6680a685b --- /dev/null +++ b/test_regress/t/t_iff.out @@ -0,0 +1,7 @@ +%Error: t/t_iff.v:64:15: syntax error, unexpected iff, expecting ')' or ',' or or + 64 | always @(d iff enable == 1) begin + | ^~~ +%Error: t/t_iff.v:69:35: syntax error, unexpected iff, expecting ')' + 69 | assert property (@(posedge clk iff enable) + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_iff.pl b/test_regress/t/t_iff.pl index 5fb4f0f50..63ac7c585 100755 --- a/test_regress/t/t_iff.pl +++ b/test_regress/t/t_iff.pl @@ -9,14 +9,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 scenarios(simulator => 1); -$Self->{vlt_all} and unsupported("Verilator unsupported, bug1482, iff not supported"); compile( + expect_filename => $Self->{golden_filename}, + fails => $Self->{vlt_all}, # Verilator unsupported, bug1482, iff not supported ); -execute( - check_finished => 1, - ); +#execute( +# check_finished => 1, +# ); ok(1); 1; diff --git a/test_regress/t/t_param_avec.out b/test_regress/t/t_param_avec.out new file mode 100644 index 000000000..842a71140 --- /dev/null +++ b/test_regress/t/t_param_avec.out @@ -0,0 +1,5 @@ +%Error: t/t_param_avec.v:34:43: Expecting expression to be constant, but variable isn't const: 'array' + : ... In instance t.i0 + 34 | localparam elementf = get_element(IDX, array); + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_param_avec.pl b/test_regress/t/t_param_avec.pl index 8271e4b7c..44c71cb71 100755 --- a/test_regress/t/t_param_avec.pl +++ b/test_regress/t/t_param_avec.pl @@ -9,14 +9,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 scenarios(simulator => 1); -$Self->{vlt_all} and unsupported("Verilator unsupported, bug477"); compile( + fails => $Self->{vlt_all}, # Verilator unsupported, bug477 + expect_filename => $Self->{golden_filename}, ); -execute( - check_finished => 1, - ); +#execute( +# check_finished => 1, +# ); ok(1); 1; diff --git a/test_regress/t/t_sv_bus_mux_demux.v b/test_regress/t/t_sv_bus_mux_demux.v index 445cda1d2..39bbb1b71 100644 --- a/test_regress/t/t_sv_bus_mux_demux.v +++ b/test_regress/t/t_sv_bus_mux_demux.v @@ -191,4 +191,4 @@ always @ (posedge clk, posedge rst) if (rst) bso_rdy = 1'b0; else bso_rdy = 1'b1; -endmodule : sv_bus_mux_demux_tb +endmodule diff --git a/test_regress/t/t_sv_bus_mux_demux/sv_bus_mux_demux_mux.sv b/test_regress/t/t_sv_bus_mux_demux/sv_bus_mux_demux_mux.sv index 8c70875ad..4d963545b 100644 --- a/test_regress/t/t_sv_bus_mux_demux/sv_bus_mux_demux_mux.sv +++ b/test_regress/t/t_sv_bus_mux_demux/sv_bus_mux_demux_mux.sv @@ -56,7 +56,7 @@ else str_vld <= bus_trn | (str_vld & ~pkt_end); // packet byte counter always @ (posedge clk, posedge rst) -if (rst) pkt_cnt <= 4'd0; +if (rst) pkt_cnt <= '0; else if (str_trn) pkt_cnt <= pkt_cnt + 3'd1; // packet byte counter end diff --git a/test_regress/t/t_udp_noname.out b/test_regress/t/t_udp_noname.out new file mode 100644 index 000000000..c82b2ceaf --- /dev/null +++ b/test_regress/t/t_udp_noname.out @@ -0,0 +1,4 @@ +%Error: t/t_udp_noname.v:15:9: syntax error, unexpected '(', expecting IDENTIFIER + 15 | udp (o, a); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_udp_noname.pl b/test_regress/t/t_udp_noname.pl index cf8db6e7e..1de24403a 100755 --- a/test_regress/t/t_udp_noname.pl +++ b/test_regress/t/t_udp_noname.pl @@ -9,14 +9,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 scenarios(simulator => 1); -$Self->{vlt_all} and unsupported("Verilator unsupported, bug468"); compile( + expect_filename => $Self->{golden_filename}, + fails => $Self->{vlt_all}, # Verilator unsupported, bug468" ); -execute( - check_finished => 1, - ); +#execute( +# check_finished => 1, +# ); ok(1); 1; diff --git a/test_regress/t/t_var_static.out b/test_regress/t/t_var_static.out new file mode 100644 index 000000000..3103c2e9b --- /dev/null +++ b/test_regress/t/t_var_static.out @@ -0,0 +1,22 @@ +%Error: t/t_var_static.v:20:7: Unsupported: Static in this context + 20 | static int st = 2; st++; return st; + | ^~~~~~ +%Error: t/t_var_static.v:26:13: Unsupported: Static in this context + 26 | function static int f_st_no (); + | ^~~~~~ +%Error: t/t_var_static.v:29:13: Unsupported: Static in this context + 29 | function static int f_st_st (); + | ^~~~~~ +%Error: t/t_var_static.v:30:7: Unsupported: Static in this context + 30 | static int st = 2; st++; return st; + | ^~~~~~ +%Error: t/t_var_static.v:32:13: Unsupported: Static in this context + 32 | function static int f_st_au (); + | ^~~~~~ +%Error: t/t_var_static.v:40:7: Unsupported: Static in this context + 40 | static int st = 2; st++; return st; + | ^~~~~~ +%Error: t/t_var_static.v:73:7: Unsupported: Static in this context + 73 | static int ist2; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_var_static.pl b/test_regress/t/t_var_static.pl index 0194e8e7d..1676c3883 100755 --- a/test_regress/t/t_var_static.pl +++ b/test_regress/t/t_var_static.pl @@ -9,14 +9,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 scenarios(simulator => 1); -$Self->{vlt_all} and unsupported("Verilator unsupported, bug546"); compile( + expect_filename => $Self->{golden_filename}, + fails => $Self->{vlt_all} # Verilator unsupported, bug546 ); -execute( - check_finished => 1, - ); +#execute( +# check_finished => 1, +# ); ok(1); 1; From e2cbcd37d822a3efefc0e8c5845505bbc0dbc900 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 24 Apr 2020 18:43:02 -0400 Subject: [PATCH 100/127] Commentary --- docs/install.adoc | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/install.adoc b/docs/install.adoc index 3d8c9fd5e..8293479f0 100644 --- a/docs/install.adoc +++ b/docs/install.adoc @@ -78,18 +78,7 @@ MSVC++. === Install Prerequisites -To build Verilator you will need to install some standard packages: - - sudo apt-get install git - sudo apt-get install autoconf - sudo apt-get install flex bison - -The following are optional, but should be installed to improve compilation speed: - - sudo apt-get install ccache - sudo apt-get install libgoogle-perftools-dev - -Additionally, to build or run Verilator you need these standard packages: +To build or run Verilator you need these standard packages: sudo apt-get install perl python3 sudo apt-get install make @@ -97,7 +86,20 @@ Additionally, to build or run Verilator you need these standard packages: sudo apt-get install libgz # Non-Ubuntu (ignore if gives error) sudo apt-get install libfl2 libfl-dev zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error) -Those developing Verilator may also want these (see internals.adoc): +To build or run the following are optional but should be installed for +good performance: + + sudo apt-get install ccache # If present at build, needed for run + sudo apt-get install libgoogle-perftools-dev + +To build Verilator you will need to install these packages; these do not +need to be present to run Verilator: + + sudo apt-get install git + sudo apt-get install autoconf + sudo apt-get install flex bison + +Those developing Verilator itself may also want these (see internals.adoc): sudo apt-get install gdb asciidoctor graphviz cmake cpan install Pod::Perldoc From 5e575f5906d516a4ebea61f07160d52c7c37b5cf Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 24 Apr 2020 19:34:26 -0400 Subject: [PATCH 101/127] Fix line numbers in tables. --- src/verilog.l | 1 + 1 file changed, 1 insertion(+) diff --git a/src/verilog.l b/src/verilog.l index 6c4e01df9..239912a5f 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -938,6 +938,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} {crnl} { yymore(); }
";" { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLELINE; }
"endtable" { yy_pop_state(); FL; return yENDTABLE; } +
"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->ppline(yytext); FL_BRK; }
. { yymore(); }
<> { FL_FWD; yyerrorf("EOF in TABLE"); yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); } From 1381d3dbdedd8042d7737925c69f8f90f56fa07d Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 25 Apr 2020 16:29:42 +0100 Subject: [PATCH 102/127] Add -Wno-tautological-bitwise-compare to model build flags (#2285) This appeases Clang 10. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index fd93c6580..401747ff9 100644 --- a/configure.ac +++ b/configure.ac @@ -334,6 +334,7 @@ m4_foreach([cflag],[ [-mno-cet], [-Qunused-arguments], [-Wno-bool-operation], + [-Wno-tautological-bitwise-compare], [-Wno-parentheses-equality], [-Wno-sign-compare], [-Wno-uninitialized], From 9991b196100873121d054ce95a11faae786138ef Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 25 Apr 2020 18:29:27 +0100 Subject: [PATCH 103/127] Another attempt at flushing threaded VCD correctly. --- include/verilated_vcd_c.cpp | 14 +++++++++----- include/verilated_vcd_c.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 9f5befff3..f52c80882 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -274,6 +274,7 @@ void VerilatedVcd::closePrev() { // This function is on the flush() call path if (!isOpen()) return; + VerilatedTrace::flush(); bufferFlush(); m_isOpen = false; m_filep->close(); @@ -300,13 +301,16 @@ void VerilatedVcd::close() { printStr(" $end\n"); } closePrev(); - // closePrev() already called VerilatedTrace::flush() via - // bufferFlush(), and there were no opportunities to enqueue further - // buffers as this close() is running on the main thread the same as dump() - // so just shutting down the trace thread will suffice. + // closePrev() called VerilatedTrace::flush(), so we just + // need to shut down the tracing thread here. VerilatedTrace::close(); } +void VerilatedVcd::flush() { + VerilatedTrace::flush(); + bufferFlush(); +} + void VerilatedVcd::printStr(const char* str) { // Not fast... while (*str) { @@ -336,13 +340,13 @@ void VerilatedVcd::bufferResize(vluint64_t minsize) { } void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE { + // This function can be called from the trace thread // This function is on the flush() call path // We add output data to m_writep. // When it gets nearly full we dump it using this routine which calls write() // This is much faster than using buffered I/O m_assertOne.check(); if (VL_UNLIKELY(!isOpen())) return; - VerilatedTrace::flush(); char* wp = m_wrBufp; while (true) { ssize_t remaining = (m_writep - wp); diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 0ee8084c8..e9838c15b 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -149,7 +149,7 @@ public: /// Close the file void close() VL_MT_UNSAFE_ONE; /// Flush any remaining data to this file - void flush() VL_MT_UNSAFE_ONE { bufferFlush(); } + void flush() VL_MT_UNSAFE_ONE; /// Is file open? bool isOpen() const { return m_isOpen; } From 87e1c36e4a4c4a2bd44e8a886b8344aad380a9e6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 25 Apr 2020 15:37:46 -0400 Subject: [PATCH 104/127] Support event data type (with some restrictions). --- Changes | 2 + src/V3Active.cpp | 10 +++ src/V3Ast.h | 18 ++-- src/V3AstNodes.h | 1 + src/V3Delayed.cpp | 17 +++- src/V3Width.cpp | 20 +++++ src/verilog.y | 11 ++- test_regress/t/t_event.pl | 21 +++++ test_regress/t/t_event.v | 81 ++++++++++++++++++ test_regress/t/t_event_copy.out | 9 ++ test_regress/t/t_event_copy.pl | 23 ++++++ test_regress/t/t_event_copy.v | 142 ++++++++++++++++++++++++++++++++ 12 files changed, 344 insertions(+), 11 deletions(-) create mode 100755 test_regress/t/t_event.pl create mode 100644 test_regress/t/t_event.v create mode 100644 test_regress/t/t_event_copy.out create mode 100755 test_regress/t/t_event_copy.pl create mode 100644 test_regress/t/t_event_copy.v diff --git a/Changes b/Changes index 483d49ecd..03d6ec43f 100644 --- a/Changes +++ b/Changes @@ -26,6 +26,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Support $ferror, and $fflush without arguments, #1638. +**** Support event data type (with some restrictions). + **** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. **** Greatly improve FST/VCD dump performance, #2244, #2246, #2250, #2257. [Geza Lore] diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 42c3ea5d1..13689cb9f 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -388,6 +388,16 @@ private: iterateChildren(nodep); } virtual void visit(AstSenItem* nodep) VL_OVERRIDE { + if (nodep->varrefp()) { + if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) { + if (basicp->isEventValue()) { + // Events need to be treated as active high so we only activate on event being + // 1 + UINFO(8, "Demote event to HIGHEDGE " << nodep << endl); + nodep->edgeType(VEdgeType::ET_HIGHEDGE); + } + } + } if (nodep->edgeType() == VEdgeType::ET_ANYEDGE) { m_itemCombo = true; // Delete the sensitivity diff --git a/src/V3Ast.h b/src/V3Ast.h index 2fd9c30ce..19a1fd6dc 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -372,6 +372,7 @@ public: BIT, BYTE, CHANDLE, + EVENTVALUE, // See comments in t_event_copy as to why this is EVENTVALUE INT, INTEGER, LOGIC, @@ -396,14 +397,16 @@ public: enum en m_e; const char* ascii() const { static const char* const names[] = { - "%E-unk", "bit", "byte", "chandle", "int", "integer", "logic", + "%E-unk", // + "bit", "byte", "chandle", "event", "int", "integer", "logic", "longint", "real", "shortint", "shortreal", "time", "string", "VerilatedScope*", "char*", "IData", "QData", "LOGIC_IMPLICIT", " MAX"}; return names[m_e]; } const char* dpiType() const { static const char* const names[] - = {"%E-unk", "svBit", "char", "void*", "int", "%E-integer", + = {"%E-unk", // + "svBit", "char", "void*", "char", "int", "%E-integer", "svLogic", "long long", "double", "short", "float", "%E-time", "const char*", "dpiScope", "const char*", "IData", "QData", "%E-logic-implicit", " MAX"}; @@ -428,6 +431,7 @@ public: case BIT: return 1; // scalar, can't bit extract unless ranged case BYTE: return 8; case CHANDLE: return 64; + case EVENTVALUE: return 1; case INT: return 32; case INTEGER: return 32; case LOGIC: return 1; // scalar, can't bit extract unless ranged @@ -449,15 +453,16 @@ public: || m_e == DOUBLE || m_e == FLOAT; } bool isUnsigned() const { - return m_e == CHANDLE || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR - || m_e == UINT32 || m_e == UINT64; + return m_e == CHANDLE || m_e == EVENTVALUE || m_e == STRING || m_e == SCOPEPTR + || m_e == CHARPTR || m_e == UINT32 || m_e == UINT64; } bool isFourstate() const { return m_e == INTEGER || m_e == LOGIC || m_e == LOGIC_IMPLICIT || m_e == TIME; } bool isZeroInit() const { // Otherwise initializes to X - return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == INT || m_e == LONGINT - || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE || m_e == FLOAT); + return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == EVENTVALUE || m_e == INT + || m_e == LONGINT || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE + || m_e == FLOAT); } bool isIntNumeric() const { // Enum increment supported return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC @@ -481,6 +486,7 @@ public: || m_e == FLOAT); } bool isDouble() const { return m_e == DOUBLE; } + bool isEventValue() const { return m_e == EVENTVALUE; } bool isString() const { return m_e == STRING; } }; inline bool operator==(const AstBasicDTypeKwd& lhs, const AstBasicDTypeKwd& rhs) { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 97014185a..602148564 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -840,6 +840,7 @@ public: } bool isBitLogic() const { return keyword().isBitLogic(); } bool isDouble() const { return keyword().isDouble(); } + bool isEventValue() const { return keyword().isEventValue(); } bool isOpaque() const { return keyword().isOpaque(); } bool isString() const { return keyword().isString(); } bool isSloppy() const { return keyword().isSloppy(); } diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index ecf80dccb..44b8bc858 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -385,6 +385,8 @@ private: nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for " "loops (non-delayed is ok - see docs)"); } + AstBasicDType* basicp = lhsp->dtypep()->basicp(); + if (basicp && basicp->isEventValue()) nodep->v3error("Unsupported: event arrays"); if (newlhsp) { nodep->lhsp(newlhsp); } else { @@ -418,9 +420,18 @@ private: if (!dlyvscp) { // First use of this delayed variable string newvarname = (string("__Vdly__") + nodep->varp()->shortName()); dlyvscp = createVarSc(oldvscp, newvarname, 0, NULL); - AstNodeAssign* prep = new AstAssignPre( - nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true), - new AstVarRef(nodep->fileline(), oldvscp, false)); + AstNodeAssign* prep; + AstBasicDType* basicp = oldvscp->dtypep()->basicp(); + if (basicp && basicp->isEventValue()) { + // Events go to zero on next timestep unless reactivated + prep = new AstAssignPre( + nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true), + new AstConst(nodep->fileline(), AstConst::LogicFalse())); + } else { + prep = new AstAssignPre(nodep->fileline(), + new AstVarRef(nodep->fileline(), dlyvscp, true), + new AstVarRef(nodep->fileline(), oldvscp, false)); + } AstNodeAssign* postp = new AstAssignPost( nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true), new AstVarRef(nodep->fileline(), dlyvscp, false)); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 36ff94be0..940adb4fb 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2025,6 +2025,8 @@ private: methodCallClass(nodep, adtypep); } else if (AstUnpackArrayDType* adtypep = VN_CAST(fromDtp, UnpackArrayDType)) { methodCallUnpack(nodep, adtypep); + } else if (basicp && basicp->isEventValue()) { + methodCallEvent(nodep, basicp); } else if (basicp && basicp->isString()) { methodCallString(nodep, basicp); } else { @@ -2431,6 +2433,18 @@ private: nodep->v3error("Unknown built-in array method " << nodep->prettyNameQ()); } } + void methodCallEvent(AstMethodCall* nodep, AstBasicDType* adtypep) { + // Method call on event + if (nodep->name() == "triggered") { + // We represent events as numbers, so can just return number + methodOkArguments(nodep, 0, 0); + AstNode* newp = nodep->fromp()->unlinkFrBack(); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else { + nodep->v3error("Unknown built-in event method " << nodep->prettyNameQ()); + } + } void methodCallString(AstMethodCall* nodep, AstBasicDType* adtypep) { // Method call on string if (nodep->name() == "len") { @@ -3036,6 +3050,12 @@ private: iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep); // if (debug()) nodep->dumpTree(cout, " AssignOut: "); } + if (AstBasicDType* basicp = nodep->rhsp()->dtypep()->basicp()) { + if (basicp->isEventValue()) { + // see t_event_copy.v for commentary on the mess involved + nodep->v3error("Unsupported: assignment of event data type"); + } + } if (AstNewDynamic* dynp = VN_CAST(nodep->rhsp(), NewDynamic)) { UINFO(9, "= new[] -> .resize(): " << nodep); AstCMethodHard* newp; diff --git a/src/verilog.y b/src/verilog.y index 4f6d2bd43..ea727f021 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1623,7 +1623,7 @@ data_typeNoRef: // ==IEEE: data_type, excluding class_type etc referenc SYMP,VFlagChildDType(),$1); } | ySTRING { $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); } | yCHANDLE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::CHANDLE); } - | yEVENT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::BIT); BBUNSUP($1, "Unsupported: event data types"); } + | yEVENT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::EVENTVALUE); } // // Rules overlap virtual_interface_declaration // // Parameters here are SV2009 // // IEEE has ['.' modport] but that will conflict with port @@ -2813,8 +2813,15 @@ statement_item: // IEEE: statement_item | yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';' { $$ = new AstDisable($1,*$2); } | yDISABLE yFORK ';' { $$ = NULL; BBUNSUP($1, "Unsupported: disable fork statements"); } // // IEEE: event_trigger - //UNSUP yP_MINUSGT hierarchical_identifier/*event*/ ';' { UNSUP } + | yP_MINUSGT idDotted/*hierarchical_identifier-event*/ ';' + { // AssignDly because we don't have stratified queue, and need to + // read events, clear next event, THEN apply this set + $$ = new AstAssignDly($1, $2, new AstConst($1, AstConst::LogicTrue())); } //UNSUP yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';' { UNSUP } + // // IEEE remove below + | yP_MINUSGTGT delayE idDotted/*hierarchical_identifier-event*/ ';' + { $$ = new AstAssignDly($1, $3, new AstConst($1, AstConst::LogicTrue())); } + // // // IEEE: loop_statement | yFOREVER stmtBlock { $$ = new AstWhile($1,new AstConst($1,AstConst::LogicTrue()),$2); } | yREPEAT '(' expr ')' stmtBlock { $$ = new AstRepeat($1,$3,$5);} diff --git a/test_regress/t/t_event.pl b/test_regress/t/t_event.pl new file mode 100755 index 000000000..1d046ed3f --- /dev/null +++ b/test_regress/t/t_event.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_event.v b/test_regress/t/t_event.v new file mode 100644 index 000000000..0f5384c14 --- /dev/null +++ b/test_regress/t/t_event.v @@ -0,0 +1,81 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2003 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`ifdef TEST_VERBOSE + `define WRITE_VERBOSE(args) $write args +`else + `define WRITE_VERBOSE(args) +`endif + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + event e1; + event e2; +`ifndef IVERILOG + event ev [3:0]; +`endif + + int cyc; + + int last_event; + always @(e1) begin + `WRITE_VERBOSE(("[%0t] e1\n", $time)); + if (!e1.triggered) $stop; + last_event[1] = 1; + end + + always @(e2) begin + `WRITE_VERBOSE(("[%0t] e2\n", $time)); + last_event[2] = 1; + end + + always @(posedge clk) begin + `WRITE_VERBOSE(("[%0t] cyc=%0d last_event=%5b\n", $time, cyc, last_event)); + cyc <= cyc + 1; + if (cyc == 1) begin + // Check no initial trigger + if (last_event != 0) $stop; + end + // + else if (cyc == 10) begin + last_event = 0; + -> e1; + end + else if (cyc == 12) begin + if (last_event != 32'b10) $stop; + last_event = 0; + end + else if (cyc == 13) begin + // Check not still triggering + if (last_event != 0) $stop; + last_event = 0; + end + // + else if (cyc == 10) begin + last_event = 0; + ->> e2; + end + else if (cyc == 12) begin + if (last_event != 32'b100) $stop; + last_event = 0; + end + else if (cyc == 13) begin + // Check not still triggering + if (last_event != 0) $stop; + last_event = 0; + end + // + else if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_event_copy.out b/test_regress/t/t_event_copy.out new file mode 100644 index 000000000..3c2a9775c --- /dev/null +++ b/test_regress/t/t_event_copy.out @@ -0,0 +1,9 @@ +%Error: t/t_event_copy.v:100:13: Unsupported: assignment of event data type + : ... In instance t + 100 | e4 = e3; + | ^ +%Error: t/t_event_copy.v:101:13: Unsupported: assignment of event data type + : ... In instance t + 101 | e3 = e2; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_event_copy.pl b/test_regress/t/t_event_copy.pl new file mode 100755 index 000000000..052947d96 --- /dev/null +++ b/test_regress/t/t_event_copy.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_event_copy.v b/test_regress/t/t_event_copy.v new file mode 100644 index 000000000..7a26fb3d9 --- /dev/null +++ b/test_regress/t/t_event_copy.v @@ -0,0 +1,142 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2003 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`ifdef TEST_VERBOSE + `define WRITE_VERBOSE(args) $write args +`else + `define WRITE_VERBOSE(args) +`endif + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + event e1; + event e2; + event e3; + event e4; +`ifndef IVERILOG + event ev [3:0]; +`endif + + int cyc; + + int last_event; + always @(e1) begin + `WRITE_VERBOSE(("[%0t] e1\n", $time)); +`ifndef IVERILOG + if (!e1.triggered) $stop; +`endif + last_event[1] = 1; + end + + always @(e2) begin + `WRITE_VERBOSE(("[%0t] e2\n", $time)); + last_event[2] = 1; + end + + always @(e3) begin + `WRITE_VERBOSE(("[%0t] e3\n", $time)); + last_event[3] = 1; + end + + always @(e4) begin + `WRITE_VERBOSE(("[%0t] e4\n", $time)); + last_event[4] = 1; + end + + always @(posedge clk) begin + `WRITE_VERBOSE(("[%0t] cyc=%0d last_event=%5b\n", $time, cyc, last_event)); + cyc <= cyc + 1; + if (cyc == 1) begin + // Check no initial trigger + if (last_event != 0) $stop; + end + // + else if (cyc == 10) begin + last_event = 0; + -> e1; + end + else if (cyc == 12) begin + if (last_event != 32'b10) $stop; + last_event = 0; + end + else if (cyc == 13) begin + // Check not still triggering + if (last_event != 0) $stop; + last_event = 0; + end + // + else if (cyc == 20) begin + last_event = 0; +`ifdef IVERILOG + -> e2; +`else + // Events are both references and events themselves. I.e. 'event e' + // declaration means 'event e = new'. Then e is a reference to that + // created event. + // + // Always having indirection is bad for performance, so Verilator + // should have 'event e' as an "EVENTVALUE" stored as a char, or + // ideally a one bit field reference (not vector as that can't be + // V3Ordered). + // + // Then events once copied become EVENTREFs, much like a ClassRef which + // points to an EVENTVALUE. Thus a Verilog "event" starts as an + // EVENTVALUE, and if an assignment is made it becomes an EVENTVALUE + // and an EVENTREF initing to that EVENTVALUE. + // + // All static scheduling for events would go out the window once an + // event can be pointed to by an EVENTREF, as basically any EVENTREF + // activation could be activating any event. A graph algorithm could + // determine what events/eventrefs are associated and only + // pessamistically schedule those events (users of EVENTVALUES) that + // are ever pointed to by an EVENTREF. + e4 = e3; // Old handle to e4 + e3 = e2; // Same event, also triggers e2 + // IEEE 2017 15.5.5.1 says that this causes a merge, and the below + // should also activate the "old e3". However we could not find any + // simulator that actually does this. Instead the "old e3" becomes + // unreachable (via old handle), but is reachable by "e4" as assigned + // earlier. + ->> e3; // Delayed +`endif + end + else if (cyc == 22) begin + if (last_event != 32'b100) $stop; + last_event = 0; + -> e2; // IEEE says triggers e3, but does not + end + else if (cyc == 24) begin + if (last_event != 32'b100) $stop; + last_event = 0; + -> e4; // Triggers old e3 + end + else if (cyc == 26) begin + if (last_event != 32'b1000) $stop; + last_event = 0; + end + // + else if (cyc == 30) begin + last_event = 0; +`ifndef IVERILOG + e3 = null; + -> e3; // Triggers nothing +`endif + end + else if (cyc == 32) begin + if (last_event != 0) $stop; + last_event = 0; + end + else if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule From 70549e1a64e82b932140baf657d34234a8a724a0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 26 Apr 2020 12:45:06 -0400 Subject: [PATCH 105/127] Internals: Parse lifetime directives; still unsupported. --- src/V3Ast.h | 32 +++++++++++++++++++++ src/V3AstNodes.cpp | 1 + src/V3AstNodes.h | 5 +++- src/V3LinkDot.cpp | 1 + src/V3LinkResolve.cpp | 40 ++++++++++++++++++-------- src/V3ParseGrammar.cpp | 1 + src/V3ParseImp.h | 1 + src/verilog.y | 65 +++++++++++++++++++++++++++++++----------- 8 files changed, 116 insertions(+), 30 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 19a1fd6dc..a9f533f2b 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -94,6 +94,32 @@ inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return o //###################################################################### +class VLifetime { +public: + enum en { NONE, AUTOMATIC, STATIC }; + enum en m_e; + const char* ascii() const { + static const char* const names[] = {"NONE", "VAUTOM", "VSTATIC"}; + return names[m_e]; + } + inline VLifetime() + : m_e(NONE) {} + // cppcheck-suppress noExplicitConstructor + inline VLifetime(en _e) + : m_e(_e) {} + explicit inline VLifetime(int _e) + : m_e(static_cast(_e)) {} + operator en() const { return m_e; } + bool isNone() const { return m_e == NONE; } + bool isAutomatic() const { return m_e == AUTOMATIC; } + bool isStatic() const { return m_e == STATIC; } +}; +inline bool operator==(const VLifetime& lhs, const VLifetime& rhs) { return lhs.m_e == rhs.m_e; } +inline bool operator==(const VLifetime& lhs, VLifetime::en rhs) { return lhs.m_e == rhs; } +inline bool operator==(VLifetime::en lhs, const VLifetime& rhs) { return lhs == rhs.m_e; } + +//###################################################################### + class VSigning { public: enum en { @@ -2575,6 +2601,7 @@ private: bool m_dpiTask : 1; // DPI import task (vs. void function) bool m_isConstructor : 1; // Class constructor bool m_pure : 1; // DPI import pure (vs. virtual pure) + VLifetime m_lifetime; // Lifetime public: AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) : AstNode(t, fl) @@ -2639,6 +2666,8 @@ public: bool isConstructor() const { return m_isConstructor; } void pure(bool flag) { m_pure = flag; } bool pure() const { return m_pure; } + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } }; class AstNodeFTaskRef : public AstNodeStmt { @@ -2715,6 +2744,7 @@ private: int m_level; // 1=top module, 2=cell off top module, ... int m_varNum; // Incrementing variable number int m_typeNum; // Incrementing implicit type number + VLifetime m_lifetime; // Lifetime VTimescale m_timeunit; // Global time unit VOptionBool m_unconnectedDrive; // State of `unconnected_drive public: @@ -2766,6 +2796,8 @@ public: bool recursive() const { return m_recursive; } void recursiveClone(bool flag) { m_recursiveClone = flag; } bool recursiveClone() const { return m_recursiveClone; } + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } void timeunit(const VTimescale& flag) { m_timeunit = flag; } VTimescale timeunit() const { return m_timeunit; } void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 8cb89dc5e..c7fb643c2 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1437,6 +1437,7 @@ void AstVar::dump(std::ostream& str) const { } if (isDpiOpenArray()) str << " [DPIOPENA]"; if (!attrClocker().unknown()) str << " [" << attrClocker().ascii() << "] "; + if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] "; str << " " << varType(); } void AstSenTree::dump(std::ostream& str) const { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 602148564..cab07a6c6 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1780,7 +1780,7 @@ private: bool m_attrSplitVar : 1; // declared with split_var metacomment bool m_fileDescr : 1; // File descriptor bool m_isConst : 1; // Table contains constant data - bool m_isStatic : 1; // Static variable + bool m_isStatic : 1; // Static C variable (for Verilog see instead isAutomatic) bool m_isPulldown : 1; // Tri0 bool m_isPullup : 1; // Tri1 bool m_isIfaceParent : 1; // dtype is reference to interface present in this module @@ -1788,6 +1788,7 @@ private: bool m_noReset : 1; // Do not do automated reset/randomization bool m_noSubst : 1; // Do not substitute out references bool m_trace : 1; // Trace this variable + VLifetime m_lifetime; // Lifetime VVarAttrClocker m_attrClocker; MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var @@ -2037,6 +2038,8 @@ public: bool attrIsolateAssign() const { return m_attrIsolateAssign; } VVarAttrClocker attrClocker() const { return m_attrClocker; } virtual string verilogKwd() const; + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } void propagateAttrFrom(AstVar* fromp) { // This is getting connected to fromp; keep attributes // Note the method below too diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 0f0aa5ad2..d5c821922 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1006,6 +1006,7 @@ class LinkDotFindVisitor : public AstNVisitor { AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::VAR, nodep->name(), VFlagChildDType(), dtypep); // Not dtype resolved yet newvarp->direction(VDirection::OUTPUT); + newvarp->lifetime(VLifetime::AUTOMATIC); newvarp->funcReturn(true); newvarp->trace(false); // Not user visible newvarp->attrIsolateAssign(nodep->attrIsolateAssign()); diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 35ea685db..90752c815 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -53,6 +53,7 @@ private: AstClass* m_classp; // Class we're inside AstNodeFTask* m_ftaskp; // Function or task we're inside AstNodeCoverOrAssert* m_assertp; // Current assertion + VLifetime m_lifetime; // Propagating lifetime int m_senitemCvtNum; // Temporary signal counter // METHODS @@ -67,14 +68,30 @@ private: UINFO(8, "MODULE " << nodep << endl); if (nodep->dead()) return; AstNodeModule* origModp = m_modp; + VLifetime origLifetime = m_lifetime; int origSenitemCvtNum = m_senitemCvtNum; { m_modp = nodep; m_senitemCvtNum = 0; + m_lifetime = nodep->lifetime(); + if (m_lifetime.isNone()) m_lifetime = VLifetime::STATIC; iterateChildren(nodep); } m_modp = origModp; m_senitemCvtNum = origSenitemCvtNum; + m_lifetime = origLifetime; + } + virtual void visit(AstClass* nodep) VL_OVERRIDE { + AstClass* origClassp = m_classp; + VLifetime origLifetime = m_lifetime; + { + m_classp = nodep; + m_lifetime = nodep->lifetime(); + if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC; + iterateChildren(nodep); + } + m_classp = origClassp; + m_lifetime = origLifetime; } virtual void visit(AstInitial* nodep) VL_OVERRIDE { iterateChildren(nodep); @@ -90,19 +107,12 @@ private: iterateChildren(nodep); m_assertp = NULL; } - virtual void visit(AstClass* nodep) VL_OVERRIDE { - AstClass* origClassp = m_classp; - { - m_classp = nodep; - iterateChildren(nodep); - } - m_classp = origClassp; - } virtual void visit(AstVar* nodep) VL_OVERRIDE { iterateChildren(nodep); if (m_classp && !nodep->isParam()) nodep->varType(AstVarType::MEMBER); if (m_classp && nodep->isParam()) nodep->v3error("Unsupported: class parameter"); if (m_ftaskp) nodep->funcLocal(true); + if (nodep->lifetime().isNone()) nodep->lifetime(m_lifetime); if (nodep->isSigModPublic()) { nodep->sigModPublic(false); // We're done with this attribute m_modp->modPublic(true); // Avoid flattening if signals are exposed @@ -119,9 +129,15 @@ private: // NodeTask: Remember its name for later resolution // Remember the existing symbol table scope if (m_classp) nodep->classMethod(true); - m_ftaskp = nodep; - iterateChildren(nodep); + VLifetime origLifetime = m_lifetime; + { + if (!nodep->lifetime().isNone()) m_lifetime = nodep->lifetime(); + if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC; + m_ftaskp = nodep; + iterateChildren(nodep); + } m_ftaskp = NULL; + m_lifetime = origLifetime; if (nodep->dpiExport()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); } } virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE { @@ -472,13 +488,13 @@ private: public: // CONSTRUCTORS - explicit LinkResolveVisitor(AstNetlist* rootp) { + explicit LinkResolveVisitor(AstNetlist* rootp) + : m_lifetime(VLifetime::STATIC) { // Static outside a module/class m_classp = NULL; m_ftaskp = NULL; m_modp = NULL; m_assertp = NULL; m_senitemCvtNum = 0; - // iterate(rootp); } virtual ~LinkResolveVisitor() {} diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 805b10974..9385ef4b1 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -183,6 +183,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, nodep->addAttrsp(attrsp); nodep->ansi(m_pinAnsi); nodep->declTyped(m_varDeclTyped); + nodep->lifetime(m_varLifetime); if (GRAMMARP->m_varDecl != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl); if (GRAMMARP->m_varIO != VDirection::NONE) { nodep->declDirection(GRAMMARP->m_varIO); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 1a079b604..975ddaebe 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -59,6 +59,7 @@ struct V3ParseBisonYYSType { VSigning::en signstate; V3ErrorCode::en errcodeen; AstAttrType::en attrtypeen; + VLifetime::en lifetime; AstNode* nodep; diff --git a/src/verilog.y b/src/verilog.y index ea727f021..2274068e9 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -50,6 +50,7 @@ public: AstVarType m_varDecl; // Type for next signal declaration (reg/wire/etc) bool m_varDeclTyped; // Var got reg/wire for dedup check VDirection m_varIO; // Direction for next signal declaration (reg/wire/etc) + VLifetime m_varLifetime; // Static/Automatic for next signal AstVar* m_varAttrp; // Current variable for attribute adding AstRange* m_gateRangep; // Current range for gate declarations AstCase* m_caseAttrp; // Current case statement for attribute adding @@ -194,9 +195,11 @@ int V3ParseGrammar::s_modTypeImpNum = 0; #define VARRESET_NONLIST(decl) { GRAMMARP->m_pinNum=0; GRAMMARP->m_pinAnsi=false; \ VARRESET(); VARDECL(decl); } // Not in a pinlist #define VARRESET() { VARDECL(UNKNOWN); VARIO(NONE); VARDTYPE_NDECL(NULL); \ + GRAMMARP->m_varLifetime = VLifetime::NONE; \ GRAMMARP->m_varDeclTyped = false; } #define VARDECL(type) { GRAMMARP->setVarDecl(AstVarType::type); } #define VARIO(type) { GRAMMARP->m_varIO = VDirection::type; } +#define VARLIFE(flag) { GRAMMARP->m_varLifetime = flag; } #define VARDTYPE(dtypep) { GRAMMARP->setDType(dtypep); GRAMMARP->m_varDeclTyped = true; } #define VARDTYPE_NDECL(dtypep) { GRAMMARP->setDType(dtypep); } // Port that is range or signed only (not a decl) @@ -794,6 +797,8 @@ class AstSenTree; // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion +// Blank lines for type insertion +// Blank lines for type insertion %start source_text @@ -852,6 +857,7 @@ packageFront: yPACKAGE lifetimeE idAny ';' { $$ = new AstPackage($3, *$3); $$->inLibrary(true); // packages are always libraries; don't want to make them a "top" + $$->lifetime($2); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); PARSEP->rootp()->addModulep($$); @@ -967,6 +973,7 @@ modFront: // // any formal arguments, as the arguments must land in the new scope. yMODULE lifetimeE idAny { $$ = new AstModule($3,*$3); + $$->lifetime($2); $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); @@ -985,6 +992,7 @@ importsAndParametersE: // IEEE: common part of module_declaration, interf udpFront: yPRIMITIVE lifetimeE idAny { $$ = new AstPrimitive($3, *$3); $$->inLibrary(true); + $$->lifetime($2); $$->modTrace(false); $$->addStmtp(new AstPragma($3, AstPragmaType::INLINE_MODULE)); GRAMMARP->m_tracingParse = false; @@ -1167,6 +1175,7 @@ intFront: yINTERFACE lifetimeE idAny/*new_interface*/ { $$ = new AstIface($3, *$3); $$->inLibrary(true); + $$->lifetime($2); PARSEP->rootp()->addModulep($$); SYMP->pushNew($$); } ; @@ -1253,6 +1262,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_header + pr pgmFront: yPROGRAM lifetimeE idAny/*new_program*/ { $$ = new AstModule($3,*$3); + $$->lifetime($2); $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); @@ -1885,19 +1895,33 @@ data_declarationVarFront: // IEEE: part of data_declaration // // // Expanded: "constE yVAR lifetimeE data_type" // // implicit_type expanded into /*empty*/ or "signingE rangeList" - /**/ yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE($3); } - | /**/ yVAR lifetimeE { VARRESET_NONLIST(VAR); VARDTYPE(new AstBasicDType($1, LOGIC_IMPLICIT)); } - | /**/ yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); } + /**/ yVAR lifetimeE data_type + { VARRESET_NONLIST(VAR); VARLIFE($2); VARDTYPE($3); } + | /**/ yVAR lifetimeE + { VARRESET_NONLIST(VAR); VARLIFE($2); + VARDTYPE(new AstBasicDType($1, LOGIC_IMPLICIT)); } + | /**/ yVAR lifetimeE signingE rangeList + { /*VARRESET-in-ddVar*/ VARLIFE($2); + VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); } // // // implicit_type expanded into /*empty*/ or "signingE rangeList" - | yCONST__ETC yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($2, VFlagChildDType(), $4)); } - | yCONST__ETC yVAR lifetimeE { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($2, VFlagChildDType(), new AstBasicDType($2, LOGIC_IMPLICIT))); } - | yCONST__ETC yVAR lifetimeE signingE rangeList { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($2, VFlagChildDType(), GRAMMARP->addRange(new AstBasicDType($2, LOGIC_IMPLICIT, $4), $5,true))); } + | yCONST__ETC yVAR lifetimeE data_type + { VARRESET_NONLIST(VAR); VARLIFE($3); + VARDTYPE(new AstConstDType($2, VFlagChildDType(), $4)); } + | yCONST__ETC yVAR lifetimeE + { VARRESET_NONLIST(VAR); VARLIFE($3); + VARDTYPE(new AstConstDType($2, VFlagChildDType(), new AstBasicDType($2, LOGIC_IMPLICIT))); } + | yCONST__ETC yVAR lifetimeE signingE rangeList + { VARRESET_NONLIST(VAR); VARLIFE($3); + VARDTYPE(new AstConstDType($2, VFlagChildDType(), + GRAMMARP->addRange(new AstBasicDType($2, LOGIC_IMPLICIT, $4), $5,true))); } // // // Expanded: "constE lifetimeE data_type" | /**/ data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); } - | /**/ lifetime data_type { VARRESET_NONLIST(VAR); VARDTYPE($2); } - | yCONST__ETC lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($1, VFlagChildDType(), $3)); } + | /**/ lifetime data_type { VARRESET_NONLIST(VAR); VARLIFE($1); VARDTYPE($2); } + | yCONST__ETC lifetimeE data_type + { VARRESET_NONLIST(VAR); VARLIFE($2); + VARDTYPE(new AstConstDType($1, VFlagChildDType(), $3)); } // // = class_new is in variable_decl_assignment ; @@ -1905,9 +1929,11 @@ data_declarationVarFrontClass: // IEEE: part of data_declaration (for class_prop // // VARRESET called before this rule // // yCONST is removed, added to memberQual rules // // implicit_type expanded into /*empty*/ or "signingE rangeList" - yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE($3); } - | yVAR lifetimeE { VARRESET_NONLIST(VAR); } - | yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); } + yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARLIFE($2); VARDTYPE($3); } + | yVAR lifetimeE { VARRESET_NONLIST(VAR); VARLIFE($2); } + | yVAR lifetimeE signingE rangeList + { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); + VARLIFE($2); } // // // Expanded: "constE lifetimeE data_type" | data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); } @@ -3484,6 +3510,7 @@ list_of_argumentsE: // IEEE: [list_of_arguments] task_declaration: // ==IEEE: task_declaration yTASK lifetimeE taskId tfGuts yENDTASK endLabelE { $$ = $3; $$->addStmtsp($4); SYMP->popScope($$); + $$->lifetime($2); GRAMMARP->endLabel($6,$$,$6); } ; @@ -3495,10 +3522,12 @@ task_prototype: // ==IEEE: task_prototype function_declaration: // IEEE: function_declaration + function_body_declaration yFUNCTION lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE { $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5); + $$->lifetime($2); SYMP->popScope($$); GRAMMARP->endLabel($7,$$,$7); } | yFUNCTION lifetimeE funcIdNew funcIsolateE tfGuts yENDFUNCTION endLabelE { $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5); + $$->lifetime($2); SYMP->popScope($$); GRAMMARP->endLabel($7,$$,$7); } ; @@ -3523,15 +3552,15 @@ method_prototype: | function_prototype { } ; -lifetimeE: // IEEE: [lifetime] - /* empty */ { } - | lifetime { } +lifetimeE: // IEEE: [lifetime] + /* empty */ { $$ = VLifetime::NONE; } + | lifetime { $$ = $1; } ; -lifetime: // ==IEEE: lifetime +lifetime: // ==IEEE: lifetime // // Note lifetime used by members is instead under memberQual - ySTATIC__ETC { BBUNSUP($1, "Unsupported: Static in this context"); } - | yAUTOMATIC { } + ySTATIC__ETC { $$ = VLifetime::STATIC; BBUNSUP($1, "Unsupported: Static in this context"); } + | yAUTOMATIC { $$ = VLifetime::AUTOMATIC; } ; taskId: @@ -5481,10 +5510,12 @@ class_declaration: // ==IEEE: part of class_declaration classFront: // IEEE: part of class_declaration classVirtualE yCLASS lifetimeE idAny/*class_identifier*/ { $$ = new AstClass($2, *$4); + $$->lifetime($3); SYMP->pushNew($$); } // // IEEE: part of interface_class_declaration | yINTERFACE yCLASS lifetimeE idAny/*class_identifier*/ { $$ = new AstClass($2, *$4); + $$->lifetime($3); SYMP->pushNew($$); BBUNSUP($2, "Unsupported: interface classes"); } ; From b79ef672e170cc5c6b5fe55ec8bde46d62cbb254 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 25 Apr 2020 19:37:59 +0100 Subject: [PATCH 106/127] Various minor optimizations of VCD trace routines - Change templated trace routines to branch table. Removed templating from trace chgBus and fullBus and replaced them with a branch table like the other there is a very small (< 1%) penalty for this on SwerRV EH1 CoreMark, but this is less than the variability of disk IO so it's worth it to keep the code simpler and smaller. - Prefetch VCD suffix buffer at the top of emit* - Increase ILP in VCD emit* routines - Use a 64-bit unaligned store to emit the VCD suffix (on x86 only) The performance difference with these is very small, but the changes hopefully make this code more performance-portable across various micro-architectures. --- include/verilated_fst_c.cpp | 14 +- include/verilated_fst_c.h | 15 +- include/verilated_trace.h | 12 +- include/verilated_trace_imp.cpp | 86 +---------- include/verilated_vcd_c.cpp | 244 +++++++++++++++++++++----------- include/verilated_vcd_c.h | 23 +-- src/V3EmitC.cpp | 3 +- 7 files changed, 205 insertions(+), 192 deletions(-) diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 1e1d44434..c4b1dc077 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -208,21 +208,31 @@ void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, f declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64); } +// Note: emit* are only ever called from one place (full* in +// verilated_trace_imp.cpp, which is included in this file at the top), +// so always inline them. + +VL_ATTR_ALWINLINE void VerilatedFst::emitBit(vluint32_t code, vluint32_t newval) { fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0"); } -template void VerilatedFst::emitBus(vluint32_t code, vluint32_t newval) { - fstWriterEmitValueChange32(m_fst, m_symbolp[code], T_Bits, newval); +VL_ATTR_ALWINLINE +void VerilatedFst::emitBus(vluint32_t code, vluint32_t newval, int bits) { + fstWriterEmitValueChange32(m_fst, m_symbolp[code], bits, newval); } +VL_ATTR_ALWINLINE void VerilatedFst::emitQuad(vluint32_t code, vluint64_t newval, int bits) { fstWriterEmitValueChange64(m_fst, m_symbolp[code], bits, newval); } +VL_ATTR_ALWINLINE void VerilatedFst::emitArray(vluint32_t code, const vluint32_t* newvalp, int bits) { fstWriterEmitValueChangeVec32(m_fst, m_symbolp[code], bits, newvalp); } +VL_ATTR_ALWINLINE void VerilatedFst::emitFloat(vluint32_t code, float newval) { fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval); } +VL_ATTR_ALWINLINE void VerilatedFst::emitDouble(vluint32_t code, double newval) { fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval); } diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 8572a0f5f..b80d8ea7a 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -67,13 +67,14 @@ protected: bool preFullDump() VL_OVERRIDE { return isOpen(); } bool preChangeDump() VL_OVERRIDE { return isOpen(); } - // Implementations of duck-typed methods for VerilatedTrace - void emitBit(vluint32_t code, vluint32_t newval); - template void emitBus(vluint32_t code, vluint32_t newval); - void emitQuad(vluint32_t code, vluint64_t newval, int bits); - void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits); - void emitFloat(vluint32_t code, float newval); - void emitDouble(vluint32_t code, double newval); + // Implementations of duck-typed methods for VerilatedTrace. These are + // called from only one place (namely full*) so always inline them. + inline void emitBit(vluint32_t code, vluint32_t newval); + inline void emitBus(vluint32_t code, vluint32_t newval, int bits); + inline void emitQuad(vluint32_t code, vluint64_t newval, int bits); + inline void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits); + inline void emitFloat(vluint32_t code, float newval); + inline void emitDouble(vluint32_t code, double newval); public: //========================================================================= diff --git a/include/verilated_trace.h b/include/verilated_trace.h index a611a436c..ee0bca3e2 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -262,7 +262,7 @@ public: // this is very hot code during tracing. // duck-typed void emitBit(vluint32_t code, vluint32_t newval) = 0; - // duck-typed template void emitBus(vluint32_t code, vluint32_t newval) = 0; + // duck-typed void emitBus(vluint32_t code, vluint32_t newval, int bits) = 0; // duck-typed void emitQuad(vluint32_t code, vluint64_t newval, int bits) = 0; // duck-typed void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits) = 0; // duck-typed void emitFloat(vluint32_t code, float newval) = 0; @@ -272,7 +272,7 @@ public: // Write to previous value buffer value and emit trace entry. void fullBit(vluint32_t* oldp, vluint32_t newval); - template void fullBus(vluint32_t* oldp, vluint32_t newval); + void fullBus(vluint32_t* oldp, vluint32_t newval, int bits); void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits); void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits); void fullFloat(vluint32_t* oldp, float newval); @@ -286,8 +286,8 @@ public: m_traceBufferWritep += 2; VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); } - template inline void chgBus(vluint32_t* oldp, vluint32_t newval) { - m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_BUS | T_Bits; + inline void chgBus(vluint32_t* oldp, vluint32_t newval, int bits) { + m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_BUS | bits; m_traceBufferWritep[1].oldp = oldp; m_traceBufferWritep[2].newBits = newval; m_traceBufferWritep += 3; @@ -339,9 +339,9 @@ public: const vluint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullBit(oldp, newval); } - template inline void CHG(Bus)(vluint32_t* oldp, vluint32_t newval) { + inline void CHG(Bus)(vluint32_t* oldp, vluint32_t newval, int bits) { const vluint32_t diff = *oldp ^ newval; - if (VL_UNLIKELY(diff)) fullBus(oldp, newval); + if (VL_UNLIKELY(diff)) fullBus(oldp, newval, bits); } inline void CHG(Quad)(vluint32_t* oldp, vluint64_t newval, int bits) { const vluint64_t diff = *reinterpret_cast(oldp) ^ newval; diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp index b5b6fc924..3dc3c33d4 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.cpp @@ -161,50 +161,15 @@ template <> void VerilatedTrace::workerThreadMain() { continue; case VerilatedTraceCommand::CHG_BUS: VL_TRACE_THREAD_DEBUG("Command CHG_BUS"); - - oldp = (readp++)->oldp; - newBits = (readp++)->newBits; - // Bits stored in bottom byte of command - switch (cmd & 0xFFU) { - case 2: chgBusImpl<2>(oldp, newBits); continue; - case 3: chgBusImpl<3>(oldp, newBits); continue; - case 4: chgBusImpl<4>(oldp, newBits); continue; - case 5: chgBusImpl<5>(oldp, newBits); continue; - case 6: chgBusImpl<6>(oldp, newBits); continue; - case 7: chgBusImpl<7>(oldp, newBits); continue; - case 8: chgBusImpl<8>(oldp, newBits); continue; - case 9: chgBusImpl<9>(oldp, newBits); continue; - case 10: chgBusImpl<10>(oldp, newBits); continue; - case 11: chgBusImpl<11>(oldp, newBits); continue; - case 12: chgBusImpl<12>(oldp, newBits); continue; - case 13: chgBusImpl<13>(oldp, newBits); continue; - case 14: chgBusImpl<14>(oldp, newBits); continue; - case 15: chgBusImpl<15>(oldp, newBits); continue; - case 16: chgBusImpl<16>(oldp, newBits); continue; - case 17: chgBusImpl<17>(oldp, newBits); continue; - case 18: chgBusImpl<18>(oldp, newBits); continue; - case 19: chgBusImpl<19>(oldp, newBits); continue; - case 20: chgBusImpl<20>(oldp, newBits); continue; - case 21: chgBusImpl<21>(oldp, newBits); continue; - case 22: chgBusImpl<22>(oldp, newBits); continue; - case 23: chgBusImpl<23>(oldp, newBits); continue; - case 24: chgBusImpl<24>(oldp, newBits); continue; - case 25: chgBusImpl<25>(oldp, newBits); continue; - case 26: chgBusImpl<26>(oldp, newBits); continue; - case 27: chgBusImpl<27>(oldp, newBits); continue; - case 28: chgBusImpl<28>(oldp, newBits); continue; - case 29: chgBusImpl<29>(oldp, newBits); continue; - case 30: chgBusImpl<30>(oldp, newBits); continue; - case 31: chgBusImpl<31>(oldp, newBits); continue; - case 32: chgBusImpl<32>(oldp, newBits); continue; - } - VL_FATAL_MT(__FILE__, __LINE__, "", "Bad number of bits in CHG_BUS command"); - break; + chgBusImpl(readp[0].oldp, readp[1].newBits, cmd & 0xFFULL); + readp += 2; + VL_TRACE_THREAD_DEBUG("Command CHG_BUS DONE"); + continue; case VerilatedTraceCommand::CHG_QUAD: VL_TRACE_THREAD_DEBUG("Command CHG_QUAD"); // Bits stored in bottom byte of command - chgQuadImpl(readp[0].oldp, readp[1].newBits, cmd & 0xFF); + chgQuadImpl(readp[0].oldp, readp[1].newBits, cmd & 0xFFULL); readp += 2; continue; case VerilatedTraceCommand::CHG_ARRAY: @@ -516,49 +481,12 @@ template <> void VerilatedTrace::fullBit(vluint32_t* oldp, vluint3 self()->emitBit(oldp - m_sigs_oldvalp, newval); } -// We want these functions specialized for sizes to avoid hard to predict -// branches, but we don't want them inlined, so we explicitly instantiate the -// template for each size used by Verilator. template <> -template -void VerilatedTrace::fullBus(vluint32_t* oldp, vluint32_t newval) { +void VerilatedTrace::fullBus(vluint32_t* oldp, vluint32_t newval, int bits) { *oldp = newval; - self()->emitBus(oldp - m_sigs_oldvalp, newval); + self()->emitBus(oldp - m_sigs_oldvalp, newval, bits); } -// Note: No specialization for width 1, covered by 'fullBit' -template void VerilatedTrace::fullBus<2>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<3>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<4>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<5>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<6>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<7>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<8>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<9>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<10>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<11>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<12>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<13>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<14>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<15>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<16>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<17>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<18>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<19>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<20>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<21>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<22>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<23>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<24>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<25>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<26>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<27>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<28>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<29>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<30>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<31>(vluint32_t* oldp, vluint32_t newval); -template void VerilatedTrace::fullBus<32>(vluint32_t* oldp, vluint32_t newval); - template <> void VerilatedTrace::fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { *reinterpret_cast(oldp) = newval; diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index f52c80882..e1ffd2293 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -611,15 +611,20 @@ void VerilatedVcd::declTriArray(vluint32_t code, const char* name, bool array, i //============================================================================= // Emit trace entries +#define VL_VCD_SUFFIXP(code) (m_suffixesp + (code)*VL_TRACE_SUFFIX_ENTRY_SIZE) + // Emit suffix, write back write pointer, check buffer void VerilatedVcd::finishLine(vluint32_t code, char* writep) { - const char* const suffixp = m_suffixesp + code * VL_TRACE_SUFFIX_ENTRY_SIZE; + const char* const suffixp = VL_VCD_SUFFIXP(code); // Copy the whole suffix (this avoid having hard to predict branches which - // helps a lot). Note suffixp could be aligned, so could load it in one go, - // but then we would be endiannes dependent which we don't have a way to - // test right now and probably would make little difference... - // Note: The maximum length of the suffix is + // helps a lot). Note: The maximum length of the suffix is // VL_TRACE_MAX_VCD_CODE_SIZE + 2 == 7, but we unroll this here for speed. +#ifdef __x86_64__ + // Copy the whole 8 bytes in one go, this works on little-endian machines + // supporting unaligned stores. + *reinterpret_cast(writep) = *reinterpret_cast(suffixp); +#else + // Portable variant writep[0] = suffixp[0]; writep[1] = suffixp[1]; writep[2] = suffixp[2]; @@ -627,139 +632,202 @@ void VerilatedVcd::finishLine(vluint32_t code, char* writep) { writep[4] = suffixp[4]; writep[5] = suffixp[5]; writep[6] = '\n'; // The 6th index is always '\n' if it's relevant, no need to fetch it. +#endif // Now write back the write pointer incremented by the actual size of the // suffix, which was stored in the last byte of the suffix buffer entry. m_writep = writep + suffixp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1]; bufferCheck(); } +// Note: emit* are only ever called from one place (full* in +// verilated_trace_imp.cpp, which is included in this file at the top), +// so always inline them. + +VL_ATTR_ALWINLINE void VerilatedVcd::emitBit(vluint32_t code, vluint32_t newval) { + // Don't prefetch suffix as it's a bit too late; char* wp = m_writep; *wp++ = '0' | static_cast(newval); finishLine(code, wp); } -template void VerilatedVcd::emitBus(vluint32_t code, vluint32_t newval) { +VL_ATTR_ALWINLINE +void VerilatedVcd::emitBus(vluint32_t code, vluint32_t newval, int bits) { + VL_PREFETCH_RD(VL_VCD_SUFFIXP(code)); char* wp = m_writep; *wp++ = 'b'; - newval <<= 32 - T_Bits; - int bits = T_Bits; - do { - *wp++ = '0' | static_cast(newval >> 31); - newval <<= 1; - } while (--bits); + wp += bits; + // clang-format off + switch (bits) { + case 32: wp[-32] = '0' | static_cast((newval >> 31) ); //FALLTHRU + case 31: wp[-31] = '0' | static_cast((newval >> 30) & 1); //FALLTHRU + case 30: wp[-30] = '0' | static_cast((newval >> 29) & 1); //FALLTHRU + case 29: wp[-29] = '0' | static_cast((newval >> 28) & 1); //FALLTHRU + case 28: wp[-28] = '0' | static_cast((newval >> 27) & 1); //FALLTHRU + case 27: wp[-27] = '0' | static_cast((newval >> 26) & 1); //FALLTHRU + case 26: wp[-26] = '0' | static_cast((newval >> 25) & 1); //FALLTHRU + case 25: wp[-25] = '0' | static_cast((newval >> 24) & 1); //FALLTHRU + case 24: wp[-24] = '0' | static_cast((newval >> 23) & 1); //FALLTHRU + case 23: wp[-23] = '0' | static_cast((newval >> 22) & 1); //FALLTHRU + case 22: wp[-22] = '0' | static_cast((newval >> 21) & 1); //FALLTHRU + case 21: wp[-21] = '0' | static_cast((newval >> 20) & 1); //FALLTHRU + case 20: wp[-20] = '0' | static_cast((newval >> 19) & 1); //FALLTHRU + case 19: wp[-19] = '0' | static_cast((newval >> 18) & 1); //FALLTHRU + case 18: wp[-18] = '0' | static_cast((newval >> 17) & 1); //FALLTHRU + case 17: wp[-17] = '0' | static_cast((newval >> 16) & 1); //FALLTHRU + case 16: wp[-16] = '0' | static_cast((newval >> 15) & 1); //FALLTHRU + case 15: wp[-15] = '0' | static_cast((newval >> 14) & 1); //FALLTHRU + case 14: wp[-14] = '0' | static_cast((newval >> 13) & 1); //FALLTHRU + case 13: wp[-13] = '0' | static_cast((newval >> 12) & 1); //FALLTHRU + case 12: wp[-12] = '0' | static_cast((newval >> 11) & 1); //FALLTHRU + case 11: wp[-11] = '0' | static_cast((newval >> 10) & 1); //FALLTHRU + case 10: wp[-10] = '0' | static_cast((newval >> 9) & 1); //FALLTHRU + case 9: wp[ -9] = '0' | static_cast((newval >> 8) & 1); //FALLTHRU + case 8: wp[ -8] = '0' | static_cast((newval >> 7) & 1); //FALLTHRU + case 7: wp[ -7] = '0' | static_cast((newval >> 6) & 1); //FALLTHRU + case 6: wp[ -6] = '0' | static_cast((newval >> 5) & 1); //FALLTHRU + case 5: wp[ -5] = '0' | static_cast((newval >> 4) & 1); //FALLTHRU + case 4: wp[ -4] = '0' | static_cast((newval >> 3) & 1); //FALLTHRU + case 3: wp[ -3] = '0' | static_cast((newval >> 2) & 1); //FALLTHRU + case 2: wp[ -2] = '0' | static_cast((newval >> 1) & 1); //FALLTHRU + /*bit*/ wp[ -1] = '0' | static_cast((newval ) & 1); //FALLTHRU + } + // clang-format on finishLine(code, wp); } +VL_ATTR_ALWINLINE void VerilatedVcd::emitQuad(vluint32_t code, vluint64_t newval, int bits) { + VL_PREFETCH_RD(VL_VCD_SUFFIXP(code)); char* wp = m_writep; *wp++ = 'b'; - newval <<= 64 - bits; // Handle the top 32 bits within the 64 bit input const int bitsInTopHalf = bits - 32; wp += bitsInTopHalf; // clang-format off switch (bitsInTopHalf) { - case 32: wp[-32] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 31: wp[-31] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 30: wp[-30] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 29: wp[-29] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 28: wp[-28] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 27: wp[-27] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 26: wp[-26] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 25: wp[-25] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 24: wp[-24] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 23: wp[-23] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 22: wp[-22] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 21: wp[-21] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 20: wp[-20] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 19: wp[-19] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 18: wp[-18] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 17: wp[-17] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 16: wp[-16] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 15: wp[-15] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 14: wp[-14] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 13: wp[-13] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 12: wp[-12] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 11: wp[-11] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 10: wp[-10] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 9: wp[ -9] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 8: wp[ -8] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 7: wp[ -7] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 6: wp[ -6] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 5: wp[ -5] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 4: wp[ -4] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 3: wp[ -3] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 2: wp[ -2] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU - case 1: wp[ -1] = '0' | static_cast(newval >> 63); newval<<=1; //FALLTHRU + case 32: wp[-32] = '0' | static_cast((newval >> 63) ); //FALLTHRU + case 31: wp[-31] = '0' | static_cast((newval >> 62) & 1); //FALLTHRU + case 30: wp[-30] = '0' | static_cast((newval >> 61) & 1); //FALLTHRU + case 29: wp[-29] = '0' | static_cast((newval >> 60) & 1); //FALLTHRU + case 28: wp[-28] = '0' | static_cast((newval >> 59) & 1); //FALLTHRU + case 27: wp[-27] = '0' | static_cast((newval >> 58) & 1); //FALLTHRU + case 26: wp[-26] = '0' | static_cast((newval >> 57) & 1); //FALLTHRU + case 25: wp[-25] = '0' | static_cast((newval >> 56) & 1); //FALLTHRU + case 24: wp[-24] = '0' | static_cast((newval >> 55) & 1); //FALLTHRU + case 23: wp[-23] = '0' | static_cast((newval >> 54) & 1); //FALLTHRU + case 22: wp[-22] = '0' | static_cast((newval >> 53) & 1); //FALLTHRU + case 21: wp[-21] = '0' | static_cast((newval >> 52) & 1); //FALLTHRU + case 20: wp[-20] = '0' | static_cast((newval >> 51) & 1); //FALLTHRU + case 19: wp[-19] = '0' | static_cast((newval >> 50) & 1); //FALLTHRU + case 18: wp[-18] = '0' | static_cast((newval >> 49) & 1); //FALLTHRU + case 17: wp[-17] = '0' | static_cast((newval >> 48) & 1); //FALLTHRU + case 16: wp[-16] = '0' | static_cast((newval >> 47) & 1); //FALLTHRU + case 15: wp[-15] = '0' | static_cast((newval >> 46) & 1); //FALLTHRU + case 14: wp[-14] = '0' | static_cast((newval >> 45) & 1); //FALLTHRU + case 13: wp[-13] = '0' | static_cast((newval >> 44) & 1); //FALLTHRU + case 12: wp[-12] = '0' | static_cast((newval >> 43) & 1); //FALLTHRU + case 11: wp[-11] = '0' | static_cast((newval >> 42) & 1); //FALLTHRU + case 10: wp[-10] = '0' | static_cast((newval >> 41) & 1); //FALLTHRU + case 9: wp[ -9] = '0' | static_cast((newval >> 40) & 1); //FALLTHRU + case 8: wp[ -8] = '0' | static_cast((newval >> 39) & 1); //FALLTHRU + case 7: wp[ -7] = '0' | static_cast((newval >> 38) & 1); //FALLTHRU + case 6: wp[ -6] = '0' | static_cast((newval >> 37) & 1); //FALLTHRU + case 5: wp[ -5] = '0' | static_cast((newval >> 36) & 1); //FALLTHRU + case 4: wp[ -4] = '0' | static_cast((newval >> 35) & 1); //FALLTHRU + case 3: wp[ -3] = '0' | static_cast((newval >> 34) & 1); //FALLTHRU + case 2: wp[ -2] = '0' | static_cast((newval >> 33) & 1); //FALLTHRU + case 1: wp[ -1] = '0' | static_cast((newval >> 32) & 1); //FALLTHRU } // clang-format on // Handle the bottom 32 bits within the 64 bit input - int remaining = 32; + vluint32_t val = static_cast(newval); // Truncate to bottom 32 bits + int loops = 4; do { - *wp++ = '0' | static_cast(newval >> 63); - newval <<= 1; - } while (--remaining); + wp[0] = '0' | static_cast((val >> 31)); + wp[1] = '0' | static_cast((val >> 30) & 1); + wp[2] = '0' | static_cast((val >> 29) & 1); + wp[3] = '0' | static_cast((val >> 28) & 1); + wp[4] = '0' | static_cast((val >> 27) & 1); + wp[5] = '0' | static_cast((val >> 26) & 1); + wp[6] = '0' | static_cast((val >> 25) & 1); + wp[7] = '0' | static_cast((val >> 24) & 1); + wp += 8; + val <<= 8; + } while (--loops); + finishLine(code, wp); } +VL_ATTR_ALWINLINE void VerilatedVcd::emitArray(vluint32_t code, const vluint32_t* newvalp, int bits) { + VL_PREFETCH_RD(VL_VCD_SUFFIXP(code)); int words = (bits + 31) / 32; char* wp = m_writep; *wp++ = 'b'; // Handle the most significant word + vluint32_t val = newvalp[--words]; const int bitsInMSW = bits % 32 == 0 ? 32 : bits % 32; - vluint32_t val = newvalp[--words] << (32 - bitsInMSW); wp += bitsInMSW; // clang-format off switch (bitsInMSW) { - case 32: wp[-32] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 31: wp[-31] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 30: wp[-30] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 29: wp[-29] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 28: wp[-28] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 27: wp[-27] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 26: wp[-26] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 25: wp[-25] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 24: wp[-24] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 23: wp[-23] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 22: wp[-22] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 21: wp[-21] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 20: wp[-20] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 19: wp[-19] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 18: wp[-18] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 17: wp[-17] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 16: wp[-16] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 15: wp[-15] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 14: wp[-14] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 13: wp[-13] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 12: wp[-12] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 11: wp[-11] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 10: wp[-10] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 9: wp[ -9] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 8: wp[ -8] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 7: wp[ -7] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 6: wp[ -6] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 5: wp[ -5] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 4: wp[ -4] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 3: wp[ -3] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 2: wp[ -2] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU - case 1: wp[ -1] = '0' | static_cast(val >> 31); val<<=1; //FALLTHRU + case 32: wp[-32] = '0' | static_cast((val >> 31) ); //FALLTHRU + case 31: wp[-31] = '0' | static_cast((val >> 30) & 1); //FALLTHRU + case 30: wp[-30] = '0' | static_cast((val >> 29) & 1); //FALLTHRU + case 29: wp[-29] = '0' | static_cast((val >> 28) & 1); //FALLTHRU + case 28: wp[-28] = '0' | static_cast((val >> 27) & 1); //FALLTHRU + case 27: wp[-27] = '0' | static_cast((val >> 26) & 1); //FALLTHRU + case 26: wp[-26] = '0' | static_cast((val >> 25) & 1); //FALLTHRU + case 25: wp[-25] = '0' | static_cast((val >> 24) & 1); //FALLTHRU + case 24: wp[-24] = '0' | static_cast((val >> 23) & 1); //FALLTHRU + case 23: wp[-23] = '0' | static_cast((val >> 22) & 1); //FALLTHRU + case 22: wp[-22] = '0' | static_cast((val >> 21) & 1); //FALLTHRU + case 21: wp[-21] = '0' | static_cast((val >> 20) & 1); //FALLTHRU + case 20: wp[-20] = '0' | static_cast((val >> 19) & 1); //FALLTHRU + case 19: wp[-19] = '0' | static_cast((val >> 18) & 1); //FALLTHRU + case 18: wp[-18] = '0' | static_cast((val >> 17) & 1); //FALLTHRU + case 17: wp[-17] = '0' | static_cast((val >> 16) & 1); //FALLTHRU + case 16: wp[-16] = '0' | static_cast((val >> 15) & 1); //FALLTHRU + case 15: wp[-15] = '0' | static_cast((val >> 14) & 1); //FALLTHRU + case 14: wp[-14] = '0' | static_cast((val >> 13) & 1); //FALLTHRU + case 13: wp[-13] = '0' | static_cast((val >> 12) & 1); //FALLTHRU + case 12: wp[-12] = '0' | static_cast((val >> 11) & 1); //FALLTHRU + case 11: wp[-11] = '0' | static_cast((val >> 10) & 1); //FALLTHRU + case 10: wp[-10] = '0' | static_cast((val >> 9) & 1); //FALLTHRU + case 9: wp[ -9] = '0' | static_cast((val >> 8) & 1); //FALLTHRU + case 8: wp[ -8] = '0' | static_cast((val >> 7) & 1); //FALLTHRU + case 7: wp[ -7] = '0' | static_cast((val >> 6) & 1); //FALLTHRU + case 6: wp[ -6] = '0' | static_cast((val >> 5) & 1); //FALLTHRU + case 5: wp[ -5] = '0' | static_cast((val >> 4) & 1); //FALLTHRU + case 4: wp[ -4] = '0' | static_cast((val >> 3) & 1); //FALLTHRU + case 3: wp[ -3] = '0' | static_cast((val >> 2) & 1); //FALLTHRU + case 2: wp[ -2] = '0' | static_cast((val >> 1) & 1); //FALLTHRU + case 1: wp[ -1] = '0' | static_cast((val ) & 1); //FALLTHRU } // clang-format on // Handle the remaining words while (words > 0) { vluint32_t val = newvalp[--words]; - int bits = 32; + int loops = 4; do { - *wp++ = '0' | static_cast(val >> 31); - val <<= 1; - } while (--bits); + wp[0] = '0' | static_cast((val >> 31)); + wp[1] = '0' | static_cast((val >> 30) & 1); + wp[2] = '0' | static_cast((val >> 29) & 1); + wp[3] = '0' | static_cast((val >> 28) & 1); + wp[4] = '0' | static_cast((val >> 27) & 1); + wp[5] = '0' | static_cast((val >> 26) & 1); + wp[6] = '0' | static_cast((val >> 25) & 1); + wp[7] = '0' | static_cast((val >> 24) & 1); + wp += 8; + val <<= 8; + } while (--loops); } finishLine(code, wp); } +VL_ATTR_ALWINLINE void VerilatedVcd::emitFloat(vluint32_t code, float newval) { + VL_PREFETCH_RD(VL_VCD_SUFFIXP(code)); char* wp = m_writep; // Buffer can't overflow before sprintf; we sized during declaration sprintf(wp, "r%.16g", static_cast(newval)); @@ -767,7 +835,9 @@ void VerilatedVcd::emitFloat(vluint32_t code, float newval) { finishLine(code, wp); } +VL_ATTR_ALWINLINE void VerilatedVcd::emitDouble(vluint32_t code, double newval) { + VL_PREFETCH_RD(VL_VCD_SUFFIXP(code)); char* wp = m_writep; // Buffer can't overflow before sprintf; we sized during declaration sprintf(wp, "r%.16g", newval); @@ -775,6 +845,8 @@ void VerilatedVcd::emitDouble(vluint32_t code, double newval) { finishLine(code, wp); } +#undef VL_VCD_SUFFIXP + #ifdef VL_TRACE_VCD_OLD_API void VerilatedVcd::fullBit(vluint32_t code, const vluint32_t newval) { diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index e9838c15b..d9049366f 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -122,13 +122,14 @@ protected: bool preFullDump() VL_OVERRIDE { return isOpen(); } bool preChangeDump() VL_OVERRIDE; - // Implementations of duck-typed methods for VerilatedTrace - void emitBit(vluint32_t code, vluint32_t newval); - template void emitBus(vluint32_t code, vluint32_t newval); - void emitQuad(vluint32_t code, vluint64_t newval, int bits); - void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits); - void emitFloat(vluint32_t code, float newval); - void emitDouble(vluint32_t code, double newval); + // Implementations of duck-typed methods for VerilatedTrace. These are + // called from only one place (namely full*) so always inline them. + inline void emitBit(vluint32_t code, vluint32_t newval); + inline void emitBus(vluint32_t code, vluint32_t newval, int bits); + inline void emitQuad(vluint32_t code, vluint64_t newval, int bits); + inline void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits); + inline void emitFloat(vluint32_t code, float newval); + inline void emitDouble(vluint32_t code, double newval); public: //========================================================================= @@ -179,8 +180,8 @@ public: // Write back to previous value buffer value and emit void fullBit(vluint32_t* oldp, vluint32_t newval) { fullBit(oldp - this->oldp(0), newval); } - template void fullBus(vluint32_t* oldp, vluint32_t newval) { - fullBus(oldp - this->oldp(0), newval, T_Bits); + void fullBus(vluint32_t* oldp, vluint32_t newval, int bits) { + fullBus(oldp - this->oldp(0), newval, bits); } void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { fullQuad(oldp - this->oldp(0), newval, bits); @@ -195,8 +196,8 @@ public: // Check previous value and emit if changed void chgBit(vluint32_t* oldp, vluint32_t newval) { chgBit(oldp - this->oldp(0), newval); } - template void chgBus(vluint32_t* oldp, vluint32_t newval) { - chgBus(oldp - this->oldp(0), newval, T_Bits); + void chgBus(vluint32_t* oldp, vluint32_t newval, int bits) { + chgBus(oldp - this->oldp(0), newval, bits); } void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { chgQuad(oldp - this->oldp(0), newval, bits); diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 28c3ace73..ee4ae3e3d 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3561,7 +3561,8 @@ class EmitCTrace : EmitCStmts { puts("vcdp->" + full + "Quad"); emitWidth = true; } else if (nodep->declp()->widthMin() > 1) { - puts("vcdp->" + full + "Bus<" + cvtToStr(nodep->declp()->widthMin()) + ">"); + puts("vcdp->" + full + "Bus"); + emitWidth = true; } else { puts("vcdp->" + full + "Bit"); } From dd967f7769206985e95ab48992c18cbbede9322c Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 25 Apr 2020 22:38:25 +0100 Subject: [PATCH 107/127] Improve trace buffer memory utilization and performance. Convert trace buffer to 32-bit entries, rather than a union containing a pointer type. Also tweaked trace entry layouts for a bit more performance. This gains another 10% on SweRV EH1 CoreMark. --- include/verilated_trace.h | 117 +++++++++++++--------------- include/verilated_trace_imp.cpp | 132 +++++++++++++++++--------------- src/V3EmitC.cpp | 31 +++++--- src/V3EmitMk.cpp | 4 +- src/V3Options.h | 3 + 5 files changed, 147 insertions(+), 140 deletions(-) diff --git a/include/verilated_trace.h b/include/verilated_trace.h index ee0bca3e2..bb0bce25a 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -81,36 +81,26 @@ public: } }; -// Commands used by thread tracing. Note that the bottom 8 bits of all these -// values are empty and are used to store small amounts of additional command -// parameters. Anonymous enum in class, as we want it scoped, but we also -// want the automatic conversion to integer types. +// Commands used by thread tracing. Anonymous enum in class, as we want +// it scoped, but we also want the automatic conversion to integer types. class VerilatedTraceCommand { public: + // These must all fit in 4 bit at the moment, as the tracing routines + // pack parameters in the top bits. enum { - CHG_BIT = 0x0000, - CHG_BUS = 0x0100, - CHG_QUAD = 0x0200, - CHG_ARRAY = 0x0300, - CHG_FLOAT = 0x0400, - CHG_DOUBLE = 0x0500, - TIME_CHANGE = 0x8000, - END = 0xf000, // End of buffer - SHUTDOWN = 0xf200 // Shutdown worker thread, also marks end of buffer + CHG_BIT_0 = 0x0, + CHG_BIT_1 = 0x1, + CHG_BUS = 0x2, + CHG_QUAD = 0x3, + CHG_ARRAY = 0x4, + CHG_FLOAT = 0x5, + CHG_DOUBLE = 0x6, + // TODO: full.. + TIME_CHANGE = 0xd, + END = 0xe, // End of buffer + SHUTDOWN = 0xf // Shutdown worker thread, also marks end of buffer }; }; - -typedef union { - vluint32_t cmd; // Command code + params in bottom 8 bits - vluint32_t* oldp; // Pointer to previous value buffer to consult/update - // Note: These are 64-bit wide, as this union already has a pointer type in it. - vluint64_t params; // Command parameter - // New signal value in various forms - vluint64_t newBits; - float newFloat; - double newDouble; - vluint64_t timeui; -} VerilatedTraceEntry; #endif class VerilatedTraceCallInfo; @@ -149,18 +139,18 @@ private: size_t m_traceBufferSize; // Buffers handed to worker for processing - VerilatedThreadQueue m_buffersToWorker; + VerilatedThreadQueue m_buffersToWorker; // Buffers returned from worker after processing - VerilatedThreadQueue m_buffersFromWorker; + VerilatedThreadQueue m_buffersFromWorker; // Get a new trace buffer that can be populated. May block if none available - VerilatedTraceEntry* getTraceBuffer(); + vluint32_t* getTraceBuffer(); // Write pointer into current buffer - VerilatedTraceEntry* m_traceBufferWritep; + vluint32_t* m_traceBufferWritep; // End of trace buffer - VerilatedTraceEntry* m_traceBufferEndp; + vluint32_t* m_traceBufferEndp; // The worker thread itself std::unique_ptr m_workerThread; @@ -169,7 +159,7 @@ private: void workerThreadMain(); // Wait until given buffer is placed in m_buffersFromWorker - void waitForBuffer(const VerilatedTraceEntry* bufferp); + void waitForBuffer(const vluint32_t* bufferp); // Shut down and join worker, if it's running, otherwise do nothing void shutdownWorker(); @@ -280,48 +270,47 @@ public: #ifdef VL_TRACE_THREADED // Threaded tracing. Just dump everything in the trace buffer - inline void chgBit(vluint32_t* oldp, vluint32_t newval) { - m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_BIT | newval; - m_traceBufferWritep[1].oldp = oldp; + inline void chgBit(vluint32_t code, vluint32_t newval) { + m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_BIT_0 | newval; + m_traceBufferWritep[1] = code; m_traceBufferWritep += 2; VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); } - inline void chgBus(vluint32_t* oldp, vluint32_t newval, int bits) { - m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_BUS | bits; - m_traceBufferWritep[1].oldp = oldp; - m_traceBufferWritep[2].newBits = newval; + inline void chgBus(vluint32_t code, vluint32_t newval, int bits) { + m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_BUS; + m_traceBufferWritep[1] = code; + m_traceBufferWritep[2] = newval; m_traceBufferWritep += 3; VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); } - inline void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { - m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_QUAD | bits; - m_traceBufferWritep[1].oldp = oldp; - m_traceBufferWritep[2].newBits = newval; + inline void chgQuad(vluint32_t code, vluint64_t newval, int bits) { + m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_QUAD; + m_traceBufferWritep[1] = code; + *reinterpret_cast(m_traceBufferWritep + 2) = newval; + m_traceBufferWritep += 4; + VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + } + inline void chgArray(vluint32_t code, const vluint32_t* newvalp, int bits) { + m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_ARRAY; + m_traceBufferWritep[1] = code; + m_traceBufferWritep += 2; + for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; } + VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + } + inline void chgFloat(vluint32_t code, float newval) { + m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_FLOAT; + m_traceBufferWritep[1] = code; + // cppcheck-suppress invalidPointerCast + *reinterpret_cast(m_traceBufferWritep + 2) = newval; m_traceBufferWritep += 3; VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); } - inline void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { - m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_ARRAY; - m_traceBufferWritep[1].oldp = oldp; - m_traceBufferWritep[2].params = bits; - m_traceBufferWritep += 3; - vluint32_t* const wp = reinterpret_cast(m_traceBufferWritep); - for (int i = 0; i < (bits + 31) / 32; ++i) { wp[i] = newvalp[i]; } - m_traceBufferWritep += (bits + 63) / 64; - VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); - } - inline void chgFloat(vluint32_t* oldp, float newval) { - m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_FLOAT; - m_traceBufferWritep[1].oldp = oldp; - m_traceBufferWritep[2].newFloat = newval; - m_traceBufferWritep += 3; - VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); - } - inline void chgDouble(vluint32_t* oldp, double newval) { - m_traceBufferWritep[0].cmd = VerilatedTraceCommand::CHG_DOUBLE; - m_traceBufferWritep[1].oldp = oldp; - m_traceBufferWritep[2].newDouble = newval; - m_traceBufferWritep += 3; + inline void chgDouble(vluint32_t code, double newval) { + m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE; + m_traceBufferWritep[1] = code; + // cppcheck-suppress invalidPointerCast + *reinterpret_cast(m_traceBufferWritep + 2) = newval; + m_traceBufferWritep += 4; VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); } diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp index 3dc3c33d4..2e5345d65 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.cpp @@ -101,8 +101,8 @@ public: // This is in .cpp file so is not widely visible //========================================================================= // Buffer management -template <> VerilatedTraceEntry* VerilatedTrace::getTraceBuffer() { - VerilatedTraceEntry* bufferp; +template <> vluint32_t* VerilatedTrace::getTraceBuffer() { + vluint32_t* bufferp; // Some jitter is expected, so some number of alternative trace buffers are // required, but don't allocate more than 8 buffers. if (m_numTraceBuffers < 8) { @@ -111,7 +111,7 @@ template <> VerilatedTraceEntry* VerilatedTrace::getTraceBuffer() ++m_numTraceBuffers; // Note: over allocate a bit so pointer comparison is well defined // if we overflow only by a small amount - bufferp = new VerilatedTraceEntry[m_traceBufferSize + 16]; + bufferp = new vluint32_t[m_traceBufferSize + 16]; } } else { // Block until a buffer becomes available @@ -120,10 +120,10 @@ template <> VerilatedTraceEntry* VerilatedTrace::getTraceBuffer() return bufferp; } -template <> void VerilatedTrace::waitForBuffer(const VerilatedTraceEntry* buffp) { +template <> void VerilatedTrace::waitForBuffer(const vluint32_t* buffp) { // Slow path code only called on flush/shutdown, so use a simple algorithm. // Collect buffers from worker and stash them until we get the one we want. - std::deque stash; + std::deque stash; do { stash.push_back(m_buffersFromWorker.get()); } while (stash.back() != buffp); // Now put them back in the queue, in the original order. while (!stash.empty()) { @@ -136,65 +136,71 @@ template <> void VerilatedTrace::waitForBuffer(const VerilatedTrac // Worker thread template <> void VerilatedTrace::workerThreadMain() { - while (true) { - VerilatedTraceEntry* const bufferp = m_buffersToWorker.get(); + bool shutdown = false; + + do { + vluint32_t* const bufferp = m_buffersToWorker.get(); VL_TRACE_THREAD_DEBUG(""); - VL_TRACE_THREAD_DEBUG("Got buffer"); + VL_TRACE_THREAD_DEBUG("Got buffer: " << bufferp); - const VerilatedTraceEntry* readp = bufferp; - - vluint32_t cmd; - unsigned bits; - vluint32_t* oldp; - vluint64_t newBits; + const vluint32_t* readp = bufferp; while (true) { - cmd = (readp++)->cmd; + const vluint32_t cmd = readp[0]; + const vluint32_t top = cmd >> 4; + // Always set this up, as it is almost always needed + vluint32_t* const oldp = m_sigs_oldvalp + readp[1]; + // Note this increment needs to be undone on commands which do not + // actually contain a code, but those are the rare cases. + readp += 2; - switch (cmd & ~0xFFU) { + switch (cmd & 0xF) { //=== // CHG_* commands - case VerilatedTraceCommand::CHG_BIT: - VL_TRACE_THREAD_DEBUG("Command CHG_BIT"); - chgBitImpl((readp++)->oldp, cmd & 1); + case VerilatedTraceCommand::CHG_BIT_0: + VL_TRACE_THREAD_DEBUG("Command CHG_BIT_0 " << top); + chgBitImpl(oldp, 0); + continue; + case VerilatedTraceCommand::CHG_BIT_1: + VL_TRACE_THREAD_DEBUG("Command CHG_BIT_1 " << top); + chgBitImpl(oldp, 1); continue; case VerilatedTraceCommand::CHG_BUS: - VL_TRACE_THREAD_DEBUG("Command CHG_BUS"); + VL_TRACE_THREAD_DEBUG("Command CHG_BUS " << top); // Bits stored in bottom byte of command - chgBusImpl(readp[0].oldp, readp[1].newBits, cmd & 0xFFULL); - readp += 2; - VL_TRACE_THREAD_DEBUG("Command CHG_BUS DONE"); + chgBusImpl(oldp, *readp, top); + readp += 1; continue; case VerilatedTraceCommand::CHG_QUAD: - VL_TRACE_THREAD_DEBUG("Command CHG_QUAD"); + VL_TRACE_THREAD_DEBUG("Command CHG_QUAD " << top); // Bits stored in bottom byte of command - chgQuadImpl(readp[0].oldp, readp[1].newBits, cmd & 0xFFULL); + chgQuadImpl(oldp, *reinterpret_cast(readp), top); readp += 2; continue; case VerilatedTraceCommand::CHG_ARRAY: - VL_TRACE_THREAD_DEBUG("Command CHG_CHG_ARRAY"); - oldp = (readp++)->oldp; - bits = (readp++)->params; - chgArrayImpl(oldp, reinterpret_cast(readp), bits); - readp += (bits + 63) / 64; + VL_TRACE_THREAD_DEBUG("Command CHG_ARRAY " << top); + chgArrayImpl(oldp, readp, top); + readp += (top + 31) / 32; continue; case VerilatedTraceCommand::CHG_FLOAT: - VL_TRACE_THREAD_DEBUG("Command CHG_FLOAT"); - chgFloatImpl(readp[0].oldp, readp[1].newFloat); - readp += 2; + VL_TRACE_THREAD_DEBUG("Command CHG_FLOAT " << top); + chgFloatImpl(oldp, *reinterpret_cast(readp)); + readp += 1; continue; case VerilatedTraceCommand::CHG_DOUBLE: - VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE"); - chgDoubleImpl(readp[0].oldp, readp[1].newDouble); + VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top); + chgDoubleImpl(oldp, *reinterpret_cast(readp)); readp += 2; continue; //=== // Rare commands case VerilatedTraceCommand::TIME_CHANGE: - VL_TRACE_THREAD_DEBUG("Command TIME_CHANGE"); - emitTimeChange((readp++)->timeui); + VL_TRACE_THREAD_DEBUG("Command TIME_CHANGE " << top); + readp -= 1; // No code in this command, undo increment + emitTimeChange(*reinterpret_cast(readp)); + readp += 2; continue; //=== @@ -202,11 +208,13 @@ template <> void VerilatedTrace::workerThreadMain() { case VerilatedTraceCommand::END: VL_TRACE_THREAD_DEBUG("Command END"); break; case VerilatedTraceCommand::SHUTDOWN: VL_TRACE_THREAD_DEBUG("Command SHUTDOWN"); + shutdown = true; break; //=== // Unknown command default: + VL_TRACE_THREAD_DEBUG("Command UNKNOWN"); VL_PRINTF_MT("Trace command: 0x%08x\n", cmd); VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command"); break; @@ -221,10 +229,7 @@ template <> void VerilatedTrace::workerThreadMain() { // Return buffer m_buffersFromWorker.put(bufferp); - - // Shut down if required - if (VL_UNLIKELY(cmd == VerilatedTraceCommand::SHUTDOWN)) return; - } + } while (VL_LIKELY(!shutdown)); } template <> void VerilatedTrace::shutdownWorker() { @@ -232,8 +237,8 @@ template <> void VerilatedTrace::shutdownWorker() { if (!m_workerThread) return; // Hand an buffer with a shutdown command to the worker thread - VerilatedTraceEntry* const bufferp = getTraceBuffer(); - bufferp[0].cmd = VerilatedTraceCommand::SHUTDOWN; + vluint32_t* const bufferp = getTraceBuffer(); + bufferp[0] = VerilatedTraceCommand::SHUTDOWN; m_buffersToWorker.put(bufferp); // Wait for it to return waitForBuffer(bufferp); @@ -260,8 +265,8 @@ template <> void VerilatedTrace::close() { template <> void VerilatedTrace::flush() { #ifdef VL_TRACE_THREADED // Hand an empty buffer to the worker thread - VerilatedTraceEntry* const bufferp = getTraceBuffer(); - bufferp[0].cmd = VerilatedTraceCommand::END; + vluint32_t* const bufferp = getTraceBuffer(); + *bufferp = VerilatedTraceCommand::END; m_buffersToWorker.put(bufferp); // Wait for it to be returned. As the processing is in-order, // this ensures all previous buffers have been processed. @@ -333,10 +338,10 @@ template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { #ifdef VL_TRACE_THREADED // Compute trace buffer size. we need to be able to store a new value for // each signal, which is 'nextCode()' entries after the init callbacks - // above have been run, plus up to 3 more words of metadata per signal, - // plus fixed overhead of 1 for a termination flag and 2 for a time stamp + // above have been run, plus up to 2 more words of metadata per signal, + // plus fixed overhead of 1 for a termination flag and 3 for a time stamp // update. - m_traceBufferSize = nextCode() + numSignals() * 3 + 3; + m_traceBufferSize = nextCode() + numSignals() * 2 + 4; // Start the worker thread m_workerThread.reset(new std::thread(&VerilatedTrace::workerThreadMain, this)); @@ -406,18 +411,21 @@ template <> void VerilatedTrace::dump(vluint64_t timeui) { } #ifdef VL_TRACE_THREADED - // Get the trace buffer we are about to fill - VerilatedTraceEntry* const bufferp = getTraceBuffer(); - m_traceBufferWritep = bufferp; - m_traceBufferEndp = bufferp + m_traceBufferSize; - // Currently only incremental dumps run on the worker thread + vluint32_t* bufferp = nullptr; if (VL_LIKELY(!m_fullDump)) { + // Get the trace buffer we are about to fill + bufferp = getTraceBuffer(); + m_traceBufferWritep = bufferp; + m_traceBufferEndp = bufferp + m_traceBufferSize; + // Tell worker to update time point - (m_traceBufferWritep++)->cmd = VerilatedTraceCommand::TIME_CHANGE; - (m_traceBufferWritep++)->timeui = timeui; + m_traceBufferWritep[0] = VerilatedTraceCommand::TIME_CHANGE; + *reinterpret_cast(m_traceBufferWritep + 1) = timeui; + m_traceBufferWritep += 3; } else { // Update time point + flush(); emitTimeChange(timeui); } #else @@ -440,14 +448,16 @@ template <> void VerilatedTrace::dump(vluint64_t timeui) { } #ifdef VL_TRACE_THREADED - // Mark end of the trace buffer we just filled - (m_traceBufferWritep++)->cmd = VerilatedTraceCommand::END; + if (VL_LIKELY(bufferp)) { + // Mark end of the trace buffer we just filled + *m_traceBufferWritep++ = VerilatedTraceCommand::END; - // Assert no buffer overflow - assert(m_traceBufferWritep - bufferp <= m_traceBufferSize); + // Assert no buffer overflow + assert(m_traceBufferWritep - bufferp <= m_traceBufferSize); - // Pass it to the worker thread - m_buffersToWorker.put(bufferp); + // Pass it to the worker thread + m_buffersToWorker.put(bufferp); + } #endif } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index ee4ae3e3d..061e0b1b3 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3547,29 +3547,30 @@ class EmitCTrace : EmitCStmts { void emitTraceChangeOne(AstTraceInc* nodep, int arrayindex) { iterateAndNextNull(nodep->precondsp()); - string full = ((m_funcp->funcType() == AstCFuncType::TRACE_FULL - || m_funcp->funcType() == AstCFuncType::TRACE_FULL_SUB) - ? "full" - : "chg"); + const bool full = (m_funcp->funcType() == AstCFuncType::TRACE_FULL + || m_funcp->funcType() == AstCFuncType::TRACE_FULL_SUB); + const string func = full ? "full" : "chg"; bool emitWidth = false; if (nodep->dtypep()->basicp()->isDouble()) { - puts("vcdp->" + full + "Double"); + puts("vcdp->" + func + "Double"); } else if (nodep->isWide() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep)) { - puts("vcdp->" + full + "Array"); + puts("vcdp->" + func + "Array"); emitWidth = true; } else if (nodep->isQuad()) { - puts("vcdp->" + full + "Quad"); + puts("vcdp->" + func + "Quad"); emitWidth = true; } else if (nodep->declp()->widthMin() > 1) { - puts("vcdp->" + full + "Bus"); + puts("vcdp->" + func + "Bus"); emitWidth = true; } else { - puts("vcdp->" + full + "Bit"); + puts("vcdp->" + func + "Bit"); } const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords()); const uint32_t code = nodep->declp()->code() + offset; - puts("(oldp+" + cvtToStr(code - m_baseCode) + ","); + puts(v3Global.opt.trueTraceThreads() && !full ? "(base+" : "(oldp+"); + puts(cvtToStr(code - m_baseCode)); + puts(","); emitTraceValue(nodep, arrayindex); if (emitWidth) puts("," + cvtToStr(nodep->declp()->widthMin())); puts(");\n"); @@ -3648,8 +3649,14 @@ class EmitCTrace : EmitCStmts { nodep->stmtsp()->v3fatalSrc("Trace sub function should contain AstTraceInc"); } m_baseCode = stmtp->declp()->code(); - puts("vluint32_t* oldp = vcdp->oldp(code+" + cvtToStr(m_baseCode) + ");\n"); - puts("if (false && vcdp && oldp) {} // Prevent unused\n"); + if (v3Global.opt.trueTraceThreads() + && nodep->funcType() == AstCFuncType::TRACE_CHANGE_SUB) { + puts("vluint32_t base = code+" + cvtToStr(m_baseCode) + ";\n"); + puts("if (false && vcdp && base) {} // Prevent unused\n"); + } else { + puts("vluint32_t* oldp = vcdp->oldp(code+" + cvtToStr(m_baseCode) + ");\n"); + puts("if (false && vcdp && oldp) {} // Prevent unused\n"); + } } else if (nodep->funcType() == AstCFuncType::TRACE_INIT_SUB) { puts("int c = code;\n"); puts("if (false && vcdp && c) {} // Prevent unused\n"); diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index af8be2aa9..19816a465 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -69,9 +69,7 @@ public: of.puts("\n"); of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n"); of.puts("VM_TRACE_THREADS = "); - of.puts(!v3Global.opt.traceThreads() - ? "0" - : cvtToStr(v3Global.opt.traceThreads() - v3Global.opt.traceFormat().fst())); + of.puts(cvtToStr(v3Global.opt.trueTraceThreads())); of.puts("\n"); of.puts("# Separate FST writer thread? 0/1 (from --trace-fst with --trace-thread > 0)\n"); of.puts("VM_TRACE_FST_WRITER_THREAD = "); diff --git a/src/V3Options.h b/src/V3Options.h index 6e4941ba8..28082d8a9 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -490,6 +490,9 @@ public: int traceMaxArray() const { return m_traceMaxArray; } int traceMaxWidth() const { return m_traceMaxWidth; } int traceThreads() const { return m_traceThreads; } + bool trueTraceThreads() const { + return traceThreads() == 0 ? 0 : traceThreads() - traceFormat().fst(); + } int unrollCount() const { return m_unrollCount; } int unrollStmts() const { return m_unrollStmts; } From 910803e6dbd7b77bb7dcba77dc42d4507efe1b71 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 27 Apr 2020 18:38:30 -0400 Subject: [PATCH 108/127] Fix error on unpacked connecting to packed, #2288. --- Changes | 2 ++ src/V3Width.cpp | 6 +++--- test_regress/t/t_inst_misarray2_bad.out | 5 +++++ test_regress/t/t_inst_misarray2_bad.pl | 20 ++++++++++++++++++++ test_regress/t/t_inst_misarray2_bad.v | 17 +++++++++++++++++ test_regress/t/t_inst_misarray_bad.out | 6 +++--- 6 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 test_regress/t/t_inst_misarray2_bad.out create mode 100755 test_regress/t/t_inst_misarray2_bad.pl create mode 100644 test_regress/t/t_inst_misarray2_bad.v diff --git a/Changes b/Changes index 03d6ec43f..d77e97f71 100644 --- a/Changes +++ b/Changes @@ -36,6 +36,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix arrayed instances connecting to slices, #2263. [Don/engr248] +**** Fix error on unpacked connecting to packed, #2288. [Joseph Shaker] + * Verilator 4.032 2020-04-04 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 940adb4fb..a80ab2073 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3519,13 +3519,13 @@ private: << exprSize << "."); UINFO(1, " Related lo: " << modDTypep->skipRefp() << endl); UINFO(1, " Related hi: " << exprDTypep->skipRefp() << endl); - } else if ((exprArrayp && !modArrayp && pinwidth != conwidth) - || (!exprArrayp && modArrayp && pinwidth != conwidth)) { + } else if ((exprArrayp && !modArrayp) || (!exprArrayp && modArrayp)) { nodep->v3error("Illegal " << nodep->prettyOperatorName() << "," << " mismatch between port which is" << (modArrayp ? "" : " not") << " an array," << " and expression which is" - << (exprArrayp ? "" : " not") << " an array."); + << (exprArrayp ? "" : " not") + << " an array. (IEEE 1800-2017 7.6)"); UINFO(1, " Related lo: " << modDTypep->skipRefp() << endl); UINFO(1, " Related hi: " << exprDTypep->skipRefp() << endl); } diff --git a/test_regress/t/t_inst_misarray2_bad.out b/test_regress/t/t_inst_misarray2_bad.out new file mode 100644 index 000000000..889bfcc7c --- /dev/null +++ b/test_regress/t/t_inst_misarray2_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_inst_misarray2_bad.v:10:17: Illegal input port connection 'i_data', mismatch between port which is not an array, and expression which is an array. (IEEE 1800-2017 7.6) + : ... In instance t + 10 | .i_data(fft_oQ[6:0]) + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_inst_misarray2_bad.pl b/test_regress/t/t_inst_misarray2_bad.pl new file mode 100755 index 000000000..32c62a917 --- /dev/null +++ b/test_regress/t/t_inst_misarray2_bad.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + + +ok(1); +1; diff --git a/test_regress/t/t_inst_misarray2_bad.v b/test_regress/t/t_inst_misarray2_bad.v new file mode 100644 index 000000000..dc55dcad4 --- /dev/null +++ b/test_regress/t/t_inst_misarray2_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire signed [16:0] fft_oQ [6:0]; + round round( + .i_data(fft_oQ[6:0]) + ); +endmodule +module round( + input wire signed [16:0] i_data // Misdeclared, not a vector + ); + wire signed [15:0] w_convergent = {10'b0, {6{~i_data[7]}}}; +endmodule diff --git a/test_regress/t/t_inst_misarray_bad.out b/test_regress/t/t_inst_misarray_bad.out index 0e0a9a157..56dd2368a 100644 --- a/test_regress/t/t_inst_misarray_bad.out +++ b/test_regress/t/t_inst_misarray_bad.out @@ -1,5 +1,5 @@ -%Error: t/t_inst_misarray_bad.v:17:27: VARREF 't.foo' is not an unpacked array, but is in an unpacked array context - : ... In instance t.foo +%Error: t/t_inst_misarray_bad.v:17:23: Illegal input port connection 'foo', mismatch between port which is an array, and expression which is not an array. (IEEE 1800-2017 7.6) + : ... In instance t 17 | .foo(foo)); - | ^~~ + | ^~~ %Error: Exiting due to From a95eb53684e48ec9abad3338831cb5611b3d9ac5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 28 Apr 2020 18:46:59 -0400 Subject: [PATCH 109/127] Commentary (#2290). --- bin/verilator | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/bin/verilator b/bin/verilator index 7d0b2c5c0..d41c2532d 100755 --- a/bin/verilator +++ b/bin/verilator @@ -5271,17 +5271,21 @@ be accessing with a /*verilator public*/ comment before the closing semicolon. Then scope into the C++ class to read the value of the signal, as you would any other member variable. -Signals are the smallest of 8-bit chars, 16-bit shorts, 32-bit longs, or -64-bit long longs that fits the width of the signal. Generally, you can -use just uint32_t's for 1 to 32 bits, or vluint64_t for 1 to 64 bits, and -the compiler will properly up-convert smaller entities. +Signals are the smallest of 8-bit unsigned chars (equivalent to uint8_t), +16-bit unsigned shorts (uint16_t), 32-bit unsigned longs (uint32_t), or +64-bit unsigned long longs (uint64_t) that fits the width of the signal. +Generally, you can use just uint32_t's for 1 to 32 bits, or vluint64_t for +1 to 64 bits, and the compiler will properly up-convert smaller entities. +Note even signed ports are declared as unsigned; you must sign extend +yourself to the appropriate signal width. Signals wider than 64 bits are stored as an array of 32-bit uint32_t's. Thus to read bits 31:0, access signal[0], and for bits 63:32, access signal[1]. Unused bits (for example bit numbers 65-96 of a 65-bit vector) -will always be zero. if you change the value you must make sure to pack -zeros in the unused bits or core-dumps may result. (Because Verilator -strips array bound checks where it believes them to be unnecessary.) +will always be zero. If you change the value you must make sure to pack +zeros in the unused bits or core-dumps may result, because Verilator strips +array bound checks where it believes them to be unnecessary to improve +performance. In the SYSTEMC example above, if you had in our.v: From 77cc335c2dabf1531f13e00740e2ab598c932176 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 28 Apr 2020 18:47:49 -0400 Subject: [PATCH 110/127] Commentary --- docs/internals.adoc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/internals.adoc b/docs/internals.adoc index eec37389c..0a11bc295 100644 --- a/docs/internals.adoc +++ b/docs/internals.adoc @@ -405,6 +405,15 @@ This sets indentation to the `cc-mode` defaults. (Verilator predates a CC-mode change of several years ago which overrides the defaults with GNU style indentation; the `c-set-style` undoes that.) +* Use "mixedCapsSymbols" instead of "underlined_symbols". + +* Uas a "p" suffix on variables that are pointers, e.g. "nodep". + +* Comment every member variable. + +Indentation is automatically maintained with "make clang-format" (using +clang-format version 10.0.0). For those manually formatting: + * Use 4 spaces per level, and no tabs. * Use 2 spaces between the end of source and the beginning of a comment. @@ -414,12 +423,6 @@ style indentation; the `c-set-style` undoes that.) * No spaces before semicolons, nor between a function's name and open parenthesis (only applies to functions; if/else has a following space). -* Use "mixedCapsSymbols" instead of "underlined_symbols". - -* Uas a "p" suffix on variables that are pointers, e.g. "nodep". - -* Comment every member variable. - === The `astgen` Script Some of the code implementing passes is extremely repetitive, and must be From c6d1a9858ab380385bf259e633e75cbf5f83b352 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 28 Apr 2020 18:47:59 -0400 Subject: [PATCH 111/127] Use clang-format 10.0.0 --- Makefile.in | 2 ++ docs/install.adoc | 7 +++---- src/V3Ast.h | 6 +++--- src/V3Number.cpp | 17 ++++++++--------- src/V3Undriven.cpp | 2 +- src/V3Unknown.cpp | 13 +++++++------ src/V3Width.cpp | 6 +++--- src/Verilator.cpp | 5 ++--- 8 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Makefile.in b/Makefile.in index f96f4c85c..b49baf8ae 100644 --- a/Makefile.in +++ b/Makefile.in @@ -460,6 +460,8 @@ CLANGFORMAT = clang-format CLANGFORMAT_FLAGS = -i clang-format: + @$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \ + || echo "*** You are not using clang-format 10.0, indents may differ from master's ***" $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) ftp: info diff --git a/docs/install.adoc b/docs/install.adoc index 8293479f0..094661f3e 100644 --- a/docs/install.adoc +++ b/docs/install.adoc @@ -90,18 +90,17 @@ To build or run the following are optional but should be installed for good performance: sudo apt-get install ccache # If present at build, needed for run - sudo apt-get install libgoogle-perftools-dev + sudo apt-get install libgoogle-perftools-dev numactl To build Verilator you will need to install these packages; these do not need to be present to run Verilator: sudo apt-get install git - sudo apt-get install autoconf - sudo apt-get install flex bison + sudo apt-get install autoconf flex bison Those developing Verilator itself may also want these (see internals.adoc): - sudo apt-get install gdb asciidoctor graphviz cmake + sudo apt-get install gdb asciidoctor graphviz cmake clang-format cpan install Pod::Perldoc cpan install Unix::Processors cpan install Parallel::Forker diff --git a/src/V3Ast.h b/src/V3Ast.h index a9f533f2b..68b7993d3 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2403,9 +2403,9 @@ public: virtual void dump(std::ostream& str) const; // For basicp() we reuse the size to indicate a "fake" basic type of same size virtual AstBasicDType* basicp() const { - return (isFourstate() ? VN_CAST(findLogicRangeDType(VNumRange(width() - 1, 0, false), - width(), numeric()), - BasicDType) + return (isFourstate() ? VN_CAST( + findLogicRangeDType(VNumRange(width() - 1, 0, false), width(), numeric()), + BasicDType) : VN_CAST(findBitRangeDType(VNumRange(width() - 1, 0, false), width(), numeric()), BasicDType)); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 0ea55b329..1e1360f33 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -203,15 +203,14 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) this->opAdd(product, addend); if (product.bitsValue(width(), 4)) { // Overflowed static int warned = 0; - v3error( - "Too many digits for " - << width() << " bit number: " << sourcep << std::endl - << ((!m_sized && !warned++) - ? (V3Error::warnMore() + "... As that number was unsized" - + " ('d...) it is limited to 32 bits (IEEE 1800-2017 " - "5.7.1)\n" - + V3Error::warnMore() + "... Suggest adding a size to it.") - : "")); + v3error("Too many digits for " + << width() << " bit number: " << sourcep << std::endl + << ((!m_sized && !warned++) ? ( + V3Error::warnMore() + "... As that number was unsized" + + " ('d...) it is limited to 32 bits (IEEE 1800-2017 " + "5.7.1)\n" + + V3Error::warnMore() + "... Suggest adding a size to it.") + : "")); while (*(cp + 1)) cp++; // Skip ahead so don't get multiple warnings } } diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 6f29dcd03..0bc57da59 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -274,7 +274,7 @@ private: && !m_inBBox // We may have falsely considered a SysIgnore as a driver && !VN_IS(nodep, VarXRef) // Xrefs might point at two different instances && !varp->fileline()->warnIsOff( - V3ErrorCode::ALWCOMBORDER)) { // Warn only once per variable + V3ErrorCode::ALWCOMBORDER)) { // Warn only once per variable nodep->v3warn(ALWCOMBORDER, "Always_comb variable driven after use: " << nodep->prettyNameQ()); varp->fileline()->modifyWarnOff(V3ErrorCode::ALWCOMBORDER, diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 86c6507ff..5abbd20c0 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -120,12 +120,13 @@ private: AstNode* abovep = prep->backp(); // Grab above point before lose it w/ next replace prep->replaceWith(new AstVarRef(fl, varp, true)); - AstIf* newp = new AstIf(fl, condp, - (needDly ? static_cast(new AstAssignDly( - fl, prep, new AstVarRef(fl, varp, false))) - : static_cast(new AstAssign( - fl, prep, new AstVarRef(fl, varp, false)))), - NULL); + AstIf* newp + = new AstIf(fl, condp, + (needDly ? static_cast( + new AstAssignDly(fl, prep, new AstVarRef(fl, varp, false))) + : static_cast( + new AstAssign(fl, prep, new AstVarRef(fl, varp, false)))), + NULL); newp->branchPred(VBranchPred::BP_LIKELY); if (debug() >= 9) newp->dumpTree(cout, " _new: "); abovep->addNextStmt(newp, abovep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a80ab2073..2d5a4d94a 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4689,9 +4689,9 @@ private: // We convert to/from vlsint32 rather than use floor() as want to make sure is // representable in integer's number of bits if (constp->isDouble() - && v3EpsilonEqual(constp->num().toDouble(), - static_cast( - static_cast(constp->num().toDouble())))) { + && v3EpsilonEqual( + constp->num().toDouble(), + static_cast(static_cast(constp->num().toDouble())))) { warnOn = false; } } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index c34bd6b6a..2f174600e 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -502,9 +502,8 @@ static void verilate(const string& argString) { // Can we skip doing everything if times are ok? V3File::addSrcDepend(v3Global.opt.bin()); if (v3Global.opt.skipIdentical().isTrue() - && V3File::checkTimes(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() - + "__verFiles.dat", - argString)) { + && V3File::checkTimes( + v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__verFiles.dat", argString)) { UINFO(1, "--skip-identical: No change to any source files, exiting\n"); return; } From 15ad3f46be13cb2a24ea9e7089c497e4a0e52842 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 28 Apr 2020 21:15:20 -0400 Subject: [PATCH 112/127] Fix logical not optimization with empty begin, #2291. --- Changes | 2 ++ src/V3Const.cpp | 3 ++- test_regress/t/t_if_swap.pl | 17 +++++++++++++++++ test_regress/t/t_if_swap.v | 24 ++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_if_swap.pl create mode 100644 test_regress/t/t_if_swap.v diff --git a/Changes b/Changes index d77e97f71..58c8272c2 100644 --- a/Changes +++ b/Changes @@ -38,6 +38,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix error on unpacked connecting to packed, #2288. [Joseph Shaker] +**** Fix logical not optimization with empty begin, #2291. [Baltazar Ortiz] + * Verilator 4.032 2020-04-04 diff --git a/src/V3Const.cpp b/src/V3Const.cpp index c36ae1f9d..7418df2fa 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1954,7 +1954,8 @@ private: || VN_IS(nodep->condp(), LogNot)) && nodep->ifsp() && nodep->elsesp()) { UINFO(4, "IF(NOT {x}) => IF(x) swapped if/else" << nodep << endl); - AstNode* condp = VN_CAST(nodep->condp(), Not)->lhsp()->unlinkFrBackWithNext(); + AstNode* condp + = VN_CAST(nodep->condp(), NodeUniop)->lhsp()->unlinkFrBackWithNext(); AstNode* ifsp = nodep->ifsp()->unlinkFrBackWithNext(); AstNode* elsesp = nodep->elsesp()->unlinkFrBackWithNext(); AstIf* ifp = new AstIf(nodep->fileline(), condp, elsesp, ifsp); diff --git a/test_regress/t/t_if_swap.pl b/test_regress/t/t_if_swap.pl new file mode 100755 index 000000000..29a7fc65c --- /dev/null +++ b/test_regress/t/t_if_swap.pl @@ -0,0 +1,17 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +ok(1); +1; diff --git a/test_regress/t/t_if_swap.v b/test_regress/t/t_if_swap.v new file mode 100644 index 000000000..d1e771433 --- /dev/null +++ b/test_regress/t/t_if_swap.v @@ -0,0 +1,24 @@ +module t + (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + integer f; + + always @(posedge clk) begin + if (!$feof(f)) begin + $display("Doing stuff with file."); + end + // Commenting out these two lines fixes the fault + else begin + end + if (!$feof(f)) begin + end + else begin + $display("Not doing stuff with file."); + end + end + +endmodule From b44efe7ef781fc140ae3279d937695363ab6802d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 28 Apr 2020 21:15:27 -0400 Subject: [PATCH 113/127] Use 'suggest' for consistent wording. --- bin/verilator | 9 ++++++--- src/V3Partition.cpp | 2 +- test_regress/t/t_debug_sigsegv_bad.pl | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/bin/verilator b/bin/verilator index d41c2532d..fb083c5c3 100755 --- a/bin/verilator +++ b/bin/verilator @@ -184,11 +184,14 @@ sub run { if (($status & 127) == 4 # SIGILL || ($status & 127) == 8 # SIGFPA || ($status & 127) == 11) { # SIGSEGV - warn "%Error: Verilator internal fault, sorry. Consider trying --debug --gdbbt\n" if !$Debug; + warn "%Error: Verilator internal fault, sorry. " + ."Suggest trying --debug --gdbbt\n" if !$Debug; } elsif (($status & 127) == 6) { # SIGABRT - warn "%Error: Verilator aborted. Consider trying --debug --gdbbt\n" if !$Debug; + warn "%Error: Verilator aborted. " + ."Suggest trying --debug --gdbbt\n" if !$Debug; } else { - warn "%Error: Verilator threw signal $status. Consider trying --debug --gdbbt\n" if !$Debug; + warn "%Error: Verilator threw signal $status. " + ."Suggest trying --debug --gdbbt\n" if !$Debug; } } if (!$opt_quiet_exit && ($status != 256 || $Debug)) { # i.e. not normal exit(1) diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index e062e6e13..11edc49dd 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -1187,7 +1187,7 @@ public: m_scoreLimit = (m_scoreLimit * 120) / 100; v3Global.rootp()->fileline()->v3warn( UNOPTTHREADS, "Thread scheduler is unable to provide requested " - "parallelism; consider asking for fewer threads."); + "parallelism; suggest asking for fewer threads."); UINFO(1, "Critical path limit was=" << oldLimit << " now=" << m_scoreLimit << endl); continue; diff --git a/test_regress/t/t_debug_sigsegv_bad.pl b/test_regress/t/t_debug_sigsegv_bad.pl index 691631fe4..cd6886e34 100755 --- a/test_regress/t/t_debug_sigsegv_bad.pl +++ b/test_regress/t/t_debug_sigsegv_bad.pl @@ -15,7 +15,7 @@ compile( v_flags => ["--debug-sigsegv"], fails => 1, expect => -'%Error: Verilator internal fault, sorry. Consider trying --debug --gdbbt +'%Error: Verilator internal fault, sorry. Suggest trying --debug --gdbbt %Error: Command Failed.*', ); From 977ceb404d76b868bb8105880ccc2d1ce8de875a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 29 Apr 2020 18:10:43 -0400 Subject: [PATCH 114/127] Mention -march-native, #2289. --- bin/verilator | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/verilator b/bin/verilator index fb083c5c3..1b448da73 100755 --- a/bin/verilator +++ b/bin/verilator @@ -2071,18 +2071,18 @@ OPT, OPT_FAST, or OPT_SLOW lib/verilated.mk. Or, use the -CFLAGS and/or the compiler or linker. Or, just for one run, pass them on the command line to make: - make OPT_FAST="-Os -fno-stack-protector" -f Vour.mk Vour__ALL.a + make OPT_FAST="-Os -march=native -fno-stack-protector" -f Vour.mk Vour__ALL.a OPT_FAST specifies optimizations for those programs that are part of the fast path, mostly code that is executed every cycle. OPT_SLOW specifies optimizations for slow-path files (plus tracing), which execute only rarely, yet take a long time to compile with optimization on. OPT specifies overall optimization and affects all compiles, including those -OPT_FAST and OPT_SLOW control. For best results, use OPT="-Os", and link -with "-static". Nearly the same results can be had with much better -compile times with OPT_FAST="-O1 -fstrict-aliasing". Higher optimization -such as "-O2" or "-O3" may help, but gcc compile times may be excessive -under O3 on even medium sized designs. +OPT_FAST and OPT_SLOW control. For best results, use OPT="-Os +-march=native", and link with "-static". Nearly the same results can be +had with much better compile times with OPT_FAST="-O1 -fstrict-aliasing". +Higher optimization such as "-O2" or "-O3" may help, but gcc compile times +may be excessive under O3 on even medium sized designs. Unfortunately, using the optimizer with SystemC files can result in compiles taking several minutes. (The SystemC libraries have many little From a6c97cc3bc5664508adabcac146833341805ae93 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 29 Apr 2020 18:41:00 -0400 Subject: [PATCH 115/127] Commentary --- .github/ISSUE_TEMPLATE/bug_report.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 3e438348e..dd8f88943 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,4 +11,6 @@ Thanks for taking the time to report this. Can you attach an example that shows the issue? (Must be openly licensed, ideally in test_regress format.) +What 'verilator --version' are you using? Did you try it with git master version? + May we assist you in trying to fix this yourself? From faf7255e832b28e65dd268b19125bbae4358c0ad Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 29 Apr 2020 18:42:28 -0400 Subject: [PATCH 116/127] Commentary --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd8f88943..5873b5bd7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,6 +11,6 @@ Thanks for taking the time to report this. Can you attach an example that shows the issue? (Must be openly licensed, ideally in test_regress format.) -What 'verilator --version' are you using? Did you try it with git master version? +What 'verilator --version' are you using? Did you try it with the git master version? -May we assist you in trying to fix this yourself? +Would you be willing to try to fix Verilator yourself with assistance? From aa9cde22c874813aa902172920557f95446f6d39 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 30 Apr 2020 00:09:09 +0100 Subject: [PATCH 117/127] Use SIMD intrinsics to render VCD traces (#2289) Use SIMD intrinsics to render VCD traces. I have measured 10-40% single threaded performance increase with VCD tracing on SweRV EH1 and lowRISC Ibex using SSE2 intrinsics to render the trace. Also helps a tiny bit with FST, but now almost all of the FST overhead is in the FST library. I have reworked the tracing routines to use more precisely sized arguments. The nice thing about this is that the performance without the intrinsics is pretty much the same as it was before, as we do at most 2x as much work as necessary, but in exchange there are no data dependent branches at all. --- include/verilated_fst_c.cpp | 55 ++++- include/verilated_fst_c.h | 12 +- include/verilated_intrinsics.h | 41 ++++ include/verilated_trace.h | 88 +++++--- include/verilated_trace_imp.cpp | 162 +++++++++++++-- include/verilated_vcd_c.cpp | 204 ++++--------------- include/verilated_vcd_c.h | 51 +++-- include/verilatedos.h | 10 + src/V3EmitC.cpp | 17 +- test_regress/t/t_trace_array_fst_portable.pl | 28 +++ test_regress/t/t_trace_complex_portable.pl | 38 ++++ 11 files changed, 451 insertions(+), 255 deletions(-) create mode 100644 include/verilated_intrinsics.h create mode 100755 test_regress/t/t_trace_array_fst_portable.pl create mode 100755 test_regress/t/t_trace_complex_portable.pl diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index c4b1dc077..c54d818d8 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -64,11 +64,13 @@ VerilatedFst::VerilatedFst(void* fst) : m_fst(fst) - , m_symbolp(NULL) {} + , m_symbolp(NULL) + , m_strbuf(NULL) {} VerilatedFst::~VerilatedFst() { if (m_fst) fstWriterClose(m_fst); if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = NULL); + if (m_strbuf) VL_DO_CLEAR(delete[] m_strbuf, m_strbuf = NULL); } void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { @@ -100,6 +102,9 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { } } m_code2symbol.clear(); + + // Allocate string buffer for arrays + if (!m_strbuf) { m_strbuf = new char[maxBits() + 32]; } } void VerilatedFst::close() { @@ -213,25 +218,59 @@ void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, f // so always inline them. VL_ATTR_ALWINLINE -void VerilatedFst::emitBit(vluint32_t code, vluint32_t newval) { +void VerilatedFst::emitBit(vluint32_t code, CData newval) { fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0"); } + VL_ATTR_ALWINLINE -void VerilatedFst::emitBus(vluint32_t code, vluint32_t newval, int bits) { - fstWriterEmitValueChange32(m_fst, m_symbolp[code], bits, newval); +void VerilatedFst::emitCData(vluint32_t code, CData newval, int bits) { + char buf[VL_BYTESIZE]; + cvtCDataToStr(buf, newval << (VL_BYTESIZE - bits)); + fstWriterEmitValueChange(m_fst, m_symbolp[code], buf); } + VL_ATTR_ALWINLINE -void VerilatedFst::emitQuad(vluint32_t code, vluint64_t newval, int bits) { - fstWriterEmitValueChange64(m_fst, m_symbolp[code], bits, newval); +void VerilatedFst::emitSData(vluint32_t code, SData newval, int bits) { + char buf[VL_SHORTSIZE]; + cvtSDataToStr(buf, newval << (VL_SHORTSIZE - bits)); + fstWriterEmitValueChange(m_fst, m_symbolp[code], buf); } + VL_ATTR_ALWINLINE -void VerilatedFst::emitArray(vluint32_t code, const vluint32_t* newvalp, int bits) { - fstWriterEmitValueChangeVec32(m_fst, m_symbolp[code], bits, newvalp); +void VerilatedFst::emitIData(vluint32_t code, IData newval, int bits) { + char buf[VL_IDATASIZE]; + cvtIDataToStr(buf, newval << (VL_IDATASIZE - bits)); + fstWriterEmitValueChange(m_fst, m_symbolp[code], buf); } + +VL_ATTR_ALWINLINE +void VerilatedFst::emitQData(vluint32_t code, QData newval, int bits) { + char buf[VL_QUADSIZE]; + cvtQDataToStr(buf, newval << (VL_QUADSIZE - bits)); + fstWriterEmitValueChange(m_fst, m_symbolp[code], buf); +} + +VL_ATTR_ALWINLINE +void VerilatedFst::emitWData(vluint32_t code, const WData* newvalp, int bits) { + int words = VL_WORDS_I(bits); + char* wp = m_strbuf; + // Convert the most significant word + const int bitsInMSW = VL_BITBIT_E(bits) ? VL_BITBIT_E(bits) : VL_EDATASIZE; + cvtEDataToStr(wp, newvalp[--words] << (VL_EDATASIZE - bitsInMSW)); + wp += bitsInMSW; + // Convert the remaining words + while (words > 0) { + cvtEDataToStr(wp, newvalp[--words]); + wp += VL_EDATASIZE; + } + fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbuf); +} + VL_ATTR_ALWINLINE void VerilatedFst::emitFloat(vluint32_t code, float newval) { fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval); } + VL_ATTR_ALWINLINE void VerilatedFst::emitDouble(vluint32_t code, double newval) { fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval); diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index b80d8ea7a..c2b0605c7 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -51,6 +51,8 @@ private: Local2FstDtype m_local2fstdtype; std::list m_curScope; fstHandle* m_symbolp; ///< same as m_code2symbol, but as an array + char* m_strbuf; ///< String buffer long enough to hold maxBits() chars + // CONSTRUCTORS VL_UNCOPYABLE(VerilatedFst); void declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, @@ -69,10 +71,12 @@ protected: // Implementations of duck-typed methods for VerilatedTrace. These are // called from only one place (namely full*) so always inline them. - inline void emitBit(vluint32_t code, vluint32_t newval); - inline void emitBus(vluint32_t code, vluint32_t newval, int bits); - inline void emitQuad(vluint32_t code, vluint64_t newval, int bits); - inline void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits); + inline void emitBit(vluint32_t code, CData newval); + inline void emitCData(vluint32_t code, CData newval, int bits); + inline void emitSData(vluint32_t code, SData newval, int bits); + inline void emitIData(vluint32_t code, IData newval, int bits); + inline void emitQData(vluint32_t code, QData newval, int bits); + inline void emitWData(vluint32_t code, const WData* newvalp, int bits); inline void emitFloat(vluint32_t code, float newval); inline void emitDouble(vluint32_t code, double newval); diff --git a/include/verilated_intrinsics.h b/include/verilated_intrinsics.h new file mode 100644 index 000000000..11b532fd7 --- /dev/null +++ b/include/verilated_intrinsics.h @@ -0,0 +1,41 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2003-2020 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* +/// +/// \file +/// \brief Verilator: Common include for target specific intrinsics. +/// +/// Code using machine specific intrinsics for optimization should +/// include this header rather than directly including he target +/// specific headers. We provide macros to check for availability +/// of instruction sets, and a common mechanism to disable them. +/// +//************************************************************************* + +#ifndef _VERILATED_INTRINSICS_H_ +#define _VERILATED_INTRINSICS_H_ 1 ///< Header Guard + +// clang-format off + +// Use VL_DISABLE_INTRINSICS to disable all intrinsics based optimization +#if !defined(VL_DISABLE_INTRINSICS) && !defined(VL_PORTABLE_ONLY) +# if defined(__SSE2__) && !defined(VL_DISABLE_SSE2) +# define VL_HAVE_SSE2 1 +# include +# endif +# if defined(__AVX2__) && defined(VL_HAVE_SSE2) && !defined(VL_DISABLE_AVX2) +# define VL_HAVE_AVX2 1 +# include +# endif +#endif + +// clang-format on + +#endif // Guard diff --git a/include/verilated_trace.h b/include/verilated_trace.h index bb0bce25a..471db6b99 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -90,11 +90,13 @@ public: enum { CHG_BIT_0 = 0x0, CHG_BIT_1 = 0x1, - CHG_BUS = 0x2, - CHG_QUAD = 0x3, - CHG_ARRAY = 0x4, - CHG_FLOAT = 0x5, - CHG_DOUBLE = 0x6, + CHG_CDATA = 0x2, + CHG_SDATA = 0x3, + CHG_IDATA = 0x4, + CHG_QDATA = 0x5, + CHG_WDATA = 0x6, + CHG_FLOAT = 0x7, + CHG_DOUBLE = 0x8, // TODO: full.. TIME_CHANGE = 0xd, END = 0xe, // End of buffer @@ -122,6 +124,7 @@ private: bool m_fullDump; ///< Whether a full dump is required on the next call to 'dump' vluint32_t m_nextCode; ///< Next code number to assign vluint32_t m_numSignals; ///< Number of distinct signals + vluint32_t m_maxBits; ///< Number of bits in the widest signal std::string m_moduleName; ///< Name of module being trace initialized now char m_scopeEscape; double m_timeRes; ///< Time resolution (ns/ms etc) @@ -176,6 +179,7 @@ protected: vluint32_t nextCode() const { return m_nextCode; } vluint32_t numSignals() const { return m_numSignals; } + vluint32_t maxBits() const { return m_maxBits; } const std::string& moduleName() const { return m_moduleName; } void fullDump(bool value) { m_fullDump = value; } vluint64_t timeLastDump() { return m_timeLastDump; } @@ -251,47 +255,65 @@ public: // these here, but we cannot afford dynamic dispatch for calling these as // this is very hot code during tracing. - // duck-typed void emitBit(vluint32_t code, vluint32_t newval) = 0; - // duck-typed void emitBus(vluint32_t code, vluint32_t newval, int bits) = 0; - // duck-typed void emitQuad(vluint32_t code, vluint64_t newval, int bits) = 0; - // duck-typed void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits) = 0; + // duck-typed void emitBit(vluint32_t code, CData newval) = 0; + // duck-typed void emitCData(vluint32_t code, CData newval, int bits) = 0; + // duck-typed void emitSData(vluint32_t code, SData newval, int bits) = 0; + // duck-typed void emitIData(vluint32_t code, IData newval, int bits) = 0; + // duck-typed void emitQData(vluint32_t code, QData newval, int bits) = 0; + // duck-typed void emitWData(vluint32_t code, const WData* newvalp, int bits) = 0; // duck-typed void emitFloat(vluint32_t code, float newval) = 0; // duck-typed void emitDouble(vluint32_t code, double newval) = 0; vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; } // Write to previous value buffer value and emit trace entry. - void fullBit(vluint32_t* oldp, vluint32_t newval); - void fullBus(vluint32_t* oldp, vluint32_t newval, int bits); - void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits); - void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits); + void fullBit(vluint32_t* oldp, CData newval); + void fullCData(vluint32_t* oldp, CData newval, int bits); + void fullSData(vluint32_t* oldp, SData newval, int bits); + void fullIData(vluint32_t* oldp, IData newval, int bits); + void fullQData(vluint32_t* oldp, QData newval, int bits); + void fullWData(vluint32_t* oldp, const WData* newvalp, int bits); void fullFloat(vluint32_t* oldp, float newval); void fullDouble(vluint32_t* oldp, double newval); #ifdef VL_TRACE_THREADED // Threaded tracing. Just dump everything in the trace buffer - inline void chgBit(vluint32_t code, vluint32_t newval) { + inline void chgBit(vluint32_t code, CData newval) { m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_BIT_0 | newval; m_traceBufferWritep[1] = code; m_traceBufferWritep += 2; VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); } - inline void chgBus(vluint32_t code, vluint32_t newval, int bits) { - m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_BUS; + inline void chgCData(vluint32_t code, CData newval, int bits) { + m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_CDATA; m_traceBufferWritep[1] = code; m_traceBufferWritep[2] = newval; m_traceBufferWritep += 3; VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); } - inline void chgQuad(vluint32_t code, vluint64_t newval, int bits) { - m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_QUAD; + inline void chgSData(vluint32_t code, SData newval, int bits) { + m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_SDATA; m_traceBufferWritep[1] = code; - *reinterpret_cast(m_traceBufferWritep + 2) = newval; + m_traceBufferWritep[2] = newval; + m_traceBufferWritep += 3; + VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + } + inline void chgIData(vluint32_t code, IData newval, int bits) { + m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_IDATA; + m_traceBufferWritep[1] = code; + m_traceBufferWritep[2] = newval; + m_traceBufferWritep += 3; + VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + } + inline void chgQData(vluint32_t code, QData newval, int bits) { + m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_QDATA; + m_traceBufferWritep[1] = code; + *reinterpret_cast(m_traceBufferWritep + 2) = newval; m_traceBufferWritep += 4; VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); } - inline void chgArray(vluint32_t code, const vluint32_t* newvalp, int bits) { - m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_ARRAY; + inline void chgWData(vluint32_t code, const WData* newvalp, int bits) { + m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_WDATA; m_traceBufferWritep[1] = code; m_traceBufferWritep += 2; for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; } @@ -324,22 +346,30 @@ public: // thread and are called chg*Impl // Check previous dumped value of signal. If changed, then emit trace entry - inline void CHG(Bit)(vluint32_t* oldp, vluint32_t newval) { + inline void CHG(Bit)(vluint32_t* oldp, CData newval) { const vluint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullBit(oldp, newval); } - inline void CHG(Bus)(vluint32_t* oldp, vluint32_t newval, int bits) { + inline void CHG(CData)(vluint32_t* oldp, CData newval, int bits) { const vluint32_t diff = *oldp ^ newval; - if (VL_UNLIKELY(diff)) fullBus(oldp, newval, bits); + if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits); } - inline void CHG(Quad)(vluint32_t* oldp, vluint64_t newval, int bits) { - const vluint64_t diff = *reinterpret_cast(oldp) ^ newval; - if (VL_UNLIKELY(diff)) fullQuad(oldp, newval, bits); + inline void CHG(SData)(vluint32_t* oldp, SData newval, int bits) { + const vluint32_t diff = *oldp ^ newval; + if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits); } - inline void CHG(Array)(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + inline void CHG(IData)(vluint32_t* oldp, IData newval, int bits) { + const vluint32_t diff = *oldp ^ newval; + if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits); + } + inline void CHG(QData)(vluint32_t* oldp, QData newval, int bits) { + const vluint64_t diff = *reinterpret_cast(oldp) ^ newval; + if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits); + } + inline void CHG(WData)(vluint32_t* oldp, const WData* newvalp, int bits) { for (int i = 0; i < (bits + 31) / 32; ++i) { if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) { - fullArray(oldp, newvalp, bits); + fullWData(oldp, newvalp, bits); return; } } diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp index 2e5345d65..78dc19a11 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.cpp @@ -23,6 +23,7 @@ # error "This file should be included in trace format implementations" #endif +#include "verilated_intrinsics.h" #include "verilated_trace.h" #if 0 @@ -166,22 +167,34 @@ template <> void VerilatedTrace::workerThreadMain() { VL_TRACE_THREAD_DEBUG("Command CHG_BIT_1 " << top); chgBitImpl(oldp, 1); continue; - case VerilatedTraceCommand::CHG_BUS: - VL_TRACE_THREAD_DEBUG("Command CHG_BUS " << top); + case VerilatedTraceCommand::CHG_CDATA: + VL_TRACE_THREAD_DEBUG("Command CHG_CDATA " << top); // Bits stored in bottom byte of command - chgBusImpl(oldp, *readp, top); + chgCDataImpl(oldp, *readp, top); readp += 1; continue; - case VerilatedTraceCommand::CHG_QUAD: - VL_TRACE_THREAD_DEBUG("Command CHG_QUAD " << top); + case VerilatedTraceCommand::CHG_SDATA: + VL_TRACE_THREAD_DEBUG("Command CHG_SDATA " << top); // Bits stored in bottom byte of command - chgQuadImpl(oldp, *reinterpret_cast(readp), top); + chgSDataImpl(oldp, *readp, top); + readp += 1; + continue; + case VerilatedTraceCommand::CHG_IDATA: + VL_TRACE_THREAD_DEBUG("Command CHG_IDATA " << top); + // Bits stored in bottom byte of command + chgIDataImpl(oldp, *readp, top); + readp += 1; + continue; + case VerilatedTraceCommand::CHG_QDATA: + VL_TRACE_THREAD_DEBUG("Command CHG_QDATA " << top); + // Bits stored in bottom byte of command + chgQDataImpl(oldp, *reinterpret_cast(readp), top); readp += 2; continue; - case VerilatedTraceCommand::CHG_ARRAY: - VL_TRACE_THREAD_DEBUG("Command CHG_ARRAY " << top); - chgArrayImpl(oldp, readp, top); - readp += (top + 31) / 32; + case VerilatedTraceCommand::CHG_WDATA: + VL_TRACE_THREAD_DEBUG("Command CHG_WDATA " << top); + chgWDataImpl(oldp, readp, top); + readp += VL_WORDS_I(top); continue; case VerilatedTraceCommand::CHG_FLOAT: VL_TRACE_THREAD_DEBUG("Command CHG_FLOAT " << top); @@ -284,6 +297,7 @@ VerilatedTrace::VerilatedTrace() , m_fullDump(true) , m_nextCode(0) , m_numSignals(0) + , m_maxBits(0) , m_scopeEscape('.') , m_timeRes(1e-9) , m_timeUnit(1e-9) @@ -318,6 +332,7 @@ template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { const vluint32_t expectedCodes = nextCode(); m_nextCode = 1; m_numSignals = 0; + m_maxBits = 0; // Call all initialize callbacks, which will call decl* for each signal. for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { @@ -355,10 +370,11 @@ void VerilatedTrace::declCode(vluint32_t code, vluint32_t bits, bo } // Note: The tri-state flag is not used by Verilator, but is here for // compatibility with some foreign code. - int codesNeeded = (bits + 31) / 32; + int codesNeeded = VL_WORDS_I(bits); if (tri) codesNeeded *= 2; m_nextCode = std::max(m_nextCode, code + codesNeeded); ++m_numSignals; + m_maxBits = std::max(m_maxBits, bits); } //========================================================================= @@ -486,35 +502,139 @@ void VerilatedTrace::addCallback(callback_t initcb, callback_t ful // that this file must be included in the format specific implementation, so // the emit* functions can be inlined for performance. -template <> void VerilatedTrace::fullBit(vluint32_t* oldp, vluint32_t newval) { +template <> void VerilatedTrace::fullBit(vluint32_t* oldp, CData newval) { *oldp = newval; self()->emitBit(oldp - m_sigs_oldvalp, newval); } template <> -void VerilatedTrace::fullBus(vluint32_t* oldp, vluint32_t newval, int bits) { +void VerilatedTrace::fullCData(vluint32_t* oldp, CData newval, int bits) { *oldp = newval; - self()->emitBus(oldp - m_sigs_oldvalp, newval, bits); + self()->emitCData(oldp - m_sigs_oldvalp, newval, bits); } template <> -void VerilatedTrace::fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { - *reinterpret_cast(oldp) = newval; - self()->emitQuad(oldp - m_sigs_oldvalp, newval, bits); +void VerilatedTrace::fullSData(vluint32_t* oldp, SData newval, int bits) { + *oldp = newval; + self()->emitSData(oldp - m_sigs_oldvalp, newval, bits); } + template <> -void VerilatedTrace::fullArray(vluint32_t* oldp, const vluint32_t* newvalp, - int bits) { - for (int i = 0; i < (bits + 31) / 32; ++i) oldp[i] = newvalp[i]; - self()->emitArray(oldp - m_sigs_oldvalp, newvalp, bits); +void VerilatedTrace::fullIData(vluint32_t* oldp, IData newval, int bits) { + *oldp = newval; + self()->emitIData(oldp - m_sigs_oldvalp, newval, bits); } + +template <> +void VerilatedTrace::fullQData(vluint32_t* oldp, QData newval, int bits) { + *reinterpret_cast(oldp) = newval; + self()->emitQData(oldp - m_sigs_oldvalp, newval, bits); +} + +template <> +void VerilatedTrace::fullWData(vluint32_t* oldp, const WData* newvalp, int bits) { + for (int i = 0; i < VL_WORDS_I(bits); ++i) oldp[i] = newvalp[i]; + self()->emitWData(oldp - m_sigs_oldvalp, newvalp, bits); +} + template <> void VerilatedTrace::fullFloat(vluint32_t* oldp, float newval) { // cppcheck-suppress invalidPointerCast *reinterpret_cast(oldp) = newval; self()->emitFloat(oldp - m_sigs_oldvalp, newval); } + template <> void VerilatedTrace::fullDouble(vluint32_t* oldp, double newval) { // cppcheck-suppress invalidPointerCast *reinterpret_cast(oldp) = newval; self()->emitDouble(oldp - m_sigs_oldvalp, newval); } + +//========================================================================= +// Primitives converting binary values to strings... + +// All of these take a destination pointer where the string will be emitted, +// and a value to convert. There are a couple of variants for efficiency. + +inline static void cvtCDataToStr(char* dstp, CData value) { +#ifdef VL_HAVE_SSE2 + // Similar to cvtSDataToStr but only the bottom 8 byte lanes are used + const __m128i a = _mm_cvtsi32_si128(value); + const __m128i b = _mm_unpacklo_epi8(a, a); + const __m128i c = _mm_shufflelo_epi16(b, 0); + const __m128i m = _mm_set1_epi64x(0x0102040810204080); + const __m128i d = _mm_cmpeq_epi8(_mm_and_si128(c, m), m); + const __m128i result = _mm_sub_epi8(_mm_set1_epi8('0'), d); + _mm_storel_epi64(reinterpret_cast<__m128i*>(dstp), result); +#else + dstp[0] = '0' | static_cast((value >> 7) & 1); + dstp[1] = '0' | static_cast((value >> 6) & 1); + dstp[2] = '0' | static_cast((value >> 5) & 1); + dstp[3] = '0' | static_cast((value >> 4) & 1); + dstp[4] = '0' | static_cast((value >> 3) & 1); + dstp[5] = '0' | static_cast((value >> 2) & 1); + dstp[6] = '0' | static_cast((value >> 1) & 1); + dstp[7] = '0' | static_cast(value & 1); +#endif +} + +inline static void cvtSDataToStr(char* dstp, SData value) { +#ifdef VL_HAVE_SSE2 + // We want each bit in the 16-bit input value to end up in a byte lane + // within the 128-bit XMM register. Note that x86 is little-endian and we + // want the MSB of the input at the low address, so we will bit-reverse + // at the same time. + + // Put value in bottom of 128-bit register a[15:0] = value + const __m128i a = _mm_cvtsi32_si128(value); + // Interleave bytes with themselves + // b[15: 0] = {2{a[ 7:0]}} == {2{value[ 7:0]}} + // b[31:16] = {2{a[15:8]}} == {2{value[15:8]}} + const __m128i b = _mm_unpacklo_epi8(a, a); + // Shuffle bottom 64 bits, note swapping high bytes with low bytes + // c[31: 0] = {2{b[31:16]}} == {4{value[15:8}} + // c[63:32] = {2{b[15: 0]}} == {4{value[ 7:0}} + const __m128i c = _mm_shufflelo_epi16(b, 0x05); + // Shuffle whole register + // d[ 63: 0] = {2{c[31: 0]}} == {8{value[15:8}} + // d[126:54] = {2{c[63:32]}} == {8{value[ 7:0}} + const __m128i d = _mm_shuffle_epi32(c, 0x50); + // Test each bit within the bytes, this sets each byte lane to 0 + // if the bit for that lane is 0 and to 0xff if the bit is 1. + const __m128i m = _mm_set1_epi64x(0x0102040810204080); + const __m128i e = _mm_cmpeq_epi8(_mm_and_si128(d, m), m); + // Convert to ASCII by subtracting the masks from ASCII '0': + // '0' - 0 is '0', '0' - -1 is '1' + const __m128i result = _mm_sub_epi8(_mm_set1_epi8('0'), e); + // Store the 16 characters to the un-aligned buffer + _mm_storeu_si128(reinterpret_cast<__m128i*>(dstp), result); +#else + cvtCDataToStr(dstp, value >> 8); + cvtCDataToStr(dstp + 8, value); +#endif +} + +inline static void cvtIDataToStr(char* dstp, IData value) { +#ifdef VL_HAVE_AVX2 + // Similar to cvtSDataToStr but the bottom 16-bits are processed in the + // top half of the YMM registerss + const __m256i a = _mm256_insert_epi32(_mm256_undefined_si256(), value, 0); + const __m256i b = _mm256_permute4x64_epi64(a, 0); + const __m256i s = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3); + const __m256i c = _mm256_shuffle_epi8(b, s); + const __m256i m = _mm256_set1_epi64x(0x0102040810204080); + const __m256i d = _mm256_cmpeq_epi8(_mm256_and_si256(c, m), m); + const __m256i result = _mm256_sub_epi8(_mm256_set1_epi8('0'), d); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(dstp), result); +#else + cvtSDataToStr(dstp, value >> 16); + cvtSDataToStr(dstp + 16, value); +#endif +} + +inline static void cvtQDataToStr(char* dstp, QData value) { + cvtIDataToStr(dstp, value >> 32); + cvtIDataToStr(dstp + 32, value); +} + +#define cvtEDataToStr cvtIDataToStr diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index e1ffd2293..e940ee789 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -35,6 +35,8 @@ # include #endif +#include "verilated_intrinsics.h" + // SPDIFF_ON #ifndef O_LARGEFILE // For example on WIN32 @@ -606,20 +608,14 @@ void VerilatedVcd::declTriArray(vluint32_t code, const char* name, bool array, i #endif // VL_TRACE_VCD_OLD_API //============================================================================= -// Trace recording routines +// Trace rendering prinitives -//============================================================================= -// Emit trace entries - -#define VL_VCD_SUFFIXP(code) (m_suffixesp + (code)*VL_TRACE_SUFFIX_ENTRY_SIZE) - -// Emit suffix, write back write pointer, check buffer void VerilatedVcd::finishLine(vluint32_t code, char* writep) { - const char* const suffixp = VL_VCD_SUFFIXP(code); + const char* const suffixp = m_suffixesp + code * VL_TRACE_SUFFIX_ENTRY_SIZE; // Copy the whole suffix (this avoid having hard to predict branches which // helps a lot). Note: The maximum length of the suffix is // VL_TRACE_MAX_VCD_CODE_SIZE + 2 == 7, but we unroll this here for speed. -#ifdef __x86_64__ +#ifdef VL_X86_64 // Copy the whole 8 bytes in one go, this works on little-endian machines // supporting unaligned stores. *reinterpret_cast(writep) = *reinterpret_cast(suffixp); @@ -639,12 +635,15 @@ void VerilatedVcd::finishLine(vluint32_t code, char* writep) { bufferCheck(); } +//============================================================================= +// emit* trace routines + // Note: emit* are only ever called from one place (full* in // verilated_trace_imp.cpp, which is included in this file at the top), // so always inline them. VL_ATTR_ALWINLINE -void VerilatedVcd::emitBit(vluint32_t code, vluint32_t newval) { +void VerilatedVcd::emitBit(vluint32_t code, CData newval) { // Don't prefetch suffix as it's a bit too late; char* wp = m_writep; *wp++ = '0' | static_cast(newval); @@ -652,182 +651,56 @@ void VerilatedVcd::emitBit(vluint32_t code, vluint32_t newval) { } VL_ATTR_ALWINLINE -void VerilatedVcd::emitBus(vluint32_t code, vluint32_t newval, int bits) { - VL_PREFETCH_RD(VL_VCD_SUFFIXP(code)); +void VerilatedVcd::emitCData(vluint32_t code, CData newval, int bits) { char* wp = m_writep; *wp++ = 'b'; - wp += bits; - // clang-format off - switch (bits) { - case 32: wp[-32] = '0' | static_cast((newval >> 31) ); //FALLTHRU - case 31: wp[-31] = '0' | static_cast((newval >> 30) & 1); //FALLTHRU - case 30: wp[-30] = '0' | static_cast((newval >> 29) & 1); //FALLTHRU - case 29: wp[-29] = '0' | static_cast((newval >> 28) & 1); //FALLTHRU - case 28: wp[-28] = '0' | static_cast((newval >> 27) & 1); //FALLTHRU - case 27: wp[-27] = '0' | static_cast((newval >> 26) & 1); //FALLTHRU - case 26: wp[-26] = '0' | static_cast((newval >> 25) & 1); //FALLTHRU - case 25: wp[-25] = '0' | static_cast((newval >> 24) & 1); //FALLTHRU - case 24: wp[-24] = '0' | static_cast((newval >> 23) & 1); //FALLTHRU - case 23: wp[-23] = '0' | static_cast((newval >> 22) & 1); //FALLTHRU - case 22: wp[-22] = '0' | static_cast((newval >> 21) & 1); //FALLTHRU - case 21: wp[-21] = '0' | static_cast((newval >> 20) & 1); //FALLTHRU - case 20: wp[-20] = '0' | static_cast((newval >> 19) & 1); //FALLTHRU - case 19: wp[-19] = '0' | static_cast((newval >> 18) & 1); //FALLTHRU - case 18: wp[-18] = '0' | static_cast((newval >> 17) & 1); //FALLTHRU - case 17: wp[-17] = '0' | static_cast((newval >> 16) & 1); //FALLTHRU - case 16: wp[-16] = '0' | static_cast((newval >> 15) & 1); //FALLTHRU - case 15: wp[-15] = '0' | static_cast((newval >> 14) & 1); //FALLTHRU - case 14: wp[-14] = '0' | static_cast((newval >> 13) & 1); //FALLTHRU - case 13: wp[-13] = '0' | static_cast((newval >> 12) & 1); //FALLTHRU - case 12: wp[-12] = '0' | static_cast((newval >> 11) & 1); //FALLTHRU - case 11: wp[-11] = '0' | static_cast((newval >> 10) & 1); //FALLTHRU - case 10: wp[-10] = '0' | static_cast((newval >> 9) & 1); //FALLTHRU - case 9: wp[ -9] = '0' | static_cast((newval >> 8) & 1); //FALLTHRU - case 8: wp[ -8] = '0' | static_cast((newval >> 7) & 1); //FALLTHRU - case 7: wp[ -7] = '0' | static_cast((newval >> 6) & 1); //FALLTHRU - case 6: wp[ -6] = '0' | static_cast((newval >> 5) & 1); //FALLTHRU - case 5: wp[ -5] = '0' | static_cast((newval >> 4) & 1); //FALLTHRU - case 4: wp[ -4] = '0' | static_cast((newval >> 3) & 1); //FALLTHRU - case 3: wp[ -3] = '0' | static_cast((newval >> 2) & 1); //FALLTHRU - case 2: wp[ -2] = '0' | static_cast((newval >> 1) & 1); //FALLTHRU - /*bit*/ wp[ -1] = '0' | static_cast((newval ) & 1); //FALLTHRU - } - // clang-format on - finishLine(code, wp); + cvtCDataToStr(wp, newval << (VL_BYTESIZE - bits)); + finishLine(code, wp + bits); } VL_ATTR_ALWINLINE -void VerilatedVcd::emitQuad(vluint32_t code, vluint64_t newval, int bits) { - VL_PREFETCH_RD(VL_VCD_SUFFIXP(code)); +void VerilatedVcd::emitSData(vluint32_t code, SData newval, int bits) { char* wp = m_writep; *wp++ = 'b'; - // Handle the top 32 bits within the 64 bit input - const int bitsInTopHalf = bits - 32; - wp += bitsInTopHalf; - // clang-format off - switch (bitsInTopHalf) { - case 32: wp[-32] = '0' | static_cast((newval >> 63) ); //FALLTHRU - case 31: wp[-31] = '0' | static_cast((newval >> 62) & 1); //FALLTHRU - case 30: wp[-30] = '0' | static_cast((newval >> 61) & 1); //FALLTHRU - case 29: wp[-29] = '0' | static_cast((newval >> 60) & 1); //FALLTHRU - case 28: wp[-28] = '0' | static_cast((newval >> 59) & 1); //FALLTHRU - case 27: wp[-27] = '0' | static_cast((newval >> 58) & 1); //FALLTHRU - case 26: wp[-26] = '0' | static_cast((newval >> 57) & 1); //FALLTHRU - case 25: wp[-25] = '0' | static_cast((newval >> 56) & 1); //FALLTHRU - case 24: wp[-24] = '0' | static_cast((newval >> 55) & 1); //FALLTHRU - case 23: wp[-23] = '0' | static_cast((newval >> 54) & 1); //FALLTHRU - case 22: wp[-22] = '0' | static_cast((newval >> 53) & 1); //FALLTHRU - case 21: wp[-21] = '0' | static_cast((newval >> 52) & 1); //FALLTHRU - case 20: wp[-20] = '0' | static_cast((newval >> 51) & 1); //FALLTHRU - case 19: wp[-19] = '0' | static_cast((newval >> 50) & 1); //FALLTHRU - case 18: wp[-18] = '0' | static_cast((newval >> 49) & 1); //FALLTHRU - case 17: wp[-17] = '0' | static_cast((newval >> 48) & 1); //FALLTHRU - case 16: wp[-16] = '0' | static_cast((newval >> 47) & 1); //FALLTHRU - case 15: wp[-15] = '0' | static_cast((newval >> 46) & 1); //FALLTHRU - case 14: wp[-14] = '0' | static_cast((newval >> 45) & 1); //FALLTHRU - case 13: wp[-13] = '0' | static_cast((newval >> 44) & 1); //FALLTHRU - case 12: wp[-12] = '0' | static_cast((newval >> 43) & 1); //FALLTHRU - case 11: wp[-11] = '0' | static_cast((newval >> 42) & 1); //FALLTHRU - case 10: wp[-10] = '0' | static_cast((newval >> 41) & 1); //FALLTHRU - case 9: wp[ -9] = '0' | static_cast((newval >> 40) & 1); //FALLTHRU - case 8: wp[ -8] = '0' | static_cast((newval >> 39) & 1); //FALLTHRU - case 7: wp[ -7] = '0' | static_cast((newval >> 38) & 1); //FALLTHRU - case 6: wp[ -6] = '0' | static_cast((newval >> 37) & 1); //FALLTHRU - case 5: wp[ -5] = '0' | static_cast((newval >> 36) & 1); //FALLTHRU - case 4: wp[ -4] = '0' | static_cast((newval >> 35) & 1); //FALLTHRU - case 3: wp[ -3] = '0' | static_cast((newval >> 34) & 1); //FALLTHRU - case 2: wp[ -2] = '0' | static_cast((newval >> 33) & 1); //FALLTHRU - case 1: wp[ -1] = '0' | static_cast((newval >> 32) & 1); //FALLTHRU - } - // clang-format on - // Handle the bottom 32 bits within the 64 bit input - vluint32_t val = static_cast(newval); // Truncate to bottom 32 bits - int loops = 4; - do { - wp[0] = '0' | static_cast((val >> 31)); - wp[1] = '0' | static_cast((val >> 30) & 1); - wp[2] = '0' | static_cast((val >> 29) & 1); - wp[3] = '0' | static_cast((val >> 28) & 1); - wp[4] = '0' | static_cast((val >> 27) & 1); - wp[5] = '0' | static_cast((val >> 26) & 1); - wp[6] = '0' | static_cast((val >> 25) & 1); - wp[7] = '0' | static_cast((val >> 24) & 1); - wp += 8; - val <<= 8; - } while (--loops); - - finishLine(code, wp); + cvtSDataToStr(wp, newval << (VL_SHORTSIZE - bits)); + finishLine(code, wp + bits); } VL_ATTR_ALWINLINE -void VerilatedVcd::emitArray(vluint32_t code, const vluint32_t* newvalp, int bits) { - VL_PREFETCH_RD(VL_VCD_SUFFIXP(code)); - int words = (bits + 31) / 32; +void VerilatedVcd::emitIData(vluint32_t code, IData newval, int bits) { + char* wp = m_writep; + *wp++ = 'b'; + cvtIDataToStr(wp, newval << (VL_IDATASIZE - bits)); + finishLine(code, wp + bits); +} + +VL_ATTR_ALWINLINE +void VerilatedVcd::emitQData(vluint32_t code, QData newval, int bits) { + char* wp = m_writep; + *wp++ = 'b'; + cvtQDataToStr(wp, newval << (VL_QUADSIZE - bits)); + finishLine(code, wp + bits); +} + +VL_ATTR_ALWINLINE +void VerilatedVcd::emitWData(vluint32_t code, const WData* newvalp, int bits) { + int words = VL_WORDS_I(bits); char* wp = m_writep; *wp++ = 'b'; // Handle the most significant word - vluint32_t val = newvalp[--words]; - const int bitsInMSW = bits % 32 == 0 ? 32 : bits % 32; + const int bitsInMSW = VL_BITBIT_E(bits) ? VL_BITBIT_E(bits) : VL_EDATASIZE; + cvtEDataToStr(wp, newvalp[--words] << (VL_EDATASIZE - bitsInMSW)); wp += bitsInMSW; - // clang-format off - switch (bitsInMSW) { - case 32: wp[-32] = '0' | static_cast((val >> 31) ); //FALLTHRU - case 31: wp[-31] = '0' | static_cast((val >> 30) & 1); //FALLTHRU - case 30: wp[-30] = '0' | static_cast((val >> 29) & 1); //FALLTHRU - case 29: wp[-29] = '0' | static_cast((val >> 28) & 1); //FALLTHRU - case 28: wp[-28] = '0' | static_cast((val >> 27) & 1); //FALLTHRU - case 27: wp[-27] = '0' | static_cast((val >> 26) & 1); //FALLTHRU - case 26: wp[-26] = '0' | static_cast((val >> 25) & 1); //FALLTHRU - case 25: wp[-25] = '0' | static_cast((val >> 24) & 1); //FALLTHRU - case 24: wp[-24] = '0' | static_cast((val >> 23) & 1); //FALLTHRU - case 23: wp[-23] = '0' | static_cast((val >> 22) & 1); //FALLTHRU - case 22: wp[-22] = '0' | static_cast((val >> 21) & 1); //FALLTHRU - case 21: wp[-21] = '0' | static_cast((val >> 20) & 1); //FALLTHRU - case 20: wp[-20] = '0' | static_cast((val >> 19) & 1); //FALLTHRU - case 19: wp[-19] = '0' | static_cast((val >> 18) & 1); //FALLTHRU - case 18: wp[-18] = '0' | static_cast((val >> 17) & 1); //FALLTHRU - case 17: wp[-17] = '0' | static_cast((val >> 16) & 1); //FALLTHRU - case 16: wp[-16] = '0' | static_cast((val >> 15) & 1); //FALLTHRU - case 15: wp[-15] = '0' | static_cast((val >> 14) & 1); //FALLTHRU - case 14: wp[-14] = '0' | static_cast((val >> 13) & 1); //FALLTHRU - case 13: wp[-13] = '0' | static_cast((val >> 12) & 1); //FALLTHRU - case 12: wp[-12] = '0' | static_cast((val >> 11) & 1); //FALLTHRU - case 11: wp[-11] = '0' | static_cast((val >> 10) & 1); //FALLTHRU - case 10: wp[-10] = '0' | static_cast((val >> 9) & 1); //FALLTHRU - case 9: wp[ -9] = '0' | static_cast((val >> 8) & 1); //FALLTHRU - case 8: wp[ -8] = '0' | static_cast((val >> 7) & 1); //FALLTHRU - case 7: wp[ -7] = '0' | static_cast((val >> 6) & 1); //FALLTHRU - case 6: wp[ -6] = '0' | static_cast((val >> 5) & 1); //FALLTHRU - case 5: wp[ -5] = '0' | static_cast((val >> 4) & 1); //FALLTHRU - case 4: wp[ -4] = '0' | static_cast((val >> 3) & 1); //FALLTHRU - case 3: wp[ -3] = '0' | static_cast((val >> 2) & 1); //FALLTHRU - case 2: wp[ -2] = '0' | static_cast((val >> 1) & 1); //FALLTHRU - case 1: wp[ -1] = '0' | static_cast((val ) & 1); //FALLTHRU - } - // clang-format on // Handle the remaining words while (words > 0) { - vluint32_t val = newvalp[--words]; - int loops = 4; - do { - wp[0] = '0' | static_cast((val >> 31)); - wp[1] = '0' | static_cast((val >> 30) & 1); - wp[2] = '0' | static_cast((val >> 29) & 1); - wp[3] = '0' | static_cast((val >> 28) & 1); - wp[4] = '0' | static_cast((val >> 27) & 1); - wp[5] = '0' | static_cast((val >> 26) & 1); - wp[6] = '0' | static_cast((val >> 25) & 1); - wp[7] = '0' | static_cast((val >> 24) & 1); - wp += 8; - val <<= 8; - } while (--loops); + cvtEDataToStr(wp, newvalp[--words]); + wp += VL_EDATASIZE; } finishLine(code, wp); } VL_ATTR_ALWINLINE void VerilatedVcd::emitFloat(vluint32_t code, float newval) { - VL_PREFETCH_RD(VL_VCD_SUFFIXP(code)); char* wp = m_writep; // Buffer can't overflow before sprintf; we sized during declaration sprintf(wp, "r%.16g", static_cast(newval)); @@ -837,7 +710,6 @@ void VerilatedVcd::emitFloat(vluint32_t code, float newval) { VL_ATTR_ALWINLINE void VerilatedVcd::emitDouble(vluint32_t code, double newval) { - VL_PREFETCH_RD(VL_VCD_SUFFIXP(code)); char* wp = m_writep; // Buffer can't overflow before sprintf; we sized during declaration sprintf(wp, "r%.16g", newval); @@ -845,8 +717,6 @@ void VerilatedVcd::emitDouble(vluint32_t code, double newval) { finishLine(code, wp); } -#undef VL_VCD_SUFFIXP - #ifdef VL_TRACE_VCD_OLD_API void VerilatedVcd::fullBit(vluint32_t code, const vluint32_t newval) { diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index d9049366f..972c8c0e7 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -124,10 +124,12 @@ protected: // Implementations of duck-typed methods for VerilatedTrace. These are // called from only one place (namely full*) so always inline them. - inline void emitBit(vluint32_t code, vluint32_t newval); - inline void emitBus(vluint32_t code, vluint32_t newval, int bits); - inline void emitQuad(vluint32_t code, vluint64_t newval, int bits); - inline void emitArray(vluint32_t code, const vluint32_t* newvalp, int bits); + inline void emitBit(vluint32_t code, CData newval); + inline void emitCData(vluint32_t code, CData newval, int bits); + inline void emitSData(vluint32_t code, SData newval, int bits); + inline void emitIData(vluint32_t code, IData newval, int bits); + inline void emitQData(vluint32_t code, QData newval, int bits); + inline void emitWData(vluint32_t code, const WData* newvalp, int bits); inline void emitFloat(vluint32_t code, float newval); inline void emitDouble(vluint32_t code, double newval); @@ -176,37 +178,48 @@ public: int lsb); void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - //========================================================================= - // Write back to previous value buffer value and emit - void fullBit(vluint32_t* oldp, vluint32_t newval) { fullBit(oldp - this->oldp(0), newval); } - void fullBus(vluint32_t* oldp, vluint32_t newval, int bits) { + void fullBit(vluint32_t* oldp, CData newval) { fullBit(oldp - this->oldp(0), newval); } + void fullCData(vluint32_t* oldp, CData newval, int bits) { fullBus(oldp - this->oldp(0), newval, bits); } - void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + void fullSData(vluint32_t* oldp, SData newval, int bits) { + fullBus(oldp - this->oldp(0), newval, bits); + } + void fullIData(vluint32_t* oldp, IData newval, int bits) { + fullBus(oldp - this->oldp(0), newval, bits); + } + void fullQData(vluint32_t* oldp, QData newval, int bits) { fullQuad(oldp - this->oldp(0), newval, bits); } - void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) { fullArray(oldp - this->oldp(0), newvalp, bits); } void fullFloat(vluint32_t* oldp, float newval) { fullFloat(oldp - this->oldp(0), newval); } void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); } - //========================================================================= - // Check previous value and emit if changed - - void chgBit(vluint32_t* oldp, vluint32_t newval) { chgBit(oldp - this->oldp(0), newval); } - void chgBus(vluint32_t* oldp, vluint32_t newval, int bits) { + inline void chgBit(vluint32_t* oldp, CData newval) { chgBit(oldp - this->oldp(0), newval); } + inline void chgCData(vluint32_t* oldp, CData newval, int bits) { chgBus(oldp - this->oldp(0), newval, bits); } - void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) { + inline void chgSData(vluint32_t* oldp, SData newval, int bits) { + chgBus(oldp - this->oldp(0), newval, bits); + } + inline void chgIData(vluint32_t* oldp, IData newval, int bits) { + chgBus(oldp - this->oldp(0), newval, bits); + } + inline void chgQData(vluint32_t* oldp, QData newval, int bits) { chgQuad(oldp - this->oldp(0), newval, bits); } - void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) { + inline void chgWData(vluint32_t* oldp, const WData* newvalp, int bits) { chgArray(oldp - this->oldp(0), newvalp, bits); } - void chgFloat(vluint32_t* oldp, float newval) { chgFloat(oldp - this->oldp(0), newval); } - void chgDouble(vluint32_t* oldp, double newval) { chgDouble(oldp - this->oldp(0), newval); } + inline void chgFloat(vluint32_t* oldp, float newval) { + chgFloat(oldp - this->oldp(0), newval); + } + inline void chgDouble(vluint32_t* oldp, double newval) { + chgDouble(oldp - this->oldp(0), newval); + } /// Inside dumping routines, dump one signal, faster when not inlined /// due to code size reduction. diff --git a/include/verilatedos.h b/include/verilatedos.h index 8f689190b..352f7f87b 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -475,6 +475,16 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type #else # define VL_STRCASECMP strcasecmp #endif + +//========================================================================= +// Macros controlling target specific optimizations + +// Define VL_PORTABLE_ONLY to disable all target specific optimizations +#ifndef VL_PORTABLE_ONLY +# ifdef __x86_64__ +# define VL_X86_64 1 +# endif +#endif // VL_PORTABLE_ONLY // clang-format on //========================================================================= diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 061e0b1b3..d31156ccf 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3550,20 +3550,23 @@ class EmitCTrace : EmitCStmts { const bool full = (m_funcp->funcType() == AstCFuncType::TRACE_FULL || m_funcp->funcType() == AstCFuncType::TRACE_FULL_SUB); const string func = full ? "full" : "chg"; - bool emitWidth = false; + bool emitWidth = true; if (nodep->dtypep()->basicp()->isDouble()) { puts("vcdp->" + func + "Double"); + emitWidth = false; } else if (nodep->isWide() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep)) { - puts("vcdp->" + func + "Array"); - emitWidth = true; + puts("vcdp->" + func + "WData"); } else if (nodep->isQuad()) { - puts("vcdp->" + func + "Quad"); - emitWidth = true; + puts("vcdp->" + func + "QData"); + } else if (nodep->declp()->widthMin() > 16) { + puts("vcdp->" + func + "IData"); + } else if (nodep->declp()->widthMin() > 8) { + puts("vcdp->" + func + "SData"); } else if (nodep->declp()->widthMin() > 1) { - puts("vcdp->" + func + "Bus"); - emitWidth = true; + puts("vcdp->" + func + "CData"); } else { puts("vcdp->" + func + "Bit"); + emitWidth = false; } const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords()); diff --git a/test_regress/t/t_trace_array_fst_portable.pl b/test_regress/t/t_trace_array_fst_portable.pl new file mode 100755 index 000000000..0b15dea3c --- /dev/null +++ b/test_regress/t/t_trace_array_fst_portable.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_trace_array.v"); +$Self->{golden_filename} = "t/t_trace_array_fst.out"; + +compile( + verilator_flags2 => ['--cc --trace-fst --trace-structs', + '-CFLAGS -DVL_PORTABLE_ONLY'], + ); + +execute( + check_finished => 1, + ); + +fst_identical($Self->trace_filename, $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_trace_complex_portable.pl b/test_regress/t/t_trace_complex_portable.pl new file mode 100755 index 000000000..b168579a4 --- /dev/null +++ b/test_regress/t/t_trace_complex_portable.pl @@ -0,0 +1,38 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +# Same test as t_trace_complex, but exercising the old VCD tracing API + +scenarios(vlt => 1); + +top_filename("t/t_trace_complex.v"); + +compile( + verilator_flags2 => ['--cc --trace -CFLAGS -DVL_PORTABLE_ONLY'], + ); + +execute( + check_finished => 1, + ); + +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_strp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_strp_strp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp_arrp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp_strp /); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru\(/); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arru\(/); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arrp\(/); +file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_strp\(/); + +vcd_identical ("$Self->{obj_dir}/simx.vcd", "t/t_trace_complex.out"); + +ok(1); +1; From 209a585a68be747ffa7fdaeac25619393a90f68f Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 30 Apr 2020 01:03:10 +0100 Subject: [PATCH 118/127] Remove VL_NEGATE_{I,Q,E}, use C native unary '-' instead This is to avoid slowing down -O0 models unnecessarily. --- include/verilated.h | 7 ------- src/V3AstNodes.h | 1 + 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index 086838c47..06a70c978 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -1428,13 +1428,6 @@ static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) VL_MT_SAFE { //========================================================================= // Math -// 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) VL_PURE { return -data; } -static inline QData VL_NEGATE_Q(QData data) VL_PURE { return -data; } -static inline EData VL_NEGATE_E(EData data) VL_PURE { return -data; } - static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP lwp) VL_MT_SAFE { EData carry = 1; for (int i = 0; i < words; ++i) { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index cab07a6c6..3a8adca4b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -5089,6 +5089,7 @@ public: virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegate(lhs); } virtual string emitVerilog() { return "%f(- %l)"; } virtual string emitC() { return "VL_NEGATE_%lq(%lW, %P, %li)"; } + virtual string emitSimpleOperator() { return "-"; } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return false; } virtual bool sizeMattersLhs() const { return true; } From dc64b43152292c3f3a44fdda088f769ddab9aaa5 Mon Sep 17 00:00:00 2001 From: Peter Horvath Date: Thu, 30 Apr 2020 13:20:31 +0200 Subject: [PATCH 119/127] Fix xcode clang bug workaround (#2295) --- docs/CONTRIBUTORS | 1 + include/verilated.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 7c70a0722..b487ca6fb 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -30,6 +30,7 @@ Mike Popoloski Nathan Kohagen Nathan Myers Patrick Stewart +Peter Horvath Peter Monsson Philipp Wagner Pieter Kapsenberg diff --git a/include/verilated.cpp b/include/verilated.cpp index 490c0d501..ddc7c05fe 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -259,7 +259,7 @@ Verilated::NonSerialized::~NonSerialized() { } } -size_t Verilated::serialized2Size() VL_PURE { return sizeof(VerilatedImp::m_ser); } +size_t Verilated::serialized2Size() VL_PURE { return sizeof(VerilatedImp::s_s.m_ser); } void* Verilated::serialized2Ptr() VL_MT_UNSAFE { return &VerilatedImp::s_s.m_ser; } //=========================================================================== From 849487da23c7fc99a11e79fcf2da58634a355f9c Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 30 Apr 2020 12:54:50 +0100 Subject: [PATCH 120/127] Modify --build to be a standalone option (#2294) - Issue an error when --build is used together with --make - When given --build, always use GNU Make to perform the build - Update documentation (examples were good as they were) - Remove the broken t_flag_build_cmake test Fixes #2280 --- bin/verilator | 45 +++++++++++------- src/V3Options.cpp | 4 ++ src/Verilator.cpp | 45 +++++++----------- .../{t_flag_build_make.pl => t_flag_build.pl} | 4 +- test_regress/t/t_flag_build_bad.out | 2 + test_regress/t/t_flag_build_bad.pl | 26 ++++++++++ test_regress/t/t_flag_build_cmake.pl | 47 ------------------- test_regress/t/t_flag_verilate.pl | 4 +- 8 files changed, 79 insertions(+), 98 deletions(-) rename test_regress/t/{t_flag_build_make.pl => t_flag_build.pl} (87%) create mode 100644 test_regress/t/t_flag_build_bad.out create mode 100755 test_regress/t/t_flag_build_bad.pl delete mode 100755 test_regress/t/t_flag_build_cmake.pl diff --git a/bin/verilator b/bin/verilator index 1b448da73..2d3c6c538 100755 --- a/bin/verilator +++ b/bin/verilator @@ -274,12 +274,12 @@ detailed descriptions in L for more information. --bbox-sys Blackbox unknown $system calls --bbox-unsup Blackbox unsupported language features --bin Override Verilator binary - --build Call make system to build executable after Verilation + --build Build model executable/library after Verilation -CFLAGS C++ Compiler flags for makefile --cc Create C++ output --cdc Clock domain crossing analysis --clk Mark specified signal as clock - --make Generate scripts for specified make system + --make Generate scripts for specified build tool --compiler Tune for specified C++ compiler --converge-limit Tune convergence settle time --coverage Enable all coverage @@ -325,7 +325,7 @@ detailed descriptions in L for more information. --language Default language standard to parse +libext++[ext]... Extensions for finding modules --lint-only Lint, but do not make output - -MAKEFLAGS Options to make/cmake during --build + -MAKEFLAGS Options to make during --build --max-num-width Maximum number width (default: 64K) --MMD Create .d dependency files --MP Create phony dependency targets @@ -545,8 +545,10 @@ output files. =item --build -After generating the SystemC/C++ code, Verilator will use the make system -to build a library or executable. See also C<--make> and C<--exe>. +After generating the SystemC/C++ code, Verilator will invoke the toolchain to +build the model library (and executable when C<--exe> is also used). Verilator +manages the build itself, and for this --build requires GNU Make to be +available on the platform. =item -CFLAGS I @@ -593,15 +595,17 @@ If clock signals are assigned to vectors and then later used individually, Verilator will attempt to decompose the vector and connect the single-bit clock signals directly. This should be transparent to the user. -=item --make I +=item --make I -Generates a script for the specified make system. +Generates a script for the specified build tool. -Supported make systems are gmake and cmake. Both can be specified. -If no make system is specified, gmake is assumed. -The executable of gmake can be configured via environment variable "MAKE". +Supported values are C for GNU Make and C for CMake. Both can be +specified together. If no build tool is specified, gmake is assumed. The +executable of gmake can be configured via environment variable "MAKE". -See also --build. +When using --build Verilator takes over the responsibility of building the +model library/executable. For this reason --make cannot be specified when +using --build. =item --compiler I @@ -951,9 +955,11 @@ for very small modules; they will always be inlined, if allowed. =item -j -Specify the parallelism for make system. This option is used when --build -options is specified. must be a positive integer or can be omitted. -Build system exploits maximum parallelism when is omitted. +Specify the level of parallelism for --build. must be a positive +integer specifying the maximum number of parallel build jobs, or can be +omitted. When is omitted, the build will not try to limit the number of +parallel build jobs but attempt to execute all independent build steps in +parallel. =item -LDFLAGS I @@ -1002,10 +1008,11 @@ If the design is not to be completely Verilated see also the --bbox-sys and =item -MAKEFLAGS -When using --build, add the specified flag to the make/cmake command line. +When using --build, add the specified flag to the invoked make command line. For multiple flags either pass them as a single argument with space separators quoted in the shell (e.g. C<-MAKEFLAGS "-a -b">), or use multiple -MAKEFLAGS -arguments (e.g. C<-MAKEFLAGS -l -MAKEFLAGS -k>). +arguments (e.g. C<-MAKEFLAGS -l -MAKEFLAGS -k>). Use of this option should not +be required for simple builds using the host toolchain. =item --max-num-width I @@ -1576,7 +1583,9 @@ Note -v is fairly standard across Verilog tools. =item --no-verilate -When using --build, disable generation of C++/SC code, and only run make/cmake. +When using --build, disable generation of C++/SC code, and execute only the +build. This can be useful for rebuilding verilated code produced by a previous +invocation of Verilator. =item +verilog1995ext+I @@ -2193,7 +2202,7 @@ needed at simulation runtime. =item MAKE -Executable of the make command used in --build option. +Names the executable of the make command invoked when using the --build option. Some operating systems may require "gmake" to this variable to launch GNU make. If this variable is not specified, "make" is used. diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 29b058b72..733cea183 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -593,6 +593,10 @@ void V3Options::notify() { "--xml-only or --E option"); } + if (m_build && (m_gmake || m_cmake)) { + cmdfl->v3error("--make cannot be used together with --build. Suggest see manual"); + } + // Make sure at least one make system is enabled if (!m_gmake && !m_cmake) m_gmake = true; diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 2f174600e..33f3c9388 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -567,41 +567,28 @@ static void verilate(const string& argString) { static void execBuildJob() { UASSERT(v3Global.opt.build(), "--build is not specified."); + UASSERT(v3Global.opt.gmake(), "--build requires GNU Make."); + UASSERT(!v3Global.opt.cmake(), "--build cannot use CMake."); UINFO(1, "Start Build\n"); - std::stringstream cmd; const V3StringList& makeFlags = v3Global.opt.makeFlags(); const int jobs = v3Global.opt.buildJobs(); UASSERT(jobs >= 0, "-j option parser in V3Options.cpp filters out negative value"); - if (v3Global.opt.gmake()) { // If both gmake and cmake are chosen, use gmake to build. - cmd << v3Global.opt.getenvMAKE(); - cmd << " -C " << v3Global.opt.makeDir(); - cmd << " -f " << v3Global.opt.prefix() << ".mk"; - if (jobs == 0) { - cmd << " -j"; - } else if (jobs > 1) { - cmd << " -j " << jobs; - } - for (V3StringList::const_iterator it = makeFlags.begin(); it != makeFlags.end(); ++it) { - cmd << ' ' << *it; - } - } else { - UASSERT(v3Global.opt.cmake(), "cmake or gmake must be chosen in V3Options.cpp"); - cmd << "cd " << v3Global.opt.makeDir() << " && "; - cmd << "cmake"; - for (V3StringList::const_iterator it = makeFlags.begin(); it != makeFlags.end(); ++it) { - cmd << ' ' << *it; - } - cmd << ' ' << V3Os::getcwd() << " && "; - cmd << "cmake --build . "; - if (jobs == 0) { - cmd << " -j"; - } else if (jobs > 1) { - cmd << " -j " << jobs; - } - } - const std::string cmdStr = cmd.str(); + std::stringstream cmd; + cmd << v3Global.opt.getenvMAKE(); + cmd << " -C " << v3Global.opt.makeDir(); + cmd << " -f " << v3Global.opt.prefix() << ".mk"; + if (jobs == 0) { + cmd << " -j"; + } else if (jobs > 1) { + cmd << " -j " << jobs; + } + for (V3StringList::const_iterator it = makeFlags.begin(); it != makeFlags.end(); ++it) { + cmd << ' ' << *it; + } + + const std::string cmdStr = cmd.str(); const int exit_code = V3Os::system(cmdStr); if (exit_code != 0) { v3error(cmdStr << " exitted with " << exit_code << std::endl); diff --git a/test_regress/t/t_flag_build_make.pl b/test_regress/t/t_flag_build.pl similarity index 87% rename from test_regress/t/t_flag_build_make.pl rename to test_regress/t/t_flag_build.pl index 0084a0b55..d5278d93f 100755 --- a/test_regress/t/t_flag_build_make.pl +++ b/test_regress/t/t_flag_build.pl @@ -15,7 +15,7 @@ top_filename("t/t_flag_make_cmake.v"); compile( # Don't call cmake nor gmake from driver.pl verilator_make_cmake => 0, verilator_make_gmake => 0, - verilator_flags2 => ['--exe --cc --build -j 2 --make gmake', + verilator_flags2 => ['--exe --cc --build -j 2', '../' . $Self->{main_filename}, '-MAKEFLAGS -p --trace'], ); @@ -26,7 +26,7 @@ execute( # If '-MAKEFLAGS --trace' is not properly processed, # the log will not contain 'CMAKE_BUILD_TYPE:STRING=Debug'. -file_grep($Self->{obj_dir} . '/vlt_compile.log', /^Vt_flag_build_make.mk:\d+: update target \'(\w+)\' due to:/, 'Vt_flag_build_make'); +file_grep($Self->{obj_dir} . '/vlt_compile.log', /^Vt_flag_build_make.mk:\d+: update target \'(\w+)\' due to:/, 'Vt_flag_build'); ok(1); 1; diff --git a/test_regress/t/t_flag_build_bad.out b/test_regress/t/t_flag_build_bad.out new file mode 100644 index 000000000..63a4df79c --- /dev/null +++ b/test_regress/t/t_flag_build_bad.out @@ -0,0 +1,2 @@ +%Error: --make cannot be used together with --build. Suggest see manual +%Error: Exiting due to diff --git a/test_regress/t/t_flag_build_bad.pl b/test_regress/t/t_flag_build_bad.pl new file mode 100755 index 000000000..8b792ff9c --- /dev/null +++ b/test_regress/t/t_flag_build_bad.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["--build --make gmake"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +compile( + verilator_flags2 => ["--build --make cmake"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_build_cmake.pl b/test_regress/t/t_flag_build_cmake.pl deleted file mode 100755 index 1c189d3c3..000000000 --- a/test_regress/t/t_flag_build_cmake.pl +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } -# DESCRIPTION: Verilator: Verilog Test driver/expect definition -# -# Copyright 2008 by Wilson Snyder. This program is free software; you -# can redistribute it and/or modify it under the terms of either the GNU -# Lesser General Public License Version 3 or the Perl Artistic License -# Version 2.0. -# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - - -scenarios(simulator => 1); -top_filename("t/t_flag_make_cmake.v"); - -# This test seems broken as the CMake build invoked by Verilator itself -# invokes Verilator.. (See #2280). Strangely though it passes when built -# from clean, so nuke it: -clean_objs(); - -compile( # Don't call cmake nor gmake from driver.pl - verilator_make_cmake => 0, - verilator_make_gmake => 0, - verilator_flags2 => ['--exe --cc --build --make cmake', - '../' . $Self->{main_filename}, - ' -MAKEFLAGS "-DTEST_NAME=' . $Self->{name} . '"', - ' -MAKEFLAGS "-DTEST_CSOURCES=' . $Self->{main_filename} . '"', - ' -MAKEFLAGS "-DTEST_OPT_FAST=-Os"', - ' -MAKEFLAGS "-DTEST_VERILATOR_ROOT=' . $ENV{VERILATOR_ROOT} . '"', - ' -MAKEFLAGS "-DTEST_VERILATOR_ARGS=\"--prefix ' . $Self->{VM_PREFIX} . ' --cc \""', - ' -MAKEFLAGS "-DTEST_VERILATOR_SOURCES=./t/t_flag_make_cmake.v"', - ' -MAKEFLAGS "-DTEST_SYSTEMC=0"', - ' -MAKEFLAGS "-DTEST_VERBOSE=0"', - ' -MAKEFLAGS "-DTEST_VERILATION=1"', - ' -MAKEFLAGS -DCMAKE_BUILD_TYPE=Debug', - ' -MAKEFLAGS -L'], - ); - -execute( - check_finished => 1, - ); - -# If '-MAKEFLAGS -DCMAKE_BUILD_TYPE=Debug' and '-MAKEFLAGS -L' are not properly processed, -# the log will not contain 'CMAKE_BUILD_TYPE:STRING=Debug'. -file_grep($Self->{obj_dir} . '/vlt_compile.log', /^CMAKE_BUILD_TYPE:STRING=(\w+)$/, 'Debug'); - -ok(1); -1; diff --git a/test_regress/t/t_flag_verilate.pl b/test_regress/t/t_flag_verilate.pl index b523b77e3..f4b0081eb 100755 --- a/test_regress/t/t_flag_verilate.pl +++ b/test_regress/t/t_flag_verilate.pl @@ -33,7 +33,7 @@ if ( -e $Self->{obj_dir} . '/Vt_flag_verilate.mk' ) { compile( # Don't call cmake nor gmake from driver.pl. Just verilate here. verilator_make_cmake => 0, verilator_make_gmake => 0, - verilator_flags2 => ['--exe --cc --make gmake --verilate', + verilator_flags2 => ['--exe --cc --verilate', '../' . $Self->{main_filename}] ); @@ -46,7 +46,7 @@ if ( ! -e $Self->{obj_dir} . '/Vt_flag_verilate.mk' ) { compile( # Don't call cmake nor gmake from driver.pl. Just build here verilator_make_cmake => 0, verilator_make_gmake => 0, - verilator_flags2 => ['--exe --cc --build --make gmake --no-verilate', + verilator_flags2 => ['--exe --cc --build --no-verilate', '../' . $Self->{main_filename}, '--debugi 1 --dump-tree'], ); From 9fd4541069c019251a864d42fa0d1fedf8db53b0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 30 Apr 2020 17:53:54 -0400 Subject: [PATCH 121/127] Fix reduction OR on wide data, broke in v4.026, #2300. --- Changes | 2 ++ include/verilatedos.h | 2 +- src/V3Expand.cpp | 3 +- test_regress/t/t_math_red.pl | 21 ++++++++++++ test_regress/t/t_math_red.v | 65 ++++++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_math_red.pl create mode 100644 test_regress/t/t_math_red.v diff --git a/Changes b/Changes index 58c8272c2..282fd56b5 100644 --- a/Changes +++ b/Changes @@ -40,6 +40,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix logical not optimization with empty begin, #2291. [Baltazar Ortiz] +**** Fix reduction OR on wide data, broke in v4.026, #2300. [Jack Koening] + * Verilator 4.032 2020-04-04 diff --git a/include/verilatedos.h b/include/verilatedos.h index 352f7f87b..66904c460 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -363,7 +363,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type #define VL_BYTESIZE 8 ///< Bits in a CData / byte #define VL_SHORTSIZE 16 ///< Bits in a SData / short #define VL_IDATASIZE 32 ///< Bits in a IData / word -#define VL_WORDSIZE IDATASIZE ///< Legacy define +#define VL_WORDSIZE VL_IDATASIZE ///< Legacy define #define VL_QUADSIZE 64 ///< Bits in a QData / quadword #define VL_EDATASIZE 32 ///< Bits in a EData (WData entry) #define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE) diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index cbc2ccfe9..6b33f497f 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -796,7 +796,8 @@ private: } newp = new AstEq( nodep->fileline(), - new AstConst(nodep->fileline(), AstConst::SizedEData(), ~VL_MASK_E(0)), newp); + new AstConst(nodep->fileline(), AstConst::SizedEData(), VL_MASK_E(VL_EDATASIZE)), + newp); VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } else { UINFO(8, " REDAND->EQ " << nodep << endl); diff --git a/test_regress/t/t_math_red.pl b/test_regress/t/t_math_red.pl new file mode 100755 index 000000000..1d046ed3f --- /dev/null +++ b/test_regress/t/t_math_red.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_red.v b/test_regress/t/t_math_red.v new file mode 100644 index 000000000..10cb292b8 --- /dev/null +++ b/test_regress/t/t_math_red.v @@ -0,0 +1,65 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2004 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0) + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + integer cyc; initial cyc=0; + + reg [67:0] r; + + wire and_reduce = &r; + wire or_reduce = |r; + wire xor_reduce = ^r; + wire xnor_reduce = ~^r; + wire check_equal = r == 68'hffff_ffff_ffff_ffff_f; + + always @(posedge clk) begin +`ifdef TEST_VERBOSE + $display("cyc=%0d, r = %x, and_reduce = %x, or=%x xor=%x check_equal = %x", + cyc, r, and_reduce, or_reduce, xor_reduce, check_equal); +`endif + cyc <= cyc + 1; + if (cyc == 1) begin + r <= 68'd0; + end + else if (cyc == 10) begin + `checkh(r, 68'h0000_0000_0000_0000_0); + `checkh(and_reduce, '0); + `checkh(or_reduce, '0); + `checkh(xor_reduce, '0); + `checkh(xnor_reduce, '1); + r <= 68'hffff_ffff_ffff_ffff_e; + end + else if (cyc == 11) begin + `checkh(r, 68'hffff_ffff_ffff_ffff_e); + `checkh(and_reduce, '0); + `checkh(or_reduce, '1); + `checkh(xor_reduce, '1); + `checkh(xnor_reduce, '0); + r <= 68'hffff_ffff_ffff_ffff_f; + end + else if (cyc == 12) begin + `checkh(r, 68'hffff_ffff_ffff_ffff_f); + `checkh(and_reduce, '1); + `checkh(or_reduce, '1); + `checkh(xor_reduce, '0); + `checkh(xnor_reduce, '1); + end + else if (cyc == 90) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + r <= 68'd0; + end + end +endmodule From e1f45dd84aed353da419d0c41d60b8665e7d09e6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 30 Apr 2020 18:52:32 -0400 Subject: [PATCH 122/127] Commentary --- Changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changes b/Changes index 282fd56b5..ffcaee1a4 100644 --- a/Changes +++ b/Changes @@ -40,7 +40,7 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix logical not optimization with empty begin, #2291. [Baltazar Ortiz] -**** Fix reduction OR on wide data, broke in v4.026, #2300. [Jack Koening] +**** Fix reduction OR on wide data, broke in v4.026, #2300. [Jack Koenig] * Verilator 4.032 2020-04-04 From a6deee2083b3030a3e7541765f58d463d0c5168b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 30 Apr 2020 19:22:58 -0400 Subject: [PATCH 123/127] Fix clock enables with bit-extends, #2299. --- Changes | 2 ++ src/V3Gate.cpp | 17 +++++++++++++---- test_regress/t/t_clk_gate_ext.pl | 21 +++++++++++++++++++++ test_regress/t/t_clk_gate_ext.v | 25 +++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100755 test_regress/t/t_clk_gate_ext.pl create mode 100644 test_regress/t/t_clk_gate_ext.v diff --git a/Changes b/Changes index ffcaee1a4..b6985a48a 100644 --- a/Changes +++ b/Changes @@ -42,6 +42,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix reduction OR on wide data, broke in v4.026, #2300. [Jack Koenig] +**** Fix clock enables with bit-extends, #2299. [Marco Widmer] + * Verilator 4.032 2020-04-04 diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index e296c8bf0..2c843c0c9 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -1497,7 +1497,7 @@ private: vvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState)); if (vsp->varp()->width() > 1) --m_seen_clk_vectors; vsp->user2(false); - return VNUser(0); + return VNUser(0); // Unused } virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) { @@ -1506,6 +1506,7 @@ private: if (const AstAssignW* assignp = VN_CAST(lvertexp->nodep(), AssignW)) { UINFO(9, "CLK DECOMP Logic (off = " << clk_offset << ") - " << lvertexp << " : " << m_clk_vsp << endl); + // RHS if (AstSel* rselp = VN_CAST(assignp->rhsp(), Sel)) { if (VN_IS(rselp->lsbp(), Const) && VN_IS(rselp->widthp(), Const)) { if (clk_offset < rselp->lsbConst() || clk_offset > rselp->msbConst()) { @@ -1521,11 +1522,17 @@ private: } else if (AstConcat* catp = VN_CAST(assignp->rhsp(), Concat)) { UINFO(9, "CLK DECOMP Concat searching - " << assignp->lhsp() << endl); int concat_offset; - if (!m_concat_visitor.concatOffset(catp, currState->m_last_vsp, concat_offset)) { + if (!m_concat_visitor.concatOffset(catp, currState->m_last_vsp, + concat_offset /*ref*/)) { return VNUser(0); } clk_offset += concat_offset; + } else if (VN_IS(assignp->rhsp(), VarRef)) { + UINFO(9, "CLK DECOMP VarRef searching - " << assignp->lhsp() << endl); + } else { + return VNUser(0); } + // LHS if (const AstSel* lselp = VN_CAST(assignp->lhsp(), Sel)) { if (VN_IS(lselp->lsbp(), Const) && VN_IS(lselp->widthp(), Const)) { clk_offset += lselp->lsbConst(); @@ -1538,8 +1545,8 @@ private: UINFO(9, "Should only make it here with clk_offset = 0" << endl); return VNUser(0); } - UINFO(9, "CLK DECOMP Connecting - " << assignp->lhsp() << " <-> " << m_clk_vsp - << endl); + UINFO(9, "CLK DECOMP Connecting - " << assignp->lhsp() << endl); + UINFO(9, " to - " << m_clk_vsp << endl); AstNode* rhsp = assignp->rhsp(); rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false)); for (V3GraphEdge* edgep = lvertexp->inBeginp(); edgep;) { @@ -1548,6 +1555,8 @@ private: new V3GraphEdge(m_graphp, m_clk_vvertexp, lvertexp, 1); m_total_decomposed_clk_vectors++; } + } else { + return VNUser(0); } GateClkDecompState nextState(clk_offset, currState->m_last_vsp); return lvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState)); diff --git a/test_regress/t/t_clk_gate_ext.pl b/test_regress/t/t_clk_gate_ext.pl new file mode 100755 index 000000000..e02817219 --- /dev/null +++ b/test_regress/t/t_clk_gate_ext.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clk_gate_ext.v b/test_regress/t/t_clk_gate_ext.v new file mode 100644 index 000000000..02f595828 --- /dev/null +++ b/test_regress/t/t_clk_gate_ext.v @@ -0,0 +1,25 @@ +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + reg clk_en = 1'b0; + wire clk_gated = clk & clk_en; + wire [1:0] clks = {1'b0, clk_gated}; + + always @(posedge clks[0]) begin + $display("ERROR: clks[0] should not be active!"); + $stop; + end + + int cyc = 0; + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule From 5ded80cf79bd7b2e955f3be345216cc088486196 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 30 Apr 2020 19:53:21 -0400 Subject: [PATCH 124/127] Fix MacOs Homebrew by removing default LIBS, #2298. --- Changes | 2 ++ include/verilated.mk.in | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Changes b/Changes index b6985a48a..fc6f1462f 100644 --- a/Changes +++ b/Changes @@ -44,6 +44,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix clock enables with bit-extends, #2299. [Marco Widmer] +**** Fix MacOs Homebrew by removing default LIBS, #2298. [Ryan Clarke] + * Verilator 4.032 2020-04-04 diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 1966bf956..bd26a59c8 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -167,11 +167,6 @@ endif preproc: -####################################################################### -##### C/H builds - -LIBS += -lm -lstdc++ - ####################################################################### # Overall Objects Linking From 6e9008fb5a06396ea44e5410822b6d3e810137c9 Mon Sep 17 00:00:00 2001 From: John Demme Date: Fri, 1 May 2020 04:42:29 -0700 Subject: [PATCH 125/127] Fix VerilatedVarProps::totalSize missing the first unpacked dim (#2296) --- docs/CONTRIBUTORS | 1 + include/verilated.cpp | 2 +- test_regress/t/t_dpi_open_c.cpp | 40 ++++++++++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index b487ca6fb..9b948c0e6 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -17,6 +17,7 @@ Iztok Jeras James Hanlon Jeremy Bennett John Coiner +John Demme Julien Margetts Kanad Kanhere Kevin Kiningham diff --git a/include/verilated.cpp b/include/verilated.cpp index ddc7c05fe..206e7335b 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2444,7 +2444,7 @@ vluint32_t VerilatedVarProps::entSize() const { size_t VerilatedVarProps::totalSize() const { size_t size = entSize(); - for (int dim = 1; dim <= dims(); ++dim) size *= m_unpacked[dim].elements(); + for (int dim = 0; dim <= dims(); ++dim) size *= m_unpacked[dim].elements(); return size; } diff --git a/test_regress/t/t_dpi_open_c.cpp b/test_regress/t/t_dpi_open_c.cpp index cf0440620..466010aca 100644 --- a/test_regress/t/t_dpi_open_c.cpp +++ b/test_regress/t/t_dpi_open_c.cpp @@ -22,6 +22,8 @@ # include "../vc_hdrs.h" #elif defined(NC) # define NEED_EXTERNS +// #elif defined(MS) +// # define NEED_EXTERNS #else # error "Unknown simulator for DPI test" #endif @@ -94,6 +96,15 @@ int dpii_failure() { return failure; } } \ } while (0) +#define CHECK_RESULT_HEX_NE(got, exp) \ + do { \ + if ((got) == (exp)) { \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << std::hex \ + << ": GOT=" << (got) << " EXP!=" << (exp) << std::endl; \ + failure = __LINE__; \ + } \ + } while (0) + void dpii_unused(const svOpenArrayHandle u) {} void _dpii_all(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { @@ -102,8 +113,10 @@ void _dpii_all(int c, int p, int u, const svOpenArrayHandle i, const svOpenArray __FILE__, __LINE__, c, p, u, svGetArrayPtr(i)); #endif (void)svGetArrayPtr(i); +#ifndef NC // NC always returns zero and warns - //(void)svSizeOfArray(i); + (void)svSizeOfArray(i); +#endif #ifndef VCS // VCS does not support dimension 0 query if (p) { int d = 0; @@ -222,8 +235,29 @@ void dpii_open_pw_u3(int c, int p, int u, const svOpenArrayHandle i, const svOpe } void dpii_open_bit(const svOpenArrayHandle i, const svOpenArrayHandle o) {} -void dpii_open_byte(const svOpenArrayHandle i, const svOpenArrayHandle o) {} -void dpii_open_int(const svOpenArrayHandle i, const svOpenArrayHandle o) {} + +void dpii_open_byte(const svOpenArrayHandle i, const svOpenArrayHandle o) { + intptr_t arrPtr = (intptr_t)svGetArrayPtr(i); + CHECK_RESULT_HEX_NE(arrPtr, 0); // All the arrays should actually exist +#ifndef NC + // NC always returns zero and warns + int sizeInputOfArray = svSizeOfArray(i); + CHECK_RESULT_HEX_NE(sizeInputOfArray, 0); // None of the test cases have zero size + CHECK_RESULT_HEX_NE(svDimensions(i), 0); // All the test cases are unpacked arrays +#endif +} + +void dpii_open_int(const svOpenArrayHandle i, const svOpenArrayHandle o) { + intptr_t arrPtr = (intptr_t)svGetArrayPtr(i); + CHECK_RESULT_HEX_NE(arrPtr, 0); // All the arrays should actually exist +#ifndef NC + // NC always returns zero and warns + int sizeInputOfArray = svSizeOfArray(i); + CHECK_RESULT_HEX_NE(sizeInputOfArray, 0); // None of the test cases have zero size + CHECK_RESULT_HEX_NE(svDimensions(i), 0); // All the test cases are unpacked arrays +#endif +} + void dpii_open_integer(const svOpenArrayHandle i, const svOpenArrayHandle o) {} void dpii_open_logic(const svOpenArrayHandle i, const svOpenArrayHandle o) {} From 8f64e4a76fedd5d295e74f9680fa70fc4c0ab615 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 2 May 2020 08:29:20 -0400 Subject: [PATCH 126/127] Support $root, #2150. --- Changes | 6 ++++-- src/V3Ast.h | 3 ++- src/V3AstNodes.h | 5 +++-- src/V3LinkDot.cpp | 13 +++++++++++++ src/verilog.l | 2 +- src/verilog.y | 7 +++++-- test_regress/t/t_var_dotted1.v | 2 ++ 7 files changed, 30 insertions(+), 8 deletions(-) diff --git a/Changes b/Changes index fc6f1462f..1b34dfc80 100644 --- a/Changes +++ b/Changes @@ -24,13 +24,15 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Add --flatten for use with --xml-only, #2270. [James Hanlon] +**** Greatly improve FST/VCD dump performance, #2244, #2246, #2250, #2257. [Geza Lore] + **** Support $ferror, and $fflush without arguments, #1638. **** Support event data type (with some restrictions). -**** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. +**** Support $root, #2150. [Keyi Zhang] -**** Greatly improve FST/VCD dump performance, #2244, #2246, #2250, #2257. [Geza Lore] +**** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. **** Fix build of fast path tracing code to use OPT_FAST, #2245. [Geza Lore] diff --git a/src/V3Ast.h b/src/V3Ast.h index 68b7993d3..ae501831e 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -900,6 +900,7 @@ class VParseRefExp { public: enum en { PX_NONE, // Used in V3LinkParse only + PX_ROOT, PX_TEXT // Unknown ID component }; enum en m_e; @@ -912,7 +913,7 @@ public: : m_e(static_cast(_e)) {} operator en() const { return m_e; } const char* ascii() const { - static const char* const names[] = {"", "TEXT", "PREDOT"}; + static const char* const names[] = {"", "$root", "TEXT", "PREDOT"}; return names[m_e]; } }; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 3a8adca4b..f113607b7 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2812,8 +2812,8 @@ private: string m_name; public: - AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp, - AstNodeFTaskRef* ftaskrefp) + AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = NULL, + AstNodeFTaskRef* ftaskrefp = NULL) : ASTGEN_SUPER(fl) , m_expect(expect) , m_name(name) { @@ -8401,6 +8401,7 @@ public: BROKEN_RTN(m_evalp && !m_evalp->brokeExists()); return NULL; } + virtual string name() const { return "$root"; } virtual void dump(std::ostream& str) const; AstNodeModule* modulesp() const { // op1 = List of modules return VN_CAST(op1p(), NodeModule); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d5c821922..9b080c9c4 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -587,6 +587,18 @@ public: else if ((cellp && cellp->modp()->origName() == ident) || (inlinep && inlinep->origModName() == ident)) { } + // $root we walk up to Netlist + else if (ident == "$root") { + lookupSymp = rootEntp(); + // We've added TOP module, now everything else is one lower + if (!m_forPrearray) { + VSymEnt* topSymp = lookupSymp->findIdFlat("TOP"); + if (!topSymp) { + topSymp->nodep()->v3fatalSrc("TOP not found under netlist for $root"); + } + lookupSymp = topSymp; + } + } // Move up and check cellname + modname else { bool crossedCell = false; // Crossed a cell boundary @@ -2079,6 +2091,7 @@ private: bool ok = false; if (!foundp) { } else if (VN_IS(foundp->nodep(), Cell) || VN_IS(foundp->nodep(), Begin) + || VN_IS(foundp->nodep(), Netlist) // for $root || VN_IS(foundp->nodep(), Module)) { // if top if (allowScope) { ok = true; diff --git a/src/verilog.l b/src/verilog.l index 239912a5f..77b30e29d 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -448,6 +448,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$onehot0" { FL; return yD_ONEHOT0; } "$past" { FL; return yD_PAST; } "$right" { FL; return yD_RIGHT; } + "$root" { FL; return yD_ROOT; } "$size" { FL; return yD_SIZE; } "$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; } "$warning" { FL; return yD_WARNING; } @@ -527,7 +528,6 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "void" { FL; return yVOID; } /* Generic unsupported warnings */ /* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */ - "$root" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "before" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "binsof" { ERROR_RSVD_WORD("SystemVerilog 2005"); } diff --git a/src/verilog.y b/src/verilog.y index 2274068e9..d61235675 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -613,6 +613,7 @@ class AstSenTree; %token yD_REALTOBITS "$realtobits" %token yD_REWIND "$rewind" %token yD_RIGHT "$right" +%token yD_ROOT "$root" %token yD_RTOI "$rtoi" %token yD_SAMPLED "$sampled" %token yD_SFORMAT "$sformat" @@ -4008,6 +4009,7 @@ exprScope: // scope and variable for use to inside an expression // // See also varRefClassBit, which is the non-expr version of most of this yTHIS { $$ = new AstConst($1, AstConst::LogicFalse()); BBUNSUP($1, "Unsupported: this"); } + | yD_ROOT { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"); } | idArrayed { $$ = $1; } | package_scopeIdFollows idArrayed { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); } | class_scopeIdFollows idArrayed { $$ = $2; BBUNSUP($1, "Unsupported: scoped class reference"); } @@ -4471,8 +4473,9 @@ idClassSel: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged va ; idDotted: - //UNSUP yD_ROOT '.' idDottedMore { UNSUP } - idDottedMore { $$ = $1; } + yD_ROOT '.' idDottedMore + { $$ = new AstDot($2, new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"), $3); } + | idDottedMore { $$ = $1; } ; idDottedMore: diff --git a/test_regress/t/t_var_dotted1.v b/test_regress/t/t_var_dotted1.v index dd6e79fce..2b0f1318b 100644 --- a/test_regress/t/t_var_dotted1.v +++ b/test_regress/t/t_var_dotted1.v @@ -35,6 +35,8 @@ module t (/*AUTOARG*/ if (cyc==2) begin if (global_cell.globali != 32'hf00d) $stop; if (global_cell2.globali != 32'hf22d) $stop; + if ($root.t.global_cell.globali != 32'hf00d) $stop; + if ($root.t.global_cell2.globali != 32'hf22d) $stop; if (outb0c0 != 32'h00) $stop; if (outb0c1 != 32'h01) $stop; if (outb1c0 != 32'h10) $stop; From 9dc65df98209f45fda3bde379e923a76265a47df Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 3 May 2020 11:14:37 -0400 Subject: [PATCH 127/127] Version bump --- Changes | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 1b34dfc80..cfff91f11 100644 --- a/Changes +++ b/Changes @@ -3,7 +3,7 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! -* Verilator 4.033 devel +* Verilator 4.034 2020-05-03 ** Add simplistic class support with many restrictions, see manual, #377. diff --git a/configure.ac b/configure.ac index 401747ff9..b21cc5868 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.033 devel], +AC_INIT([Verilator],[4.034 2020-05-03], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file