// -*- mode: C++; c-file-style: "cc-mode" -*- //============================================================================= // // THIS MODULE IS PUBLICLY LICENSED // // Copyright 2012-2017 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 //============================================================================= // 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; public: // CREATORS 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(const VerilatedSerialize&) VL_EQ_DELETE; ///< N/A, no copy constructor 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; public: // CREATORS 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: VerilatedDeserialize(const VerilatedDeserialize&) VL_EQ_DELETE; ///< N/A, no copy constructor 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: // CREATORS 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: // CREATORS 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<>(VerilatedDeserialize& os, std::string& rhs) { vluint32_t len=0; os>>len; rhs.resize(len); return os.read((void*)rhs.data(), len); } #endif // guard