2012-08-27 01:13:47 +00:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
//=============================================================================
|
|
|
|
//
|
|
|
|
// THIS MODULE IS PUBLICLY LICENSED
|
|
|
|
//
|
2019-01-04 00:17:22 +00:00
|
|
|
// Copyright 2001-2019 by Wilson Snyder. This program is free software;
|
2012-08-27 01:13:47 +00:00
|
|
|
// 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
|
|
|
|
///
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
#include "verilatedos.h"
|
|
|
|
#include "verilated.h"
|
|
|
|
#include "verilated_save.h"
|
|
|
|
|
|
|
|
#include <cerrno>
|
2018-10-14 11:04:18 +00:00
|
|
|
#include <fcntl.h>
|
2012-08-27 01:13:47 +00:00
|
|
|
|
|
|
|
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
|
|
|
# include <io.h>
|
|
|
|
#else
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2018-11-29 00:59:10 +00:00
|
|
|
#ifndef O_LARGEFILE // For example on WIN32
|
2012-11-14 01:36:20 +00:00
|
|
|
# define O_LARGEFILE 0
|
|
|
|
#endif
|
|
|
|
#ifndef O_NONBLOCK
|
|
|
|
# define O_NONBLOCK 0
|
|
|
|
#endif
|
2018-10-14 22:39:33 +00:00
|
|
|
#ifndef O_CLOEXEC
|
|
|
|
# define O_CLOEXEC 0
|
|
|
|
#endif
|
2012-11-14 01:36:20 +00:00
|
|
|
|
2012-08-27 01:13:47 +00:00
|
|
|
// CONSTANTS
|
2018-11-29 00:59:10 +00:00
|
|
|
static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n"; ///< Value of first bytes of each file
|
|
|
|
static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
|
2012-08-27 01:13:47 +00:00
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
//=============================================================================
|
|
|
|
//=============================================================================
|
|
|
|
// Searalization
|
|
|
|
|
2018-08-25 13:52:45 +00:00
|
|
|
bool VerilatedDeserialize::readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
2012-08-27 01:13:47 +00:00
|
|
|
bufferCheck();
|
2018-10-14 22:39:33 +00:00
|
|
|
const vluint8_t* __restrict dp = static_cast<const vluint8_t* __restrict>(datap);
|
2012-08-27 01:13:47 +00:00
|
|
|
vluint8_t miss = 0;
|
|
|
|
while (size--) {
|
|
|
|
miss |= (*dp++ ^ *m_cp++);
|
|
|
|
}
|
|
|
|
return (miss!=0);
|
|
|
|
}
|
|
|
|
|
2018-08-25 13:52:45 +00:00
|
|
|
VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
2012-08-27 01:13:47 +00:00
|
|
|
if (VL_UNLIKELY(readDiffers(datap,size))) {
|
2017-09-23 11:32:37 +00:00
|
|
|
std::string fn = filename();
|
2017-10-07 19:01:19 +00:00
|
|
|
std::string msg = std::string("Can't deserialize save-restore file as was made from different model");
|
2017-10-19 23:40:51 +00:00
|
|
|
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
2012-08-27 01:13:47 +00:00
|
|
|
close();
|
|
|
|
}
|
|
|
|
return *this; // For function chaining
|
|
|
|
}
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedSerialize::header() VL_MT_UNSAFE_ONE {
|
2012-08-27 01:13:47 +00:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
2012-08-27 01:13:47 +00:00
|
|
|
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
|
|
|
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
2017-09-23 11:32:37 +00:00
|
|
|
std::string fn = filename();
|
2017-10-07 19:01:19 +00:00
|
|
|
std::string msg = std::string("Can't deserialize; file has wrong header signature");
|
2017-10-19 23:40:51 +00:00
|
|
|
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
2012-08-27 01:13:47 +00:00
|
|
|
close();
|
|
|
|
}
|
|
|
|
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
|
|
|
|
}
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedSerialize::trailer() VL_MT_UNSAFE_ONE {
|
2012-08-27 01:13:47 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
2012-08-27 01:13:47 +00:00
|
|
|
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
|
|
|
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
|
2017-09-23 11:32:37 +00:00
|
|
|
std::string fn = filename();
|
2017-10-07 19:01:19 +00:00
|
|
|
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature");
|
2017-10-19 23:40:51 +00:00
|
|
|
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
2012-08-27 01:13:47 +00:00
|
|
|
close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
//=============================================================================
|
|
|
|
//=============================================================================
|
|
|
|
// Opening/Closing
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
|
|
|
m_assertOne.check();
|
2012-08-27 01:13:47 +00:00
|
|
|
if (isOpen()) return;
|
2017-10-25 02:56:58 +00:00
|
|
|
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n",filenamep););
|
2012-08-27 01:13:47 +00:00
|
|
|
|
|
|
|
if (filenamep[0]=='|') {
|
2018-11-29 00:59:10 +00:00
|
|
|
assert(0); // Not supported yet.
|
2012-08-27 01:13:47 +00:00
|
|
|
} else {
|
2013-02-03 18:27:37 +00:00
|
|
|
// cppcheck-suppress duplicateExpression
|
2018-10-14 22:39:33 +00:00
|
|
|
m_fd = ::open(filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC
|
2018-08-25 13:52:45 +00:00
|
|
|
, 0666);
|
2012-08-27 01:13:47 +00:00
|
|
|
if (m_fd<0) {
|
|
|
|
// User code can check isOpen()
|
|
|
|
m_isOpen = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_isOpen = true;
|
|
|
|
m_filename = filenamep;
|
|
|
|
m_cp = m_bufp;
|
|
|
|
header();
|
|
|
|
}
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
|
|
|
m_assertOne.check();
|
2012-08-27 01:13:47 +00:00
|
|
|
if (isOpen()) return;
|
2017-10-25 02:56:58 +00:00
|
|
|
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n",filenamep););
|
2012-08-27 01:13:47 +00:00
|
|
|
|
|
|
|
if (filenamep[0]=='|') {
|
2018-11-29 00:59:10 +00:00
|
|
|
assert(0); // Not supported yet.
|
2012-08-27 01:13:47 +00:00
|
|
|
} else {
|
2013-02-03 18:27:37 +00:00
|
|
|
// cppcheck-suppress duplicateExpression
|
2018-10-14 22:39:33 +00:00
|
|
|
m_fd = ::open(filenamep, O_CREAT|O_RDONLY|O_LARGEFILE|O_CLOEXEC
|
2018-08-25 13:52:45 +00:00
|
|
|
, 0666);
|
2012-08-27 01:13:47 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedSave::close() VL_MT_UNSAFE_ONE {
|
2012-08-27 01:13:47 +00:00
|
|
|
if (!isOpen()) return;
|
|
|
|
trailer();
|
|
|
|
flush();
|
|
|
|
m_isOpen = false;
|
|
|
|
::close(m_fd); // May get error, just ignore it
|
|
|
|
}
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedRestore::close() VL_MT_UNSAFE_ONE {
|
2012-08-27 01:13:47 +00:00
|
|
|
if (!isOpen()) return;
|
|
|
|
trailer();
|
|
|
|
flush();
|
|
|
|
m_isOpen = false;
|
|
|
|
::close(m_fd); // May get error, just ignore it
|
|
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
// Buffer management
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
|
|
|
|
m_assertOne.check();
|
2012-08-27 01:13:47 +00:00
|
|
|
if (VL_UNLIKELY(!isOpen())) return;
|
|
|
|
vluint8_t* wp = m_bufp;
|
|
|
|
while (1) {
|
|
|
|
ssize_t remaining = (m_cp - wp);
|
|
|
|
if (remaining==0) break;
|
|
|
|
errno = 0;
|
2018-08-25 13:52:45 +00:00
|
|
|
ssize_t got = ::write(m_fd, wp, remaining);
|
2012-08-27 01:13:47 +00:00
|
|
|
if (got>0) {
|
|
|
|
wp += got;
|
|
|
|
} else if (got < 0) {
|
|
|
|
if (errno != EAGAIN && errno != EINTR) {
|
|
|
|
// write failed, presume error (perhaps out of disk space)
|
2017-09-23 11:32:37 +00:00
|
|
|
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
2017-10-19 23:40:51 +00:00
|
|
|
VL_FATAL_MT("",0,"",msg.c_str());
|
2012-08-27 01:13:47 +00:00
|
|
|
close();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-29 00:59:10 +00:00
|
|
|
m_cp = m_bufp; // Reset buffer
|
2012-08-27 01:13:47 +00:00
|
|
|
}
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
|
|
|
|
m_assertOne.check();
|
2012-08-27 01:13:47 +00:00
|
|
|
if (VL_UNLIKELY(!isOpen())) return;
|
|
|
|
// Move remaining characters down to start of buffer. (No memcpy, overlaps allowed)
|
|
|
|
vluint8_t* rp = m_bufp;
|
2015-12-15 00:58:22 +00:00
|
|
|
for (vluint8_t* sp=m_cp; sp < m_endp;) *rp++ = *sp++; // Overlaps
|
2012-08-27 01:13:47 +00:00
|
|
|
m_endp = m_bufp + (m_endp - m_cp);
|
2018-11-29 00:59:10 +00:00
|
|
|
m_cp = m_bufp; // Reset buffer
|
2017-09-11 23:18:58 +00:00
|
|
|
// Read into buffer starting at m_endp
|
2012-08-27 01:13:47 +00:00
|
|
|
while (1) {
|
|
|
|
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
|
|
|
|
if (remaining==0) break;
|
|
|
|
errno = 0;
|
2018-08-25 13:52:45 +00:00
|
|
|
ssize_t got = ::read(m_fd, m_endp, remaining);
|
2012-08-27 01:13:47 +00:00
|
|
|
if (got>0) {
|
|
|
|
m_endp += got;
|
|
|
|
} else if (got < 0) {
|
|
|
|
if (errno != EAGAIN && errno != EINTR) {
|
|
|
|
// write failed, presume error (perhaps out of disk space)
|
2017-09-23 11:32:37 +00:00
|
|
|
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
2017-10-19 23:40:51 +00:00
|
|
|
VL_FATAL_MT("",0,"",msg.c_str());
|
2012-08-27 01:13:47 +00:00
|
|
|
close();
|
|
|
|
break;
|
2018-11-29 00:59:10 +00:00
|
|
|
}
|
|
|
|
} else { // got==0, EOF
|
|
|
|
// Fill buffer from here to end with NULLs so reader's don't
|
|
|
|
// need to check eof each character.
|
2012-08-27 01:13:47 +00:00
|
|
|
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
// Serialization of types
|
|
|
|
|
|
|
|
|