Add --savable to support model save/restore.
This commit is contained in:
parent
9309d0b00f
commit
9c00fd10de
2
Changes
2
Changes
|
|
@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||||
|
|
||||||
* Verilator 3.84*** devel
|
* Verilator 3.84*** devel
|
||||||
|
|
||||||
|
*** Add --savable to support model save/restore. [Jeremy Bennett]
|
||||||
|
|
||||||
*** Support '{} assignment pattern on structures, part of bug355.
|
*** Support '{} assignment pattern on structures, part of bug355.
|
||||||
|
|
||||||
**** Fix double-deep parameter cell WIDTHs, bug541. [Hiroki Honda]
|
**** Fix double-deep parameter cell WIDTHs, bug541. [Hiroki Honda]
|
||||||
|
|
|
||||||
|
|
@ -303,6 +303,7 @@ descriptions in the next sections for more information.
|
||||||
--private Debugging; see docs
|
--private Debugging; see docs
|
||||||
--psl Enable PSL parsing
|
--psl Enable PSL parsing
|
||||||
--public Debugging; see docs
|
--public Debugging; see docs
|
||||||
|
--savable Enable model save-restore
|
||||||
--sc Create SystemC output
|
--sc Create SystemC output
|
||||||
--sp Create SystemPerl output
|
--sp Create SystemPerl output
|
||||||
--stats Create statistics file
|
--stats Create statistics file
|
||||||
|
|
@ -816,6 +817,27 @@ inlining. This will also turn off inlining as if all modules had a
|
||||||
/*verilator public_module*/, unless the module specifically enabled it with
|
/*verilator public_module*/, unless the module specifically enabled it with
|
||||||
/*verilator inline_module*/.
|
/*verilator inline_module*/.
|
||||||
|
|
||||||
|
=item --savable
|
||||||
|
|
||||||
|
Enable including save and restore functions in the generated model.
|
||||||
|
|
||||||
|
The user code must create a VerilatedSerialize or VerilatedDeserialze
|
||||||
|
object then calling the << or >> operators on the generated model and any
|
||||||
|
other data the process needs saved/restored. For example:
|
||||||
|
|
||||||
|
void save_model(const char* filenamep) {
|
||||||
|
VerilatedSave os;
|
||||||
|
os.open(filenamep);
|
||||||
|
os << main_time; // user code must save the timestamp, etc
|
||||||
|
os << *topp;
|
||||||
|
}
|
||||||
|
void restore_model(const char* filenamep) {
|
||||||
|
VerilatedRestore os;
|
||||||
|
os.open(filenamep);
|
||||||
|
os >> main_time;
|
||||||
|
os >> *topp;
|
||||||
|
}
|
||||||
|
|
||||||
=item --sc
|
=item --sc
|
||||||
|
|
||||||
Specifies SystemC output mode; see also --cc and -sp.
|
Specifies SystemC output mode; see also --cc and -sp.
|
||||||
|
|
|
||||||
|
|
@ -33,14 +33,10 @@
|
||||||
// Global variables
|
// Global variables
|
||||||
|
|
||||||
// Slow path variables
|
// Slow path variables
|
||||||
int Verilated::s_randReset = 0;
|
|
||||||
VerilatedVoidCb Verilated::s_flushCb = NULL;
|
VerilatedVoidCb Verilated::s_flushCb = NULL;
|
||||||
|
|
||||||
// Keep below together in one cache line
|
// Keep below together in one cache line
|
||||||
int Verilated::s_debug = 0;
|
Verilated::Serialized Verilated::s_s;
|
||||||
bool Verilated::s_calcUnusedSigs = false;
|
|
||||||
bool Verilated::s_gotFinish = false;
|
|
||||||
bool Verilated::s_assertOn = true;
|
|
||||||
VL_THREAD const VerilatedScope* Verilated::t_dpiScopep = NULL;
|
VL_THREAD const VerilatedScope* Verilated::t_dpiScopep = NULL;
|
||||||
VL_THREAD const char* Verilated::t_dpiFilename = "";
|
VL_THREAD const char* Verilated::t_dpiFilename = "";
|
||||||
VL_THREAD int Verilated::t_dpiLineno = 0;
|
VL_THREAD int Verilated::t_dpiLineno = 0;
|
||||||
|
|
@ -81,6 +77,17 @@ void vl_fatal (const char* filename, int linenum, const char* hier, const char*
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
// Overall class init
|
||||||
|
|
||||||
|
Verilated::Serialized::Serialized() {
|
||||||
|
s_randReset = 0;
|
||||||
|
s_debug = 0;
|
||||||
|
s_calcUnusedSigs = false;
|
||||||
|
s_gotFinish = false;
|
||||||
|
s_assertOn = true;
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
// Random reset -- Only called at init time, so don't inline.
|
// Random reset -- Only called at init time, so don't inline.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -219,14 +219,18 @@ struct Verilated {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
private:
|
private:
|
||||||
// Slow path variables
|
// Slow path variables
|
||||||
static int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
|
||||||
static VerilatedVoidCb s_flushCb; ///< Flush callback function
|
static VerilatedVoidCb s_flushCb; ///< Flush callback function
|
||||||
|
|
||||||
// Fast path
|
static struct Serialized { // All these members serialized/deserialized
|
||||||
static int s_debug; ///< See accessors... only when VL_DEBUG set
|
// Slow path
|
||||||
static bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
|
int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
||||||
static bool s_gotFinish; ///< A $finish statement executed
|
// Fast path
|
||||||
static bool s_assertOn; ///< Assertions are enabled
|
int s_debug; ///< See accessors... only when VL_DEBUG set
|
||||||
|
bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
|
||||||
|
bool s_gotFinish; ///< A $finish statement executed
|
||||||
|
bool s_assertOn; ///< Assertions are enabled
|
||||||
|
Serialized();
|
||||||
|
} s_s;
|
||||||
|
|
||||||
static VL_THREAD const VerilatedScope* t_dpiScopep; ///< DPI context scope
|
static VL_THREAD const VerilatedScope* t_dpiScopep; ///< DPI context scope
|
||||||
static VL_THREAD const char* t_dpiFilename; ///< DPI context filename
|
static VL_THREAD const char* t_dpiFilename; ///< DPI context filename
|
||||||
|
|
@ -241,29 +245,29 @@ public:
|
||||||
/// 0 = Set to zeros
|
/// 0 = Set to zeros
|
||||||
/// 1 = Set all bits to one
|
/// 1 = Set all bits to one
|
||||||
/// 2 = Randomize all bits
|
/// 2 = Randomize all bits
|
||||||
static void randReset(int val) { s_randReset=val; }
|
static void randReset(int val) { s_s.s_randReset=val; }
|
||||||
static int randReset() { return s_randReset; } ///< Return randReset value
|
static int randReset() { return s_s.s_randReset; } ///< Return randReset value
|
||||||
|
|
||||||
/// Enable debug of internal verilated code
|
/// Enable debug of internal verilated code
|
||||||
static inline void debug(int level) { s_debug = level; }
|
static inline void debug(int level) { s_s.s_debug = level; }
|
||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
static inline int debug() { return s_debug; } ///< Return debug value
|
static inline int debug() { return s_s.s_debug; } ///< Return debug value
|
||||||
#else
|
#else
|
||||||
static inline int debug() { return 0; } ///< Constant 0 debug, so C++'s optimizer rips up
|
static inline int debug() { return 0; } ///< Constant 0 debug, so C++'s optimizer rips up
|
||||||
#endif
|
#endif
|
||||||
/// Enable calculation of unused signals
|
/// Enable calculation of unused signals
|
||||||
static void calcUnusedSigs(bool flag) { s_calcUnusedSigs=flag; }
|
static void calcUnusedSigs(bool flag) { s_s.s_calcUnusedSigs=flag; }
|
||||||
static bool calcUnusedSigs() { return s_calcUnusedSigs; } ///< Return calcUnusedSigs value
|
static bool calcUnusedSigs() { return s_s.s_calcUnusedSigs; } ///< Return calcUnusedSigs value
|
||||||
/// Did the simulation $finish?
|
/// Did the simulation $finish?
|
||||||
static void gotFinish(bool flag) { s_gotFinish=flag; }
|
static void gotFinish(bool flag) { s_s.s_gotFinish=flag; }
|
||||||
static bool gotFinish() { return s_gotFinish; } ///< Return if got a $finish
|
static bool gotFinish() { return s_s.s_gotFinish; } ///< Return if got a $finish
|
||||||
/// Allow traces to at some point be enabled (disables some optimizations)
|
/// Allow traces to at some point be enabled (disables some optimizations)
|
||||||
static void traceEverOn(bool flag) {
|
static void traceEverOn(bool flag) {
|
||||||
if (flag) { calcUnusedSigs(flag); }
|
if (flag) { calcUnusedSigs(flag); }
|
||||||
}
|
}
|
||||||
/// Enable/disable assertions
|
/// Enable/disable assertions
|
||||||
static void assertOn(bool flag) { s_assertOn=flag; }
|
static void assertOn(bool flag) { s_s.s_assertOn=flag; }
|
||||||
static bool assertOn() { return s_assertOn; }
|
static bool assertOn() { return s_s.s_assertOn; }
|
||||||
/// Flush callback for VCD waves
|
/// Flush callback for VCD waves
|
||||||
static void flushCb(VerilatedVoidCb cb);
|
static void flushCb(VerilatedVoidCb cb);
|
||||||
static void flushCall() { if (s_flushCb) (*s_flushCb)(); }
|
static void flushCall() { if (s_flushCb) (*s_flushCb)(); }
|
||||||
|
|
@ -293,6 +297,8 @@ public:
|
||||||
static const char* dpiFilenamep() { return t_dpiFilename; }
|
static const char* dpiFilenamep() { return t_dpiFilename; }
|
||||||
static int dpiLineno() { return t_dpiLineno; }
|
static int dpiLineno() { return t_dpiLineno; }
|
||||||
static int exportFuncNum(const char* namep);
|
static int exportFuncNum(const char* namep);
|
||||||
|
static size_t serializedSize() { return sizeof(s_s); }
|
||||||
|
static void* serializedPtr() { return &s_s; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
`define _VERILATED_V_ 1
|
`define _VERILATED_V_ 1
|
||||||
|
|
||||||
// Hide verilator pragmas from other tools
|
// Hide verilator pragmas from other tools
|
||||||
`ifdef verilator `else
|
`ifdef VERILATOR `else
|
||||||
`define coverage_block_off
|
`define coverage_block_off
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,9 @@ class VerilatedImp {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
static VerilatedImp s_s; ///< Static Singleton; One and only static this
|
static VerilatedImp s_s; ///< Static Singleton; One and only static this
|
||||||
|
|
||||||
ArgVec m_argVec; ///< Argument list
|
// Nothing here is save-restored; users expected to re-register appropriately
|
||||||
|
|
||||||
|
ArgVec m_argVec; ///< Argument list (NOT save-restored, may want different results)
|
||||||
bool m_argVecLoaded; ///< Ever loaded argument list
|
bool m_argVecLoaded; ///< Ever loaded argument list
|
||||||
UserMap m_userMap; ///< Map of <(scope,userkey), userData>
|
UserMap m_userMap; ///< Map of <(scope,userkey), userData>
|
||||||
ScopeNameMap m_nameMap; ///< Map of <scope_name, scope pointer>
|
ScopeNameMap m_nameMap; ///< Map of <scope_name, scope pointer>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,224 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// THIS MODULE IS PUBLICLY LICENSED
|
||||||
|
//
|
||||||
|
// Copyright 2001-2012 by Wilson Snyder. This program is free software;
|
||||||
|
// you can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
///
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
#include "verilatedos.h"
|
||||||
|
#include "verilated.h"
|
||||||
|
#include "verilated_save.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||||
|
# include <io.h>
|
||||||
|
#else
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CONSTANTS
|
||||||
|
static const char* VLTSAVE_HEADER_STR = "verilatorsave01\n"; ///< Value of first bytes of each file
|
||||||
|
static const char* VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//=============================================================================
|
||||||
|
//=============================================================================
|
||||||
|
// Searalization
|
||||||
|
|
||||||
|
bool VerilatedDeserialize::readDiffers (const void* __restrict datap, size_t size) {
|
||||||
|
bufferCheck();
|
||||||
|
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||||
|
vluint8_t miss = 0;
|
||||||
|
while (size--) {
|
||||||
|
miss |= (*dp++ ^ *m_cp++);
|
||||||
|
}
|
||||||
|
return (miss!=0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VerilatedDeserialize& VerilatedDeserialize::readAssert (const void* __restrict datap, size_t size) {
|
||||||
|
if (VL_UNLIKELY(readDiffers(datap,size))) {
|
||||||
|
string msg = (string)"Can't deserialize save-restore file as was made from different model";
|
||||||
|
vl_fatal(filename().c_str(), 0, "", msg.c_str());
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
return *this; // For function chaining
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerilatedSerialize::header() {
|
||||||
|
VerilatedSerialize& os = *this; // So can cut and paste standard << code below
|
||||||
|
assert((strlen(VLTSAVE_HEADER_STR) & 7) == 0); // Keep aligned
|
||||||
|
os.write(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR));
|
||||||
|
|
||||||
|
// Verilated doesn't do it itself, as if we're not using save/restore
|
||||||
|
// it doesn't need to compile this stuff in
|
||||||
|
os.write(Verilated::serializedPtr(), Verilated::serializedSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerilatedDeserialize::header() {
|
||||||
|
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||||
|
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
||||||
|
string msg = (string)"Can't deserialize; file has wrong header signature";
|
||||||
|
vl_fatal(filename().c_str(), 0, "", msg.c_str());
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerilatedSerialize::trailer() {
|
||||||
|
VerilatedSerialize& os = *this; // So can cut and paste standard << code below
|
||||||
|
assert((strlen(VLTSAVE_TRAILER_STR) & 7) == 0); // Keep aligned
|
||||||
|
os.write(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerilatedDeserialize::trailer() {
|
||||||
|
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||||
|
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
|
||||||
|
string msg = (string)"Can't deserialize; file has wrong end-of-file signature";
|
||||||
|
vl_fatal(filename().c_str(), 0, "", msg.c_str());
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//=============================================================================
|
||||||
|
//=============================================================================
|
||||||
|
// Opening/Closing
|
||||||
|
|
||||||
|
void VerilatedSave::open (const char* filenamep) {
|
||||||
|
if (isOpen()) return;
|
||||||
|
VL_DEBUG_IF(VL_PRINTF("-vltSave: opening save file %s\n",filenamep););
|
||||||
|
|
||||||
|
if (filenamep[0]=='|') {
|
||||||
|
assert(0); // Not supported yet.
|
||||||
|
} else {
|
||||||
|
m_fd = ::open (filenamep, 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_filename = filenamep;
|
||||||
|
m_cp = m_bufp;
|
||||||
|
header();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerilatedRestore::open (const char* filenamep) {
|
||||||
|
if (isOpen()) return;
|
||||||
|
VL_DEBUG_IF(VL_PRINTF("-vltRestore: opening restore file %s\n",filenamep););
|
||||||
|
|
||||||
|
if (filenamep[0]=='|') {
|
||||||
|
assert(0); // Not supported yet.
|
||||||
|
} else {
|
||||||
|
m_fd = ::open (filenamep, O_CREAT|O_RDONLY|O_LARGEFILE
|
||||||
|
, 0666);
|
||||||
|
if (m_fd<0) {
|
||||||
|
// User code can check isOpen()
|
||||||
|
m_isOpen = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_isOpen = true;
|
||||||
|
m_filename = filenamep;
|
||||||
|
m_cp = m_bufp;
|
||||||
|
m_endp = m_bufp;
|
||||||
|
header();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerilatedSave::close () {
|
||||||
|
if (!isOpen()) return;
|
||||||
|
trailer();
|
||||||
|
flush();
|
||||||
|
m_isOpen = false;
|
||||||
|
::close(m_fd); // May get error, just ignore it
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerilatedRestore::close () {
|
||||||
|
if (!isOpen()) return;
|
||||||
|
trailer();
|
||||||
|
flush();
|
||||||
|
m_isOpen = false;
|
||||||
|
::close(m_fd); // May get error, just ignore it
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Buffer management
|
||||||
|
|
||||||
|
void VerilatedSave::flush() {
|
||||||
|
if (VL_UNLIKELY(!isOpen())) return;
|
||||||
|
vluint8_t* wp = m_bufp;
|
||||||
|
while (1) {
|
||||||
|
ssize_t remaining = (m_cp - wp);
|
||||||
|
if (remaining==0) break;
|
||||||
|
errno = 0;
|
||||||
|
ssize_t got = ::write (m_fd, wp, remaining);
|
||||||
|
if (got>0) {
|
||||||
|
wp += got;
|
||||||
|
} else if (got < 0) {
|
||||||
|
if (errno != EAGAIN && errno != EINTR) {
|
||||||
|
// write failed, presume error (perhaps out of disk space)
|
||||||
|
string msg = string(__FUNCTION__)+": "+strerror(errno);
|
||||||
|
vl_fatal("",0,"",msg.c_str());
|
||||||
|
close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_cp = m_bufp; // Reset buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerilatedRestore::fill() {
|
||||||
|
if (VL_UNLIKELY(!isOpen())) return;
|
||||||
|
// Move remaining characters down to start of buffer. (No memcpy, overlaps allowed)
|
||||||
|
vluint8_t* rp = m_bufp;
|
||||||
|
for (vluint8_t* sp=m_cp; rp < m_endp;) *rp++ = *sp++; // Overlaps
|
||||||
|
m_endp = m_bufp + (m_endp - m_cp);
|
||||||
|
m_cp = m_bufp; // Reset buffer
|
||||||
|
// Read into buffer starting at m_endp
|
||||||
|
while (1) {
|
||||||
|
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
|
||||||
|
if (remaining==0) break;
|
||||||
|
errno = 0;
|
||||||
|
ssize_t got = ::read (m_fd, m_endp, remaining);
|
||||||
|
if (got>0) {
|
||||||
|
m_endp += got;
|
||||||
|
} else if (got < 0) {
|
||||||
|
if (errno != EAGAIN && errno != EINTR) {
|
||||||
|
// write failed, presume error (perhaps out of disk space)
|
||||||
|
string msg = string(__FUNCTION__)+": "+strerror(errno);
|
||||||
|
vl_fatal("",0,"",msg.c_str());
|
||||||
|
close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else { // got==0, EOF
|
||||||
|
// Fill buffer from here to end with NULLs so reader's don't need to check eof each character.
|
||||||
|
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Serialization of types
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,234 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// THIS MODULE IS PUBLICLY LICENSED
|
||||||
|
//
|
||||||
|
// Copyright 2012-2012 by Wilson Snyder. This program is free software;
|
||||||
|
// you can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||||
|
//
|
||||||
|
// 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 Save-restore serialization of verilated modules
|
||||||
|
///
|
||||||
|
/// AUTHOR: Wilson Snyder
|
||||||
|
///
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
#ifndef _VERILATED_SAVE_C_H_
|
||||||
|
#define _VERILATED_SAVE_C_H_ 1
|
||||||
|
|
||||||
|
#include "verilatedos.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VerilatedSerialBase - internal base class for common code between VerilatedSerialize and VerilatedDeserialize
|
||||||
|
|
||||||
|
class VerilatedSerialBase {
|
||||||
|
protected:
|
||||||
|
// MEMBERS
|
||||||
|
// For speed, keep m_cp as the first member of this structure
|
||||||
|
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||||
|
vluint8_t* m_bufp; ///< Output buffer
|
||||||
|
bool m_isOpen; ///< True indicates open file/stream
|
||||||
|
string m_filename;
|
||||||
|
|
||||||
|
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||||
|
inline static size_t bufferInsertSize() { return 16*1024; }
|
||||||
|
|
||||||
|
// CREATORS
|
||||||
|
VerilatedSerialBase() {
|
||||||
|
m_isOpen = false;
|
||||||
|
m_bufp = new vluint8_t [bufferSize()];
|
||||||
|
m_cp = m_bufp;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
// CREATORS
|
||||||
|
virtual ~VerilatedSerialBase() {
|
||||||
|
close();
|
||||||
|
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||||
|
}
|
||||||
|
// METHODS
|
||||||
|
bool isOpen() const { return m_isOpen; }
|
||||||
|
string filename() const { return m_filename; }
|
||||||
|
virtual void close() { flush(); }
|
||||||
|
virtual void flush() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VerilatedSerialize - convert structures to a stream representation
|
||||||
|
|
||||||
|
class VerilatedSerialize : public VerilatedSerialBase {
|
||||||
|
protected:
|
||||||
|
virtual void close() { flush(); }
|
||||||
|
virtual void flush() {}
|
||||||
|
void header();
|
||||||
|
void trailer();
|
||||||
|
public:
|
||||||
|
// CREATORS
|
||||||
|
VerilatedSerialize() {}
|
||||||
|
virtual ~VerilatedSerialize() { close(); }
|
||||||
|
// METHODS
|
||||||
|
VerilatedSerialize& 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 (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
return *this; // For function chaining
|
||||||
|
}
|
||||||
|
inline VerilatedSerialize& write (const void* __restrict datap, size_t size) {
|
||||||
|
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||||
|
while (size) {
|
||||||
|
bufferCheck();
|
||||||
|
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||||
|
const vluint8_t* __restrict maxp = dp + blk;
|
||||||
|
while (dp < maxp) *m_cp++ = *dp++;
|
||||||
|
size -= blk;
|
||||||
|
}
|
||||||
|
return *this; // For function chaining
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VerilatedDeserial - load structures from a stream representation
|
||||||
|
|
||||||
|
class VerilatedDeserialize : public VerilatedSerialBase {
|
||||||
|
protected:
|
||||||
|
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
|
||||||
|
virtual void fill() = 0;
|
||||||
|
void header();
|
||||||
|
void trailer();
|
||||||
|
public:
|
||||||
|
// CREATORS
|
||||||
|
VerilatedDeserialize() {}
|
||||||
|
virtual ~VerilatedDeserialize() { close(); }
|
||||||
|
// METHODS
|
||||||
|
inline VerilatedDeserialize& read (void* __restrict datap, size_t size) {
|
||||||
|
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
|
||||||
|
while (size) {
|
||||||
|
bufferCheck();
|
||||||
|
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||||
|
const vluint8_t* __restrict maxp = dp + blk;
|
||||||
|
while (dp < maxp) *dp++ = *m_cp++;
|
||||||
|
size -= blk;
|
||||||
|
}
|
||||||
|
return *this; // For function chaining
|
||||||
|
}
|
||||||
|
// Read a datum and compare with expected value
|
||||||
|
bool readDiffers (const void* __restrict datap, size_t size);
|
||||||
|
VerilatedDeserialize& readAssert (const void* __restrict datap, size_t size);
|
||||||
|
VerilatedDeserialize& readAssert (vluint64_t data) { return readAssert(&data, sizeof(data)); }
|
||||||
|
VerilatedDeserialize& 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 (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
|
||||||
|
fill();
|
||||||
|
}
|
||||||
|
return *this; // For function chaining
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VerilatedSave - serialize to a file
|
||||||
|
|
||||||
|
class VerilatedSave : public VerilatedSerialize {
|
||||||
|
private:
|
||||||
|
int m_fd; ///< File descriptor we're writing to
|
||||||
|
|
||||||
|
public:
|
||||||
|
// CREATORS
|
||||||
|
VerilatedSave() {}
|
||||||
|
virtual ~VerilatedSave() { close(); }
|
||||||
|
// METHODS
|
||||||
|
void open(const char* filenamep); ///< Open the file; call isOpen() to see if errors
|
||||||
|
void open(const string& filename) { open(filename.c_str()); }
|
||||||
|
virtual void close();
|
||||||
|
virtual void flush();
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VerilatedRestore - deserialize from a file
|
||||||
|
|
||||||
|
class VerilatedRestore : public VerilatedDeserialize {
|
||||||
|
private:
|
||||||
|
int m_fd; ///< File descriptor we're writing to
|
||||||
|
|
||||||
|
public:
|
||||||
|
// CREATORS
|
||||||
|
VerilatedRestore() {}
|
||||||
|
virtual ~VerilatedRestore() { close(); }
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
void open(const char* filenamep); ///< Open the file; call isOpen() to see if errors
|
||||||
|
void open(const string& filename) { open(filename.c_str()); }
|
||||||
|
virtual void close();
|
||||||
|
virtual void flush() {}
|
||||||
|
virtual void fill();
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint64_t& rhs) {
|
||||||
|
return os.write(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint64_t& rhs){
|
||||||
|
return os.read(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint32_t& rhs) {
|
||||||
|
return os.write(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint32_t& rhs) {
|
||||||
|
return os.read(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint16_t& rhs) {
|
||||||
|
return os.write(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint16_t& rhs) {
|
||||||
|
return os.read(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint8_t& rhs) {
|
||||||
|
return os.write(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint8_t& rhs) {
|
||||||
|
return os.read(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, bool& rhs) {
|
||||||
|
return os.write(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, bool& rhs) {
|
||||||
|
return os.read(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, double& rhs) {
|
||||||
|
return os.write(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, double& rhs) {
|
||||||
|
return os.read(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, float& rhs) {
|
||||||
|
return os.write(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, float& rhs) {
|
||||||
|
return os.read(&rhs, sizeof(rhs));
|
||||||
|
}
|
||||||
|
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, string& rhs) {
|
||||||
|
vluint32_t len=rhs.length();
|
||||||
|
os<<len;
|
||||||
|
return os.write(rhs.data(), len);
|
||||||
|
}
|
||||||
|
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, string& rhs) {
|
||||||
|
vluint32_t len;
|
||||||
|
os>>len;
|
||||||
|
rhs.resize(len);
|
||||||
|
return os.read((void*)rhs.data(), len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // guard
|
||||||
|
|
@ -219,6 +219,7 @@ RAW_OBJS = \
|
||||||
V3SplitAs.o \
|
V3SplitAs.o \
|
||||||
V3Stats.o \
|
V3Stats.o \
|
||||||
V3StatsReport.o \
|
V3StatsReport.o \
|
||||||
|
V3String.o \
|
||||||
V3Subst.o \
|
V3Subst.o \
|
||||||
V3Table.o \
|
V3Table.o \
|
||||||
V3Task.o \
|
V3Task.o \
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
|
#include "V3String.h"
|
||||||
#include "V3Config.h"
|
#include "V3Config.h"
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
@ -89,7 +90,7 @@ class V3ConfigIgnores {
|
||||||
it = m_ignFiles.find(filename);
|
it = m_ignFiles.find(filename);
|
||||||
// Make new list for this file of all matches
|
// Make new list for this file of all matches
|
||||||
for (IgnFiles::iterator fnit = m_ignWilds.begin(); fnit != m_ignWilds.end(); ++fnit) {
|
for (IgnFiles::iterator fnit = m_ignWilds.begin(); fnit != m_ignWilds.end(); ++fnit) {
|
||||||
if (V3Options::wildmatch(filename.c_str(), fnit->first.c_str())) {
|
if (VString::wildmatch(filename.c_str(), fnit->first.c_str())) {
|
||||||
for (IgnLines::iterator lit = fnit->second.begin(); lit != fnit->second.end(); ++lit) {
|
for (IgnLines::iterator lit = fnit->second.begin(); lit != fnit->second.end(); ++lit) {
|
||||||
it->second.insert(*lit);
|
it->second.insert(*lit);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
|
#include "V3String.h"
|
||||||
#include "V3EmitC.h"
|
#include "V3EmitC.h"
|
||||||
#include "V3EmitCBase.h"
|
#include "V3EmitCBase.h"
|
||||||
|
|
||||||
|
|
@ -842,6 +843,7 @@ class EmitCImp : EmitCStmts {
|
||||||
void emitCoverageDecl(AstNodeModule* modp);
|
void emitCoverageDecl(AstNodeModule* modp);
|
||||||
void emitCoverageImp(AstNodeModule* modp);
|
void emitCoverageImp(AstNodeModule* modp);
|
||||||
void emitDestructorImp(AstNodeModule* modp);
|
void emitDestructorImp(AstNodeModule* modp);
|
||||||
|
void emitSavableImp(AstNodeModule* modp);
|
||||||
void emitTextSection(AstType type);
|
void emitTextSection(AstType type);
|
||||||
void emitIntFuncDecls(AstNodeModule* modp);
|
void emitIntFuncDecls(AstNodeModule* modp);
|
||||||
// High level
|
// High level
|
||||||
|
|
@ -1436,7 +1438,7 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
|
||||||
// compatible, and have a common wrapper.
|
// compatible, and have a common wrapper.
|
||||||
puts("void "+modClassName(m_modp)+"::__vlCoverInsert(uint32_t* countp, bool enable, const char* filenamep, int lineno, int column,\n");
|
puts("void "+modClassName(m_modp)+"::__vlCoverInsert(uint32_t* countp, bool enable, const char* filenamep, int lineno, int column,\n");
|
||||||
puts( "const char* hierp, const char* pagep, const char* commentp) {\n");
|
puts( "const char* hierp, const char* pagep, const char* commentp) {\n");
|
||||||
puts( "static uint32_t fake_zero_count = 0;\n");
|
puts( "static uint32_t fake_zero_count = 0;\n"); // static doesn't need save-restore as constant
|
||||||
puts( "if (!enable) countp = &fake_zero_count;\n"); // Used for second++ instantiation of identical bin
|
puts( "if (!enable) countp = &fake_zero_count;\n"); // Used for second++ instantiation of identical bin
|
||||||
puts( "*countp = 0;\n");
|
puts( "*countp = 0;\n");
|
||||||
puts( "SP_COVER_INSERT(countp,");
|
puts( "SP_COVER_INSERT(countp,");
|
||||||
|
|
@ -1459,6 +1461,79 @@ void EmitCImp::emitDestructorImp(AstNodeModule* modp) {
|
||||||
puts("}\n");
|
puts("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitCImp::emitSavableImp(AstNodeModule* modp) {
|
||||||
|
if (v3Global.opt.savable() ) {
|
||||||
|
puts("\n// Savable\n");
|
||||||
|
for (int de=0; de<2; ++de) {
|
||||||
|
string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize";
|
||||||
|
string funcname = de ? "__Vdeserialize" : "__Vserialize";
|
||||||
|
string writeread = de ? "read" : "write";
|
||||||
|
string op = de ? ">>" : "<<";
|
||||||
|
puts("void "+modClassName(modp)+"::"+funcname+"("+classname+"& os) {\n");
|
||||||
|
// Place a computed checksum to insure proper structure save/restore formatting
|
||||||
|
// OK if this hash includes some things we won't dump, since just looking for loading the wrong model
|
||||||
|
VHashFnv hash;
|
||||||
|
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||||
|
if (AstVar* varp = nodep->castVar()) {
|
||||||
|
hash.hash(varp->name());
|
||||||
|
hash.hash(varp->dtypep()->width());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ofp()->printf( "vluint64_t __Vcheckval = VL_ULL(0x%" VL_PRI64 "x);\n",
|
||||||
|
hash.value());
|
||||||
|
if (de) {
|
||||||
|
puts("os.readAssert(__Vcheckval);\n");
|
||||||
|
} else {
|
||||||
|
puts("os<<__Vcheckval;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save all members
|
||||||
|
if (v3Global.opt.inhibitSim()) puts("os"+op+"__Vm_inhibitSim;\n");
|
||||||
|
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||||
|
if (AstVar* varp = nodep->castVar()) {
|
||||||
|
if (varp->isIO() && modp->isTop() && optSystemC()) {
|
||||||
|
// System C top I/O doesn't need loading, as the lower level subinst code does it.
|
||||||
|
}
|
||||||
|
else if (varp->isParam()) {}
|
||||||
|
else if (varp->isStatic() && varp->isConst()) {}
|
||||||
|
else {
|
||||||
|
int vects = 0;
|
||||||
|
// This isn't very robust and may need cleanup for other data types
|
||||||
|
for (AstArrayDType* arrayp=varp->dtypeSkipRefp()->castArrayDType(); arrayp;
|
||||||
|
arrayp = arrayp->subDTypep()->skipRefp()->castArrayDType()) {
|
||||||
|
int vecnum = vects++;
|
||||||
|
if (arrayp->msb() < arrayp->lsb()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
|
||||||
|
string ivar = string("__Vi")+cvtToStr(vecnum);
|
||||||
|
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
|
||||||
|
puts("{ int __Vi"+cvtToStr(vecnum)+"="+cvtToStr(0)+";");
|
||||||
|
puts(" for (; "+ivar+"<"+cvtToStr(arrayp->elementsConst()));
|
||||||
|
puts("; ++"+ivar+") {\n");
|
||||||
|
}
|
||||||
|
if (varp->basicp() && (varp->basicp()->keyword() == AstBasicDTypeKwd::STRING
|
||||||
|
|| !varp->basicp()->isWide())) {
|
||||||
|
puts("os"+op+varp->name());
|
||||||
|
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
|
||||||
|
puts(";\n");
|
||||||
|
} else {
|
||||||
|
puts("os."+writeread+"(&"+varp->name());
|
||||||
|
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
|
||||||
|
puts(",sizeof("+varp->name());
|
||||||
|
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
|
||||||
|
puts("));\n");
|
||||||
|
}
|
||||||
|
for (int v=0; v<vects; ++v) puts( "}}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modp->isTop()) { // Save the children
|
||||||
|
puts( "__VlSymsp->"+funcname+"(os);\n");
|
||||||
|
}
|
||||||
|
puts("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmitCImp::emitStaticDecl(AstNodeModule* modp) {
|
void EmitCImp::emitStaticDecl(AstNodeModule* modp) {
|
||||||
// Need implementation here. Be careful of alignment code; needs to be uniquified
|
// Need implementation here. Be careful of alignment code; needs to be uniquified
|
||||||
// with module name to avoid multiple symbols.
|
// with module name to avoid multiple symbols.
|
||||||
|
|
@ -1675,8 +1750,12 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||||
} else {
|
} else {
|
||||||
puts("#include \"verilated.h\"\n");
|
puts("#include \"verilated.h\"\n");
|
||||||
}
|
}
|
||||||
|
if (v3Global.opt.savable()) {
|
||||||
|
puts("#include \"verilated_save.h\"\n");
|
||||||
|
}
|
||||||
if (v3Global.opt.coverage()) {
|
if (v3Global.opt.coverage()) {
|
||||||
puts("#include \"SpCoverage.h\"\n");
|
puts("#include \"SpCoverage.h\"\n");
|
||||||
|
if (v3Global.opt.savable()) v3error("--coverage and --savable not supported together");
|
||||||
}
|
}
|
||||||
if (v3Global.needHInlines()) { // Set by V3EmitCInlines; should have been called before us
|
if (v3Global.needHInlines()) { // Set by V3EmitCInlines; should have been called before us
|
||||||
puts("#include \""+topClassName()+"__Inlines.h\"\n");
|
puts("#include \""+topClassName()+"__Inlines.h\"\n");
|
||||||
|
|
@ -1842,10 +1921,22 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||||
puts("static void traceFull ("+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("static void traceChg ("+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code);\n");
|
||||||
}
|
}
|
||||||
|
if (v3Global.opt.savable()) {
|
||||||
|
puts("void __Vserialize(VerilatedSerialize& os);\n");
|
||||||
|
puts("void __Vdeserialize(VerilatedDeserialize& os);\n");
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
puts("} VL_ATTR_ALIGNED(64);\n");
|
puts("} VL_ATTR_ALIGNED(128);\n");
|
||||||
puts("\n");
|
puts("\n");
|
||||||
|
|
||||||
|
// Save/restore
|
||||||
|
if (v3Global.opt.savable() && modp->isTop()) {
|
||||||
|
puts("inline VerilatedSerialize& operator<<(VerilatedSerialize& os, "+modClassName(modp)+"& rhs) {rhs.__Vserialize(os); return os;}\n");
|
||||||
|
puts("inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, "+modClassName(modp)+"& rhs) {rhs.__Vdeserialize(os); return os;}\n");
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
// finish up h-file
|
// finish up h-file
|
||||||
if (!optSystemPerl()) {
|
if (!optSystemPerl()) {
|
||||||
puts("#endif /*guard*/\n");
|
puts("#endif /*guard*/\n");
|
||||||
|
|
@ -1893,6 +1984,7 @@ void EmitCImp::emitImp(AstNodeModule* modp) {
|
||||||
emitCtorImp(modp);
|
emitCtorImp(modp);
|
||||||
emitConfigureImp(modp);
|
emitConfigureImp(modp);
|
||||||
emitDestructorImp(modp);
|
emitDestructorImp(modp);
|
||||||
|
emitSavableImp(modp);
|
||||||
emitCoverageImp(modp);
|
emitCoverageImp(modp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -339,8 +339,13 @@ void EmitCSyms::emitSymHdr() {
|
||||||
puts("\n// METHODS\n");
|
puts("\n// METHODS\n");
|
||||||
puts("inline const char* name() { return __Vm_namep; }\n");
|
puts("inline const char* name() { return __Vm_namep; }\n");
|
||||||
puts("inline bool getClearActivity() { bool r=__Vm_activity; __Vm_activity=false; return r;}\n");
|
puts("inline bool getClearActivity() { bool r=__Vm_activity; __Vm_activity=false; return r;}\n");
|
||||||
|
if (v3Global.opt.savable() ) {
|
||||||
|
puts("void __Vserialize(VerilatedSerialize& os);\n");
|
||||||
|
puts("void __Vdeserialize(VerilatedDeserialize& os);\n");
|
||||||
|
}
|
||||||
puts("\n");
|
puts("\n");
|
||||||
puts("} VL_ATTR_ALIGNED(64);\n");
|
puts("} VL_ATTR_ALIGNED(64);\n");
|
||||||
|
puts("\n");
|
||||||
puts("#endif /*guard*/\n");
|
puts("#endif /*guard*/\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -498,7 +503,28 @@ void EmitCSyms::emitSymImp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
puts("}\n");
|
puts("}\n");
|
||||||
puts("\n");
|
|
||||||
|
if (v3Global.opt.savable() ) {
|
||||||
|
puts("\n");
|
||||||
|
for (int de=0; de<2; ++de) {
|
||||||
|
string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize";
|
||||||
|
string funcname = de ? "__Vdeserialize" : "__Vserialize";
|
||||||
|
string op = de ? ">>" : "<<";
|
||||||
|
puts("void "+symClassName()+"::"+funcname+"("+classname+"& os) {\n");
|
||||||
|
puts( "// LOCAL STATE\n");
|
||||||
|
// __Vm_namep presumably already correct
|
||||||
|
puts( "os"+op+"__Vm_activity;\n");
|
||||||
|
puts( "os"+op+"__Vm_didInit;\n");
|
||||||
|
puts( "// SUBCELL STATE\n");
|
||||||
|
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||||
|
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
|
||||||
|
if (!modp->isTop()) {
|
||||||
|
puts( scopep->nameDotless()+"."+funcname+"(os);\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,9 @@ public:
|
||||||
if (v3Global.dpi()) {
|
if (v3Global.dpi()) {
|
||||||
putMakeClassEntry(of, "verilated_dpi.cpp");
|
putMakeClassEntry(of, "verilated_dpi.cpp");
|
||||||
}
|
}
|
||||||
|
if (v3Global.opt.savable()) {
|
||||||
|
putMakeClassEntry(of, "verilated_save.cpp");
|
||||||
|
}
|
||||||
if (v3Global.opt.systemPerl()) {
|
if (v3Global.opt.systemPerl()) {
|
||||||
putMakeClassEntry(of, "Sp.cpp"); // Note Sp.cpp includes SpTraceVcdC
|
putMakeClassEntry(of, "Sp.cpp"); // Note Sp.cpp includes SpTraceVcdC
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
|
#include "V3String.h"
|
||||||
#include "V3EmitXml.h"
|
#include "V3EmitXml.h"
|
||||||
#include "V3EmitCBase.h"
|
#include "V3EmitCBase.h"
|
||||||
|
|
||||||
|
|
@ -64,12 +65,12 @@ class EmitXmlFileVisitor : public EmitCBaseVisitor {
|
||||||
|
|
||||||
// XML methods
|
// XML methods
|
||||||
void outputTag(AstNode* nodep, string tag) {
|
void outputTag(AstNode* nodep, string tag) {
|
||||||
if (tag=="") tag = V3Options::downcase(nodep->typeName());
|
if (tag=="") tag = VString::downcase(nodep->typeName());
|
||||||
puts("<"+tag+" "+nodep->fileline()->xml());
|
puts("<"+tag+" "+nodep->fileline()->xml());
|
||||||
if (nodep->name()!="") { puts(" name="); putsQuoted(nodep->prettyName()); }
|
if (nodep->name()!="") { puts(" name="); putsQuoted(nodep->prettyName()); }
|
||||||
}
|
}
|
||||||
void outputChildrenEnd(AstNode* nodep, string tag) {
|
void outputChildrenEnd(AstNode* nodep, string tag) {
|
||||||
if (tag=="") tag = V3Options::downcase(nodep->typeName());
|
if (tag=="") tag = VString::downcase(nodep->typeName());
|
||||||
if (nodep->op1p() || nodep->op2p() || nodep->op3p() || nodep->op4p()) {
|
if (nodep->op1p() || nodep->op2p() || nodep->op3p() || nodep->op4p()) {
|
||||||
puts(">\n");
|
puts(">\n");
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
|
#include "V3String.h"
|
||||||
#include "V3Options.h"
|
#include "V3Options.h"
|
||||||
#include "V3Error.h"
|
#include "V3Error.h"
|
||||||
#include "V3File.h"
|
#include "V3File.h"
|
||||||
|
|
@ -367,7 +368,7 @@ void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) {
|
||||||
void V3Options::unlinkRegexp(const string& dir, const string& regexp) {
|
void V3Options::unlinkRegexp(const string& dir, const string& regexp) {
|
||||||
if (DIR* dirp = opendir(dir.c_str())) {
|
if (DIR* dirp = opendir(dir.c_str())) {
|
||||||
while (struct dirent* direntp = readdir(dirp)) {
|
while (struct dirent* direntp = readdir(dirp)) {
|
||||||
if (wildmatch(direntp->d_name, regexp.c_str())) {
|
if (VString::wildmatch(direntp->d_name, regexp.c_str())) {
|
||||||
string fullname = dir + "/" + string(direntp->d_name);
|
string fullname = dir + "/" + string(direntp->d_name);
|
||||||
unlink (fullname.c_str());
|
unlink (fullname.c_str());
|
||||||
}
|
}
|
||||||
|
|
@ -433,9 +434,9 @@ string V3Options::getenvSYSTEMC_ARCH() {
|
||||||
#else
|
#else
|
||||||
struct utsname uts;
|
struct utsname uts;
|
||||||
uname(&uts);
|
uname(&uts);
|
||||||
string sysname = downcase(uts.sysname); // aka 'uname -s'
|
string sysname = VString::downcase(uts.sysname); // aka 'uname -s'
|
||||||
if (wildmatch(sysname.c_str(), "*solaris*")) { var = "gccsparcOS5"; }
|
if (VString::wildmatch(sysname.c_str(), "*solaris*")) { var = "gccsparcOS5"; }
|
||||||
else if (wildmatch(sysname.c_str(), "*cygwin*")) { var ="cygwin"; }
|
else if (VString::wildmatch(sysname.c_str(), "*cygwin*")) { var ="cygwin"; }
|
||||||
else { var = "linux"; }
|
else { var = "linux"; }
|
||||||
#endif
|
#endif
|
||||||
setenvStr("SYSTEMC_ARCH", var,"From sysname '"+sysname+"'");
|
setenvStr("SYSTEMC_ARCH", var,"From sysname '"+sysname+"'");
|
||||||
|
|
@ -542,54 +543,6 @@ string V3Options::getenvVERILATOR_ROOT() {
|
||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
|
||||||
// Wildcard
|
|
||||||
|
|
||||||
// Double procedures, inlined, unrolls loop much better
|
|
||||||
inline bool V3Options::wildmatchi(const char* s, const char* p) {
|
|
||||||
for ( ; *p; s++, p++) {
|
|
||||||
if (*p!='*') {
|
|
||||||
if (((*s)!=(*p)) && *p != '?')
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Trailing star matches everything.
|
|
||||||
if (!*++p) return true;
|
|
||||||
while (wildmatch(s, p) == false)
|
|
||||||
if (*++s == '\0')
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (*s == '\0');
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V3Options::wildmatch(const char* s, const char* p) {
|
|
||||||
for ( ; *p; s++, p++) {
|
|
||||||
if (*p!='*') {
|
|
||||||
if (((*s)!=(*p)) && *p != '?')
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Trailing star matches everything.
|
|
||||||
if (!*++p) return true;
|
|
||||||
while (wildmatchi(s, p) == false)
|
|
||||||
if (*++s == '\0')
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (*s == '\0');
|
|
||||||
}
|
|
||||||
|
|
||||||
string V3Options::downcase(const string& str) {
|
|
||||||
string out = str;
|
|
||||||
for (string::iterator pos = out.begin(); pos != out.end(); ++pos) {
|
|
||||||
*pos = tolower(*pos);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// V3 Options accessors
|
// V3 Options accessors
|
||||||
|
|
||||||
|
|
@ -737,6 +690,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||||
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profileCFuncs = flag; }
|
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profileCFuncs = flag; }
|
||||||
else if ( onoff (sw, "-psl", flag/*ref*/) ) { m_psl = flag; }
|
else if ( onoff (sw, "-psl", flag/*ref*/) ) { m_psl = flag; }
|
||||||
else if ( onoff (sw, "-public", flag/*ref*/) ) { m_public = flag; }
|
else if ( onoff (sw, "-public", flag/*ref*/) ) { m_public = flag; }
|
||||||
|
else if ( onoff (sw, "-savable", flag/*ref*/) ) { m_savable = flag; }
|
||||||
else if ( !strcmp (sw, "-sc") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = false; }
|
else if ( !strcmp (sw, "-sc") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = false; }
|
||||||
else if ( onoff (sw, "-skip-identical", flag/*ref*/) ) { m_skipIdentical = flag; }
|
else if ( onoff (sw, "-skip-identical", flag/*ref*/) ) { m_skipIdentical = flag; }
|
||||||
else if ( !strcmp (sw, "-sp") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = true; }
|
else if ( !strcmp (sw, "-sp") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = true; }
|
||||||
|
|
@ -1181,6 +1135,7 @@ V3Options::V3Options() {
|
||||||
m_preprocOnly = false;
|
m_preprocOnly = false;
|
||||||
m_psl = false;
|
m_psl = false;
|
||||||
m_public = false;
|
m_public = false;
|
||||||
|
m_savable = false;
|
||||||
m_skipIdentical = true;
|
m_skipIdentical = true;
|
||||||
m_stats = false;
|
m_stats = false;
|
||||||
m_systemC = false;
|
m_systemC = false;
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ class V3Options {
|
||||||
bool m_profileCFuncs;// main switch: --profile-cfuncs
|
bool m_profileCFuncs;// main switch: --profile-cfuncs
|
||||||
bool m_psl; // main switch: --psl
|
bool m_psl; // main switch: --psl
|
||||||
bool m_public; // main switch: --public
|
bool m_public; // main switch: --public
|
||||||
|
bool m_savable; // main switch: --savable
|
||||||
bool m_systemC; // main switch: --sc: System C instead of simple C++
|
bool m_systemC; // main switch: --sc: System C instead of simple C++
|
||||||
bool m_skipIdentical;// main switch: --skip-identical
|
bool m_skipIdentical;// main switch: --skip-identical
|
||||||
bool m_systemPerl; // main switch: --sp: System Perl instead of SystemC (m_systemC also set)
|
bool m_systemPerl; // main switch: --sp: System Perl instead of SystemC (m_systemC also set)
|
||||||
|
|
@ -192,7 +193,6 @@ class V3Options {
|
||||||
string parseFileArg(const string& optdir, const string& relfilename);
|
string parseFileArg(const string& optdir, const string& relfilename);
|
||||||
string filePathCheckOneDir(const string& modname, const string& dirname);
|
string filePathCheckOneDir(const string& modname, const string& dirname);
|
||||||
|
|
||||||
static bool wildmatchi(const char* s, const char* p);
|
|
||||||
static string getenvStr(const string& envvar, const string& defaultValue);
|
static string getenvStr(const string& envvar, const string& defaultValue);
|
||||||
static void setenvStr(const string& envvar, const string& value, const string& why);
|
static void setenvStr(const string& envvar, const string& value, const string& why);
|
||||||
static string getenvSYSTEMPERLGuts();
|
static string getenvSYSTEMPERLGuts();
|
||||||
|
|
@ -223,6 +223,7 @@ class V3Options {
|
||||||
bool systemPerl() const { return m_systemPerl; }
|
bool systemPerl() const { return m_systemPerl; }
|
||||||
bool usingSystemCLibs() const { return !lintOnly() && (systemPerl() || systemC()); }
|
bool usingSystemCLibs() const { return !lintOnly() && (systemPerl() || systemC()); }
|
||||||
bool usingSystemPerlLibs() const { return !lintOnly() && (systemPerl() || coverage()); }
|
bool usingSystemPerlLibs() const { return !lintOnly() && (systemPerl() || coverage()); }
|
||||||
|
bool savable() const { return m_savable; }
|
||||||
bool skipIdentical() const { return m_skipIdentical; }
|
bool skipIdentical() const { return m_skipIdentical; }
|
||||||
bool stats() const { return m_stats; }
|
bool stats() const { return m_stats; }
|
||||||
bool assertOn() const { return m_assert; } // assertOn as __FILE__ may be defined
|
bool assertOn() const { return m_assert; } // assertOn as __FILE__ may be defined
|
||||||
|
|
@ -321,10 +322,6 @@ class V3Options {
|
||||||
void parseOptsList (FileLine* fl, const string& optdir, int argc, char** argv);
|
void parseOptsList (FileLine* fl, const string& optdir, int argc, char** argv);
|
||||||
void parseOptsFile (FileLine* fl, const string& filename, bool rel);
|
void parseOptsFile (FileLine* fl, const string& filename, bool rel);
|
||||||
|
|
||||||
// METHODS (generic string utilities)
|
|
||||||
static bool wildmatch(const char* s, const char* p);
|
|
||||||
static string downcase(const string& str);
|
|
||||||
|
|
||||||
// METHODS (generic file utilities)
|
// METHODS (generic file utilities)
|
||||||
static string filenameFromDirBase (const string& dir, const string& basename);
|
static string filenameFromDirBase (const string& dir, const string& basename);
|
||||||
static string filenameNonDir (const string& filename); ///< Return non-directory part of filename
|
static string filenameNonDir (const string& filename); ///< Return non-directory part of filename
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator: Options parsing
|
||||||
|
//
|
||||||
|
// Code available from: http://www.veripool.org/verilator
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2012 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// Verilator 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.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#include "config_build.h"
|
||||||
|
#include "verilatedos.h"
|
||||||
|
|
||||||
|
#include "V3String.h"
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
// Wildcard
|
||||||
|
|
||||||
|
// Double procedures, inlined, unrolls loop much better
|
||||||
|
inline bool VString::wildmatchi(const char* s, const char* p) {
|
||||||
|
for ( ; *p; s++, p++) {
|
||||||
|
if (*p!='*') {
|
||||||
|
if (((*s)!=(*p)) && *p != '?')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Trailing star matches everything.
|
||||||
|
if (!*++p) return true;
|
||||||
|
while (wildmatch(s, p) == false)
|
||||||
|
if (*++s == '\0')
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (*s == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VString::wildmatch(const char* s, const char* p) {
|
||||||
|
for ( ; *p; s++, p++) {
|
||||||
|
if (*p!='*') {
|
||||||
|
if (((*s)!=(*p)) && *p != '?')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Trailing star matches everything.
|
||||||
|
if (!*++p) return true;
|
||||||
|
while (wildmatchi(s, p) == false)
|
||||||
|
if (*++s == '\0')
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (*s == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
string VString::downcase(const string& str) {
|
||||||
|
string out = str;
|
||||||
|
for (string::iterator pos = out.begin(); pos != out.end(); ++pos) {
|
||||||
|
*pos = tolower(*pos);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator: String manipulation
|
||||||
|
//
|
||||||
|
// Code available from: http://www.veripool.org/verilator
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2012 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// Verilator 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.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#ifndef _V3STRING_H_
|
||||||
|
#define _V3STRING_H_ 1
|
||||||
|
|
||||||
|
#include "config_build.h"
|
||||||
|
#include "verilatedos.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
// VString - String manipulation
|
||||||
|
|
||||||
|
class VString {
|
||||||
|
static bool wildmatchi(const char* s, const char* p);
|
||||||
|
public:
|
||||||
|
// METHODS (generic string utilities)
|
||||||
|
static bool wildmatch(const char* s, const char* p);
|
||||||
|
static string downcase(const string& str);
|
||||||
|
};
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
// Compute FNV1a (Fowler/Noll/Vo) hashes
|
||||||
|
// See http://www.isthe.com/chongo/tech/comp/fnv/index.html
|
||||||
|
// Algorithmic basis for these functions was in the public domain, by chongo <Landon Curt Noll>
|
||||||
|
|
||||||
|
class VHashFnv {
|
||||||
|
enum { FNV1_64_INIT = 0xcbf29ce484222325ULL }; // Initial value
|
||||||
|
vluint64_t m_hash;
|
||||||
|
|
||||||
|
inline void hashC(uint8_t c) {
|
||||||
|
m_hash ^= c;
|
||||||
|
// Below is faster than m_hash *= 0x100000001b3ULL;
|
||||||
|
m_hash += ((m_hash << 1) + (m_hash << 4) + (m_hash << 5)
|
||||||
|
+ (m_hash << 7) + (m_hash << 8) + (m_hash << 40));
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
VHashFnv() : m_hash(FNV1_64_INIT) {}
|
||||||
|
~VHashFnv() {}
|
||||||
|
|
||||||
|
vluint64_t value() const { return m_hash; }
|
||||||
|
|
||||||
|
VHashFnv& hash(const void* bufp, size_t len) { // Memory
|
||||||
|
const uint8_t* bp = (const uint8_t*)bufp;
|
||||||
|
const uint8_t* be = bp + len;
|
||||||
|
while (bp < be) hashC((vluint64_t)*bp++);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
VHashFnv& hash(const char* strp) { // String
|
||||||
|
const uint8_t* sp = (const uint8_t*)strp;
|
||||||
|
while (*sp) hashC((vluint64_t)*sp++);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
VHashFnv& hash(const string& str) { return hash(str.c_str()); }
|
||||||
|
VHashFnv& hash(vluint64_t n) {
|
||||||
|
hashC(n>>0); hashC(n>>8); hashC(n>>16); hashC(n>>24);
|
||||||
|
hashC(n>>32); hashC(n>>40); hashC(n>>48); hashC(n>>56);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
VHashFnv& hash(uint32_t n) {
|
||||||
|
hashC(n>>0); hashC(n>>8); hashC(n>>16); hashC(n>>24);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
VHashFnv& hash(uint16_t n) {
|
||||||
|
hashC(n>>0); hashC(n>>8);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
VHashFnv& hash(uint8_t n) { hashC(n); return *this; }
|
||||||
|
VHashFnv& hash(int n) { hashC((vluint64_t)n); return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
|
||||||
|
#endif // guard
|
||||||
|
|
@ -666,7 +666,7 @@ private:
|
||||||
// We could use 64-bits of a MD5/SHA hash rather than a string here,
|
// We could use 64-bits of a MD5/SHA hash rather than a string here,
|
||||||
// but the compare is only done on first call then memoized, so it's not worth optimizing.
|
// but the compare is only done on first call then memoized, so it's not worth optimizing.
|
||||||
string stmt;
|
string stmt;
|
||||||
stmt += "static int __Vfuncnum = -1;\n";
|
stmt += "static int __Vfuncnum = -1;\n"; // Static doesn't need save-restore as if below will re-fill proper value
|
||||||
// First time init (faster than what the compiler does if we did a singleton
|
// First time init (faster than what the compiler does if we did a singleton
|
||||||
stmt += "if (VL_UNLIKELY(__Vfuncnum==-1)) { __Vfuncnum = Verilated::exportFuncNum(\""+nodep->cname()+"\"); }\n";
|
stmt += "if (VL_UNLIKELY(__Vfuncnum==-1)) { __Vfuncnum = Verilated::exportFuncNum(\""+nodep->cname()+"\"); }\n";
|
||||||
// If the find fails, it will throw an error
|
// If the find fails, it will throw an error
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
|
#include "V3String.h"
|
||||||
#include "V3Undriven.h"
|
#include "V3Undriven.h"
|
||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
|
|
||||||
|
|
@ -135,7 +136,7 @@ public:
|
||||||
bool unusedMatch(AstVar* nodep) {
|
bool unusedMatch(AstVar* nodep) {
|
||||||
const char* regexpp = v3Global.opt.unusedRegexp().c_str();
|
const char* regexpp = v3Global.opt.unusedRegexp().c_str();
|
||||||
if (!regexpp || !*regexpp) return false;
|
if (!regexpp || !*regexpp) return false;
|
||||||
return V3Options::wildmatch(nodep->prettyName().c_str(), regexpp);
|
return VString::wildmatch(nodep->prettyName().c_str(), regexpp);
|
||||||
}
|
}
|
||||||
void reportViolations() {
|
void reportViolations() {
|
||||||
// Combine bits into overall state
|
// Combine bits into overall state
|
||||||
|
|
|
||||||
|
|
@ -476,6 +476,7 @@ sub compile_vlt_flags {
|
||||||
$self->{sc} = 1 if ($checkflags =~ /-sc\b/);
|
$self->{sc} = 1 if ($checkflags =~ /-sc\b/);
|
||||||
$self->{sp} = 1 if ($checkflags =~ /-sp\b/);
|
$self->{sp} = 1 if ($checkflags =~ /-sp\b/);
|
||||||
$self->{trace} = 1 if ($opt_trace || $checkflags =~ /-trace\b/);
|
$self->{trace} = 1 if ($opt_trace || $checkflags =~ /-trace\b/);
|
||||||
|
$self->{savable} = 1 if ($checkflags =~ /-savable\b/);
|
||||||
$self->{coverage} = 1 if ($checkflags =~ /-coverage\b/);
|
$self->{coverage} = 1 if ($checkflags =~ /-coverage\b/);
|
||||||
|
|
||||||
my @verilator_flags = @{$param{verilator_flags}};
|
my @verilator_flags = @{$param{verilator_flags}};
|
||||||
|
|
@ -963,15 +964,39 @@ sub _make_main {
|
||||||
print $fh "#include \"systemc.h\"\n" if $self->sc;
|
print $fh "#include \"systemc.h\"\n" if $self->sc;
|
||||||
print $fh "#include \"systemperl.h\"\n" if $self->sp;
|
print $fh "#include \"systemperl.h\"\n" if $self->sp;
|
||||||
print $fh "#include \"verilated_vcd_c.h\"\n" if $self->{trace} && !$self->sp;
|
print $fh "#include \"verilated_vcd_c.h\"\n" if $self->{trace} && !$self->sp;
|
||||||
|
print $fh "#include \"verilated_save.h\"\n" if $self->{savable};
|
||||||
print $fh "#include \"SpTraceVcd.h\"\n" if $self->{trace} && $self->sp;
|
print $fh "#include \"SpTraceVcd.h\"\n" if $self->{trace} && $self->sp;
|
||||||
|
|
||||||
print $fh "$VM_PREFIX * topp;\n";
|
print $fh "$VM_PREFIX * topp;\n";
|
||||||
if (!$self->sc_or_sp) {
|
if (!$self->sc_or_sp) {
|
||||||
print $fh "unsigned int main_time = false;\n";
|
print $fh "vluint64_t main_time = false;\n";
|
||||||
print $fh "double sc_time_stamp () {\n";
|
print $fh "double sc_time_stamp () {\n";
|
||||||
print $fh " return main_time;\n";
|
print $fh " return main_time;\n";
|
||||||
print $fh "}\n";
|
print $fh "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($self->{savable}) {
|
||||||
|
$fh->print("\n");
|
||||||
|
$fh->print("void save_model(const char* filenamep) {\n");
|
||||||
|
$fh->print(" VL_PRINTF(\"Saving model to '%s'\\n\", filenamep);\n");
|
||||||
|
$fh->print(" VerilatedSave os;\n");
|
||||||
|
$fh->print(" os.open(filenamep);\n");
|
||||||
|
$fh->print(" os << main_time;\n");
|
||||||
|
$fh->print(" os << *topp;\n");
|
||||||
|
$fh->print(" os.close();\n");
|
||||||
|
$fh->print("}\n");
|
||||||
|
$fh->print("\n");
|
||||||
|
$fh->print("void restore_model(const char* filenamep) {\n");
|
||||||
|
$fh->print(" VL_PRINTF(\"Restoring model from '%s'\\n\", filenamep);\n");
|
||||||
|
$fh->print(" VerilatedRestore os;\n");
|
||||||
|
$fh->print(" os.open(filenamep);\n");
|
||||||
|
$fh->print(" os >> main_time;\n");
|
||||||
|
$fh->print(" os >> *topp;\n");
|
||||||
|
$fh->print(" os.close();\n");
|
||||||
|
$fh->print("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Main
|
||||||
if ($self->sc_or_sp) {
|
if ($self->sc_or_sp) {
|
||||||
print $fh "extern int sc_main(int argc, char **argv);\n";
|
print $fh "extern int sc_main(int argc, char **argv);\n";
|
||||||
print $fh "int sc_main(int argc, char **argv) {\n";
|
print $fh "int sc_main(int argc, char **argv) {\n";
|
||||||
|
|
@ -1017,9 +1042,24 @@ sub _make_main {
|
||||||
$fh->print("#endif\n");
|
$fh->print("#endif\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
print $fh " ${set}fastclk = false;\n" if $self->{inputs}{fastclk};
|
if ($self->{savable}) {
|
||||||
print $fh " ${set}clk = false;\n" if $self->{inputs}{clk};
|
$fh->print(" const char* save_time_strp = Verilated::commandArgsPlusMatch(\"save_time=\");\n");
|
||||||
|
$fh->print(" const char* save_restore_strp = Verilated::commandArgsPlusMatch(\"save_restore=\");\n");
|
||||||
|
$fh->print(" unsigned int save_time = !save_time_strp[0] ? 0 : atoi(save_time_strp+strlen(\"+save_time=\"));\n");
|
||||||
|
$fh->print(" unsigned int save_restore = !save_restore_strp[0] ? 0 : 1;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($self->{savable}) {
|
||||||
|
$fh->print(" if (save_restore) {\n");
|
||||||
|
$fh->print(" restore_model(\"$self->{obj_dir}/saved.vltsv\");\n");
|
||||||
|
$fh->print(" } else {\n");
|
||||||
|
} else {
|
||||||
|
$fh->print(" {\n");
|
||||||
|
}
|
||||||
|
print $fh " ${set}fastclk = false;\n" if $self->{inputs}{fastclk};
|
||||||
|
print $fh " ${set}clk = false;\n" if $self->{inputs}{clk};
|
||||||
_print_advance_time($self, $fh, 10);
|
_print_advance_time($self, $fh, 10);
|
||||||
|
print $fh " }\n";
|
||||||
|
|
||||||
print $fh " while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {\n";
|
print $fh " while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {\n";
|
||||||
for (my $i=0; $i<5; $i++) {
|
for (my $i=0; $i<5; $i++) {
|
||||||
|
|
@ -1032,6 +1072,13 @@ sub _make_main {
|
||||||
print $fh " ${set}clk=!${set}clk;\n";
|
print $fh " ${set}clk=!${set}clk;\n";
|
||||||
$action = 1;
|
$action = 1;
|
||||||
}
|
}
|
||||||
|
if ($self->{savable}) {
|
||||||
|
$fh->print(" if (sc_time_stamp() == save_time && save_time) {\n");
|
||||||
|
$fh->print(" save_model(\"$self->{obj_dir}/saved.vltsv\");\n");
|
||||||
|
$fh->print(" printf(\"Exiting after save_model\\n\");\n");
|
||||||
|
$fh->print(" exit(0);\n");
|
||||||
|
$fh->print(" }\n");
|
||||||
|
}
|
||||||
_print_advance_time($self, $fh, 1, $action);
|
_print_advance_time($self, $fh, 1, $action);
|
||||||
}
|
}
|
||||||
print $fh " }\n";
|
print $fh " }\n";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
|
||||||
|
compile (
|
||||||
|
v_flags2 => ["--savable"],
|
||||||
|
save_time => 500,
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>0,
|
||||||
|
all_run_flags => ['+save_time=500'],
|
||||||
|
);
|
||||||
|
|
||||||
|
-r "$Self->{obj_dir}/saved.vltsv" or $Self->error("Saved.vltsv not created\n");
|
||||||
|
|
||||||
|
execute (
|
||||||
|
all_run_flags => ['+save_restore=1'],
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2012 by Wilson Snyder.
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
/*verilator no_inline_module*/ // So we'll get hiearachy we can test
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
sub sub (/*AUTOINST*/
|
||||||
|
// Inputs
|
||||||
|
.clk (clk));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module sub (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
/*verilator no_inline_module*/ // So we'll get hiearachy we can test
|
||||||
|
|
||||||
|
integer cyc=0;
|
||||||
|
|
||||||
|
reg [127:0] save128;
|
||||||
|
reg [47:0] save48;
|
||||||
|
reg [1:0] save2;
|
||||||
|
reg [255:0] cycdone; // Make sure each cycle executes exactly once
|
||||||
|
reg [31:0] vec[2:1][2:1];
|
||||||
|
real r;
|
||||||
|
string s,s2;
|
||||||
|
|
||||||
|
// Test loop
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$write("[%0t] cyc==%0d\n",$time, cyc);
|
||||||
|
`endif
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
if (cycdone[cyc[7:0]]) $stop;
|
||||||
|
cycdone[cyc[7:0]] <= '1;
|
||||||
|
if (cyc==0) begin
|
||||||
|
// Setup
|
||||||
|
save128 <= 128'hc77bb9b3784ea0914afe43fb79d7b71e;
|
||||||
|
save48 <= 48'h4afe43fb79d7;
|
||||||
|
save2 <= 2'b10;
|
||||||
|
vec[1][1] <= 32'h0101;
|
||||||
|
vec[1][2] <= 32'h0102;
|
||||||
|
vec[2][1] <= 32'h0201;
|
||||||
|
vec[2][2] <= 32'h0202;
|
||||||
|
r <= 1.234;
|
||||||
|
s <= "hello";
|
||||||
|
end
|
||||||
|
if (cyc==1) begin
|
||||||
|
if ($test$plusargs("save_restore")!=0) begin
|
||||||
|
// Don't allow the restored model to run from time 0, it must run from a restore
|
||||||
|
$write("%%Error: didn't really restore\n");
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else if (cyc==99) begin
|
||||||
|
if (save128 !== 128'hc77bb9b3784ea0914afe43fb79d7b71e) $stop;
|
||||||
|
if (save48 !== 48'h4afe43fb79d7) $stop;
|
||||||
|
if (save2 !== 2'b10) $stop;
|
||||||
|
if (cycdone !== {{(256-99){1'b0}}, {99{1'b1}}}) $stop;
|
||||||
|
if (vec[1][1] !== 32'h0101) $stop;
|
||||||
|
if (vec[1][2] !== 32'h0102) $stop;
|
||||||
|
if (vec[2][1] !== 32'h0201) $stop;
|
||||||
|
if (vec[2][2] !== 32'h0202) $stop;
|
||||||
|
if (r != 1.234) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue