File: verilated_save.h

package info (click to toggle)
verilator 4.038-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 29,596 kB
  • sloc: cpp: 90,585; perl: 15,101; ansic: 8,573; yacc: 3,626; lex: 1,616; makefile: 1,101; sh: 175; python: 145
file content (284 lines) | stat: -rw-r--r-- 10,624 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2000-2020 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.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//=============================================================================
///
/// \file
/// \brief Save-restore serialization of verilated modules
///
//=============================================================================

#ifndef _VERILATED_SAVE_C_H_
#define _VERILATED_SAVE_C_H_ 1

#include "verilatedos.h"
#include "verilated_heavy.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) VL_DO_CLEAR(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;
            for (; 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) VL_DO_CLEAR(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 = static_cast<vluint8_t* __restrict>(datap);
        while (size) {
            bufferCheck();
            size_t blk = size;
            if (blk > bufferInsertSize()) blk = bufferInsertSize();
            const vluint8_t* __restrict maxp = dp + blk;
            for (; 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() VL_OVERRIDE { close(); }
    // METHODS
    /// Open the file; call isOpen() to see if errors
    void open(const char* filenamep) VL_MT_UNSAFE_ONE;
    void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
    virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
    virtual void flush() VL_OVERRIDE 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() VL_OVERRIDE { close(); }

    // METHODS
    /// Open the file; call isOpen() to see if errors
    void open(const char* filenamep) VL_MT_UNSAFE_ONE;
    void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
    virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
    virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE {}
    virtual void fill() VL_OVERRIDE 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);
}
template <class T_Key, class T_Value>
VerilatedSerialize& operator<<(VerilatedSerialize& os, VlAssocArray<T_Key, T_Value>& rhs) {
    os << rhs.atDefault();
    vluint32_t len = rhs.size();
    os << len;
    for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = rhs.begin(); it != rhs.end();
         ++it) {
        T_Key index = it->first;  // Copy to get around const_iterator
        T_Value value = it->second;
        os << index << value;
    }
    return os;
}
template <class T_Key, class T_Value>
VerilatedDeserialize& operator>>(VerilatedDeserialize& os, VlAssocArray<T_Key, T_Value>& rhs) {
    os >> rhs.atDefault();
    vluint32_t len = 0;
    os >> len;
    rhs.clear();
    for (vluint32_t i = 0; i < len; ++i) {
        T_Key index;
        T_Value value;
        os >> index;
        os >> value;
        rhs.at(index) = value;
    }
    return os;
}

#endif  // Guard