Merge branch 'master' into develop-v5

This commit is contained in:
Krzysztof Bieganski 2022-05-25 11:06:38 +02:00
commit d7a75dc026
62 changed files with 958 additions and 308 deletions

View File

@ -40,6 +40,11 @@ jobs:
- m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-20.04 # Build -m32 only on ubuntu-20.04
- {os: ubuntu-18.04, m32: 1} - {os: ubuntu-18.04, m32: 1}
include:
# Build GCC 10 on ubuntu-20.04
- os: ubuntu-20.04
compiler: { cc: gcc-10, cxx: g++-10 }
m32: 0
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }} ${{ matrix.m32 && '| -m32' || '' }} name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }} ${{ matrix.m32 && '| -m32' || '' }}
env: env:
@ -102,6 +107,13 @@ jobs:
- m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-20.04 # Build -m32 only on ubuntu-20.04
- {os: ubuntu-18.04, m32: 1} - {os: ubuntu-18.04, m32: 1}
include:
# Test with GCC 10 on ubuntu-20.04 without m32
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-0}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-1}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-2}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: vltmt-0}
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: vltmt-1}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.suite }} ${{ matrix.m32 && '| -m32' || '' }} name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.suite }} ${{ matrix.m32 && '| -m32' || '' }}
env: env:

View File

