mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
252 lines
9.3 KiB
C++
252 lines
9.3 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//=============================================================================
|
|
//
|
|
// THIS MODULE IS PUBLICLY LICENSED
|
|
//
|
|
// Copyright 2012-2018 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
|
|
///
|
|
//=============================================================================
|
|
|
|
#ifndef _VERILATED_SAVE_C_H_
|
|
#define _VERILATED_SAVE_C_H_ 1
|
|
|
|
#include "verilatedos.h"
|
|
|
|
#include <string>
|
|
|
|
//=============================================================================
|
|
// VerilatedSerialize - convert structures to a stream representation
|
|
// This class is not thread safe, it must be called by a single thread
|
|
|
|
class VerilatedSerialize {
|
|
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
|
|
std::string m_filename; ///< Filename, for error messages
|
|
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
|
|
|
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
|
inline static size_t bufferInsertSize() { return 16*1024; }
|
|
|
|
void header() VL_MT_UNSAFE_ONE;
|
|
void trailer() VL_MT_UNSAFE_ONE;
|
|
|
|
// CONSTRUCTORS
|
|
VL_UNCOPYABLE(VerilatedSerialize);
|
|
public:
|
|
VerilatedSerialize() {
|
|
m_isOpen = false;
|
|
m_bufp = new vluint8_t [bufferSize()];
|
|
m_cp = m_bufp;
|
|
}
|
|
virtual ~VerilatedSerialize() {
|
|
close();
|
|
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
|
}
|
|
// METHODS
|
|
bool isOpen() const { return m_isOpen; }
|
|
std::string filename() const { return m_filename; }
|
|
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
|
virtual void flush() VL_MT_UNSAFE_ONE {}
|
|
inline VerilatedSerialize& write(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
|
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
|
|
}
|
|
private:
|
|
VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
|
// Flush the write buffer if there's not enough space left for new information
|
|
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
|
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
|
|
flush();
|
|
}
|
|
return *this; // For function chaining
|
|
}
|
|
};
|
|
|
|
//=============================================================================
|
|
// VerilatedDeserial - load structures from a stream representation
|
|
// This class is not thread safe, it must be called by a single thread
|
|
|
|
class VerilatedDeserialize {
|
|
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
|
|
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
|
|
bool m_isOpen; ///< True indicates open file/stream
|
|
std::string m_filename; ///< Filename, for error messages
|
|
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
|
|
|
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
|
inline static size_t bufferInsertSize() { return 16*1024; }
|
|
|
|
virtual void fill() = 0;
|
|
void header() VL_MT_UNSAFE_ONE;
|
|
void trailer() VL_MT_UNSAFE_ONE;
|
|
|
|
// CONSTRUCTORS
|
|
VL_UNCOPYABLE(VerilatedDeserialize);
|
|
public:
|
|
VerilatedDeserialize() {
|
|
m_isOpen = false;
|
|
m_bufp = new vluint8_t [bufferSize()];
|
|
m_cp = m_bufp;
|
|
m_endp = NULL;
|
|
}
|
|
virtual ~VerilatedDeserialize() {
|
|
close();
|
|
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
|
}
|
|
// METHODS
|
|
bool isOpen() const { return m_isOpen; }
|
|
std::string filename() const { return m_filename; }
|
|
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
|
virtual void flush() VL_MT_UNSAFE_ONE {}
|
|
inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
|
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
|
|
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
|
|
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
|
VerilatedDeserialize& readAssert(vluint64_t data) VL_MT_UNSAFE_ONE {
|
|
return readAssert(&data, sizeof(data)); }
|
|
private:
|
|
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
|
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
|
// Flush the write buffer if there's not enough space left for new information
|
|
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
|
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
|
|
fill();
|
|
}
|
|
return *this; // For function chaining
|
|
}
|
|
};
|
|
|
|
//=============================================================================
|
|
// VerilatedSave - serialize to a file
|
|
// This class is not thread safe, it must be called by a single thread
|
|
|
|
class VerilatedSave : public VerilatedSerialize {
|
|
private:
|
|
int m_fd; ///< File descriptor we're writing to
|
|
|
|
public:
|
|
// CONSTRUCTORS
|
|
VerilatedSave() { m_fd=-1; }
|
|
virtual ~VerilatedSave() { close(); }
|
|
// METHODS
|
|
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
|
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
|
virtual void close() VL_MT_UNSAFE_ONE;
|
|
virtual void flush() VL_MT_UNSAFE_ONE;
|
|
};
|
|
|
|
//=============================================================================
|
|
// VerilatedRestore - deserialize from a file
|
|
// This class is not thread safe, it must be called by a single thread
|
|
|
|
class VerilatedRestore : public VerilatedDeserialize {
|
|
private:
|
|
int m_fd; ///< File descriptor we're writing to
|
|
|
|
public:
|
|
// CONSTRUCTORS
|
|
VerilatedRestore() { m_fd=-1; }
|
|
virtual ~VerilatedRestore() { close(); }
|
|
|
|
// METHODS
|
|
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
|
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
|
virtual void close() VL_MT_UNSAFE_ONE;
|
|
virtual void flush() VL_MT_UNSAFE_ONE {}
|
|
virtual void fill() VL_MT_UNSAFE_ONE;
|
|
};
|
|
|
|
//=============================================================================
|
|
|
|
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, std::string& rhs) {
|
|
vluint32_t len=rhs.length();
|
|
os<<len;
|
|
return os.write(rhs.data(), len);
|
|
}
|
|
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, std::string& rhs) {
|
|
vluint32_t len=0;
|
|
os>>len;
|
|
rhs.resize(len);
|
|
return os.read((void*)rhs.data(), len);
|
|
}
|
|
|
|
#endif // guard
|