diff --git a/Changes b/Changes index fe3708f38..45bd0ed9d 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,9 @@ indicates the contributor was also the author of the fix; Thanks! * Verilator 3.800*** +** SystemPerl is no longer required for tracing. + Applications must use VerilatedVcdC class in place of SpTraceVcdC. + ** SystemVerilog 1800-2009 is now the default language. Thus "global" etc are now keywords. See the --language option. diff --git a/bin/verilator b/bin/verilator index 7ec0e6b57..a6829e4d3 100755 --- a/bin/verilator +++ b/bin/verilator @@ -660,11 +660,11 @@ designs with only one top. Adds waveform tracing code to the model. Verilator will generate additional {prefix}__Trace*.cpp files that will need to be compiled. In -addition Sp.cpp (for SystemC traces) or SpTraceVcdC.c (for C++ only) from -the SystemPerl kit's src directory must be compiled and linked in. If -using the Verilator generated Makefiles, these will be added as source -targets for you. If you're not using the Verilator makefiles, you will -need to add these to your Makefile manually. +addition verilated_vcd_sc.cpp (for SystemC traces) or verilated_vcd_c.c +(for both) must be compiled and linked in. If using the Verilator +generated Makefiles, these will be added as source targets for you. If +you're not using the Verilator makefiles, you will need to add these to +your Makefile manually. Having tracing compiled in may result in some small performance losses, even when waveforms are not turned on during model execution. @@ -2527,31 +2527,30 @@ maximum typically needed. =item How do I generate waveforms (traces) in C++? -See the next question for tracing in SystemPerl mode. +See the next question for tracing in SystemC mode. -Add the --trace switch to Verilator, and make sure the SystemPerl package -is installed. SystemC itself does not need to be installed for C++ only -tracing. You do not even need to compile SystemPerl; you may simply untar -the SystemPerl kit and point the SYSTEMPERL environment variable to the -untarred directory. +Add the --trace switch to Verilator, and in your top level C code, call +Verilated::traceEverOn(true). Then create a VerilatedVcdCFile object, and +in your main loop call "trace_object->dump(time)" every time step, and +finally call "trace_object->close()". For an example, see below and the +test_c/sim_main.cpp file of the distribution. -In your top level C code, call Verilated::traceEverOn(true). Then create a -SpTraceVcdC object, and in your main loop call "trace_object->dump(time)" -every time step, and finally call "trace_object->close()". For an example, -see below and the test_c/sim_main.cpp file of the distribution. - -You also need to compile SpTraceVcdC.cpp and add it to your link. This is -done for you if using the Verilator --exe flag. +You also need to compile verilated_vcd_c.cpp and add it to your link. This +is done for you if using the Verilator --exe flag. Note you can also call ->trace on multiple Verilated objects with the same trace file if you want all data to land in the same output file. - #include "SpTraceVcdC.h" +Note also older versions of Verilator used the SystemPerl package and +SpTraceVcdCFile class. This still works, but is depreciated as it requires +strong coupling between the Verilator and SystemPerl versions. + + #include "verilated_vcd_c.h" ... int main(int argc, char **argv, char **env) { ... Verilated::traceEverOn(true); - SpTraceVcdCFile* tfp = new SpTraceVcdCFile; + VerilatedVcdCFile* tfp = new VerilatedVcdCFile; topp->trace (tfp, 99); tfp->open ("obj_dir/t_trace_ena_cc/simx.vcd"); ... @@ -2562,32 +2561,30 @@ trace file if you want all data to land in the same output file. tfp->close(); } -=item How do I generate waveforms (traces) in SystemC/SystemPerl? +=item How do I generate waveforms (traces) in SystemC? -Add the --trace switch to Verilator, and make sure the SystemPerl package -is installed. - -In your top level C sc_main code, include SpTraceVcd.h. Then call -Verilated::traceEverOn(true). Then create a SpTraceFile object as you -would create a normal SystemC trace file. For an example, see the call to -SpTraceFile in the test_sp/sc_main.cpp file of the distribution, and below. +Add the --trace switch to Verilator, and in your top level C sc_main code, +include verilated_vcd_sc.h. Then call Verilated::traceEverOn(true). Then +create a VerilatedVcdSc object as you would create a normal SystemC trace +file. For an example, see the call to VerilatedVcdSc in the +test_sp/sc_main.cpp file of the distribution, and below. Alternatively you may use the C++ trace mechanism described in the previous question, however the timescale and timeprecision will not inherited from your SystemC settings. -You'll then need to compile in Sp.cpp, which includes SpTraceVcd.cpp among -other things. +You also need to compile verilated_vcd_sc.cpp and add it to your link. +This is done for you if using the Verilator --exe flag. Note you can also call ->trace on multiple Verilated objects with the same trace file if you want all data to land in the same output file. - #include "SpTraceVcd.h" + #include "verilated_vcd_sc.h" ... int main(int argc, char **argv, char **env) { ... Verilated::traceEverOn(true); - SpTraceFile* tfp = new SpTraceFile; + VerilatedVcdSc* tfp = new VerilatedVcdSc; topp->trace (tfp, 99); tfp->open ("obj_dir/t_trace_ena_cc/simx.vcd"); ... @@ -2604,9 +2601,9 @@ commercial offerings. =item How do I reduce the size of large waveform (trace) files? -First, instead of calling SpTraceVcdCFile->open at the beginning of time, +First, instead of calling VerilatedVcdC->open at the beginning of time, delay calling it until the time stamp where you want to tracing to begin. -Likewise you can also call SpTraceVcdCFile->open before the end of time +Likewise you can also call VerilatedVcdC->open before the end of time (perhaps a short period after you detect a verification error.) Next, add /*verilator tracing_off*/ to any very low level modules you never @@ -2620,9 +2617,12 @@ network disk. Network disks are generally far slower. =item How do I do coverage analysis? Verilator supports both block (line) coverage and user inserted functional -coverage. First, run verilator with the --coverage option. If you're -using your own makefile, compile the model with the GCC flag --DSP_COVERAGE_ENABLE (if using Verilator's, it will do this for you.) +coverage. Both currently require SystemPerl output mode and the SystemPerl +package. + +First, run verilator with the --coverage option. If you're using your own +makefile, compile the model with the GCC flag -DSP_COVERAGE_ENABLE (if +using Verilator's, it will do this for you.) Run your tests in different directories. Each test will create a logs/coverage.pl file. @@ -2839,7 +2839,7 @@ performance gain. In 2009, major SystemVerilog and DPI language support was added. Currently, various language features and performance enhancements are added -as the need arises. Verilator is now about 2x faster than in 2002, and is +as the need arises. Verilator is now about 3x faster than in 2002, and is faster than many popular commercial simulators. =head1 CONTRIBUTORS diff --git a/include/verilated.h b/include/verilated.h index c20756e82..79f73b0be 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -39,6 +39,13 @@ // avoided and instead in verilated_heavy.h to reduce compile time using namespace std; +//============================================================================= +// Switches + +#if VM_TRACE // Verilator tracing requested +# define WAVES 1 // Set backward compatibility flag as in systemperl.h +#endif + //========================================================================= // Basic types @@ -57,6 +64,8 @@ typedef WData* WDataOutP; ///< Array output from a function class SpTraceVcd; class SpTraceVcdCFile; +class VerilatedVcd; +class VerilatedVcdC; //========================================================================= /// Base class for all Verilated module classes diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp new file mode 100644 index 000000000..20eac0e0d --- /dev/null +++ b/include/verilated_vcd_c.cpp @@ -0,0 +1,671 @@ +// -*- SystemC -*- +//============================================================================= +// +// THIS MODULE IS PUBLICLY LICENSED +// +// Copyright 2001-2010 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. +// +// This is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +//============================================================================= +/// +/// \file +/// \brief C++ Tracing in VCD Format +/// +/// AUTHOR: Wilson Snyder +/// +//============================================================================= +// SPDIFF_OFF + +#include "verilatedos.h" +#include "verilated.h" +#include "verilated_vcd_c.h" + +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# include +#else +# include +#endif + +// SPDIFF_ON + +#ifndef O_LARGEFILE // For example on WIN32 +# define O_LARGEFILE 0 +#endif +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif + +//============================================================================= +// Global + +vector VerilatedVcd::s_vcdVecp; ///< List of all created traces + +//============================================================================= +// VerilatedVcdCallInfo +/// Internal callback routines for each module being traced. +//// +/// Each SystemPerl module that wishes to be traced registers a set of +/// callbacks stored in this class. When the trace file is being +/// constructed, this class provides the callback routines to be executed. + +class VerilatedVcdCallInfo { +protected: + friend class VerilatedVcd; + VerilatedVcdCallback_t m_initcb; ///< Initialization Callback function + VerilatedVcdCallback_t m_fullcb; ///< Full Dumping Callback function + VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function + void* m_userthis; ///< Fake "this" for caller + vluint32_t m_code; ///< Starting code number + // CREATORS + VerilatedVcdCallInfo (VerilatedVcdCallback_t icb, VerilatedVcdCallback_t fcb, + VerilatedVcdCallback_t changecb, + void* ut, vluint32_t code) + : m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {}; +}; + +//============================================================================= +//============================================================================= +//============================================================================= +// Opening/Closing + +void VerilatedVcd::open (const char* filename) { + if (isOpen()) return; + + // Assertions, as we cast enum to vluint32_t pointers in AutoTrace.pm + enum VerilatedVcd_enumtest { FOO = 1 }; + if (sizeof(VerilatedVcd_enumtest) != sizeof(vluint32_t)) { + vl_fatal(__FILE__,__LINE__,"", "Internal: VerilatedVcd::open cast assumption violated"); + } + + // Set member variables + m_filename = filename; + s_vcdVecp.push_back(this); + + openNext (m_rolloverMB!=0); + if (!isOpen()) return; + + dumpHeader(); + + // Allocate space now we know the number of codes + if (!m_sigs_oldvalp) { + m_sigs_oldvalp = new vluint32_t [m_nextCode+10]; + } + + if (m_rolloverMB) { + openNext(true); + if (!isOpen()) return; + } +} + +void VerilatedVcd::openNext (bool incFilename) { + // Open next filename in concat sequence, mangle filename if + // incFilename is true. + closePrev(); // Close existing + if (incFilename) { + // Find _0000.{ext} in filename + string name = m_filename; + size_t pos=name.rfind("."); + if (pos>8 && 0==strncmp("_cat",name.c_str()+pos-8,4) + && isdigit(name.c_str()[pos-4]) + && isdigit(name.c_str()[pos-3]) + && isdigit(name.c_str()[pos-2]) + && isdigit(name.c_str()[pos-1])) { + // Increment code. + if ((++(name[pos-1])) > '9') { + name[pos-1] = '0'; + if ((++(name[pos-2])) > '9') { + name[pos-2] = '0'; + if ((++(name[pos-3])) > '9') { + name[pos-3] = '0'; + if ((++(name[pos-4])) > '9') { + name[pos-4] = '0'; + }}}} + } else { + // Append _cat0000 + name.insert(pos,"_cat0000"); + } + m_filename = name; + } + if (m_filename[0]=='|') { + assert(0); // Not supported yet. + } else { + m_fd = ::open (m_filename.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK + , 0666); + if (m_fd<0) { + // User code can check isOpen() + m_isOpen = false; + return; + } + } + m_isOpen = true; + m_fullDump = true; // First dump must be full + m_wroteBytes = 0; +} + +VerilatedVcd::~VerilatedVcd() { + close(); + if (m_wrBufp) { delete[] m_wrBufp; m_wrBufp=NULL; } + if (m_sigs_oldvalp) { delete[] m_sigs_oldvalp; m_sigs_oldvalp=NULL; } + // Remove from list of traces + vector::iterator pos = find(s_vcdVecp.begin(), s_vcdVecp.end(), this); + if (pos != s_vcdVecp.end()) { s_vcdVecp.erase(pos); } +} + +void VerilatedVcd::closePrev () { + if (!isOpen()) return; + + bufferFlush(); + m_isOpen = false; + ::close(m_fd); +} + +void VerilatedVcd::closeErr () { + // Close due to an error. We might abort before even getting here, + // depending on the definition of vl_fatal. + if (!isOpen()) return; + + // No buffer flush, just fclose + m_isOpen = false; + ::close(m_fd); // May get error, just ignore it +} + +void VerilatedVcd::close() { + if (!isOpen()) return; + if (m_evcd) { + printStr("$vcdclose "); + printTime(m_timeLastDump); + printStr(" $end\n"); + } + closePrev(); +} + +void VerilatedVcd::printStr (const char* str) { + // Not fast... + while (*str) { + *m_writep++ = *str++; + bufferCheck(); + } +} + +void VerilatedVcd::printQuad (vluint64_t n) { + char buf [100]; + sprintf(buf,"%llu",(long long unsigned)n); + printStr(buf); +} + +void VerilatedVcd::printTime (vluint64_t timeui) { + // VCD file format specification does not allow non-integers for timestamps + // Dinotrace doesn't mind, but Cadence vvision seems to choke + if (timeui < m_timeLastDump) { + timeui = m_timeLastDump; + static bool backTime = false; + if (!backTime) { + backTime = true; + VL_PRINTF("VCD time is moving backwards, wave file may be incorrect.\n"); + } + } + m_timeLastDump = timeui; + printQuad(timeui); +} + +void VerilatedVcd::bufferFlush () { + // We add output data to m_writep. + // When it gets nearly full we dump it using this routine which calls write() + // This is much faster than using buffered I/O + if (!isOpen()) return; + char* wp = m_wrBufp; + while (1) { + size_t remaining = (m_writep - wp); + if (remaining==0) break; + errno = 0; + int got = write (m_fd, wp, remaining); + if (got>0) { + wp += got; + m_wroteBytes += got; + } else if (got < 0) { + if (errno != EAGAIN && errno != EINTR) { + // write failed, presume error (perhaps out of disk space) + string msg = (string)"VerilatedVcd::bufferFlush: "+strerror(errno); + vl_fatal("",0,"",msg.c_str()); + closeErr(); + break; + } + } + } + + // Reset buffer + m_writep = m_wrBufp; +} + +//============================================================================= +// Simple methods + +void VerilatedVcd::set_time_unit (const char* unitp) { + string unitstr (unitp); + //cout<<" set_time_unit ("<=1e0) { suffixp="s"; value *= 1e0; } + else if (value>=1e-3 ) { suffixp="ms"; value *= 1e3; } + else if (value>=1e-6 ) { suffixp="us"; value *= 1e6; } + else if (value>=1e-9 ) { suffixp="ns"; value *= 1e9; } + else if (value>=1e-12) { suffixp="ps"; value *= 1e12; } + else if (value>=1e-15) { suffixp="fs"; value *= 1e15; } + else if (value>=1e-18) { suffixp="as"; value *= 1e18; } + char valuestr[100]; sprintf(valuestr,"%d%s",(int)(value), suffixp); + return valuestr; // Gets converted to string, so no ref to stack +} + +//============================================================================= +// Definitions + +void VerilatedVcd::printIndent (int level_change) { + if (level_change<0) m_modDepth += level_change; + assert(m_modDepth>=0); + for (int i=0; i0) m_modDepth += level_change; +} + +void VerilatedVcd::dumpHeader () { + printStr("$version Generated by VerilatedVcd $end\n"); + time_t time_str = time(NULL); + printStr("$date "); printStr(ctime(&time_str)); printStr(" $end\n"); + + printStr("$timescale "); + printStr(doubleToTimescale(m_timeRes).c_str()); + printStr(" $end\n"); + + // Take signal information from each module and build m_namemapp + m_namemapp = new NameMap; + for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) { + VerilatedVcdCallInfo *cip = m_callbacks[ent]; + cip->m_code = nextCode(); + (cip->m_initcb) (this, cip->m_userthis, cip->m_code); + } + + // Signal header + assert (m_modDepth==0); + printIndent(1); + printStr("\n"); + + // We detect the spaces in module names to determine hierarchy. This + // allows signals to be declared without fixed ordering, which is + // required as Verilog signals might be separately declared from + // "SP_TRACE" signals. + + // Print the signal names + const char* lastName = ""; + for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) { + const char* hiername = (*it).first.c_str(); + const char* decl = (*it).second.c_str(); + + // Determine difference between the old and new names + const char* lp = lastName; + const char* np = hiername; + lastName = hiername; + + // Skip common prefix, it must break at a space or tab + for (; *np && (*np == *lp); np++, lp++) {} + while (np!=hiername && *np && *np!=' ' && *np!='\t') { np--; lp--; } + //cout <<"hier "<1) { + printIndent(-1); + printStr("$upscope $end\n"); + } + + printIndent(-1); + printStr("$enddefinitions $end\n\n\n"); + assert (m_modDepth==0); + + // Reclaim storage + delete m_namemapp; +} + +void VerilatedVcd::module (string name) { + m_modName = name; +} + +void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep, + int arraynum, bool tri, bool bussed, int msb, int lsb) { + if (!code) { vl_fatal(__FILE__,__LINE__,"","Internal: internal trace problem, code 0 is illegal"); } + + int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1; + int codesNeeded = 1+int(bits/32); + if (tri) codesNeeded *= 2; // Space in change array for __en signals + + // Make sure array is large enough + m_nextCode = max(nextCode(), code+codesNeeded); + if (m_sigs.capacity() <= m_nextCode) { + m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up + } + + // Save declaration info + VerilatedVcdSig sig = VerilatedVcdSig(code, bits); + m_sigs.push_back(sig); + + // Split name into basename + // Spaces and tabs aren't legal in VCD signal names, so: + // Space separates each level of scope + // Tab separates final scope from signal name + // Tab sorts before spaces, so signals nicely will print before scopes + // Note the hiername may be nothing, if so we'll add "\t{name}" + string nameasstr = name; + if (m_modName!="") { nameasstr = m_modName+m_scopeEscape+nameasstr; } // Optional ->module prefix + string hiername; + string basename; + for (const char* cp=nameasstr.c_str(); *cp; cp++) { + if (isScopeEscape(*cp)) { + // Ahh, we've just read a scope, not a basename + if (hiername!="") hiername += " "; + hiername += basename; + basename = ""; + } else { + basename += *cp; + } + } + hiername += "\t"+basename; + + // Print reference + string decl = "$var "; + if (m_evcd) decl += "port"; else decl += wirep; // usually "wire" + char buf [1000]; + sprintf(buf, " %2d ", bits); + decl += buf; + if (m_evcd) { + sprintf(buf, "<%d", code); + decl += buf; + } else { + decl += stringCode(code); + } + decl += " "; + decl += basename; + if (arraynum>=0) { + sprintf(buf, "(%d)", arraynum); + decl += buf; + hiername += buf; + } + if (bussed) { + sprintf(buf, " [%d:%d]", msb, lsb); + decl += buf; + } + decl += " $end\n"; + m_namemapp->insert(make_pair(hiername,decl)); +} + +void VerilatedVcd::declBit (vluint32_t code, const char* name, int arraynum) +{ declare (code, name, "wire", arraynum, false, false, 0, 0); } +void VerilatedVcd::declBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb) +{ declare (code, name, "wire", arraynum, false, true, msb, lsb); } +void VerilatedVcd::declQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb) +{ declare (code, name, "wire", arraynum, false, true, msb, lsb); } +void VerilatedVcd::declArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb) +{ declare (code, name, "wire", arraynum, false, true, msb, lsb); } +void VerilatedVcd::declTriBit (vluint32_t code, const char* name, int arraynum) +{ declare (code, name, "wire", arraynum, true, false, 0, 0); } +void VerilatedVcd::declTriBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb) +{ declare (code, name, "wire", arraynum, true, true, msb, lsb); } +void VerilatedVcd::declTriQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb) +{ declare (code, name, "wire", arraynum, true, true, msb, lsb); } +void VerilatedVcd::declTriArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb) +{ declare (code, name, "wire", arraynum, true, true, msb, lsb); } +void VerilatedVcd::declFloat (vluint32_t code, const char* name, int arraynum) +{ declare (code, name, "real", arraynum, false, false, 31, 0); } +void VerilatedVcd::declDouble (vluint32_t code, const char* name, int arraynum) +{ declare (code, name, "real", arraynum, false, false, 63, 0); } + +//============================================================================= + +void VerilatedVcd::fullDouble (vluint32_t code, const double newval) { + (*((double*)&m_sigs_oldvalp[code])) = newval; + // Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes) + sprintf(m_writep, "r%.16g", newval); + m_writep += strlen(m_writep); + *m_writep++=' '; printCode(code); *m_writep++='\n'; + bufferCheck(); +} +void VerilatedVcd::fullFloat (vluint32_t code, const float newval) { + (*((float*)&m_sigs_oldvalp[code])) = newval; + // Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes) + sprintf(m_writep, "r%.16g", (double)newval); + m_writep += strlen(m_writep); + *m_writep++=' '; printCode(code); *m_writep++='\n'; + bufferCheck(); +} + +//============================================================================= +// Callbacks + +void VerilatedVcd::addCallback ( + VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, VerilatedVcdCallback_t changecb, + void* userthis) +{ + if (isOpen()) { + string msg = (string)"Internal: "+__FILE__+"::"+__FUNCTION__+" called with already open file"; + vl_fatal(__FILE__,__LINE__,"",msg.c_str()); + } + VerilatedVcdCallInfo* vci = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis, nextCode()); + m_callbacks.push_back(vci); +} + +//============================================================================= +// Dumping + +void VerilatedVcd::dumpFull (vluint64_t timeui) { + dumpPrep (timeui); + for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) { + VerilatedVcdCallInfo *cip = m_callbacks[ent]; + (cip->m_fullcb) (this, cip->m_userthis, cip->m_code); + } + dumpDone (); +} + +void VerilatedVcd::dump (vluint64_t timeui) { + if (!isOpen()) return; + if (m_fullDump) { + m_fullDump = false; // No need for more full dumps + dumpFull(timeui); + return; + } + if (m_rolloverMB && m_wroteBytes > this->m_rolloverMB) { + openNext(true); + if (!isOpen()) return; + } + dumpPrep (timeui); + for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) { + VerilatedVcdCallInfo *cip = m_callbacks[ent]; + (cip->m_changecb) (this, cip->m_userthis, cip->m_code); + } + dumpDone(); +} + +void VerilatedVcd::dumpPrep (vluint64_t timeui) { + printStr("#"); + printTime(timeui); + printStr("\n"); +} + +void VerilatedVcd::dumpDone () { +} + +//====================================================================== +// Static members + +void VerilatedVcd::flush_all() { + for (vluint32_t ent = 0; ent< s_vcdVecp.size(); ent++) { + VerilatedVcd* vcdp = s_vcdVecp[ent]; + vcdp->flush(); + } +} + +//====================================================================== +//====================================================================== +//====================================================================== + +#ifdef VERILATED_VCD_TEST +vluint32_t v1, v2, s1, s2[3]; +vluint32_t tri96[3]; +vluint32_t tri96__tri[3]; +vluint8_t ch; +vluint64_t timestamp = 1; +double doub = 0; + +void vcdInit (VerilatedVcd* vcdp, void* userthis, vluint32_t code) { + vcdp->scopeEscape('.'); + vcdp->module ("top"); + vcdp->declBus (0x2, "v1",-1,5,1); + vcdp->declBus (0x3, "v2",-1,6,0); + vcdp->module ("top.sub1"); + vcdp->declBit (0x4, "s1",-1); + vcdp->declBit (0x5, "ch",-1); + vcdp->module ("top.sub2"); + vcdp->declArray (0x6, "s2",-1, 40,3); + // Note need to add 3 for next code. + vcdp->module ("top2"); + vcdp->declBus (0x2, "t2v1",-1,4,1); + vcdp->declTriBit (0x10, "io1", -1); + vcdp->declTriBus (0x12, "io5", -1,4,0); + vcdp->declTriArray (0x16, "io96",-1,95,0); + // Note need to add 6 for next code. + vcdp->declDouble (0x1c, "doub",-1); + // Note need to add 2 for next code. +} + +void vcdFull (VerilatedVcd* vcdp, void* userthis, vluint32_t code) { + vcdp->fullBus (0x2, v1,5); + vcdp->fullBus (0x3, v2,7); + vcdp->fullBit (0x4, s1); + vcdp->fullBus (0x5, ch,2); + vcdp->fullArray(0x6, &s2[0], 38); + vcdp->fullTriBit (0x10, tri96[0]&1, tri96__tri[0]&1); + vcdp->fullTriBus (0x12, tri96[0]&0x1f, tri96__tri[0]&0x1f, 5); + vcdp->fullTriArray (0x16, tri96, tri96__tri, 96); + vcdp->fullDouble(0x1c, doub); +} + +void vcdChange (VerilatedVcd* vcdp, void* userthis, vluint32_t code) { + vcdp->chgBus (0x2, v1,5); + vcdp->chgBus (0x3, v2,7); + vcdp->chgBit (0x4, s1); + vcdp->chgBus (0x5, ch,2); + vcdp->chgArray(0x6, &s2[0], 38); + vcdp->chgTriBit (0x10, tri96[0]&1, tri96__tri[0]&1); + vcdp->chgTriBus (0x12, tri96[0]&0x1f, tri96__tri[0]&0x1f, 5); + vcdp->chgTriArray (0x16, tri96, tri96__tri, 96); + vcdp->chgDouble (0x1c, doub); +} + +main() { + cout<<"test: O_LARGEFILE="<spTrace()->addCallback (&vcdInit, &vcdFull, &vcdChange, 0); + vcdp->open ("test.vcd"); + // Dumping + vcdp->dump(timestamp++); + v1 = 0xfff; + tri96[2] = 4; tri96[1] = 2; tri96[0] = 1; + tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri + doub = 1.5; + vcdp->dump(timestamp++); + v2 = 0x1; + s2[1] = 2; + tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change + doub = -1.66e13; + vcdp->dump(timestamp++); + ch = 2; + tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1; + doub = -3.33e-13; + vcdp->dump(timestamp++); + vcdp->dump(timestamp++); +# ifdef VERILATED_VCD_TEST_64BIT + vluint64_t bytesPerDump = 15ULL; + for (vluint64_t i=0; i<((1ULL<<32) / bytesPerDump); i++) { + v1 = i; + vcdp->dump(timestamp++); + } +# endif + vcdp->close(); + } +} +#endif + +//******************************************************************** +// Local Variables: +// compile-command: "mkdir -p ../test_dir && cd ../test_dir && g++ -DVERILATED_VCD_TEST ../src/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd" +// End: diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h new file mode 100644 index 000000000..6d4d8678d --- /dev/null +++ b/include/verilated_vcd_c.h @@ -0,0 +1,421 @@ +// -*- SystemC -*- +//============================================================================= +// +// THIS MODULE IS PUBLICLY LICENSED +// +// Copyright 2001-2010 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. +// +// This is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +//============================================================================= +/// +/// \file +/// \brief C++ Tracing in VCD Format +/// +/// AUTHOR: Wilson Snyder +/// +//============================================================================= +// SPDIFF_OFF + +#ifndef _VERILATED_VCD_C_H_ +#define _VERILATED_VCD_C_H_ 1 + +#include "verilatedos.h" + +#include +#include +#include +using namespace std; + +#define VERILATED_VCD_VERSION 1333 // Version number of this file AS_AN_INTEGER + +class VerilatedVcd; +class VerilatedVcdCallInfo; + +// SPDIFF_ON +//============================================================================= +// VerilatedVcdSig +/// Internal data on one signal being traced. + +class VerilatedVcdSig { +protected: + friend class VerilatedVcd; + vluint32_t m_code; ///< VCD file code number + int m_bits; ///< Size of value in bits + VerilatedVcdSig (vluint32_t code, int bits) + : m_code(code), m_bits(bits) {} +public: + ~VerilatedVcdSig() {} +}; + +//============================================================================= + +typedef void (*VerilatedVcdCallback_t)(VerilatedVcd* vcdp, void* userthis, vluint32_t code); + +//============================================================================= +// VerilatedVcd +/// Create a SystemPerl VCD dump + +class VerilatedVcd { +private: + bool m_isOpen; ///< True indicates open file + bool m_evcd; ///< True for evcd format + int m_fd; ///< File descriptor we're writing to + string m_filename; ///< Filename we're writing to (if open) + vluint64_t m_rolloverMB; ///< MB of file size to rollover at + char m_scopeEscape; ///< Character to separate scope components + int m_modDepth; ///< Depth of module hierarchy + bool m_fullDump; ///< True indicates dump ignoring if changed + vluint32_t m_nextCode; ///< Next code number to assign + string m_modName; ///< Module name being traced now + double m_timeRes; ///< Time resolution (ns/ms etc) + double m_timeUnit; ///< Time units (ns/ms etc) + vluint64_t m_timeLastDump; ///< Last time we did a dump + + char* m_wrBufp; ///< Output buffer + char* m_writep; ///< Write pointer into output buffer + vluint64_t m_wroteBytes; ///< Number of bytes written to this file + + vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values + vector m_sigs; ///< Pointer to signal information + vector m_callbacks; ///< Routines to perform dumping + typedef map NameMap; + NameMap* m_namemapp; ///< List of names for the header + static vector s_vcdVecp; ///< List of all created traces + + inline size_t bufferSize() { return 256*1024; } // See below for slack calculation + inline size_t bufferInsertSize() { return 16*1024; } + void bufferFlush(); + void bufferCheck() { + // Flush the write buffer if there's not enough space left for new information + // We only call this once per vector, so we need enough slop for a very wide "b###" line + if (m_writep > (m_wrBufp+(bufferSize()-bufferInsertSize()))) { + bufferFlush(); + } + } + void closePrev(); + void closeErr(); + void openNext(); + void printIndent (int levelchange); + void printStr (const char* str); + void printQuad (vluint64_t n); + void printTime (vluint64_t timeui); + void declare (vluint32_t code, const char* name, const char* wirep, + int arraynum, bool tri, bool bussed, int msb, int lsb); + + void dumpHeader(); + void dumpPrep (vluint64_t timeui); + void dumpFull (vluint64_t timeui); + void dumpDone (); + inline void printCode (vluint32_t code) { + if (code>=(94*94*94)) *m_writep++ = ((char)((code/94/94/94)%94+33)); + if (code>=(94*94)) *m_writep++ = ((char)((code/94/94)%94+33)); + if (code>=(94)) *m_writep++ = ((char)((code/94)%94+33)); + *m_writep++ = ((char)((code)%94+33)); + } + string stringCode (vluint32_t code) { + string out; + if (code>=(94*94*94)) out += ((char)((code/94/94/94)%94+33)); + if (code>=(94*94)) out += ((char)((code/94/94)%94+33)); + if (code>=(94)) out += ((char)((code/94)%94+33)); + return out + ((char)((code)%94+33)); + } + +protected: + // METHODS + void evcd(bool flag) { m_evcd = flag; } + +public: + // CREATORS + VerilatedVcd () : m_isOpen(false), m_rolloverMB(0), m_modDepth(0), m_nextCode(1) { + m_wrBufp = new char [bufferSize()]; + m_writep = m_wrBufp; + m_namemapp = NULL; + m_timeRes = m_timeUnit = 1e-9; + m_timeLastDump = 0; + m_sigs_oldvalp = NULL; + m_evcd = false; + m_scopeEscape = '.'; // Backward compatibility + m_wroteBytes = 0; + } + ~VerilatedVcd(); + + // ACCESSORS + /// Inside dumping routines, return next VCD signal code + vluint32_t nextCode() const {return m_nextCode;} + /// Set size in megabytes after which new file should be created + void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB=rolloverMB; }; + /// Is file open? + bool isOpen() const { return m_isOpen; } + /// Change character that splits scopes. Note whitespace are ALWAYS escapes. + void scopeEscape(char flag) { m_scopeEscape = flag; } + /// Is this an escape? + inline bool isScopeEscape(char c) { return isspace(c) || c==m_scopeEscape; } + + // METHODS + void open (const char* filename); ///< Open the file; call isOpen() to see if errors + void openNext (bool incFilename); ///< Open next data-only file + void flush() { bufferFlush(); } ///< Flush any remaining data + static void flush_all(); ///< Flush any remaining data from all files + void close (); ///< Close the file + + void set_time_unit (const char* unit); ///< Set time units (s/ms, defaults to ns) + void set_time_unit (const string& unit) { set_time_unit(unit.c_str()); } + + void set_time_resolution (const char* unit); ///< Set time resolution (s/ms, defaults to ns) + void set_time_resolution (const string& unit) { set_time_resolution(unit.c_str()); } + + double timescaleToDouble (const char* unitp); + string doubleToTimescale (double value); + + /// Inside dumping routines, called each cycle to make the dump + void dump (vluint64_t timeui); + /// Call dump with a absolute unscaled time in seconds + void dumpSeconds (double secs) { dump((vluint64_t)(secs * m_timeRes)); } + + /// Inside dumping routines, declare callbacks for tracings + void addCallback (VerilatedVcdCallback_t init, VerilatedVcdCallback_t full, + VerilatedVcdCallback_t change, + void* userthis); + + /// Inside dumping routines, declare a module + void module (const string name); + /// Inside dumping routines, declare a signal + void declBit (vluint32_t code, const char* name, int arraynum); + void declBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb); + void declQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb); + void declArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb); + void declTriBit (vluint32_t code, const char* name, int arraynum); + void declTriBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb); + void declTriQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb); + void declTriArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb); + void declDouble (vluint32_t code, const char* name, int arraynum); + void declFloat (vluint32_t code, const char* name, int arraynum); + // ... other module_start for submodules (based on cell name) + + /// Inside dumping routines, dump one signal + void fullBit (vluint32_t code, const vluint32_t newval) { + // Note the &1, so we don't require clean input -- makes more common no change case faster + m_sigs_oldvalp[code] = newval; + *m_writep++=('0'+(char)(newval&1)); printCode(code); *m_writep++='\n'; + bufferCheck(); + } + void fullBus (vluint32_t code, const vluint32_t newval, int bits) { + m_sigs_oldvalp[code] = newval; + *m_writep++='b'; + for (int bit=bits-1; bit>=0; --bit) { + *m_writep++=((newval&(1L<=0; --bit) { + *m_writep++=((newval&(1ULL<=0; --bit) { + *m_writep++=((newval[(bit/32)]&(1L<<(bit&0x1f)))?'1':'0'); + } + *m_writep++=' '; printCode(code); *m_writep++='\n'; + bufferCheck(); + } + void fullTriBit (vluint32_t code, const vluint32_t newval, const vluint32_t newtri) { + m_sigs_oldvalp[code] = newval; + m_sigs_oldvalp[code+1] = newtri; + *m_writep++ = "01zz"[m_sigs_oldvalp[code] + | (m_sigs_oldvalp[code+1]<<1)]; + printCode(code); *m_writep++='\n'; + bufferCheck(); + } + void fullTriBus (vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) { + m_sigs_oldvalp[code] = newval; + m_sigs_oldvalp[code+1] = newtri; + *m_writep++='b'; + for (int bit=bits-1; bit>=0; --bit) { + *m_writep++ = "01zz"[((newval >> bit)&1) + | (((newtri >> bit)&1)<<1)]; + } + *m_writep++=' '; printCode(code); *m_writep++='\n'; + bufferCheck(); + } + void fullTriQuad (vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) { + (*((vluint64_t*)&m_sigs_oldvalp[code])) = newval; + (*((vluint64_t*)&m_sigs_oldvalp[code+1])) = newtri; + *m_writep++='b'; + for (int bit=bits-1; bit>=0; --bit) { + *m_writep++ = "01zz"[((newval >> bit)&1ULL) + | (((newtri >> bit)&1ULL)<<1ULL)]; + } + *m_writep++=' '; printCode(code); *m_writep++='\n'; + bufferCheck(); + } + void fullTriArray (vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits) { + for (int word=0; word<(((bits-1)/32)+1); ++word) { + m_sigs_oldvalp[code+word*2] = newvalp[word]; + m_sigs_oldvalp[code+word*2+1] = newtrip[word]; + } + *m_writep++='b'; + for (int bit=bits-1; bit>=0; --bit) { + vluint32_t valbit = (newvalp[(bit/32)]>>(bit&0x1f)) & 1; + vluint32_t tribit = (newtrip[(bit/32)]>>(bit&0x1f)) & 1; + *m_writep++ = "01zz"[valbit | (tribit<<1)]; + } + *m_writep++=' '; printCode(code); *m_writep++='\n'; + bufferCheck(); + } + void fullDouble (vluint32_t code, const double newval); + void fullFloat (vluint32_t code, const float newval); + + /// Inside dumping routines, dump one signal as unknowns + /// Presently this code doesn't change the oldval vector. + /// Thus this is for special standalone applications that after calling + /// fullBitX, must when then value goes non-X call fullBit. + inline void fullBitX (vluint32_t code) { + *m_writep++='x'; printCode(code); *m_writep++='\n'; + bufferCheck(); + } + inline void fullBusX (vluint32_t code, int bits) { + *m_writep++='b'; + for (int bit=bits-1; bit>=0; --bit) { + *m_writep++='x'; + } + *m_writep++=' '; printCode(code); *m_writep++='\n'; + bufferCheck(); + } + inline void fullQuadX (vluint32_t code, int bits) { fullBusX (code, bits); } + inline void fullArrayX (vluint32_t code, int bits) { fullBusX (code, bits); } + + /// Inside dumping routines, dump one signal if it has changed + inline void chgBit (vluint32_t code, const vluint32_t newval) { + vluint32_t diff = m_sigs_oldvalp[code] ^ newval; + if (VL_UNLIKELY(diff)) { + // Verilator 3.510 and newer provide clean input, so the below is only for back compatibility + if (VL_UNLIKELY(diff & 1)) { // Change after clean? + fullBit (code, newval); + } + } + } + inline void chgBus (vluint32_t code, const vluint32_t newval, int bits) { + vluint32_t diff = m_sigs_oldvalp[code] ^ newval; + if (VL_UNLIKELY(diff)) { + if (VL_UNLIKELY(bits==32 || (diff & ((1U<=20050714) + // SystemC 2.1.v1 +void VerilatedVcdSc::write_comment (const std::string &) {} +void VerilatedVcdSc::trace (const unsigned int &, const std::string &, const char **) {} + +# define DECL_TRACE_METHOD_A(tp) \ + void VerilatedVcdSc::trace( const tp& object, const std::string& name ) {} +# define DECL_TRACE_METHOD_B(tp) \ + void VerilatedVcdSc::trace( const tp& object, const std::string& name, int width ) {} + + DECL_TRACE_METHOD_A( bool ) + DECL_TRACE_METHOD_A( sc_dt::sc_bit ) + DECL_TRACE_METHOD_A( sc_dt::sc_logic ) + + DECL_TRACE_METHOD_B( unsigned char ) + DECL_TRACE_METHOD_B( unsigned short ) + DECL_TRACE_METHOD_B( unsigned int ) + DECL_TRACE_METHOD_B( unsigned long ) +#ifdef SYSTEMC_64BIT_PATCHES + DECL_TRACE_METHOD_B( unsigned long long) +#endif + DECL_TRACE_METHOD_B( char ) + DECL_TRACE_METHOD_B( short ) + DECL_TRACE_METHOD_B( int ) + DECL_TRACE_METHOD_B( long ) + DECL_TRACE_METHOD_B( sc_dt::int64 ) + DECL_TRACE_METHOD_B( sc_dt::uint64 ) + + DECL_TRACE_METHOD_A( float ) + DECL_TRACE_METHOD_A( double ) + DECL_TRACE_METHOD_A( sc_dt::sc_int_base ) + DECL_TRACE_METHOD_A( sc_dt::sc_uint_base ) + DECL_TRACE_METHOD_A( sc_dt::sc_signed ) + DECL_TRACE_METHOD_A( sc_dt::sc_unsigned ) + + DECL_TRACE_METHOD_A( sc_dt::sc_fxval ) + DECL_TRACE_METHOD_A( sc_dt::sc_fxval_fast ) + DECL_TRACE_METHOD_A( sc_dt::sc_fxnum ) + DECL_TRACE_METHOD_A( sc_dt::sc_fxnum_fast ) + + DECL_TRACE_METHOD_A( sc_dt::sc_bv_base ) + DECL_TRACE_METHOD_A( sc_dt::sc_lv_base ) + +//-------------------------------------------------- +#elif (SYSTEMC_VERSION>20011000) + // SystemC 2.0.1 +void VerilatedVcdSc::write_comment (const sc_string &) {} +void VerilatedVcdSc::trace (const unsigned int &, const sc_string &, const char **) {} + +#define DECL_TRACE_METHOD_A(tp) \ + void VerilatedVcdSc::trace( const tp& object, const sc_string& name ) {} +#define DECL_TRACE_METHOD_B(tp) \ + void VerilatedVcdSc::trace( const tp& object, const sc_string& name, int width ) {} + + DECL_TRACE_METHOD_A( bool ) + DECL_TRACE_METHOD_A( sc_bit ) + DECL_TRACE_METHOD_A( sc_logic ) + DECL_TRACE_METHOD_B( unsigned char ) + DECL_TRACE_METHOD_B( unsigned short ) + DECL_TRACE_METHOD_B( unsigned int ) + DECL_TRACE_METHOD_B( unsigned long ) +#ifdef SYSTEMC_64BIT_PATCHES + DECL_TRACE_METHOD_B( unsigned long long) +#endif +#if (SYSTEMC_VERSION>20041000) + DECL_TRACE_METHOD_B( unsigned long long) + DECL_TRACE_METHOD_B( long long) +#endif + DECL_TRACE_METHOD_B( char ) + DECL_TRACE_METHOD_B( short ) + DECL_TRACE_METHOD_B( int ) + DECL_TRACE_METHOD_B( long ) + DECL_TRACE_METHOD_A( float ) + DECL_TRACE_METHOD_A( double ) + DECL_TRACE_METHOD_A( sc_int_base ) + DECL_TRACE_METHOD_A( sc_uint_base ) + DECL_TRACE_METHOD_A( sc_signed ) + DECL_TRACE_METHOD_A( sc_unsigned ) + DECL_TRACE_METHOD_A( sc_fxval ) + DECL_TRACE_METHOD_A( sc_fxval_fast ) + DECL_TRACE_METHOD_A( sc_fxnum ) + DECL_TRACE_METHOD_A( sc_fxnum_fast ) + DECL_TRACE_METHOD_A( sc_bv_base ) + DECL_TRACE_METHOD_A( sc_lv_base ) + +//-------------------------------------------------- +#else + // SystemC 1.2.1beta +void VerilatedVcdSc::write_comment (const sc_string &) {} +void VerilatedVcdSc::trace (const unsigned int &, const sc_string &, const char **) {} + +#define DECL_TRACE_METHOD_A(tp) \ + void VerilatedVcdSc::trace( const tp& object, const sc_string& name ) {} +#define DECL_TRACE_METHOD_B(tp) \ + void VerilatedVcdSc::trace( const tp& object, const sc_string& name, int width ) {} + + DECL_TRACE_METHOD_A( bool ) + DECL_TRACE_METHOD_B( unsigned char ) + DECL_TRACE_METHOD_B( short unsigned int ) + DECL_TRACE_METHOD_B( unsigned int ) + DECL_TRACE_METHOD_B( long unsigned int ) + DECL_TRACE_METHOD_B( char ) + DECL_TRACE_METHOD_B( short int ) + DECL_TRACE_METHOD_B( int ) + DECL_TRACE_METHOD_B( long int ) + DECL_TRACE_METHOD_A( float ) + DECL_TRACE_METHOD_A( double ) + DECL_TRACE_METHOD_A( sc_bit ) + DECL_TRACE_METHOD_A( sc_logic ) + DECL_TRACE_METHOD_A( sc_bool_vector ) + DECL_TRACE_METHOD_A( sc_logic_vector ) + DECL_TRACE_METHOD_A( sc_signal_bool_vector ) + DECL_TRACE_METHOD_A( sc_signal_logic_vector ) + DECL_TRACE_METHOD_A( sc_uint_base ) + DECL_TRACE_METHOD_A( sc_int_base ) + DECL_TRACE_METHOD_A( sc_unsigned ) + DECL_TRACE_METHOD_A( sc_signed ) + DECL_TRACE_METHOD_A( sc_signal_resolved ) + DECL_TRACE_METHOD_A( sc_signal_resolved_vector ) + DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base ) + DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base ) +#endif + +#undef DECL_TRACE_METHOD_A +#undef DECL_TRACE_METHOD_B + +//******************************************************************** diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h new file mode 100644 index 000000000..ce4d1d1ec --- /dev/null +++ b/include/verilated_vcd_sc.h @@ -0,0 +1,213 @@ +// -*- SystemC -*- +//============================================================================= +// +// THIS MODULE IS PUBLICLY LICENSED +// +// Copyright 2001-2010 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. +// +// This is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +//============================================================================= +/// +/// \file +/// \brief SystemPerl tracing in VCD format +/// +/// AUTHOR: Wilson Snyder +/// +//============================================================================= +// SPDIFF_OFF + +#ifndef _VERILATED_VCD_SC_H_ +#define _VERILATED_VCD_SC_H_ 1 + +#include "verilated_sc.h" +#include "verilated_vcd_c.h" + +// SPDIFF_ON +//============================================================================= +// VerilatedVcdSc +/// +/// This class is passed to the SystemC simulation kernel, just like a +/// documented SystemC trace format. + +class VerilatedVcdSc + : sc_trace_file + , public VerilatedVcdC +{ +public: + VerilatedVcdSc() { + sc_get_curr_simcontext()->add_trace_file(this); +# if (SYSTEMC_VERSION>=20060505) + // We want to avoid a depreciated warning, but still be back compatible. + // Turning off the message just for this still results in an annoying "to turn off" message. + sc_time t1sec(1,SC_SEC); + if (t1sec.to_default_time_units()!=0) { + sc_time tunits(1.0/t1sec.to_default_time_units(),SC_SEC); + spTrace()->set_time_unit(tunits.to_string()); + } + spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); +# elif (SYSTEMC_VERSION>20011000) + // To confuse matters 2.1.beta returns a char* here, while 2.1.v1 returns a std::string + // we allow both flavors with overloaded set_time_* functions. + spTrace()->set_time_unit(sc_get_default_time_unit().to_string()); + spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); +# endif + } + + virtual ~VerilatedVcdSc() {} + /// Called by SystemC simulate() + virtual void cycle (bool delta_cycle) { +# if (SYSTEMC_VERSION>20011000) + if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); } +# else + // VCD files must have integer timestamps, so we write all times in increments of time_resolution + if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); } +# endif + } + +private: + /// Fake outs for linker + +#ifdef NC_SYSTEMC + // Cadence Incisive has these as abstract functions so we must create them + virtual void set_time_unit( int exponent10_seconds ) {} // deprecated + virtual void set_time_unit( double v, sc_time_unit tu ) {} +#endif + + +//-------------------------------------------------- +# if (SYSTEMC_VERSION>=20050714) + // SystemC 2.1.v1 +# define DECL_TRACE_METHOD_A(tp) \ + virtual void trace( const tp& object, const std::string& name ); +# define DECL_TRACE_METHOD_B(tp) \ + virtual void trace( const tp& object, const std::string& name, int width ); + + virtual void write_comment (const std::string &); + virtual void trace (const unsigned int &, const std::string &, const char **); + + DECL_TRACE_METHOD_A( bool ) + DECL_TRACE_METHOD_A( sc_dt::sc_bit ) + DECL_TRACE_METHOD_A( sc_dt::sc_logic ) + + DECL_TRACE_METHOD_B( unsigned char ) + DECL_TRACE_METHOD_B( unsigned short ) + DECL_TRACE_METHOD_B( unsigned int ) + DECL_TRACE_METHOD_B( unsigned long ) +#ifdef SYSTEMC_64BIT_PATCHES + DECL_TRACE_METHOD_B( unsigned long long) +#endif + DECL_TRACE_METHOD_B( char ) + DECL_TRACE_METHOD_B( short ) + DECL_TRACE_METHOD_B( int ) + DECL_TRACE_METHOD_B( long ) + DECL_TRACE_METHOD_B( sc_dt::int64 ) + DECL_TRACE_METHOD_B( sc_dt::uint64 ) + + DECL_TRACE_METHOD_A( float ) + DECL_TRACE_METHOD_A( double ) + DECL_TRACE_METHOD_A( sc_dt::sc_int_base ) + DECL_TRACE_METHOD_A( sc_dt::sc_uint_base ) + DECL_TRACE_METHOD_A( sc_dt::sc_signed ) + DECL_TRACE_METHOD_A( sc_dt::sc_unsigned ) + + DECL_TRACE_METHOD_A( sc_dt::sc_fxval ) + DECL_TRACE_METHOD_A( sc_dt::sc_fxval_fast ) + DECL_TRACE_METHOD_A( sc_dt::sc_fxnum ) + DECL_TRACE_METHOD_A( sc_dt::sc_fxnum_fast ) + + DECL_TRACE_METHOD_A( sc_dt::sc_bv_base ) + DECL_TRACE_METHOD_A( sc_dt::sc_lv_base ) + +//-------------------------------------------------- +# elif (SYSTEMC_VERSION>20011000) + // SystemC 2.0.1 +# define DECL_TRACE_METHOD_A(tp) \ + virtual void trace( const tp& object, const sc_string& name ); +# define DECL_TRACE_METHOD_B(tp) \ + virtual void trace( const tp& object, const sc_string& name, int width ); + + virtual void write_comment (const sc_string &); + virtual void trace (const unsigned int &, const sc_string &, const char **); + virtual void delta_cycles (bool) {} + virtual void space( int n ) {} + + DECL_TRACE_METHOD_A( bool ) + DECL_TRACE_METHOD_A( sc_bit ) + DECL_TRACE_METHOD_A( sc_logic ) + DECL_TRACE_METHOD_B( unsigned char ) + DECL_TRACE_METHOD_B( unsigned short ) + DECL_TRACE_METHOD_B( unsigned int ) + DECL_TRACE_METHOD_B( unsigned long ) +#ifdef SYSTEMC_64BIT_PATCHES + DECL_TRACE_METHOD_B( unsigned long long) +#endif +#if (SYSTEMC_VERSION>20041000) + DECL_TRACE_METHOD_B( unsigned long long) + DECL_TRACE_METHOD_B( long long) +#endif + DECL_TRACE_METHOD_B( char ) + DECL_TRACE_METHOD_B( short ) + DECL_TRACE_METHOD_B( int ) + DECL_TRACE_METHOD_B( long ) + DECL_TRACE_METHOD_A( float ) + DECL_TRACE_METHOD_A( double ) + DECL_TRACE_METHOD_A( sc_int_base ) + DECL_TRACE_METHOD_A( sc_uint_base ) + DECL_TRACE_METHOD_A( sc_signed ) + DECL_TRACE_METHOD_A( sc_unsigned ) + DECL_TRACE_METHOD_A( sc_fxval ) + DECL_TRACE_METHOD_A( sc_fxval_fast ) + DECL_TRACE_METHOD_A( sc_fxnum ) + DECL_TRACE_METHOD_A( sc_fxnum_fast ) + DECL_TRACE_METHOD_A( sc_bv_base ) + DECL_TRACE_METHOD_A( sc_lv_base ) + +//-------------------------------------------------- +# else + // SystemC 1.2.1beta +# define DECL_TRACE_METHOD_A(tp) \ + virtual void trace( const tp& object, const sc_string& name ); +# define DECL_TRACE_METHOD_B(tp) \ + virtual void trace( const tp& object, const sc_string& name, int width ); + + virtual void write_comment (const sc_string &); + virtual void trace (const unsigned int &, const sc_string &, const char **); + + DECL_TRACE_METHOD_A( bool ) + DECL_TRACE_METHOD_B( unsigned char ) + DECL_TRACE_METHOD_B( short unsigned int ) + DECL_TRACE_METHOD_B( unsigned int ) + DECL_TRACE_METHOD_B( long unsigned int ) + DECL_TRACE_METHOD_B( char ) + DECL_TRACE_METHOD_B( short int ) + DECL_TRACE_METHOD_B( int ) + DECL_TRACE_METHOD_B( long int ) + DECL_TRACE_METHOD_A( float ) + DECL_TRACE_METHOD_A( double ) + DECL_TRACE_METHOD_A( sc_bit ) + DECL_TRACE_METHOD_A( sc_logic ) + DECL_TRACE_METHOD_A( sc_bool_vector ) + DECL_TRACE_METHOD_A( sc_logic_vector ) + DECL_TRACE_METHOD_A( sc_signal_bool_vector ) + DECL_TRACE_METHOD_A( sc_signal_logic_vector ) + DECL_TRACE_METHOD_A( sc_uint_base ) + DECL_TRACE_METHOD_A( sc_int_base ) + DECL_TRACE_METHOD_A( sc_unsigned ) + DECL_TRACE_METHOD_A( sc_signed ) + DECL_TRACE_METHOD_A( sc_signal_resolved ) + DECL_TRACE_METHOD_A( sc_signal_resolved_vector ) + DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base ) + DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base ) +# endif + +# undef DECL_TRACE_METHOD_A +# undef DECL_TRACE_METHOD_B +}; + +#endif // guard diff --git a/nodist/spdiff b/nodist/spdiff new file mode 100755 index 000000000..b8e4d7adb --- /dev/null +++ b/nodist/spdiff @@ -0,0 +1,138 @@ +#!/usr/bin/perl -w +###################################################################### +# +# Copyright 2010-2010 by Wilson Snyder. This package 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +###################################################################### + +# DESCRIPTION: Diff Verilator includes against SystemPerl include files + +use Getopt::Long; +use IO::File; +use strict; + +our $Debug; +our $Bad; + +if (! GetOptions ( + #"help" => \&usage, + "debug" => sub { $Debug = 1; }, + )) { + die "usage();" +} + +diff("$ARGV[0]/include/verilated_vcd_c.h", "$ARGV[1]/src/SpTraceVcdC.h"); +diff("$ARGV[0]/include/verilated_vcd_sc.h", "$ARGV[1]/src/SpTraceVcd.h"); +diff("$ARGV[0]/include/verilated_vcd_c.cpp", "$ARGV[1]/src/SpTraceVcdC.cpp"); +diff("$ARGV[0]/include/verilated_vcd_sc.cpp", "$ARGV[1]/src/SpTraceVcd.cpp"); + +exit(10) if $Bad; + +sub diff { + my $a=shift; + my $b=shift; + + my $ta = "/tmp/spdiff.$$.a"; + my $tb = "/tmp/spdiff.$$.b"; + + prep($a,$ta); + prep($b,$tb); + + system("diff -u -w $ta $tb"); +} + +sub prep { + my $filename = shift; + my $wfilename = shift; + + my $sp; + if ($filename =~ m!src/Sp!) { + $sp = "Sp"; + } elsif ($filename =~ m!include/verilated!) { + } else { + die "%Error: Not sure if Sp/Verilated: $filename,\n"; + } + + my $fh = IO::File->new("<$filename") or die "%Error: $! $filename"; + my $fho = IO::File->new(">$wfilename") or die "%Error: $! writing $wfilename"; + + my @wf; + my $off; + while (defined(my $line = $fh->getline)) { + if ($line =~ m!// *SPDIFF_OFF!) { + $off = 1; + next; + } elsif ($line =~ m!// *SPDIFF_ON!) { + $off = 0; + next; + } + next if $off; + + next if $line =~ /compile-command:/; + $line =~ s/SP_ABORT.*// if $sp; + $line =~ s/SP_NOTICE.*// if $sp; + $line =~ s/vl_fatal.*// if !$sp; + $line =~ s/VL_PRINT.*// if !$sp; + + push @wf, $line; + + my $check = $line; + $check =~ s/\bspace//i; + $check =~ s/\bsplit//i; + $check =~ s/"SP_TRACE"//; + + if ($sp && $check =~ /Verilat/i + && $check !~ /and newer/) { + warn "%Warning: $filename:$.: Verilator text in Sp version: $line"; + $Bad = 1; + } elsif (!$sp && $check =~ /\b(Sp|SP)/ + ) { + warn "%Warning: $filename:$.: Sp text in Verilator version: $line"; + $Bad = 1; + } elsif (!$sp && $check =~ /\print($wholefile); +} + +# Local Variables: +# compile-command: "./spdiff $SYP $V4" +# End: diff --git a/readme.pod b/readme.pod index a5628d63d..41b68a04b 100644 --- a/readme.pod +++ b/readme.pod @@ -78,14 +78,14 @@ SYSTEMC_ARCH to the architecture name you used with SystemC, generally =item -If you will be using SystemC, download and install Verilog-Perl, -L. +If you will be using SystemPerl or coverage, download and install +Verilog-Perl, L. =item -If you will be using SystemC, download and install System-Perl, -L. Note you'll need to set a -C environment variable to point to the downloaded kit. +If you will be using SystemPerl or coverage, download and install +System-Perl, L. Note you'll need to +set a C environment variable to point to the downloaded kit. Optionally also set C to point to the installed headers. diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 0a2bef4b4..d6b189f3f 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1614,11 +1614,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) { } } if (v3Global.opt.trace()) { - if (optSystemPerl()) { - puts("class SpTraceVcd;\n"); - } else { - puts("class SpTraceVcdCFile;\n"); - } + puts("class "+v3Global.opt.traceClassBase()+";\n"); } puts("\n//----------\n\n"); @@ -1723,7 +1719,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) { } if (v3Global.opt.trace() && !optSystemPerl()) { if (modp->isTop()) puts("/// Trace signals in the model; called by application code\n"); - puts("void trace (SpTraceVcdCFile* tfp, int levels, int options=0);\n"); + puts("void trace (VerilatedVcdC* tfp, int levels, int options=0);\n"); } puts("\n// USER METHODS\n"); @@ -1756,9 +1752,9 @@ void EmitCImp::emitInt(AstNodeModule* modp) { if (!optSystemPerl() && v3Global.opt.trace()) { ofp()->putsPrivate(false); // public: - puts("static void traceInit (SpTraceVcd* vcdp, void* userthis, uint32_t code);\n"); - puts("static void traceFull (SpTraceVcd* vcdp, void* userthis, uint32_t code);\n"); - puts("static void traceChg (SpTraceVcd* vcdp, void* userthis, uint32_t code);\n"); + puts("static void traceInit ("+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code);\n"); + puts("static void traceFull ("+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code);\n"); + puts("static void traceChg ("+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code);\n"); } puts("} VL_ATTR_ALIGNED(64);\n"); @@ -1920,8 +1916,9 @@ class EmitCTrace : EmitCStmts { // Includes if (optSystemPerl()) { puts("#include \"SpTraceVcd.h\"\n"); + } else { + puts("#include \"verilated_vcd_c.h\"\n"); } - puts("#include \"SpTraceVcdC.h\"\n"); puts("#include \""+ symClassName() +".h\"\n"); puts("\n"); } @@ -1933,7 +1930,7 @@ class EmitCTrace : EmitCStmts { if (optSystemPerl()) { puts("SpTraceFile* tfp, int, int) {\n"); } else { - puts("SpTraceVcdCFile* tfp, int, int) {\n"); + puts("VerilatedVcdC* tfp, int, int) {\n"); } puts( "tfp->spTrace()->addCallback (" "&"+topClassName()+"::traceInit" @@ -1941,23 +1938,20 @@ class EmitCTrace : EmitCStmts { +", &"+topClassName()+"::traceChg, this);\n"); puts("}\n"); - puts("void "+topClassName()+"::traceInit(SpTraceVcd* vcdp, void* userthis, uint32_t code) {\n"); + puts("void "+topClassName()+"::traceInit(" + +v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n"); puts("// Callback from vcd->open()\n"); puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n"); puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); puts("if (!Verilated::calcUnusedSigs()) vl_fatal(__FILE__,__LINE__,__FILE__,\"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n"); - //Future; need to wait to estabilish backwards compatibility - puts("#if defined(SPTRACEVCDC_VERSION) && SPTRACEVCDC_VERSION >= 1330\n"); puts("vcdp->scopeEscape(' ');\n"); puts("t->traceInitThis (vlSymsp, vcdp, code);\n"); puts("vcdp->scopeEscape('.');\n"); // Restore so SystemPerl traced files won't break - puts("#else\n"); - puts("t->traceInitThis (vlSymsp, vcdp, code);\n"); - puts("#endif\n"); puts("}\n"); - puts("void "+topClassName()+"::traceFull(SpTraceVcd* vcdp, void* userthis, uint32_t code) {\n"); + puts("void "+topClassName()+"::traceFull(" + +v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n"); puts("// Callback from vcd->dump()\n"); puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n"); puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); @@ -1970,7 +1964,8 @@ class EmitCTrace : EmitCStmts { void emitTraceFast() { puts("\n//======================\n\n"); - puts("void "+topClassName()+"::traceChg(SpTraceVcd* vcdp, void* userthis, uint32_t code) {\n"); + puts("void "+topClassName()+"::traceChg(" + +v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n"); puts("// Callback from vcd->dump()\n"); puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n"); puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 83232a55d..8090d9da9 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -85,7 +85,10 @@ public: putMakeClassEntry(of, "Sp.cpp"); // Note Sp.cpp includes SpTraceVcdC } else if (v3Global.opt.trace()) { - putMakeClassEntry(of, "SpTraceVcdC.cpp"); + putMakeClassEntry(of, "verilated_vcd_c.cpp"); + if (v3Global.opt.systemC()) { + putMakeClassEntry(of, "verilated_vcd_sc.cpp"); + } } } else if (support==2 && slow) { @@ -187,7 +190,7 @@ public: } of.puts("\n### Link rules... (from --exe)\n"); - of.puts(v3Global.opt.prefix()+": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(SP_SRCS) $(VM_PREFIX)__ALL.a\n"); + of.puts(v3Global.opt.prefix()+": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a\n"); of.puts("\t$(LINK) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ $(LIBS) $(SC_LIBS) 2>&1 | c++filt\n"); of.puts("\n"); } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 7dc067eb2..09f75c39c 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -406,7 +406,7 @@ string V3Options::getenvSYSTEMPERL_INCLUDE() { // We warn about $SYSTEMPERL instead of _INCLUDE since that's more likely // what users will want to set. if (var == "") { - v3fatal("Need $SYSTEMPERL and $SYSTEMPERL_INCLUDE in environment for --sp or --trace\n" + v3fatal("Need $SYSTEMPERL and $SYSTEMPERL_INCLUDE in environment for --sp or --coverage\n" "Probably System-Perl isn't installed, see http://www.veripool.org/systemperl\n"); } else if (var != "" && !V3Options::fileStatNormal(var+"/systemperl.h")) { diff --git a/src/V3Options.h b/src/V3Options.h index c4df7496a..20dcb69e1 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -205,7 +205,7 @@ class V3Options { bool systemC() const { return m_systemC; } bool systemPerl() const { return m_systemPerl; } bool usingSystemCLibs() const { return !lintOnly() && (systemPerl() || systemC()); } - bool usingSystemPerlLibs() const { return !lintOnly() && (systemPerl() || trace()); } + bool usingSystemPerlLibs() const { return !lintOnly() && (systemPerl() || coverage()); } bool skipIdentical() const { return m_skipIdentical; } bool stats() const { return m_stats; } bool assertOn() const { return m_assert; } // assertOn as __FILE__ may be defined @@ -279,6 +279,9 @@ class V3Options { bool oSubstConst() const { return m_oSubstConst; } bool oTable() const { return m_oTable; } + // METHODS (uses above) + string traceClassBase() const { return systemPerl() ? "SpTraceVcd" : "VerilatedVcd"; } + // METHODS (from main) static string version(); static string argString(int argc, char** argv); ///< Return list of arguments as simple string diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index e4a9081aa..ef173be25 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -339,7 +339,8 @@ private: AstCFunc* newCFunc(AstCFuncType type, const string& name, AstCFunc* basep) { AstCFunc* funcp = new AstCFunc(basep->fileline(), name, basep->scopep()); funcp->slow(basep->slow()); - funcp->argTypes(EmitCBaseVisitor::symClassVar()+", SpTraceVcd* vcdp, uint32_t code"); + funcp->argTypes(EmitCBaseVisitor::symClassVar() + +", "+v3Global.opt.traceClassBase()+"* vcdp, uint32_t code"); funcp->funcType(type); funcp->symProlog(true); basep->addNext(funcp); diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index f131dee07..be55467e1 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -86,7 +86,7 @@ private: AstCFunc* newCFunc(AstCFuncType type, const string& name, bool slow) { AstCFunc* funcp = new AstCFunc(m_scopetopp->fileline(), name, m_scopetopp); funcp->slow(slow); - funcp->argTypes(EmitCBaseVisitor::symClassVar()+", SpTraceVcd* vcdp, uint32_t code"); + funcp->argTypes(EmitCBaseVisitor::symClassVar()+", "+v3Global.opt.traceClassBase()+"* vcdp, uint32_t code"); funcp->funcType(type); funcp->symProlog(true); m_scopetopp->addActivep(funcp); diff --git a/test_c/Makefile b/test_c/Makefile index cd30450c5..415876219 100644 --- a/test_c/Makefile +++ b/test_c/Makefile @@ -31,8 +31,7 @@ test_debug: prep_dbg compile run test_valgrind: prep_vg compile run VERILATOR_FLAGS = --cc -f $(VERILATOR_ROOT)/test_v/input.vc top.v -#Note turning on traces requires SystemPerl to be installed -#VERILATOR_FLAGS += --trace +VERILATOR_FLAGS += --trace prep: $(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG) $(VERILATOR_FLAGS) diff --git a/test_c/Makefile_obj b/test_c/Makefile_obj index d6538019e..792d03182 100644 --- a/test_c/Makefile_obj +++ b/test_c/Makefile_obj @@ -29,12 +29,7 @@ endif ####################################################################### # Linking final exe -- presumes have a sim_main.cpp -SP_SRCS = verilated.o -ifeq ($(VM_TRACE),1) - SP_SRCS += SpTraceVcdC.o -endif - -simx: sim_main.o $(SP_SRCS) $(VM_PREFIX)__ALL.a +simx: sim_main.o $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a $(LINK) $(LDFLAGS) -g $^ $(LOADLIBES) $(LDLIBS) -o $@ $(LIBS) 2>&1 | c++filt sim_main.o: sim_main.cpp $(VM_PREFIX).h diff --git a/test_c/sim_main.cpp b/test_c/sim_main.cpp index 1e2efef6c..a53851a6a 100644 --- a/test_c/sim_main.cpp +++ b/test_c/sim_main.cpp @@ -8,7 +8,7 @@ #include // Defines common routines #include "Vtop.h" // From Verilating "top.v" #if VM_TRACE -# include // Trace file format header (from SystemPerl) +# include // Trace file format header #endif Vtop *top; // Instantiation of module @@ -28,8 +28,8 @@ int main(int argc, char **argv, char **env) { #if VM_TRACE // If verilator was invoked with --trace Verilated::traceEverOn(true); // Verilator must compute traced signals - cout << "Enabling waves...\n"; - SpTraceVcdCFile* tfp = new SpTraceVcdCFile; + VL_PRINTF("Enabling waves...\n"); + VerilatedVcdC* tfp = new VerilatedVcdC; top->trace (tfp, 99); // Trace 99 levels of hierarchy tfp->open ("vlt_dump.vcd"); // Open the dump file #endif diff --git a/test_regress/Makefile_obj b/test_regress/Makefile_obj index a11601f39..d180dd007 100644 --- a/test_regress/Makefile_obj +++ b/test_regress/Makefile_obj @@ -50,7 +50,7 @@ ifeq ($(VM_SP_OR_SC),1) endif #Default compile, using normal make rules -#$(VM_PREFIX): $(SP_SRCS) $(VK_OBJS) +#$(VM_PREFIX): $(VK_GLOBAL_OBJS) $(VK_OBJS) # $(LINK) $(LDFLAGS) -g $^ $(LOADLIBES) $(LDLIBS) -o $@ $(LIBS) 2>&1 | c++filt #Our own compile rules; Faster compile, all in one file diff --git a/test_regress/driver.pl b/test_regress/driver.pl index ec3cd3b43..ba28eabd4 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -462,7 +462,7 @@ sub compile { $self->error("Test requires SystemC; ignore error since not installed\n"); return 1; } - elsif ($self->{trace} && !$Have_System_Perl) { + elsif ($self->{coverage} && !$Have_System_Perl) { $self->error("Test requires SystemPerl; ignore error since not installed\n"); return 1; } @@ -729,7 +729,7 @@ sub _make_main { print $fh "#include \"verilated.h\"\n"; print $fh "#include \"systemc.h\"\n" if $self->sc; print $fh "#include \"systemperl.h\"\n" if $self->sp; - print $fh "#include \"SpTraceVcdC.h\"\n" if $self->{trace} && !$self->sp; + print $fh "#include \"verilated_vcd_c.h\"\n" if $self->{trace} && !$self->sp; print $fh "#include \"SpTraceVcd.h\"\n" if $self->{trace} && $self->sp; print $fh "$VM_PREFIX * topp;\n"; @@ -774,7 +774,7 @@ sub _make_main { if ($self->{sp}) { $fh->print(" SpTraceFile* tfp = new SpTraceFile;\n"); } else { - $fh->print(" SpTraceVcdCFile* tfp = new SpTraceVcdCFile;\n"); + $fh->print(" VerilatedVcdC* tfp = new VerilatedVcdC;\n"); } $fh->print(" topp->trace (tfp, 99);\n"); $fh->print(" tfp->open (\"$self->{obj_dir}/simx.vcd\");\n"); diff --git a/test_regress/t/t_dist_spdiff.pl b/test_regress/t/t_dist_spdiff.pl new file mode 100755 index 000000000..ffbae6609 --- /dev/null +++ b/test_regress/t/t_dist_spdiff.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 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. + +my $root = ".."; +if (!-r "$root/.git") { + $Self->skip("Not in a git repository"); +} else { + my $cmd = "cd $root && nodist/spdiff . $ENV{SYSTEMPERL}"; + my $grep = `$cmd`; + print "$grep\n"; + if ($grep ne "") { + $Self->error("Include mismatches SystemPerl src\n"); + } +} + +ok(1); +1; diff --git a/test_regress/t/t_trace_public_func.cpp b/test_regress/t/t_trace_public_func.cpp index b638dfcf5..69ad5e915 100644 --- a/test_regress/t/t_trace_public_func.cpp +++ b/test_regress/t/t_trace_public_func.cpp @@ -4,7 +4,7 @@ // without warranty, 2008 by Wilson Snyder. #include -#include +#include #include "Vt_trace_public_func.h" #include "Vt_trace_public_func_t.h" @@ -23,7 +23,7 @@ int main(int argc, char **argv, char **env) { Verilated::debug(0); Verilated::traceEverOn(true); - SpTraceVcdCFile* tfp = new SpTraceVcdCFile; + VerilatedVcdC* tfp = new VerilatedVcdC; top->trace(tfp,99); tfp->open("obj_dir/t_trace_public_func/simx.vcd"); diff --git a/test_regress/t/t_trace_public_sig.cpp b/test_regress/t/t_trace_public_sig.cpp index 6cc17a6c2..d24086e35 100644 --- a/test_regress/t/t_trace_public_sig.cpp +++ b/test_regress/t/t_trace_public_sig.cpp @@ -4,7 +4,7 @@ // without warranty, 2008 by Wilson Snyder. #include -#include +#include #include "Vt_trace_public_sig.h" #include "Vt_trace_public_sig_t.h" @@ -23,7 +23,7 @@ int main(int argc, char **argv, char **env) { Verilated::debug(0); Verilated::traceEverOn(true); - SpTraceVcdCFile* tfp = new SpTraceVcdCFile; + VerilatedVcdC* tfp = new VerilatedVcdC; top->trace(tfp,99); tfp->open("obj_dir/t_trace_public_sig/simx.vcd"); diff --git a/test_sc/Makefile b/test_sc/Makefile index 5f5d7e7f2..7acbd7e5b 100644 --- a/test_sc/Makefile +++ b/test_sc/Makefile @@ -29,6 +29,7 @@ test_debug: precopy prep_dbg preproc compile run V_FLAGS = -f $(VERILATOR_ROOT)/test_v/input.vc VERILATOR_FLAGS = --sc $(V_FLAGS) top.v +VERILATOR_FLAGS += --trace precopy: obj_dir obj_dir/sc_main.cpp obj_dir/sc_main.cpp: ../test_sp/sc_main.cpp diff --git a/test_sc/Makefile_obj b/test_sc/Makefile_obj index edc9e0261..8d2f88162 100644 --- a/test_sc/Makefile_obj +++ b/test_sc/Makefile_obj @@ -16,9 +16,7 @@ default: simx include Vtop.mk ####################################################################### -# Use sp_log.cpp, so we can get output in sim.log -CPPFLAGS += -DUTIL_PRINTF=printf CPPFLAGS += -Wno-deprecated CPPFLAGS += $(SYSTEMC_CXX_FLAGS) @@ -27,11 +25,9 @@ LDFLAGS += $(SYSTEMC_CXX_FLAGS) ####################################################################### # Linking final exe -- presumes have a sim_main.cpp -SP_SRCS = verilated.o - SC_LIB = $(SYSTEMC)/lib-$(VM_SC_TARGET_ARCH)/libsystemc.a -simx: sc_main.o $(SP_SRCS) \ +simx: sc_main.o $(VK_GLOBAL_OBJS) \ $(VM_PREFIX)__ALL.a $(SC_LIB) $(LINK) $(LDFLAGS) -g $^ $(LOADLIBES) $(LDLIBS) -o $@ $(SC_LIBS) $(LIBS) 2>&1 | c++filt diff --git a/test_sp/Makefile_obj b/test_sp/Makefile_obj index 710ebad60..d36faa5ac 100644 --- a/test_sp/Makefile_obj +++ b/test_sp/Makefile_obj @@ -31,11 +31,9 @@ LDFLAGS += $(SYSTEMC_CXX_FLAGS) ####################################################################### # Linking final exe -- presumes have a sim_main.cpp -SP_SRCS = Sp.o verilated.o - SC_LIB = $(SYSTEMC)/lib-$(VM_SC_TARGET_ARCH)/libsystemc.a -simx: sc_main.o $(SP_SRCS) \ +simx: sc_main.o $(VK_GLOBAL_OBJS) \ $(VM_PREFIX)__ALL.a $(SC_LIB) $(LINK) $(LDFLAGS) -g $^ $(LOADLIBES) $(LDLIBS) -o $@ $(SC_LIBS) $(LIBS) 2>&1 | c++filt diff --git a/test_sp/sc_main.cpp b/test_sp/sc_main.cpp index 091c3e070..661a32d56 100644 --- a/test_sp/sc_main.cpp +++ b/test_sp/sc_main.cpp @@ -19,6 +19,7 @@ # include "SpCoverage.h" #else # include "systemc.h" // SystemC global header +# include "verilated_vcd_sc.h" // Tracing #endif #include "Vtop.h" // Top level header, generated from verilog @@ -118,7 +119,11 @@ int sc_main(int argc, char* argv[]) { #if WAVES cout << "Enabling waves...\n"; +# ifdef SYSTEMPERL SpTraceFile* tfp = new SpTraceFile; +# else + VerilatedVcdSc* tfp = new VerilatedVcdSc; +# endif top->trace (tfp, 99); tfp->open ("vlt_dump.vcd"); #endif @@ -156,7 +161,7 @@ int sc_main(int argc, char* argv[]) { #endif if (!passed) { - UTIL_PRINTF ("A Test failed!!\n"); + VL_PRINTF ("A Test failed!!\n"); abort(); }