@ -25,7 +25,13 @@ Verilator 4.223 devel
**Minor:** **Minor:**
* Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD]
* Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick]
* Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD]
* Support non-ANSI interface port declarations (#3439). [Geza Lore, Shunyao CAD]
* Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix hang with large case statement optimization (#3405). [Mike Urbach]
* Fix 'with' operator with type casting (#3387). [xiak95]
* Fix incorrect conditional merging (#3409). [Raynard Qiao]
* Fix passing VL_TRACE_FST_WRITER_THREAD in CMake build. [Geza Lore, Shunyao CAD]
Verilator 4.222 2022-05-02 Verilator 4.222 2022-05-02
@ -257,7 +263,7 @@ Verilator 4.204 2021-06-12
* Fix to emit 'else if' without nesting (#2944). [Geza Lore] * Fix to emit 'else if' without nesting (#2944). [Geza Lore]
* Fix part select issues in LATCH warning (#2948) (#2938). [Julien Margetts] * Fix part select issues in LATCH warning (#2948) (#2938). [Julien Margetts]
* Fix to not emit empty files with low split limits (#2961). [Geza Lore] * Fix to not emit empty files with low split limits (#2961). [Geza Lore]
* Fix merging of assignments in C++ code (#2970). [Ruper Swarbrick] * Fix merging of assignments in C++ code (#2970). [Rupert Swarbrick]
* Fix unused variable warnings (#2991). [Pieter Kapsenberg] * Fix unused variable warnings (#2991). [Pieter Kapsenberg]
* Fix --protect-ids when using SV classes (#2994). [Geza Lore] * Fix --protect-ids when using SV classes (#2994). [Geza Lore]
* Fix constant function calls with uninitialized value (#2995). [yanx21] * Fix constant function calls with uninitialized value (#2995). [yanx21]

View File

@ -110,6 +110,9 @@ model. Here is a simple example:
Verilated::commandArgs(argc, argv); // Remember args Verilated::commandArgs(argc, argv); // Remember args
top = new Vtop; // Create model top = new Vtop; // Create model
// Do not instead make Vtop as a file-scope static
// variable, as the "C++ static initialization order fiasco"
// may cause a crash
top->reset_l = 0; // Set some inputs top->reset_l = 0; // Set some inputs

View File

@ -87,7 +87,7 @@ compiles under all the options above, plus using MSVC++.
Install Prerequisites Install Prerequisites
--------------------- ---------------------
To build or run Verilator you need these standard packages: To build or run Verilator, you need these standard packages:
:: ::
@ -98,13 +98,20 @@ To build or run Verilator you need these standard packages:
sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error) sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
sudo apt-get install zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error) sudo apt-get install zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error)
To build or run the following are optional but should be installed for good To build or run Verilator, the following are optional but should be installed
performance: for good performance:
:: ::
sudo apt-get install ccache # If present at build, needed for run sudo apt-get install ccache # If present at build, needed for run
sudo apt-get install libgoogle-perftools-dev numactl perl-doc sudo apt-get install libgoogle-perftools-dev numactl
The following is optional but is recommended for nicely rendered command line
help when running Verilator:
::
sudo apt-get install perl-doc
To build Verilator you will need to install these packages; these do not To build Verilator you will need to install these packages; these do not
need to be present to run Verilator: need to be present to run Verilator:
@ -118,7 +125,7 @@ Those developing Verilator itself may also want these (see internals.rst):
:: ::
sudo apt-get install gdb graphviz cmake clang clang-format-11 gprof lcov sudo apt-get install gdb graphviz cmake clang clang-format-11 gprof lcov
sudo pip3 install sphinx sphinx_rtd_theme breathe sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe
cpan install Pod::Perldoc cpan install Pod::Perldoc
cpan install Parallel::Forker cpan install Parallel::Forker

View File

@ -257,7 +257,6 @@ Rodionov
Rolfe Rolfe
Roodselaar Roodselaar
Runtime Runtime
Ruper
Ruud Ruud
Rystsov Rystsov
STandarD STandarD

View File

@ -34,6 +34,8 @@ int main(int argc, char** argv, char** env) {
// Using unique_ptr is similar to // Using unique_ptr is similar to
// "VerilatedContext* contextp = new VerilatedContext" then deleting at end. // "VerilatedContext* contextp = new VerilatedContext" then deleting at end.
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext}; const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
// Do not instead make Vtop as a file-scope static variable, as the
// "C++ static initialization order fiasco" may cause a crash
// Set debug level, 0 is off, 9 is highest presently used // Set debug level, 0 is off, 9 is highest presently used
// May be overridden by commandArgs argument parsing // May be overridden by commandArgs argument parsing

View File

@ -2289,7 +2289,17 @@ VerilatedContext::VerilatedContext()
} }
// Must declare here not in interface, as otherwise forward declarations not known // Must declare here not in interface, as otherwise forward declarations not known
VerilatedContext::~VerilatedContext() {} VerilatedContext::~VerilatedContext() {
checkMagic(this);
m_magic = 0x1; // Arbitrary but 0x1 is what Verilator src uses for a deleted pointer
}
void VerilatedContext::checkMagic(const VerilatedContext* contextp) {
if (VL_UNLIKELY(!contextp || contextp->m_magic != MAGIC)) {
VL_FATAL_MT("", 0, "", // LCOV_EXCL_LINE
"Attempt to create model using a bad/deleted VerilatedContext pointer");
}
}
VerilatedContext::Serialized::Serialized() { VerilatedContext::Serialized::Serialized() {
m_timeunit = VL_TIME_UNIT; // Initial value until overriden by _Vconfigure m_timeunit = VL_TIME_UNIT; // Initial value until overriden by _Vconfigure
@ -2657,6 +2667,7 @@ const VerilatedScopeNameMap* VerilatedContext::scopeNameMap() VL_MT_SAFE {
VerilatedSyms::VerilatedSyms(VerilatedContext* contextp) VerilatedSyms::VerilatedSyms(VerilatedContext* contextp)
: _vm_contextp__(contextp ? contextp : Verilated::threadContextp()) { : _vm_contextp__(contextp ? contextp : Verilated::threadContextp()) {
VerilatedContext::checkMagic(_vm_contextp__);
Verilated::threadContextp(_vm_contextp__); Verilated::threadContextp(_vm_contextp__);
#ifdef VL_THREADED #ifdef VL_THREADED
__Vm_evalMsgQp = new VerilatedEvalMsgQueue; __Vm_evalMsgQp = new VerilatedEvalMsgQueue;
@ -2664,6 +2675,7 @@ VerilatedSyms::VerilatedSyms(VerilatedContext* contextp)
} }
VerilatedSyms::~VerilatedSyms() { VerilatedSyms::~VerilatedSyms() {
VerilatedContext::checkMagic(_vm_contextp__);
#ifdef VL_THREADED #ifdef VL_THREADED
delete __Vm_evalMsgQp; delete __Vm_evalMsgQp;
#endif #endif

View File

@ -374,6 +374,10 @@ protected:
// List of free descriptors in the MCT region [4, 32) // List of free descriptors in the MCT region [4, 32)
std::vector<IData> m_fdFreeMct VL_GUARDED_BY(m_fdMutex); std::vector<IData> m_fdFreeMct VL_GUARDED_BY(m_fdMutex);
// Magic to check for bad construction
static constexpr uint64_t MAGIC = 0xC35F9A6E5298EE6EULL; // SHA256 "VerilatedContext"
uint64_t m_magic = MAGIC;
private: private:
// CONSTRUCTORS // CONSTRUCTORS
VL_UNCOPYABLE(VerilatedContext); VL_UNCOPYABLE(VerilatedContext);
@ -535,6 +539,10 @@ public: // But for internal use only
// Internal: Serialization setup // Internal: Serialization setup
static constexpr size_t serialized1Size() VL_PURE { return sizeof(m_s); } static constexpr size_t serialized1Size() VL_PURE { return sizeof(m_s); }
void* serialized1Ptr() VL_MT_UNSAFE { return &m_s; } void* serialized1Ptr() VL_MT_UNSAFE { return &m_s; }
// Internal: Check magic number
static void checkMagic(const VerilatedContext* contextp);
void selfTestClearMagic() { m_magic = 0x2; }
}; };
//=========================================================================== //===========================================================================

View File

@ -56,6 +56,7 @@ VK_CPPFLAGS_ALWAYS += \
-DVM_SC=$(VM_SC) \ -DVM_SC=$(VM_SC) \
-DVM_TRACE=$(VM_TRACE) \ -DVM_TRACE=$(VM_TRACE) \
-DVM_TRACE_FST=$(VM_TRACE_FST) \ -DVM_TRACE_FST=$(VM_TRACE_FST) \
-DVM_TRACE_VCD=$(VM_TRACE_VCD) \
$(CFG_CXXFLAGS_NO_UNUSED) \ $(CFG_CXXFLAGS_NO_UNUSED) \
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users

View File

@ -123,10 +123,6 @@ public:
protected: protected:
friend class VerilatedCovContext; friend class VerilatedCovContext;
virtual ~VerilatedCovImp() override { clearGuts(); } virtual ~VerilatedCovImp() override { clearGuts(); }
static VerilatedCovImp& imp() VL_MT_SAFE {
static VerilatedCovImp s_singleton;
return s_singleton;
}
private: private:
// PRIVATE METHODS // PRIVATE METHODS

View File

@ -228,7 +228,7 @@ void VlPgoProfiler<T_Entries>::write(const char* modelp, const std::string& file
// So when we have multiple models in an executable, possibly even // So when we have multiple models in an executable, possibly even
// running on different threads, each will have a different symtab so // running on different threads, each will have a different symtab so
// each will collect is own data correctly. However when each is // each will collect is own data correctly. However when each is
// destroid we need to get all the data, not keep overwriting and only // destroyed we need to get all the data, not keep overwriting and only
// get the last model's data. // get the last model's data.
static bool s_firstCall = true; static bool s_firstCall = true;

View File

@ -22,6 +22,10 @@
#ifndef VERILATOR_VERILATED_TRACE_H_ #ifndef VERILATOR_VERILATED_TRACE_H_
#define VERILATOR_VERILATED_TRACE_H_ #define VERILATOR_VERILATED_TRACE_H_
#ifdef VL_TRACE_THREADED
#define VL_TRACE_OFFLOAD
#endif
// clang-format off // clang-format off
#include "verilated.h" #include "verilated.h"
@ -32,7 +36,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
# include <condition_variable> # include <condition_variable>
# include <deque> # include <deque>
# include <thread> # include <thread>
@ -40,9 +44,9 @@
// clang-format on // clang-format on
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
//============================================================================= //=============================================================================
// Threaded tracing // Offloaded tracing
// A simple synchronized first in first out queue // A simple synchronized first in first out queue
template <class T> class VerilatedThreadQueue final { // LCOV_EXCL_LINE // lcov bug template <class T> class VerilatedThreadQueue final { // LCOV_EXCL_LINE // lcov bug
@ -88,7 +92,7 @@ public:
// Commands used by thread tracing. Anonymous enum in class, as we want // Commands used by thread tracing. Anonymous enum in class, as we want
// it scoped, but we also want the automatic conversion to integer types. // it scoped, but we also want the automatic conversion to integer types.
class VerilatedTraceCommand final { class VerilatedTraceOffloadCommand final {
public: public:
// These must all fit in 4 bit at the moment, as the tracing routines // These must all fit in 4 bit at the moment, as the tracing routines
// pack parameters in the top bits. // pack parameters in the top bits.
@ -172,33 +176,33 @@ private:
// Close the file on termination // Close the file on termination
static void onExit(void* selfp) VL_MT_UNSAFE_ONE; static void onExit(void* selfp) VL_MT_UNSAFE_ONE;
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
// Number of total trace buffers that have been allocated // Number of total offload buffers that have been allocated
uint32_t m_numTraceBuffers; uint32_t m_numOffloadBuffers;
// Size of trace buffers // Size of offload buffers
size_t m_traceBufferSize; size_t m_offloadBufferSize;
// Buffers handed to worker for processing // Buffers handed to worker for processing
VerilatedThreadQueue<uint32_t*> m_buffersToWorker; VerilatedThreadQueue<uint32_t*> m_offloadBuffersToWorker;
// Buffers returned from worker after processing // Buffers returned from worker after processing
VerilatedThreadQueue<uint32_t*> m_buffersFromWorker; VerilatedThreadQueue<uint32_t*> m_offloadBuffersFromWorker;
// Write pointer into current buffer // Write pointer into current buffer
uint32_t* m_traceBufferWritep; uint32_t* m_offloadBufferWritep;
// End of trace buffer // End of offload buffer
uint32_t* m_traceBufferEndp; uint32_t* m_offloadBufferEndp;
// The worker thread itself // The offload worker thread itself
std::unique_ptr<std::thread> m_workerThread; std::unique_ptr<std::thread> m_workerThread;
// Get a new trace buffer that can be populated. May block if none available // Get a new offload buffer that can be populated. May block if none available
uint32_t* getTraceBuffer(); uint32_t* getOffloadBuffer();
// The function executed by the worker thread // The function executed by the offload worker thread
void workerThreadMain(); void offloadWorkerThreadMain();
// Wait until given buffer is placed in m_buffersFromWorker // Wait until given offload buffer is placed in m_offloadBuffersFromWorker
void waitForBuffer(const uint32_t* bufferp); void waitForOffloadBuffer(const uint32_t* bufferp);
// Shut down and join worker, if it's running, otherwise do nothing // Shut down and join worker, if it's running, otherwise do nothing
void shutdownWorker(); void shutdownOffloadWorker();
#endif #endif
// CONSTRUCTORS // CONSTRUCTORS
@ -307,56 +311,56 @@ public:
void fullWData(uint32_t* oldp, const WData* newvalp, int bits); void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
void fullDouble(uint32_t* oldp, double newval); void fullDouble(uint32_t* oldp, double newval);
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
// Threaded tracing. Just dump everything in the trace buffer // Offloaded tracing. Just dump everything in the offload buffer
inline void chgBit(uint32_t code, CData newval) { inline void chgBit(uint32_t code, CData newval) {
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_BIT_0 | newval; m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_BIT_0 | newval;
m_traceBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
m_traceBufferWritep += 2; m_offloadBufferWritep += 2;
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgCData(uint32_t code, CData newval, int bits) { inline void chgCData(uint32_t code, CData newval, int bits) {
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_CDATA; m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_CDATA;
m_traceBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
m_traceBufferWritep[2] = newval; m_offloadBufferWritep[2] = newval;
m_traceBufferWritep += 3; m_offloadBufferWritep += 3;
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgSData(uint32_t code, SData newval, int bits) { inline void chgSData(uint32_t code, SData newval, int bits) {
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_SDATA; m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_SDATA;
m_traceBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
m_traceBufferWritep[2] = newval; m_offloadBufferWritep[2] = newval;
m_traceBufferWritep += 3; m_offloadBufferWritep += 3;
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgIData(uint32_t code, IData newval, int bits) { inline void chgIData(uint32_t code, IData newval, int bits) {
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_IDATA; m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_IDATA;
m_traceBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
m_traceBufferWritep[2] = newval; m_offloadBufferWritep[2] = newval;
m_traceBufferWritep += 3; m_offloadBufferWritep += 3;
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgQData(uint32_t code, QData newval, int bits) { inline void chgQData(uint32_t code, QData newval, int bits) {
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_QDATA; m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_QDATA;
m_traceBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
*reinterpret_cast<QData*>(m_traceBufferWritep + 2) = newval; *reinterpret_cast<QData*>(m_offloadBufferWritep + 2) = newval;
m_traceBufferWritep += 4; m_offloadBufferWritep += 4;
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgWData(uint32_t code, const WData* newvalp, int bits) { inline void chgWData(uint32_t code, const WData* newvalp, int bits) {
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_WDATA; m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_WDATA;
m_traceBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
m_traceBufferWritep += 2; m_offloadBufferWritep += 2;
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; } for (int i = 0; i < (bits + 31) / 32; ++i) { *m_offloadBufferWritep++ = newvalp[i]; }
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
inline void chgDouble(uint32_t code, double newval) { inline void chgDouble(uint32_t code, double newval) {
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE; m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_DOUBLE;
m_traceBufferWritep[1] = code; m_offloadBufferWritep[1] = code;
// cppcheck-suppress invalidPointerCast // cppcheck-suppress invalidPointerCast
*reinterpret_cast<double*>(m_traceBufferWritep + 2) = newval; *reinterpret_cast<double*>(m_offloadBufferWritep + 2) = newval;
m_traceBufferWritep += 4; m_offloadBufferWritep += 4;
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
} }
#define CHG(name) chg##name##Impl #define CHG(name) chg##name##Impl
@ -364,8 +368,8 @@ public:
#define CHG(name) chg##name #define CHG(name) chg##name
#endif #endif
// In non-threaded mode, these are called directly by the trace callbacks, // In non-offload mode, these are called directly by the trace callbacks,
// and are called chg*. In threaded mode, they are called by the worker // and are called chg*. In offload mode, they are called by the worker
// thread and are called chg*Impl // thread and are called chg*Impl
// Check previous dumped value of signal. If changed, then emit trace entry // Check previous dumped value of signal. If changed, then emit trace entry

View File

@ -33,9 +33,9 @@
#if 0 #if 0
# include <iostream> # include <iostream>
# define VL_TRACE_THREAD_DEBUG(msg) std::cout << "TRACE THREAD: " << msg << std::endl # define VL_TRACE_OFFLOAD_DEBUG(msg) std::cout << "TRACE OFFLOAD THREAD: " << msg << std::endl
#else #else
# define VL_TRACE_THREAD_DEBUG(msg) # define VL_TRACE_OFFLOAD_DEBUG(msg)
#endif #endif
// clang-format on // clang-format on
@ -78,37 +78,37 @@ static std::string doubleToTimescale(double value) {
return valuestr; // Gets converted to string, so no ref to stack return valuestr; // Gets converted to string, so no ref to stack
} }
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
//========================================================================= //=========================================================================
// Buffer management // Buffer management
template <> uint32_t* VerilatedTrace<VL_DERIVED_T>::getTraceBuffer() { template <> uint32_t* VerilatedTrace<VL_DERIVED_T>::getOffloadBuffer() {
uint32_t* bufferp; uint32_t* bufferp;
// Some jitter is expected, so some number of alternative trace buffers are // Some jitter is expected, so some number of alternative offlaod buffers are
// required, but don't allocate more than 8 buffers. // required, but don't allocate more than 8 buffers.
if (m_numTraceBuffers < 8) { if (m_numOffloadBuffers < 8) {
// Allocate a new buffer if none is available // Allocate a new buffer if none is available
if (!m_buffersFromWorker.tryGet(bufferp)) { if (!m_offloadBuffersFromWorker.tryGet(bufferp)) {
++m_numTraceBuffers; ++m_numOffloadBuffers;
// Note: over allocate a bit so pointer comparison is well defined // Note: over allocate a bit so pointer comparison is well defined
// if we overflow only by a small amount // if we overflow only by a small amount
bufferp = new uint32_t[m_traceBufferSize + 16]; bufferp = new uint32_t[m_offloadBufferSize + 16];
} }
} else { } else {
// Block until a buffer becomes available // Block until a buffer becomes available
bufferp = m_buffersFromWorker.get(); bufferp = m_offloadBuffersFromWorker.get();
} }
return bufferp; return bufferp;
} }
template <> void VerilatedTrace<VL_DERIVED_T>::waitForBuffer(const uint32_t* buffp) { template <> void VerilatedTrace<VL_DERIVED_T>::waitForOffloadBuffer(const uint32_t* buffp) {
// Slow path code only called on flush/shutdown, so use a simple algorithm. // 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. // Collect buffers from worker and stash them until we get the one we want.
std::deque<uint32_t*> stash; std::deque<uint32_t*> stash;
do { stash.push_back(m_buffersFromWorker.get()); } while (stash.back() != buffp); do { stash.push_back(m_offloadBuffersFromWorker.get()); } while (stash.back() != buffp);
// Now put them back in the queue, in the original order. // Now put them back in the queue, in the original order.
while (!stash.empty()) { while (!stash.empty()) {
m_buffersFromWorker.put_front(stash.back()); m_offloadBuffersFromWorker.put_front(stash.back());
stash.pop_back(); stash.pop_back();
} }
} }
@ -116,14 +116,14 @@ template <> void VerilatedTrace<VL_DERIVED_T>::waitForBuffer(const uint32_t* buf
//========================================================================= //=========================================================================
// Worker thread // Worker thread
template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() { template <> void VerilatedTrace<VL_DERIVED_T>::offloadWorkerThreadMain() {
bool shutdown = false; bool shutdown = false;
do { do {
uint32_t* const bufferp = m_buffersToWorker.get(); uint32_t* const bufferp = m_offloadBuffersToWorker.get();
VL_TRACE_THREAD_DEBUG(""); VL_TRACE_OFFLOAD_DEBUG("");
VL_TRACE_THREAD_DEBUG("Got buffer: " << bufferp); VL_TRACE_OFFLOAD_DEBUG("Got buffer: " << bufferp);
const uint32_t* readp = bufferp; const uint32_t* readp = bufferp;
@ -139,53 +139,53 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
switch (cmd & 0xF) { switch (cmd & 0xF) {
//=== //===
// CHG_* commands // CHG_* commands
case VerilatedTraceCommand::CHG_BIT_0: case VerilatedTraceOffloadCommand::CHG_BIT_0:
VL_TRACE_THREAD_DEBUG("Command CHG_BIT_0 " << top); VL_TRACE_OFFLOAD_DEBUG("Command CHG_BIT_0 " << top);
chgBitImpl(oldp, 0); chgBitImpl(oldp, 0);
continue; continue;
case VerilatedTraceCommand::CHG_BIT_1: case VerilatedTraceOffloadCommand::CHG_BIT_1:
VL_TRACE_THREAD_DEBUG("Command CHG_BIT_1 " << top); VL_TRACE_OFFLOAD_DEBUG("Command CHG_BIT_1 " << top);
chgBitImpl(oldp, 1); chgBitImpl(oldp, 1);
continue; continue;
case VerilatedTraceCommand::CHG_CDATA: case VerilatedTraceOffloadCommand::CHG_CDATA:
VL_TRACE_THREAD_DEBUG("Command CHG_CDATA " << top); VL_TRACE_OFFLOAD_DEBUG("Command CHG_CDATA " << top);
// Bits stored in bottom byte of command // Bits stored in bottom byte of command
chgCDataImpl(oldp, *readp, top); chgCDataImpl(oldp, *readp, top);
readp += 1; readp += 1;
continue; continue;
case VerilatedTraceCommand::CHG_SDATA: case VerilatedTraceOffloadCommand::CHG_SDATA:
VL_TRACE_THREAD_DEBUG("Command CHG_SDATA " << top); VL_TRACE_OFFLOAD_DEBUG("Command CHG_SDATA " << top);
// Bits stored in bottom byte of command // Bits stored in bottom byte of command
chgSDataImpl(oldp, *readp, top); chgSDataImpl(oldp, *readp, top);
readp += 1; readp += 1;
continue; continue;
case VerilatedTraceCommand::CHG_IDATA: case VerilatedTraceOffloadCommand::CHG_IDATA:
VL_TRACE_THREAD_DEBUG("Command CHG_IDATA " << top); VL_TRACE_OFFLOAD_DEBUG("Command CHG_IDATA " << top);
// Bits stored in bottom byte of command // Bits stored in bottom byte of command
chgIDataImpl(oldp, *readp, top); chgIDataImpl(oldp, *readp, top);
readp += 1; readp += 1;
continue; continue;
case VerilatedTraceCommand::CHG_QDATA: case VerilatedTraceOffloadCommand::CHG_QDATA:
VL_TRACE_THREAD_DEBUG("Command CHG_QDATA " << top); VL_TRACE_OFFLOAD_DEBUG("Command CHG_QDATA " << top);
// Bits stored in bottom byte of command // Bits stored in bottom byte of command
chgQDataImpl(oldp, *reinterpret_cast<const QData*>(readp), top); chgQDataImpl(oldp, *reinterpret_cast<const QData*>(readp), top);
readp += 2; readp += 2;
continue; continue;
case VerilatedTraceCommand::CHG_WDATA: case VerilatedTraceOffloadCommand::CHG_WDATA:
VL_TRACE_THREAD_DEBUG("Command CHG_WDATA " << top); VL_TRACE_OFFLOAD_DEBUG("Command CHG_WDATA " << top);
chgWDataImpl(oldp, readp, top); chgWDataImpl(oldp, readp, top);
readp += VL_WORDS_I(top); readp += VL_WORDS_I(top);
continue; continue;
case VerilatedTraceCommand::CHG_DOUBLE: case VerilatedTraceOffloadCommand::CHG_DOUBLE:
VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top); VL_TRACE_OFFLOAD_DEBUG("Command CHG_DOUBLE " << top);
chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp)); chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp));
readp += 2; readp += 2;
continue; continue;
//=== //===
// Rare commands // Rare commands
case VerilatedTraceCommand::TIME_CHANGE: case VerilatedTraceOffloadCommand::TIME_CHANGE:
VL_TRACE_THREAD_DEBUG("Command TIME_CHANGE " << top); VL_TRACE_OFFLOAD_DEBUG("Command TIME_CHANGE " << top);
readp -= 1; // No code in this command, undo increment readp -= 1; // No code in this command, undo increment
emitTimeChange(*reinterpret_cast<const uint64_t*>(readp)); emitTimeChange(*reinterpret_cast<const uint64_t*>(readp));
readp += 2; readp += 2;
@ -193,16 +193,16 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
//=== //===
// Commands ending this buffer // Commands ending this buffer
case VerilatedTraceCommand::END: VL_TRACE_THREAD_DEBUG("Command END"); break; case VerilatedTraceOffloadCommand::END: VL_TRACE_OFFLOAD_DEBUG("Command END"); break;
case VerilatedTraceCommand::SHUTDOWN: case VerilatedTraceOffloadCommand::SHUTDOWN:
VL_TRACE_THREAD_DEBUG("Command SHUTDOWN"); VL_TRACE_OFFLOAD_DEBUG("Command SHUTDOWN");
shutdown = true; shutdown = true;
break; break;
//=== //===
// Unknown command // Unknown command
default: { // LCOV_EXCL_START default: { // LCOV_EXCL_START
VL_TRACE_THREAD_DEBUG("Command UNKNOWN"); VL_TRACE_OFFLOAD_DEBUG("Command UNKNOWN");
VL_PRINTF_MT("Trace command: 0x%08x\n", cmd); VL_PRINTF_MT("Trace command: 0x%08x\n", cmd);
VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command"); VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command");
break; break;
@ -214,23 +214,23 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
break; break;
} }
VL_TRACE_THREAD_DEBUG("Returning buffer"); VL_TRACE_OFFLOAD_DEBUG("Returning buffer");
// Return buffer // Return buffer
m_buffersFromWorker.put(bufferp); m_offloadBuffersFromWorker.put(bufferp);
} while (VL_LIKELY(!shutdown)); } while (VL_LIKELY(!shutdown));
} }
template <> void VerilatedTrace<VL_DERIVED_T>::shutdownWorker() { template <> void VerilatedTrace<VL_DERIVED_T>::shutdownOffloadWorker() {
// If the worker thread is not running, done.. // If the worker thread is not running, done..
if (!m_workerThread) return; if (!m_workerThread) return;
// Hand an buffer with a shutdown command to the worker thread // Hand an buffer with a shutdown command to the worker thread
uint32_t* const bufferp = getTraceBuffer(); uint32_t* const bufferp = getOffloadBuffer();
bufferp[0] = VerilatedTraceCommand::SHUTDOWN; bufferp[0] = VerilatedTraceOffloadCommand::SHUTDOWN;
m_buffersToWorker.put(bufferp); m_offloadBuffersToWorker.put(bufferp);
// Wait for it to return // Wait for it to return
waitForBuffer(bufferp); waitForOffloadBuffer(bufferp);
// Join the thread and delete it // Join the thread and delete it
m_workerThread->join(); m_workerThread->join();
m_workerThread.reset(nullptr); m_workerThread.reset(nullptr);
@ -242,24 +242,24 @@ template <> void VerilatedTrace<VL_DERIVED_T>::shutdownWorker() {
// Life cycle // Life cycle
template <> void VerilatedTrace<VL_DERIVED_T>::closeBase() { template <> void VerilatedTrace<VL_DERIVED_T>::closeBase() {
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
shutdownWorker(); shutdownOffloadWorker();
while (m_numTraceBuffers) { while (m_numOffloadBuffers) {
delete[] m_buffersFromWorker.get(); delete[] m_offloadBuffersFromWorker.get();
--m_numTraceBuffers; --m_numOffloadBuffers;
} }
#endif #endif
} }
template <> void VerilatedTrace<VL_DERIVED_T>::flushBase() { template <> void VerilatedTrace<VL_DERIVED_T>::flushBase() {
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
// Hand an empty buffer to the worker thread // Hand an empty buffer to the worker thread
uint32_t* const bufferp = getTraceBuffer(); uint32_t* const bufferp = getOffloadBuffer();
*bufferp = VerilatedTraceCommand::END; *bufferp = VerilatedTraceOffloadCommand::END;
m_buffersToWorker.put(bufferp); m_offloadBuffersToWorker.put(bufferp);
// Wait for it to be returned. As the processing is in-order, // Wait for it to be returned. As the processing is in-order,
// this ensures all previous buffers have been processed. // this ensures all previous buffers have been processed.
waitForBuffer(bufferp); waitForOffloadBuffer(bufferp);
#endif #endif
} }
@ -293,8 +293,8 @@ VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
, m_timeUnit { , m_timeUnit {
1e-9 1e-9
} }
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
, m_numTraceBuffers { 0 } , m_numOffloadBuffers { 0 }
#endif #endif
{ {
set_time_unit(Verilated::threadContextp()->timeunitString()); set_time_unit(Verilated::threadContextp()->timeunitString());
@ -306,7 +306,7 @@ template <> VerilatedTrace<VL_DERIVED_T>::~VerilatedTrace() {
if (m_sigs_enabledp) VL_DO_CLEAR(delete[] m_sigs_enabledp, m_sigs_enabledp = nullptr); if (m_sigs_enabledp) VL_DO_CLEAR(delete[] m_sigs_enabledp, m_sigs_enabledp = nullptr);
Verilated::removeFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this); Verilated::removeFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
Verilated::removeExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this); Verilated::removeExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
closeBase(); closeBase();
#endif #endif
} }
@ -362,16 +362,17 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
Verilated::addFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this); Verilated::addFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
Verilated::addExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this); Verilated::addExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
// Compute trace buffer size. we need to be able to store a new value for // Compute offload buffer size. we need to be able to store a new value for
// each signal, which is 'nextCode()' entries after the init callbacks // each signal, which is 'nextCode()' entries after the init callbacks
// above have been run, plus up to 2 more words of metadata per signal, // 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 // plus fixed overhead of 1 for a termination flag and 3 for a time stamp
// update. // update.
m_traceBufferSize = nextCode() + numSignals() * 2 + 4; m_offloadBufferSize = nextCode() + numSignals() * 2 + 4;
// Start the worker thread // Start the worker thread
m_workerThread.reset(new std::thread{&VerilatedTrace<VL_DERIVED_T>::workerThreadMain, this}); m_workerThread.reset(
new std::thread{&VerilatedTrace<VL_DERIVED_T>::offloadWorkerThreadMain, this});
#endif #endif
} }
@ -477,19 +478,19 @@ template <> void VerilatedTrace<VL_DERIVED_T>::dump(uint64_t timeui) VL_MT_SAFE_
if (!preChangeDump()) return; if (!preChangeDump()) return;
} }
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
// Currently only incremental dumps run on the worker thread // Currently only incremental dumps run on the worker thread
uint32_t* bufferp = nullptr; uint32_t* bufferp = nullptr;
if (VL_LIKELY(!m_fullDump)) { if (VL_LIKELY(!m_fullDump)) {
// Get the trace buffer we are about to fill // Get the offload buffer we are about to fill
bufferp = getTraceBuffer(); bufferp = getOffloadBuffer();
m_traceBufferWritep = bufferp; m_offloadBufferWritep = bufferp;
m_traceBufferEndp = bufferp + m_traceBufferSize; m_offloadBufferEndp = bufferp + m_offloadBufferSize;
// Tell worker to update time point // Tell worker to update time point
m_traceBufferWritep[0] = VerilatedTraceCommand::TIME_CHANGE; m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::TIME_CHANGE;
*reinterpret_cast<uint64_t*>(m_traceBufferWritep + 1) = timeui; *reinterpret_cast<uint64_t*>(m_offloadBufferWritep + 1) = timeui;
m_traceBufferWritep += 3; m_offloadBufferWritep += 3;
} else { } else {
// Update time point // Update time point
flushBase(); flushBase();
@ -519,16 +520,16 @@ template <> void VerilatedTrace<VL_DERIVED_T>::dump(uint64_t timeui) VL_MT_SAFE_
cbr.m_dumpCb(cbr.m_userp, self()); cbr.m_dumpCb(cbr.m_userp, self());
} }
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_OFFLOAD
if (VL_LIKELY(bufferp)) { if (VL_LIKELY(bufferp)) {
// Mark end of the trace buffer we just filled // Mark end of the offload buffer we just filled
*m_traceBufferWritep++ = VerilatedTraceCommand::END; *m_offloadBufferWritep++ = VerilatedTraceOffloadCommand::END;
// Assert no buffer overflow // Assert no buffer overflow
assert(m_traceBufferWritep - bufferp <= m_traceBufferSize); assert(m_offloadBufferWritep - bufferp <= m_offloadBufferSize);
// Pass it to the worker thread // Pass it to the worker thread
m_buffersToWorker.put(bufferp); m_offloadBuffersToWorker.put(bufferp);
} }
#endif #endif
} }

View File

@ -351,7 +351,7 @@ public:
// Can't just overload operator[] or provide a "at" reference to set, // Can't just overload operator[] or provide a "at" reference to set,
// because we need to be able to insert only when the value is set // because we need to be able to insert only when the value is set
T_Value& at(int32_t index) { T_Value& at(int32_t index) {
static T_Value s_throwAway; static VL_THREAD_LOCAL T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize // Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
s_throwAway = atDefault(); s_throwAway = atDefault();
@ -362,7 +362,7 @@ public:
} }
// Accessing. Verilog: v = assoc[index] // Accessing. Verilog: v = assoc[index]
const T_Value& at(int32_t index) const { const T_Value& at(int32_t index) const {
static T_Value s_throwAway; static VL_THREAD_LOCAL T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize // Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
return atDefault(); return atDefault();

View File

@ -292,7 +292,7 @@ void VerilatedVcd::bufferResize(uint64_t minsize) {
} }
void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE { void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
// This function can be called from the trace thread // This function can be called from the trace offload thread
// This function is on the flush() call path // This function is on the flush() call path
// We add output data to m_writep. // We add output data to m_writep.
// When it gets nearly full we dump it using this routine which calls write() // When it gets nearly full we dump it using this routine which calls write()

View File

@ -81,8 +81,9 @@ public:
// To simplify our free list, we use a size large enough for all derived types // To simplify our free list, we use a size large enough for all derived types
// We reserve word zero for the next pointer, as that's safer in case a // We reserve word zero for the next pointer, as that's safer in case a
// dangling reference to the original remains around. // dangling reference to the original remains around.
static const size_t chunk = 96; static constexpr size_t CHUNK_SIZE = 96;
if (VL_UNCOVERABLE(size > chunk)) VL_FATAL_MT(__FILE__, __LINE__, "", "increase chunk"); if (VL_UNCOVERABLE(size > CHUNK_SIZE))
VL_FATAL_MT(__FILE__, __LINE__, "", "increase CHUNK_SIZE");
if (VL_LIKELY(t_freeHead)) { if (VL_LIKELY(t_freeHead)) {
uint8_t* const newp = t_freeHead; uint8_t* const newp = t_freeHead;
t_freeHead = *(reinterpret_cast<uint8_t**>(newp)); t_freeHead = *(reinterpret_cast<uint8_t**>(newp));
@ -90,7 +91,7 @@ public:
return newp + 8; return newp + 8;
} }
// +8: 8 bytes for next // +8: 8 bytes for next
uint8_t* newp = reinterpret_cast<uint8_t*>(::operator new(chunk + 8)); uint8_t* newp = reinterpret_cast<uint8_t*>(::operator new(CHUNK_SIZE + 8));
*(reinterpret_cast<uint32_t*>(newp)) = activeMagic(); *(reinterpret_cast<uint32_t*>(newp)) = activeMagic();
return newp + 8; return newp + 8;
} }

View File

@ -2521,10 +2521,12 @@ public:
class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt {
protected: protected:
AstNodeAssign(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) AstNodeAssign(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp,
AstNode* timingControlp = nullptr)
: AstNodeStmt{t, fl} { : AstNodeStmt{t, fl} {
setOp1p(rhsp); setOp1p(rhsp);
setOp2p(lhsp); setOp2p(lhsp);
addNOp3p(timingControlp);
dtypeFrom(lhsp); dtypeFrom(lhsp);
} }
@ -2535,6 +2537,9 @@ public:
// So iteration hits the RHS which is "earlier" in execution order, it's op1, not op2 // 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* rhsp() const { return op1p(); } // op1 = Assign from
AstNode* lhsp() const { return op2p(); } // op2 = Assign to AstNode* lhsp() const { return op2p(); } // op2 = Assign to
// op3 = Timing controls (delays, event controls)
AstNode* timingControlp() const { return op3p(); }
void addTimingControlp(AstNode* const np) { addNOp3p(np); }
void rhsp(AstNode* np) { setOp1p(np); } void rhsp(AstNode* np) { setOp1p(np); }
void lhsp(AstNode* np) { setOp2p(np); } void lhsp(AstNode* np) { setOp2p(np); }
virtual bool hasDType() const override { return true; } virtual bool hasDType() const override { return true; }

View File

@ -1350,7 +1350,8 @@ void AstClassPackage::cloneRelink() {
} }
void AstClass::insertCache(AstNode* nodep) { void AstClass::insertCache(AstNode* nodep) {
const bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef) const bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())); || (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())
|| VN_IS(nodep, CFunc));
if (doit) { if (doit) {
if (m_members.find(nodep->name()) != m_members.end()) { if (m_members.find(nodep->name()) != m_members.end()) {
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ()); nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
@ -1361,7 +1362,14 @@ void AstClass::insertCache(AstNode* nodep) {
} }
void AstClass::repairCache() { void AstClass::repairCache() {
clearCache(); clearCache();
for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { insertCache(itemp); } for (auto* itemp = membersp(); itemp; itemp = itemp->nextp()) {
if (const auto* const scopep = VN_CAST(itemp, Scope)) {
for (auto* itemp = scopep->blocksp(); itemp; itemp = itemp->nextp())
insertCache(itemp);
} else {
insertCache(itemp);
}
}
} }
bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) { bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) {
// TAIL RECURSIVE // TAIL RECURSIVE

View File

@ -2141,6 +2141,9 @@ public:
virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); }
// op1 = Range of variable // op1 = Range of variable
AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); }
// op2 = Net delay
AstNode* delayp() const { return op2p(); }
void delayp(AstNode* const nodep) { setNOp2p(nodep); }
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
// (Slow) recurse down to find basic data type (Note don't need virtual - // (Slow) recurse down to find basic data type (Note don't need virtual -
// AstVar isn't a NodeDType) // AstVar isn't a NodeDType)
@ -3488,8 +3491,8 @@ public:
class AstAssign final : public AstNodeAssign { class AstAssign final : public AstNodeAssign {
public: public:
AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp) AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr)
: ASTGEN_SUPER_Assign(fl, lhsp, rhsp) { : ASTGEN_SUPER_Assign(fl, lhsp, rhsp, timingControlp) {
dtypeFrom(lhsp); dtypeFrom(lhsp);
} }
ASTNODE_NODE_FUNCS(Assign) ASTNODE_NODE_FUNCS(Assign)
@ -3514,8 +3517,8 @@ public:
class AstAssignDly final : public AstNodeAssign { class AstAssignDly final : public AstNodeAssign {
public: public:
AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp) AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr)
: ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp) {} : ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp, timingControlp) {}
ASTNODE_NODE_FUNCS(AssignDly) ASTNODE_NODE_FUNCS(AssignDly)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
return new AstAssignDly(this->fileline(), lhsp, rhsp); return new AstAssignDly(this->fileline(), lhsp, rhsp);
@ -3838,15 +3841,18 @@ public:
class AstDelay final : public AstNodeStmt { class AstDelay final : public AstNodeStmt {
// Delay statement // Delay statement
public: public:
AstDelay(FileLine* fl, AstNode* lhsp) AstDelay(FileLine* fl, AstNode* lhsp, AstNode* stmtsp)
: ASTGEN_SUPER_Delay(fl) { : ASTGEN_SUPER_Delay(fl) {
setOp1p(lhsp); setOp1p(lhsp);
setNOp2p(stmtsp);
} }
ASTNODE_NODE_FUNCS(Delay) ASTNODE_NODE_FUNCS(Delay)
virtual bool same(const AstNode* samep) const override { return true; } virtual bool same(const AstNode* samep) const override { return true; }
// //
AstNode* lhsp() const { return op1p(); } // op2 = Statements to evaluate AstNode* lhsp() const { return op1p(); } // op1 = delay value
void lhsp(AstNode* nodep) { setOp1p(nodep); } void lhsp(AstNode* nodep) { setOp1p(nodep); }
void stmtsp(AstNode* nodep) { setOp2p(nodep); } // op2 = statements under delay
AstNode* stmtsp() const { return op2p(); }
}; };
class AstGenCase final : public AstNodeCase { class AstGenCase final : public AstNodeCase {
@ -5246,15 +5252,15 @@ public:
} }
}; };
class AstTimingControl final : public AstNodeStmt { class AstEventControl final : public AstNodeStmt {
// Parents: stmtlist // Parents: stmtlist
public: public:
AstTimingControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp)
: ASTGEN_SUPER_TimingControl(fl) { : ASTGEN_SUPER_EventControl(fl) {
setNOp1p(sensesp); setNOp1p(sensesp);
setNOp2p(stmtsp); setNOp2p(stmtsp);
} }
ASTNODE_NODE_FUNCS(TimingControl) ASTNODE_NODE_FUNCS(EventControl)
virtual string verilogKwd() const override { return "@(%l) %r"; } virtual string verilogKwd() const override { return "@(%l) %r"; }
virtual bool isGateOptimizable() const override { return false; } virtual bool isGateOptimizable() const override { return false; }
virtual bool isPredictOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; }

View File

@ -76,6 +76,33 @@ private:
return a + "__DOT__" + b; return a + "__DOT__" + b;
} }
void dotNames(const AstNodeBlock* const nodep, const char* const blockName) {
UINFO(8, "nname " << m_namedScope << endl);
if (nodep->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) {
const string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos + strlen("__DOT__"));
if (nodep->name() != "") {
m_displayScope = dot(m_displayScope, ident);
m_namedScope = dot(m_namedScope, ident);
}
m_unnamedScope = dot(m_unnamedScope, ident);
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* const inlinep = new AstCellInline(
nodep->fileline(), m_unnamedScope, blockName, m_modp->timeunit());
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
}
}
// Remap var names and replace lower Begins
iterateAndNextNull(nodep->stmtsp());
}
void liftNode(AstNode* nodep) { void liftNode(AstNode* nodep) {
nodep->unlinkFrBack(); nodep->unlinkFrBack();
if (m_ftaskp) { if (m_ftaskp) {
@ -141,30 +168,8 @@ private:
VL_RESTORER(m_namedScope); VL_RESTORER(m_namedScope);
VL_RESTORER(m_unnamedScope); VL_RESTORER(m_unnamedScope);
{ {
UINFO(8, "nname " << m_namedScope << endl); dotNames(nodep, "__BEGIN__");
if (nodep->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) {
const string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos + strlen("__DOT__"));
if (nodep->name() != "") {
m_displayScope = dot(m_displayScope, ident);
m_namedScope = dot(m_namedScope, ident);
}
m_unnamedScope = dot(m_unnamedScope, ident);
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* const inlinep = new AstCellInline(
nodep->fileline(), m_unnamedScope, "__BEGIN__", m_modp->timeunit());
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
}
}
// Remap var names and replace lower Begins
iterateAndNextNull(nodep->stmtsp());
UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier"); UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier");
// Cleanup // Cleanup

View File

@ -97,6 +97,7 @@ private:
m_prefix = nodep->name() + "__02e"; // . m_prefix = nodep->name() + "__02e"; // .
iterateChildren(nodep); iterateChildren(nodep);
} }
nodep->repairCache();
} }
virtual void visit(AstNodeModule* nodep) override { virtual void visit(AstNodeModule* nodep) override {
// Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule) // Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule)

View File

@ -308,7 +308,8 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
} }
emitDispState.pushFormat(pfmt); emitDispState.pushFormat(pfmt);
if (!ignore) { if (!ignore) {
if (argp->dtypep()->basicp()->keyword() == VBasicDTypeKwd::STRING) { if (argp->dtypep()->basicp()
&& argp->dtypep()->basicp()->keyword() == VBasicDTypeKwd::STRING) {
// string in SystemVerilog is std::string in C++ which is not POD // string in SystemVerilog is std::string in C++ which is not POD
emitDispState.pushArg(' ', nullptr, "-1"); emitDispState.pushArg(' ', nullptr, "-1");
} else { } else {

View File

@ -771,7 +771,7 @@ class EmitCTrace final : EmitCFunc {
const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords()); const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords());
const uint32_t code = nodep->declp()->code() + offset; const uint32_t code = nodep->declp()->code() + offset;
puts(v3Global.opt.trueTraceThreads() && !nodep->full() ? "(base+" : "(oldp+"); puts(v3Global.opt.useTraceOffloadThread() && !nodep->full() ? "(base+" : "(oldp+");
puts(cvtToStr(code - nodep->baseCode())); puts(cvtToStr(code - nodep->baseCode()));
puts(","); puts(",");
emitTraceValue(nodep, arrayindex); emitTraceValue(nodep, arrayindex);

View File

@ -114,19 +114,18 @@ class CMakeEmitter final {
*of << "# Threaded output mode? 0/1/N threads (from --threads)\n"; *of << "# Threaded output mode? 0/1/N threads (from --threads)\n";
cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads())); cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads()));
*of << "# Threaded tracing output mode? 0/1/N threads (from --trace-threads)\n"; *of << "# Threaded tracing output mode? 0/1/N threads (from --trace-threads)\n";
cmake_set_raw(*of, name + "_TRACE_THREADS", cvtToStr(v3Global.opt.traceThreads())); cmake_set_raw(*of, name + "_TRACE_THREADS",
cvtToStr(v3Global.opt.useTraceOffloadThread()));
cmake_set_raw(*of, name + "_TRACE_FST_WRITER_THREAD",
v3Global.opt.traceThreads() && v3Global.opt.traceFormat().fst() ? "1" : "0");
*of << "# Struct output mode? 0/1 (from --trace-structs)\n"; *of << "# Struct output mode? 0/1 (from --trace-structs)\n";
cmake_set_raw(*of, name + "_TRACE_STRUCTS", cvtToStr(v3Global.opt.traceStructs())); cmake_set_raw(*of, name + "_TRACE_STRUCTS", cvtToStr(v3Global.opt.traceStructs()));
*of << "# VCD Tracing output mode? 0/1 (from --trace)\n"; *of << "# VCD Tracing output mode? 0/1 (from --trace)\n";
cmake_set_raw(*of, name + "_TRACE_VCD", cmake_set_raw(*of, name + "_TRACE_VCD",
(v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD)) (v3Global.opt.trace() && v3Global.opt.traceFormat().vcd()) ? "1" : "0");
? "1" *of << "# FST Tracing output mode? 0/1 (from --trace-fst)\n";
: "0");
*of << "# FST Tracing output mode? 0/1 (from --fst-trace)\n";
cmake_set_raw(*of, name + "_TRACE_FST", cmake_set_raw(*of, name + "_TRACE_FST",
(v3Global.opt.trace() && (v3Global.opt.traceFormat() != TraceFormat::VCD)) (v3Global.opt.trace() && v3Global.opt.traceFormat().fst()) ? "1" : "0");
? "1"
: "0");
*of << "\n### Sources...\n"; *of << "\n### Sources...\n";
std::vector<string> classes_fast; std::vector<string> classes_fast;

View File

@ -65,13 +65,17 @@ public:
of.puts("VM_TRACE = "); of.puts("VM_TRACE = ");
of.puts(v3Global.opt.trace() ? "1" : "0"); of.puts(v3Global.opt.trace() ? "1" : "0");
of.puts("\n"); of.puts("\n");
of.puts("# Tracing output mode in VCD format? 0/1 (from --trace)\n");
of.puts("VM_TRACE_VCD = ");
of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().vcd() ? "1" : "0");
of.puts("\n");
of.puts("# Tracing output mode in FST format? 0/1 (from --trace-fst)\n"); of.puts("# Tracing output mode in FST format? 0/1 (from --trace-fst)\n");
of.puts("VM_TRACE_FST = "); of.puts("VM_TRACE_FST = ");
of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().fst() ? "1" : "0"); of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().fst() ? "1" : "0");
of.puts("\n"); of.puts("\n");
of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n"); of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n");
of.puts("VM_TRACE_THREADS = "); of.puts("VM_TRACE_THREADS = ");
of.puts(cvtToStr(v3Global.opt.trueTraceThreads())); of.puts(cvtToStr(v3Global.opt.useTraceOffloadThread()));
of.puts("\n"); of.puts("\n");
of.puts("# Separate FST writer thread? 0/1 (from --trace-fst with --trace-thread > 0)\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("VM_TRACE_FST_WRITER_THREAD = ");

View File

@ -1478,11 +1478,11 @@ private:
// Need to set pin numbers after varnames are created // Need to set pin numbers after varnames are created
// But before we do the final resolution based on names // But before we do the final resolution based on names
VSymEnt* const foundp = m_statep->getNodeSym(m_modp)->findIdFlat(nodep->name()); VSymEnt* const foundp = m_statep->getNodeSym(m_modp)->findIdFlat(nodep->name());
AstVar* const refp = foundp ? VN_AS(foundp->nodep(), Var) : nullptr; AstVar* const refp = foundp ? VN_CAST(foundp->nodep(), Var) : nullptr;
if (!refp) { if (!foundp) {
nodep->v3error( nodep->v3error(
"Input/output/inout declaration not found for port: " << nodep->prettyNameQ()); "Input/output/inout declaration not found for port: " << nodep->prettyNameQ());
} else if (!refp->isIO() && !refp->isIfaceRef()) { } else if (!refp || (!refp->isIO() && !refp->isIfaceRef())) {
nodep->v3error("Pin is not an in/out/inout/interface: " << nodep->prettyNameQ()); nodep->v3error("Pin is not an in/out/inout/interface: " << nodep->prettyNameQ());
} else { } else {
if (refp->user4()) { if (refp->user4()) {
@ -1729,7 +1729,6 @@ class LinkDotScopeVisitor final : public VNVisitor {
// Note we allow AstNodeStmt's as generates may be under them // Note we allow AstNodeStmt's as generates may be under them
virtual void visit(AstCell*) override {} virtual void visit(AstCell*) override {}
virtual void visit(AstVar*) override {} virtual void visit(AstVar*) override {}
virtual void visit(AstNodeMath*) override {}
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:

View File

@ -582,12 +582,12 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
nodep->timeunit(m_modp->timeunit()); nodep->timeunit(m_modp->timeunit());
} }
virtual void visit(AstTimingControl* nodep) override { virtual void visit(AstEventControl* nodep) override {
cleanFileline(nodep); cleanFileline(nodep);
iterateChildren(nodep); iterateChildren(nodep);
AstAlways* const alwaysp = VN_CAST(nodep->backp(), Always); AstAlways* const alwaysp = VN_CAST(nodep->backp(), Always);
if (alwaysp && alwaysp->keyword() == VAlwaysKwd::ALWAYS_COMB) { if (alwaysp && alwaysp->keyword() == VAlwaysKwd::ALWAYS_COMB) {
alwaysp->v3error("Timing control statements not legal under always_comb " alwaysp->v3error("Event control statements not legal under always_comb "
"(IEEE 1800-2017 9.2.2.2.2)\n" "(IEEE 1800-2017 9.2.2.2.2)\n"
<< nodep->warnMore() << "... Suggest use a normal 'always'"); << nodep->warnMore() << "... Suggest use a normal 'always'");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);

View File

@ -382,15 +382,24 @@ private:
return false; return false;
} }
void addToList(AstNode* nodep, AstNode* condp, int line) { bool addToList(AstNode* nodep, AstNode* condp, int line) {
// Set up head of new list if node is first in list // Set up head of new list if node is first in list
if (!m_mgFirstp) { if (!m_mgFirstp) {
UASSERT_OBJ(condp, nodep, "Cannot start new list without condition " << line); UASSERT_OBJ(condp, nodep, "Cannot start new list without condition " << line);
// Mark variable references in the condition
condp->foreach<AstVarRef>([](const AstVarRef* nodep) { nodep->varp()->user1(1); });
// Now check again if mergeable. We need this to pick up assignments to conditions,
// e.g.: 'c = c ? a : b' at the beginning of the list, which is in fact not mergeable
// because it updates the condition. We simply bail on these.
if (m_checkMergeable(nodep) != Mergeable::YES) {
// Clear marked variables
AstNode::user1ClearTree();
// We did not add to the list
return false;
}
m_mgFirstp = nodep; m_mgFirstp = nodep;
m_mgCondp = condp; m_mgCondp = condp;
m_listLenght = 0; m_listLenght = 0;
// Mark variable references in the condition
condp->foreach<AstVarRef>([](const AstVarRef* nodep) { nodep->varp()->user1(1); });
// Add any preceding nodes to the list that would allow us to extend the merge range // Add any preceding nodes to the list that would allow us to extend the merge range
for (;;) { for (;;) {
AstNode* const backp = m_mgFirstp->backp(); AstNode* const backp = m_mgFirstp->backp();
@ -416,6 +425,8 @@ private:
m_mgNextp = nodep->nextp(); m_mgNextp = nodep->nextp();
// If last under parent, done with current list // If last under parent, done with current list
if (!m_mgNextp) mergeEnd(__LINE__); if (!m_mgNextp) mergeEnd(__LINE__);
// We did add to the list
return true;
} }
// If this node is the next expected node and is helpful to add to the list, do so, // If this node is the next expected node and is helpful to add to the list, do so,
@ -424,13 +435,10 @@ private:
UASSERT_OBJ(m_mgFirstp, nodep, "List must be open"); UASSERT_OBJ(m_mgFirstp, nodep, "List must be open");
if (m_mgNextp == nodep) { if (m_mgNextp == nodep) {
if (isSimplifiableNode(nodep)) { if (isSimplifiableNode(nodep)) {
addToList(nodep, nullptr, __LINE__); if (addToList(nodep, nullptr, __LINE__)) return true;
return true; } else if (isCheapNode(nodep)) {
}
if (isCheapNode(nodep)) {
nodep->user2(1); nodep->user2(1);
addToList(nodep, nullptr, __LINE__); if (addToList(nodep, nullptr, __LINE__)) return true;
return true;
} }
} }
// Not added to list, so we are done with the current list // Not added to list, so we are done with the current list

View File

@ -137,6 +137,7 @@ public:
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning : m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
operator en() const { return m_e; } operator en() const { return m_e; }
bool fst() const { return m_e == FST; } bool fst() const { return m_e == FST; }
bool vcd() const { return m_e == VCD; }
string classBase() const { string classBase() const {
static const char* const names[] = {"VerilatedVcd", "VerilatedFst"}; static const char* const names[] = {"VerilatedVcd", "VerilatedFst"};
return names[m_e]; return names[m_e];
@ -515,7 +516,7 @@ public:
int traceMaxArray() const { return m_traceMaxArray; } int traceMaxArray() const { return m_traceMaxArray; }
int traceMaxWidth() const { return m_traceMaxWidth; } int traceMaxWidth() const { return m_traceMaxWidth; }
int traceThreads() const { return m_traceThreads; } int traceThreads() const { return m_traceThreads; }
bool trueTraceThreads() const { bool useTraceOffloadThread() const {
return traceThreads() == 0 ? 0 : traceThreads() - traceFormat().fst(); return traceThreads() == 0 ? 0 : traceThreads() - traceFormat().fst();
} }
int unrollCount() const { return m_unrollCount; } int unrollCount() const { return m_unrollCount; }

View File

@ -189,6 +189,8 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
nodep->ansi(m_pinAnsi); nodep->ansi(m_pinAnsi);
nodep->declTyped(m_varDeclTyped); nodep->declTyped(m_varDeclTyped);
nodep->lifetime(m_varLifetime); nodep->lifetime(m_varLifetime);
nodep->delayp(m_netDelayp);
m_netDelayp = nullptr;
if (GRAMMARP->m_varDecl != VVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl); if (GRAMMARP->m_varDecl != VVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl);
if (GRAMMARP->m_varIO != VDirection::NONE) { if (GRAMMARP->m_varIO != VDirection::NONE) {
nodep->declDirection(GRAMMARP->m_varIO); nodep->declDirection(GRAMMARP->m_varIO);

View File

@ -520,7 +520,7 @@ private:
"tracep->oldp(vlSymsp->__Vm_baseCode);\n"); "tracep->oldp(vlSymsp->__Vm_baseCode);\n");
} else { } else {
// Change dump sub function // Change dump sub function
if (v3Global.opt.trueTraceThreads()) { if (v3Global.opt.useTraceOffloadThread()) {
addInitStr("const uint32_t base VL_ATTR_UNUSED = " addInitStr("const uint32_t base VL_ATTR_UNUSED = "
"vlSymsp->__Vm_baseCode + " "vlSymsp->__Vm_baseCode + "
+ cvtToStr(baseCode) + ";\n"); + cvtToStr(baseCode) + ";\n");

View File

@ -595,6 +595,7 @@ private:
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return; return;
} }
if (nodep->stmtsp()) nodep->addNextHere(nodep->stmtsp()->unlinkFrBack());
nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement."); nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement.");
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
} }
@ -1323,10 +1324,10 @@ private:
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
virtual void visit(AstTimingControl* nodep) override { virtual void visit(AstEventControl* nodep) override {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: timing control statement in this location\n" nodep->v3warn(E_UNSUPPORTED, "Unsupported: event control statement in this location\n"
<< nodep->warnMore() << nodep->warnMore()
<< "... Suggest have one timing control statement " << "... Suggest have one event control statement "
<< "per procedure, at the top of the procedure"); << "per procedure, at the top of the procedure");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} }
@ -2725,7 +2726,7 @@ private:
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"r_" + nodep->name(), withp); "r_" + nodep->name(), withp);
newp->dtypeFrom(adtypep->subDTypep()); newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep());
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->makeStatement();
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|| nodep->name() == "unique_index") { || nodep->name() == "unique_index") {
@ -2949,7 +2950,7 @@ private:
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"r_" + nodep->name(), withp); "r_" + nodep->name(), withp);
newp->dtypeFrom(adtypep->subDTypep()); newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep());
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->makeStatement();
} else if (nodep->name() == "reverse" || nodep->name() == "shuffle" } else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
|| nodep->name() == "sort" || nodep->name() == "rsort") { || nodep->name() == "sort" || nodep->name() == "rsort") {
@ -3986,6 +3987,11 @@ private:
nodep->v3warn(E_UNSUPPORTED, "Unsupported: assignment of event data type"); nodep->v3warn(E_UNSUPPORTED, "Unsupported: assignment of event data type");
} }
} }
if (nodep->timingControlp()) {
nodep->timingControlp()->v3warn(
ASSIGNDLY, "Unsupported: Ignoring timing control on this assignment.");
nodep->timingControlp()->unlinkFrBackWithNext()->deleteTree();
}
if (VN_IS(nodep->rhsp(), EmptyQueue)) { if (VN_IS(nodep->rhsp(), EmptyQueue)) {
UINFO(9, "= {} -> .delete(): " << nodep); UINFO(9, "= {} -> .delete(): " << nodep);
if (!VN_IS(nodep->lhsp()->dtypep()->skipRefp(), QueueDType)) { if (!VN_IS(nodep->lhsp()->dtypep()->skipRefp(), QueueDType)) {

View File

@ -40,6 +40,13 @@
#define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg) #define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg)
#define GATEUNSUP(fl, tok) \ #define GATEUNSUP(fl, tok) \
{ BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); } { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); }
#define PRIMDLYUNSUP(nodep) \
{ \
if (nodep) { \
nodep->v3warn(ASSIGNDLY, "Unsupported: Ignoring delay on this primitive."); \
nodep->deleteTree(); \
} \
}
//====================================================================== //======================================================================
// Statics (for here only) // Statics (for here only)
@ -60,6 +67,7 @@ public:
AstCase* m_caseAttrp = nullptr; // Current case statement for attribute adding AstCase* m_caseAttrp = nullptr; // Current case statement for attribute adding
AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration
AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration
AstNode* m_netDelayp = nullptr; // Pointer to delay for next signal declaration
AstNodeModule* m_modp = nullptr; // Last module for timeunits AstNodeModule* m_modp = nullptr; // Last module for timeunits
bool m_pinAnsi = false; // In ANSI port list bool m_pinAnsi = false; // In ANSI port list
FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations
@ -96,6 +104,31 @@ public:
string newtext = deQuote(fileline, text); string newtext = deQuote(fileline, text);
return new AstText(fileline, newtext); return new AstText(fileline, newtext);
} }
AstNode* createCellOrIfaceRef(FileLine* fileline, const string& name, AstPin* pinlistp,
AstNodeRange* rangelistp) {
// Must clone m_instParamp as may be comma'ed list of instances
VSymEnt* const foundp = SYMP->symCurrentp()->findIdFallback(name);
if (foundp && VN_IS(foundp->nodep(), Port)) {
// It's a non-ANSI interface, not a cell declaration
m_varAttrp = nullptr;
m_varDecl = VVarType::IFACEREF;
m_varIO = VDirection::NONE;
m_varLifetime = VLifetime::NONE;
setDType(new AstIfaceRefDType{fileline, "", GRAMMARP->m_instModule});
m_varDeclTyped = true;
AstVar* const nodep = createVariable(fileline, name, rangelistp, nullptr);
return nodep;
}
AstCell* const nodep = new AstCell{fileline,
GRAMMARP->m_instModuleFl,
name,
GRAMMARP->m_instModule,
pinlistp,
AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true),
GRAMMARP->scrubRange(rangelistp)};
nodep->trace(GRAMMARP->allTracingOn(fileline));
return nodep;
}
AstDisplay* createDisplayError(FileLine* fileline) { AstDisplay* createDisplayError(FileLine* fileline) {
AstDisplay* nodep = new AstDisplay(fileline, VDisplayType::DT_ERROR, "", nullptr, nullptr); AstDisplay* nodep = new AstDisplay(fileline, VDisplayType::DT_ERROR, "", nullptr, nullptr);
nodep->addNext(new AstStop(fileline, true)); nodep->addNext(new AstStop(fileline, true));
@ -138,6 +171,7 @@ public:
if (m_varDTypep) VL_DO_CLEAR(m_varDTypep->deleteTree(), m_varDTypep = nullptr); if (m_varDTypep) VL_DO_CLEAR(m_varDTypep->deleteTree(), m_varDTypep = nullptr);
m_varDTypep = dtypep; m_varDTypep = dtypep;
} }
void setNetDelay(AstNode* netDelayp) { m_netDelayp = netDelayp; }
void pinPush() { void pinPush() {
m_pinStack.push(m_pinNum); m_pinStack.push(m_pinNum);
m_pinNum = 1; m_pinNum = 1;
@ -1409,8 +1443,10 @@ port_declNetE: // IEEE: part of port_declaration, optional net
; ;
portSig<nodep>: portSig<nodep>:
id/*port*/ { $$ = new AstPort($<fl>1,PINNUMINC(),*$1); } id/*port*/
| idSVKwd { $$ = new AstPort($<fl>1,PINNUMINC(),*$1); } { $$ = new AstPort{$<fl>1, PINNUMINC(), *$1}; SYMP->reinsert($$); }
| idSVKwd
{ $$ = new AstPort{$<fl>1, PINNUMINC(), *$1}; SYMP->reinsert($$); }
; ;
//********************************************************************** //**********************************************************************
@ -1708,11 +1744,13 @@ net_dataTypeE<nodeDTypep>:
var_data_type { $$ = $1; } var_data_type { $$ = $1; }
| signingE rangeList delayE | signingE rangeList delayE
{ $$ = GRAMMARP->addRange(new AstBasicDType{$2->fileline(), LOGIC, $1}, { $$ = GRAMMARP->addRange(new AstBasicDType{$2->fileline(), LOGIC, $1},
$2, true); } // not implicit $2, true);
GRAMMARP->setNetDelay($3); } // not implicit
| signing | signing
{ $$ = new AstBasicDType{$<fl>1, LOGIC, $1}; } // not implicit { $$ = new AstBasicDType{$<fl>1, LOGIC, $1}; } // not implicit
| /*implicit*/ delayE | /*implicit*/ delayE
{ $$ = new AstBasicDType{CRELINE(), LOGIC}; } // not implicit { $$ = new AstBasicDType{CRELINE(), LOGIC};
GRAMMARP->setNetDelay($1); } // not implicit
; ;
net_type: // ==IEEE: net_type net_type: // ==IEEE: net_type
@ -2392,7 +2430,15 @@ module_common_item<nodep>: // ==IEEE: module_common_item
; ;
continuous_assign<nodep>: // IEEE: continuous_assign continuous_assign<nodep>: // IEEE: continuous_assign
yASSIGN strengthSpecE delayE assignList ';' { $$ = $4; } yASSIGN strengthSpecE delayE assignList ';'
{
$$ = $4;
if ($3)
for (auto* nodep = $$; nodep; nodep = nodep->nextp()) {
auto* const assignp = VN_AS(nodep, NodeAssign);
assignp->addTimingControlp(nodep == $$ ? $3 : $3->cloneTree(false));
}
}
; ;
initial_construct<nodep>: // IEEE: initial_construct initial_construct<nodep>: // IEEE: initial_construct
@ -2633,22 +2679,21 @@ assignOne<nodep>:
variable_lvalue '=' expr { $$ = new AstAssignW($2,$1,$3); } variable_lvalue '=' expr { $$ = new AstAssignW($2,$1,$3); }
; ;
//UNSUPdelay_or_event_controlE<nodep>: // IEEE: delay_or_event_control plus empty delay_or_event_controlE<nodep>: // IEEE: delay_or_event_control plus empty
//UNSUP /* empty */ { $$ = nullptr; } /* empty */ { $$ = nullptr; }
//UNSUP | delay_control { $$ = $1; } | delay_control { $$ = $1; }
//UNSUP | event_control { $$ = $1; } | event_control { $$ = $1; }
//UNSUP | yREPEAT '(' expr ')' event_control { } //UNSUP | yREPEAT '(' expr ')' event_control { }
//UNSUP ;
delayE:
/* empty */ { }
| delay { }
; ;
delay: delayE<nodep>:
/* empty */ { $$ = nullptr; }
| delay { $$ = $1; }
;
delay<nodep>:
delay_control delay_control
{ $1->v3warn(ASSIGNDLY, "Unsupported: Ignoring delay on this assignment/primitive."); { $$ = $1; }
DEL($1); }
; ;
delay_control<nodep>: //== IEEE: delay_control delay_control<nodep>: //== IEEE: delay_control
@ -2685,8 +2730,9 @@ netSig<varp>: // IEEE: net_decl_assignment - one element from
{ $$ = VARDONEA($<fl>1,*$1, nullptr, $2); } { $$ = VARDONEA($<fl>1,*$1, nullptr, $2); }
| netId sigAttrListE '=' expr | netId sigAttrListE '=' expr
{ $$ = VARDONEA($<fl>1, *$1, nullptr, $2); { $$ = VARDONEA($<fl>1, *$1, nullptr, $2);
$$->addNext(new AstAssignW{$3, new AstVarRef{$<fl>1, *$1, VAccess::WRITE}, $4}); } auto* const assignp = new AstAssignW{$3, new AstVarRef{$<fl>1, *$1, VAccess::WRITE}, $4};
| netId variable_dimensionList sigAttrListE if ($$->delayp()) assignp->addTimingControlp($$->delayp()->unlinkFrBack()); // IEEE 1800-2017 10.3.3
$$->addNext(assignp); } | netId variable_dimensionList sigAttrListE
{ $$ = VARDONEA($<fl>1,*$1, $2, $3); } { $$ = VARDONEA($<fl>1,*$1, $2, $3); }
; ;
@ -2853,18 +2899,11 @@ instnameList<nodep>:
| instnameList ',' instnameParen { $$ = $1->addNext($3); } | instnameList ',' instnameParen { $$ = $1->addNext($3); }
; ;
instnameParen<cellp>: instnameParen<nodep>:
// // Must clone m_instParamp as may be comma'ed list of instances id instRangeListE '(' cellpinList ')'
id instRangeListE '(' cellpinList ')' { $$ = new AstCell($<fl>1, GRAMMARP->m_instModuleFl, { $$ = GRAMMARP->createCellOrIfaceRef($<fl>1, *$1, $4, $2); }
*$1, GRAMMARP->m_instModule, $4, | id instRangeListE
AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), { $$ = GRAMMARP->createCellOrIfaceRef($<fl>1, *$1, nullptr, $2); }
GRAMMARP->scrubRange($2));
$$->trace(GRAMMARP->allTracingOn($<fl>1)); }
| id instRangeListE { $$ = new AstCell($<fl>1, GRAMMARP->m_instModuleFl,
*$1, GRAMMARP->m_instModule, nullptr,
AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true),
GRAMMARP->scrubRange($2));
$$->trace(GRAMMARP->allTracingOn($<fl>1)); }
//UNSUP instRangeListE '(' cellpinList ')' { UNSUP } // UDP //UNSUP instRangeListE '(' cellpinList ')' { UNSUP } // UDP
// // Adding above and switching to the Verilog-Perl syntax // // Adding above and switching to the Verilog-Perl syntax
// // causes a shift conflict due to use of idClassSel inside exprScope. // // causes a shift conflict due to use of idClassSel inside exprScope.
@ -3144,12 +3183,10 @@ statement_item<nodep>: // IEEE: statement_item
| fexprLvalue '=' dynamic_array_new ';' { $$ = new AstAssign($2, $1, $3); } | fexprLvalue '=' dynamic_array_new ';' { $$ = new AstAssign($2, $1, $3); }
// //
// // IEEE: nonblocking_assignment // // IEEE: nonblocking_assignment
| fexprLvalue yP_LTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); } | fexprLvalue yP_LTE delay_or_event_controlE expr ';'
//UNSUP fexprLvalue yP_LTE delay_or_event_controlE expr ';' { UNSUP } { $$ = new AstAssignDly{$2, $1, $4, $3}; }
// | yASSIGN idClassSel '=' delay_or_event_controlE expr ';'
// // IEEE: procedural_continuous_assignment { $$ = new AstAssign{$1, $2, $5, $4}; }
| yASSIGN idClassSel '=' delayE expr ';' { $$ = new AstAssign($1,$2,$5); }
//UNSUP: delay_or_event_controlE above
| yDEASSIGN variable_lvalue ';' | yDEASSIGN variable_lvalue ';'
{ $$ = nullptr; BBUNSUP($1, "Unsupported: Verilog 1995 deassign"); } { $$ = nullptr; BBUNSUP($1, "Unsupported: Verilog 1995 deassign"); }
| yFORCE variable_lvalue '=' expr ';' | yFORCE variable_lvalue '=' expr ';'
@ -3225,9 +3262,7 @@ statement_item<nodep>: // IEEE: statement_item
// // IEEE: event_trigger // // IEEE: event_trigger
| yP_MINUSGT idDotted/*hierarchical_identifier-event*/ ';' | yP_MINUSGT idDotted/*hierarchical_identifier-event*/ ';'
{ $$ = new AstFireEvent{$1, $2, false}; } { $$ = new AstFireEvent{$1, $2, false}; }
//UNSUP yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';' { UNSUP } | yP_MINUSGTGT delay_or_event_controlE idDotted/*hierarchical_identifier-event*/ ';'
// // IEEE remove below
| yP_MINUSGTGT delayE idDotted/*hierarchical_identifier-event*/ ';'
{ $$ = new AstFireEvent{$1, $3, true}; } { $$ = new AstFireEvent{$1, $3, true}; }
// //
// // IEEE: loop_statement // // IEEE: loop_statement
@ -3252,8 +3287,8 @@ statement_item<nodep>: // IEEE: statement_item
// //
| par_block { $$ = $1; } | par_block { $$ = $1; }
// // IEEE: procedural_timing_control_statement + procedural_timing_control // // IEEE: procedural_timing_control_statement + procedural_timing_control
| delay_control stmtBlock { $$ = new AstDelay($1->fileline(), $1); $$->addNextNull($2); } | delay_control stmtBlock { $$ = new AstDelay{$1->fileline(), $1, $2}; }
| event_control stmtBlock { $$ = new AstTimingControl(FILELINE_OR_CRE($1), $1, $2); } | event_control stmtBlock { $$ = new AstEventControl(FILELINE_OR_CRE($1), $1, $2); }
//UNSUP cycle_delay stmtBlock { UNSUP } //UNSUP cycle_delay stmtBlock { UNSUP }
// //
| seq_block { $$ = $1; } | seq_block { $$ = $1; }
@ -3314,11 +3349,10 @@ statementVerilatorPragmas<nodep>:
//UNSUP ; //UNSUP ;
foperator_assignment<nodep>: // IEEE: operator_assignment (for first part of expression) foperator_assignment<nodep>: // IEEE: operator_assignment (for first part of expression)
fexprLvalue '=' delayE expr { $$ = new AstAssign($2,$1,$4); } fexprLvalue '=' delay_or_event_controlE expr { $$ = new AstAssign{$2, $1, $4, $3}; }
| fexprLvalue '=' yD_FOPEN '(' expr ')' { $$ = new AstFOpenMcd($3,$1,$5); } | fexprLvalue '=' yD_FOPEN '(' expr ')' { $$ = new AstFOpenMcd($3,$1,$5); }
| fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); } | fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); }
// //
//UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP }
//UNSUP ~f~exprLvalue yP_PLUS(etc) expr { UNSUP } //UNSUP ~f~exprLvalue yP_PLUS(etc) expr { UNSUP }
| fexprLvalue yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); }
| fexprLvalue yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); }
@ -4688,22 +4722,22 @@ stream_expressionOrDataType<nodep>: // IEEE: from streaming_concatenation
// Gate declarations // Gate declarations
gateDecl<nodep>: gateDecl<nodep>:
yBUF delayE gateBufList ';' { $$ = $3; } yBUF delayE gateBufList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yBUFIF0 delayE gateBufif0List ';' { $$ = $3; } | yBUFIF0 delayE gateBufif0List ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yBUFIF1 delayE gateBufif1List ';' { $$ = $3; } | yBUFIF1 delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNOT delayE gateNotList ';' { $$ = $3; } | yNOT delayE gateNotList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNOTIF0 delayE gateNotif0List ';' { $$ = $3; } | yNOTIF0 delayE gateNotif0List ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNOTIF1 delayE gateNotif1List ';' { $$ = $3; } | yNOTIF1 delayE gateNotif1List ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yAND delayE gateAndList ';' { $$ = $3; } | yAND delayE gateAndList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNAND delayE gateNandList ';' { $$ = $3; } | yNAND delayE gateNandList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yOR delayE gateOrList ';' { $$ = $3; } | yOR delayE gateOrList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNOR delayE gateNorList ';' { $$ = $3; } | yNOR delayE gateNorList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yXOR delayE gateXorList ';' { $$ = $3; } | yXOR delayE gateXorList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yXNOR delayE gateXnorList ';' { $$ = $3; } | yXNOR delayE gateXnorList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yPULLUP delayE gatePullupList ';' { $$ = $3; } | yPULLUP delayE gatePullupList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yPULLDOWN delayE gatePulldownList ';' { $$ = $3; } | yPULLDOWN delayE gatePulldownList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNMOS delayE gateBufif1List ';' { $$ = $3; } // ~=bufif1, as don't have strengths yet | yNMOS delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } // ~=bufif1, as don't have strengths yet
| yPMOS delayE gateBufif0List ';' { $$ = $3; } // ~=bufif0, as don't have strengths yet | yPMOS delayE gateBufif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } // ~=bufif0, as don't have strengths yet
// //
| yTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tran"); } // Unsupported | yTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tran"); } // Unsupported
| yRCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rcmos"); } // Unsupported | yRCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rcmos"); } // Unsupported

View File

@ -1892,6 +1892,7 @@ sub _make_main {
$fh->print(" if (save_time && ${time} == save_time) {\n"); $fh->print(" if (save_time && ${time} == save_time) {\n");
$fh->print(" save_model(\"$self->{obj_dir}/saved.vltsv\");\n"); $fh->print(" save_model(\"$self->{obj_dir}/saved.vltsv\");\n");
$fh->print(" printf(\"Exiting after save_model\\n\");\n"); $fh->print(" printf(\"Exiting after save_model\\n\");\n");
$fh->print(" topp.reset(nullptr);\n");
$fh->print(" return 0;\n"); $fh->print(" return 0;\n");
$fh->print(" }\n"); $fh->print(" }\n");
} }

View File

@ -1,17 +1,21 @@
%Warning-ASSIGNDLY: t/t_delay.v:22:13: Unsupported: Ignoring delay on this assignment/primitive. %Warning-ASSIGNDLY: t/t_delay.v:22:13: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
22 | assign #(1.2000000000000000) dly1 = dly0 + 32'h1; 22 | assign #(1.2000000000000000) dly1 = dly0 + 32'h1;
| ^~~~~~~~~~~~~~~~~~ | ^~~~~~~~~~~~~~~~~~
... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest
... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message.
%Warning-ASSIGNDLY: t/t_delay.v:27:19: Unsupported: Ignoring delay on this assignment/primitive. %Warning-ASSIGNDLY: t/t_delay.v:27:19: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
27 | dly0 <= #0 32'h11; 27 | dly0 <= #0 32'h11;
| ^ | ^
%Warning-ASSIGNDLY: t/t_delay.v:30:19: Unsupported: Ignoring delay on this assignment/primitive. %Warning-ASSIGNDLY: t/t_delay.v:30:19: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
30 | dly0 <= #0.12 dly0 + 32'h12; 30 | dly0 <= #0.12 dly0 + 32'h12;
| ^~~~ | ^~~~
%Warning-ASSIGNDLY: t/t_delay.v:38:25: Unsupported: Ignoring delay on this assignment/primitive. %Warning-ASSIGNDLY: t/t_delay.v:38:26: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
38 | dly0 <= #(dly_s.dly) 32'h55; 38 | dly0 <= #(dly_s.dly) 32'h55;
| ^ | ^~~
%Warning-STMTDLY: t/t_delay.v:43:11: Unsupported: Ignoring delay on this delayed statement. %Warning-STMTDLY: t/t_delay.v:43:11: Unsupported: Ignoring delay on this delayed statement.
: ... In instance t : ... In instance t
43 | #100 $finish; 43 | #100 $finish;

View File

@ -1,12 +1,12 @@
%Error-UNSUPPORTED: t/t_event_control_unsup.v:14:7: Unsupported: timing control statement in this location %Error-UNSUPPORTED: t/t_event_control_unsup.v:14:7: Unsupported: event control statement in this location
: ... In instance t : ... In instance t
: ... Suggest have one timing control statement per procedure, at the top of the procedure : ... Suggest have one event control statement per procedure, at the top of the procedure
14 | @(clk); 14 | @(clk);
| ^ | ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_event_control_unsup.v:16:7: Unsupported: timing control statement in this location %Error-UNSUPPORTED: t/t_event_control_unsup.v:16:7: Unsupported: event control statement in this location
: ... In instance t : ... In instance t
: ... Suggest have one timing control statement per procedure, at the top of the procedure : ... Suggest have one event control statement per procedure, at the top of the procedure
16 | @(clk); 16 | @(clk);
| ^ | ^
%Error: Exiting due to %Error: Exiting due to

View File

@ -87,7 +87,7 @@ sub check_cpp {
my $fh = IO::File->new("<$filename") or error("$! $filenme"); my $fh = IO::File->new("<$filename") or error("$! $filenme");
my @funcs; my @funcs;
while (defined(my $line = $fh->getline)) { while (defined(my $line = $fh->getline)) {
if ($line =~ /^(void|IData)\s+(.*::.*)/) { if ($line =~ /^(void|IData)\s+(.*::.*){/) {
my $func = $2; my $func = $2;
$func =~ s/\(.*$//; $func =~ s/\(.*$//;
print "\tFunc $func\n" if $Self->{verbose}; print "\tFunc $func\n" if $Self->{verbose};

View File

@ -28,7 +28,7 @@ for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp")) {
# have been evaluated inside the compiler. So there should be # have been evaluated inside the compiler. So there should be
# no references to 'sum' in the .cpp. # no references to 'sum' in the .cpp.
for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp")) { for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp")) {
file_grep_not($file, qr/sum/); file_grep_not($file, qr/[^a-zA-Z]sum[^a-zA-Z]/);
} }
ok(1); ok(1);

View File

@ -0,0 +1,12 @@
%Warning-ASSIGNDLY: t/t_gate_basic.v:23:12: Unsupported: Ignoring delay on this primitive.
23 | not #(0.108) NT0 (nt0, a[0]);
| ^~~~~
... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest
... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message.
%Warning-ASSIGNDLY: t/t_gate_basic.v:24:11: Unsupported: Ignoring delay on this primitive.
24 | and #1 AN0 (an0, a[0], b[0]);
| ^
%Warning-ASSIGNDLY: t/t_gate_basic.v:25:12: Unsupported: Ignoring delay on this primitive.
25 | nand #(2,3) ND0 (nd0, a[0], b[0], b[1]);
| ^
%Error: Exiting due to

View File

@ -0,0 +1,22 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Antmicro Ltd. 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);
top_filename("t/t_gate_basic.v");
lint(
verilator_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME -Wno-UNUSED"],
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,21 @@
#!/usr/bin/env 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);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -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, 2022 by Geza Lore.
// SPDX-License-Identifier: CC0-1.0
interface iface(input logic clk);
logic [31:0] d = 0;
logic [31:0] q = 0;
endinterface
module mod(a);
iface a; // This is not a CELL, it is a port declaration
always @(posedge a.clk) a.q <= a.d;
endmodule
module t(clk);
input clk;
iface iface_inst(clk);
mod mod_inst(iface_inst);
int cyc = 0;
always @(posedge clk) begin
iface_inst.d <= cyc;
if (cyc > 1 && iface_inst.q != cyc - 2) $stop;
end
always @(posedge clk) begin
cyc <= cyc + 1;
if (cyc == 100) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

View File

@ -1,4 +1,4 @@
%Error: t/t_lint_comb_bad.v:14:4: Timing control statements not legal under always_comb (IEEE 1800-2017 9.2.2.2.2) %Error: t/t_lint_comb_bad.v:14:4: Event control statements not legal under always_comb (IEEE 1800-2017 9.2.2.2.2)
: ... Suggest use a normal 'always' : ... Suggest use a normal 'always'
14 | always_comb @(*) begin 14 | always_comb @(*) begin
| ^~~~~~~~~~~ | ^~~~~~~~~~~

View File

@ -0,0 +1,29 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 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=> ["--stats"]
);
execute();
if ($Self->{vlt_all}) {
file_grep($Self->{stats}, qr/Optimizations, MergeCond merges\s+(\d+)/i,
0);
file_grep($Self->{stats}, qr/Optimizations, MergeCond merged items\s+(\d+)/i,
0);
file_grep($Self->{stats}, qr/Optimizations, MergeCond longest merge\s+(\d+)/i,
0);
}
ok(1);
1;

View File

@ -0,0 +1,93 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Raynard Qiao.
// SPDX-License-Identifier: CC0-1.0
module t(/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc = 0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [3:0] din = crc[3:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire row_found; // From test of Test.v
wire [1:0] row_idx; // From test of Test.v
// End of automatics
Test test(/*AUTOINST*/
// Outputs
.row_idx (row_idx[1:0]),
.row_found (row_found),
// Inputs
.din (din));
// Aggregate outputs into a single result vector
wire [63:0] result = {48'b0, din, 7'b0, row_found, 2'b0, row_idx};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x result=%x\n", $time, cyc, crc, result);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]};
sum <= result ^ {sum[62:0], sum[63] ^ sum[2] ^ sum[0]};
if (cyc == 0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= '0;
end
else if (cyc < 10) begin
sum <= '0;
end
else if (cyc == 99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum);
if (crc !== 64'hc77bb9b3784ea091) $stop;
// What checksum will we end up with (above print should match)
`define EXPECTED_SUM 64'h8b61595b704e511f
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test(/*AUTOARG*/
// Outputs
row_idx, row_found,
// Inputs
din
);
input din;
output [1:0] row_idx;
output row_found;
reg [3:0] din;
reg [3:0] wide_din;
reg row_found;
reg [1:0] row_idx;
always_comb begin
integer x;
row_idx = {2{1'b0}};
row_found = 1'b0;
// Bug #3409: After unrolling, these conditionals should not be merged
// as row_found is assigned.
for (x = 0; $unsigned(x) < 4; x = x + 1) begin
row_idx = !row_found ? x[1:0] : row_idx;
row_found = !row_found ? din[x] : row_found;
end
end
endmodule

View File

@ -0,0 +1,31 @@
%Warning-ASSIGNDLY: t/t_timing_intra_assign_delay.v:12:11: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
12 | assign #10 val2 = val1;
| ^~
... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest
... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message.
%Warning-STMTDLY: t/t_timing_intra_assign_delay.v:16:6: Unsupported: Ignoring delay on this delayed statement.
: ... In instance t
16 | #10 val1 = 2;
| ^~
%Error-UNSUPPORTED: t/t_timing_intra_assign_delay.v:17:5: Unsupported: fork statements
: ... In instance t
17 | fork #5 val1 = 3; join_none
| ^~~~
%Warning-ASSIGNDLY: t/t_timing_intra_assign_delay.v:18:13: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
18 | val1 = #10 val1 + 2;
| ^~
%Warning-ASSIGNDLY: t/t_timing_intra_assign_delay.v:19:14: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
19 | val1 <= #10 val1 + 2;
| ^~
%Error-UNSUPPORTED: t/t_timing_intra_assign_delay.v:20:5: Unsupported: fork statements
: ... In instance t
20 | fork #5 val1 = 5; join_none
| ^~~~
%Warning-STMTDLY: t/t_timing_intra_assign_delay.v:21:6: Unsupported: Ignoring delay on this delayed statement.
: ... In instance t
21 | #20 $write("*-* All Finished *-*\n");
| ^~
%Error: Exiting due to

View File

@ -0,0 +1,20 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Antmicro Ltd. 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 => ['-Wall -Wno-DECLFILENAME'],
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,24 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t;
int val1, val2;
always @val1 $write("[%0t] val1=%0d val2=%0d\n", $time, val1, val2);
assign #10 val2 = val1;
initial begin
val1 = 1;
#10 val1 = 2;
fork #5 val1 = 3; join_none
val1 = #10 val1 + 2;
val1 <= #10 val1 + 2;
fork #5 val1 = 5; join_none
#20 $write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,32 @@
%Error-UNSUPPORTED: t/t_timing_intra_assign_event.v:15:5: Unsupported: event control statement in this location
: ... In instance t
: ... Suggest have one event control statement per procedure, at the top of the procedure
15 | @e val = 2;
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_timing_intra_assign_event.v:16:5: Unsupported: fork statements
: ... In instance t
16 | fork begin
| ^~~~
%Warning-ASSIGNDLY: t/t_timing_intra_assign_event.v:21:11: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
21 | val = @e val + 2;
| ^
... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message.
%Warning-ASSIGNDLY: t/t_timing_intra_assign_event.v:22:12: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
22 | val <= @e val + 2;
| ^
%Error-UNSUPPORTED: t/t_timing_intra_assign_event.v:23:5: Unsupported: fork statements
: ... In instance t
23 | fork begin
| ^~~~
%Warning-STMTDLY: t/t_timing_intra_assign_event.v:29:6: Unsupported: Ignoring delay on this delayed statement.
: ... In instance t
29 | #1 $write("*-* All Finished *-*\n");
| ^
%Warning-STMTDLY: t/t_timing_intra_assign_event.v:33:12: Unsupported: Ignoring delay on this delayed statement.
: ... In instance t
33 | initial #1 ->e;
| ^
%Error: Exiting due to

View File

@ -0,0 +1,20 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Antmicro Ltd. 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 => ['-Wall -Wno-DECLFILENAME'],
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -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, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t;
int val;
event e;
always @val $write("val=%0d\n", val);
initial begin
val = 1;
@e val = 2;
fork begin
@e #1 val = 3;
->e;
end join_none
->e;
val = @e val + 2;
val <= @e val + 2;
fork begin
@e val = 5;
->e;
end join_none
->e;
->e;
#1 $write("*-* All Finished *-*\n");
$finish;
end
initial #1 ->e;
endmodule

View File

@ -0,0 +1,11 @@
%Warning-ASSIGNDLY: t/t_timing_net_delay.v:13:15: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
13 | wire[3:0] #4 val1 = cyc;
| ^
... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest
... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message.
%Warning-ASSIGNDLY: t/t_timing_net_delay.v:17:12: Unsupported: Ignoring timing control on this assignment.
: ... In instance t
17 | assign #4 val2 = cyc;
| ^
%Error: Exiting due to

View File

@ -0,0 +1,20 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Antmicro Ltd. 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 => ['-Wall -Wno-DECLFILENAME'],
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -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, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
wire[3:0] #4 val1 = cyc;
wire[3:0] #4 val2;
reg[3:0] cyc = 0;
assign #4 val2 = cyc;
always @(posedge clk) begin
cyc <= cyc + 1;
`ifdef TEST_VERBOSE
$write("[%0t] cyc=%0d, val1=%0d, val2=%0d\n", $time, cyc, val1, val2);
`endif
if (cyc >= 4 && val1 != cyc-1 && val2 != cyc-3) $stop;
if (cyc == 15) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

View File

@ -6,40 +6,53 @@
// any use, without warranty, 2020 by Wilson Snyder. // any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
`define stop $stop
`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*/); module t (/*AUTOARG*/);
initial begin initial begin
int tofind; int tofind;
int aliases[$]; int aliases[$];
int found[$]; int found[$];
int id;
int i; int i;
byte byteq[$] = {2, -1, 127};
aliases = '{ 1, 4, 6, 8}; aliases = '{ 1, 4, 6, 8};
tofind = 6; tofind = 6;
found = aliases.find with (item == 1); found = aliases.find with (item == 1);
`checkh(found.size, 1);
found = aliases.find(j) with (j == tofind); found = aliases.find(j) with (j == tofind);
`checkh(found.size, 1);
// And as function // And as function
aliases.find(i) with (i == tofind); aliases.find(i) with (i == tofind);
// No parenthesis // No parenthesis
found = aliases.find with (item == i); tofind = 0;
aliases.find with (item == i); found = aliases.find with (item == tofind);
`checkh(found.size, 0);
aliases.find with (item == tofind);
`ifdef VERILATOR // bug3387
// No expression (e.g. x.randomize() with {}) i = aliases.sum();
// Hack until randomize() supported `checkh(i, 'h13);
found = aliases.sort() with {}; i = byteq.sum() with (int'(item));
`endif `checkh(i, 128);
// Unique (array method) // Unique (array method)
id = 4; tofind = 4;
found = aliases.find with (id); found = aliases.find with (tofind); // "true" match
found = aliases.find() with (item == id); `checkh(found.size, 4);
found = aliases.find(i) with (i == id); found = aliases.find() with (item == tofind);
`checkh(found.size, 1);
found = aliases.find(i) with (i == tofind);
`checkh(found.size, 1);
i = aliases.or(v) with (v); i = aliases.or(v) with (v);
`checkh(i, 'hf);
i = aliases.and(v) with (v); i = aliases.and(v) with (v);
`checkh(i, 0);
i = aliases.xor(v) with (v); i = aliases.xor(v) with (v);
`checkh(i, 'hb);
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
$finish; $finish;

View File

@ -0,0 +1,24 @@
//
// DESCRIPTION: Verilator: Verilog Multiple Model Test Module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
#include <verilated.h>
#include VM_PREFIX_INCLUDE
int main(int argc, char** argv, char** env) {
// Create contexts
VerilatedContext* contextp{new VerilatedContext};
// Ideally we'd do this, but then address sanitizer blows up
// delete contextp; // Test mistake - deleting contextp
contextp->selfTestClearMagic();
// instantiate verilated design
std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp, "TOP"}};
return 0;
}

View File

@ -0,0 +1,2 @@
%Error: Attempt to create model using a bad/deleted VerilatedContext pointer
Aborting...

View File

@ -0,0 +1,25 @@
#!/usr/bin/env perl
if (!$::Driver) { use strict; use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Multiple Model Test Module
#
# Copyright 2020-2021 by Andreas Kuster. 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(
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"],
);
execute(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,9 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module top;
initial $finish;
endmodule

View File

@ -266,6 +266,10 @@ function(verilate TARGET)
set_property(TARGET ${TARGET} PROPERTY VERILATOR_TRACE_THREADED ON) set_property(TARGET ${TARGET} PROPERTY VERILATOR_TRACE_THREADED ON)
endif() endif()
if (${VERILATE_PREFIX}_TRACE_FST_WRITER_THREAD)
set_property(TARGET ${TARGET} PROPERTY VERILATOR_TRACE_FST_WRITER_TRHEAD ON)
endif()
if (${VERILATE_PREFIX}_COVERAGE) if (${VERILATE_PREFIX}_COVERAGE)
# If any verilate() call specifies COVERAGE, define VM_COVERAGE in the final build # If any verilate() call specifies COVERAGE, define VM_COVERAGE in the final build
set_property(TARGET ${TARGET} PROPERTY VERILATOR_COVERAGE ON) set_property(TARGET ${TARGET} PROPERTY VERILATOR_COVERAGE ON)
@ -327,6 +331,7 @@ function(verilate TARGET)
VM_SC=$<BOOL:$<TARGET_PROPERTY:VERILATOR_SYSTEMC>> VM_SC=$<BOOL:$<TARGET_PROPERTY:VERILATOR_SYSTEMC>>
$<$<BOOL:$<TARGET_PROPERTY:VERILATOR_THREADED>>:VL_THREADED> $<$<BOOL:$<TARGET_PROPERTY:VERILATOR_THREADED>>:VL_THREADED>
$<$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE_THREADED>>:VL_TRACE_THREADED> $<$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE_THREADED>>:VL_TRACE_THREADED>
$<$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE_FST_WRITER_TRHEAD>>:VL_TRACE_FST_WRITER_THREAD>
VM_TRACE=$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE>> VM_TRACE=$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE>>
VM_TRACE_VCD=$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE_VCD>> VM_TRACE_VCD=$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE_VCD>>
VM_TRACE_FST=$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE_FST>> VM_TRACE_FST=$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE_FST>>