File: verilated_vcd_c.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 (394 lines) | stat: -rw-r--r-- 17,294 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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2001-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 C++ Tracing in VCD Format
///
//=============================================================================
// SPDIFF_OFF

#ifndef _VERILATED_VCD_C_H_
#define _VERILATED_VCD_C_H_ 1

#include "verilated.h"
#include "verilated_trace.h"

#include <map>
#include <string>
#include <vector>

class VerilatedVcd;

// SPDIFF_ON
//=============================================================================
// VerilatedFile
/// File handling routines, which can be overrode for e.g. socket I/O

class VerilatedVcdFile {
private:
    int m_fd;  ///< File descriptor we're writing to
public:
    // METHODS
    VerilatedVcdFile()
        : m_fd(0) {}
    virtual ~VerilatedVcdFile() {}
    virtual bool open(const std::string& name) VL_MT_UNSAFE;
    virtual void close() VL_MT_UNSAFE;
    virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE;
};

//=============================================================================
// VerilatedVcd
/// Base class to create a Verilator VCD dump
/// This is an internally used class - see VerilatedVcdC for what to call from applications

class VerilatedVcd : public VerilatedTrace<VerilatedVcd> {
private:
    // Give the superclass access to private bits (to avoid virtual functions)
    friend class VerilatedTrace<VerilatedVcd>;

    //=========================================================================
    // VCD specific internals

    VerilatedVcdFile* m_filep;  ///< File we're writing to
    bool m_fileNewed;  ///< m_filep needs destruction
    bool m_isOpen;  ///< True indicates open file
    bool m_evcd;  ///< True for evcd format
    std::string m_filename;  ///< Filename we're writing to (if open)
    vluint64_t m_rolloverMB;  ///< MB of file size to rollover at
    int m_modDepth;  ///< Depth of module hierarchy

    char* m_wrBufp;  ///< Output buffer
    char* m_wrFlushp;  ///< Output buffer flush trigger location
    char* m_writep;  ///< Write pointer into output buffer
    vluint64_t m_wrChunkSize;  ///< Output buffer size
    vluint64_t m_wroteBytes;  ///< Number of bytes written to this file

    std::vector<char> m_suffixes;  ///< VCD line end string codes + metadata
    const char* m_suffixesp;  ///< Pointer to first element of above

    typedef std::map<std::string, std::string> NameMap;
    NameMap* m_namemapp;  ///< List of names for the header

    void bufferResize(vluint64_t minsize);
    void bufferFlush() VL_MT_UNSAFE_ONE;
    inline void 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_writep > m_wrFlushp)) { bufferFlush(); }
    }
    void closePrev();
    void closeErr();
    void openNext();
    void makeNameMap();
    void deleteNameMap();
    void printIndent(int level_change);
    void printStr(const char* str);
    void printQuad(vluint64_t n);
    void printTime(vluint64_t timeui);
    void declare(vluint32_t code, const char* name, const char* wirep, bool array, int arraynum,
                 bool tri, bool bussed, int msb, int lsb);

    void dumpHeader();

    char* writeCode(char* writep, vluint32_t code);

    void finishLine(vluint32_t code, char* writep);

    // CONSTRUCTORS
    VL_UNCOPYABLE(VerilatedVcd);

protected:
    //=========================================================================
    // Implementation of VerilatedTrace interface

    // Implementations of protected virtual methods for VerilatedTrace
    void emitTimeChange(vluint64_t timeui) VL_OVERRIDE;

    // Hooks called from VerilatedTrace
    bool preFullDump() VL_OVERRIDE { return isOpen(); }
    bool preChangeDump() VL_OVERRIDE;

    // Implementations of duck-typed methods for VerilatedTrace. These are
    // called from only one place (namely full*) so always inline them.
    inline void emitBit(vluint32_t code, CData newval);
    inline void emitCData(vluint32_t code, CData newval, int bits);
    inline void emitSData(vluint32_t code, SData newval, int bits);
    inline void emitIData(vluint32_t code, IData newval, int bits);
    inline void emitQData(vluint32_t code, QData newval, int bits);
    inline void emitWData(vluint32_t code, const WData* newvalp, int bits);
    inline void emitDouble(vluint32_t code, double newval);

public:
    //=========================================================================
    // External interface to client code

    explicit VerilatedVcd(VerilatedVcdFile* filep = NULL);
    ~VerilatedVcd();

    // ACCESSORS
    /// Set size in megabytes after which new file should be created
    void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB = rolloverMB; }

    // METHODS
    /// Open the file; call isOpen() to see if errors
    void open(const char* filename) VL_MT_UNSAFE_ONE;
    /// Open next data-only file
    void openNext(bool incFilename) VL_MT_UNSAFE_ONE;
    /// Close the file
    void close() VL_MT_UNSAFE_ONE;
    /// Flush any remaining data to this file
    void flush() VL_MT_UNSAFE_ONE;
    /// Is file open?
    bool isOpen() const { return m_isOpen; }

    //=========================================================================
    // Internal interface to Verilator generated code

    void declBit(vluint32_t code, const char* name, bool array, int arraynum);
    void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
    void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
    void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
    void declDouble(vluint32_t code, const char* name, bool array, int arraynum);

#ifdef VL_TRACE_VCD_OLD_API
    //=========================================================================
    // Note: These are only for testing for backward compatibility with foreign
    // code and is not used by Verilator. Do not use these as there is no
    // guarantee of functionality.

    void declTriBit(vluint32_t code, const char* name, bool array, int arraynum);
    void declTriBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
    void declTriQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb,
                     int lsb);
    void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb,
                      int lsb);

    void fullBit(vluint32_t* oldp, CData newval) { fullBit(oldp - this->oldp(0), newval); }
    void fullCData(vluint32_t* oldp, CData newval, int bits) {
        fullBus(oldp - this->oldp(0), newval, bits);
    }
    void fullSData(vluint32_t* oldp, SData newval, int bits) {
        fullBus(oldp - this->oldp(0), newval, bits);
    }
    void fullIData(vluint32_t* oldp, IData newval, int bits) {
        fullBus(oldp - this->oldp(0), newval, bits);
    }
    void fullQData(vluint32_t* oldp, QData newval, int bits) {
        fullQuad(oldp - this->oldp(0), newval, bits);
    }
    void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
        fullArray(oldp - this->oldp(0), newvalp, bits);
    }
    void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); }

    inline void chgBit(vluint32_t* oldp, CData newval) { chgBit(oldp - this->oldp(0), newval); }
    inline void chgCData(vluint32_t* oldp, CData newval, int bits) {
        chgBus(oldp - this->oldp(0), newval, bits);
    }
    inline void chgSData(vluint32_t* oldp, SData newval, int bits) {
        chgBus(oldp - this->oldp(0), newval, bits);
    }
    inline void chgIData(vluint32_t* oldp, IData newval, int bits) {
        chgBus(oldp - this->oldp(0), newval, bits);
    }
    inline void chgQData(vluint32_t* oldp, QData newval, int bits) {
        chgQuad(oldp - this->oldp(0), newval, bits);
    }
    inline void chgWData(vluint32_t* oldp, const WData* newvalp, int bits) {
        chgArray(oldp - this->oldp(0), newvalp, bits);
    }
    inline void chgDouble(vluint32_t* oldp, double newval) {
        chgDouble(oldp - this->oldp(0), newval);
    }

    /// Inside dumping routines, dump one signal, faster when not inlined
    /// due to code size reduction.
    void fullBit(vluint32_t code, const vluint32_t newval);
    void fullBus(vluint32_t code, const vluint32_t newval, int bits);
    void fullQuad(vluint32_t code, const vluint64_t newval, int bits);
    void fullArray(vluint32_t code, const vluint32_t* newvalp, int bits);
    void fullArray(vluint32_t code, const vluint64_t* newvalp, int bits);
    void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
    void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
    void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri, int bits);
    void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
                      int bits);
    void fullDouble(vluint32_t code, const double newval);

    /// Inside dumping routines, dump one signal if it has changed.
    /// We do want to inline these to avoid calls when the value did not change.
    inline void chgBit(vluint32_t code, const vluint32_t newval) {
        vluint32_t diff = oldp(code)[0] ^ newval;
        if (VL_UNLIKELY(diff)) fullBit(code, newval);
    }
    inline void chgBus(vluint32_t code, const vluint32_t newval, int bits) {
        vluint32_t diff = oldp(code)[0] ^ newval;
        if (VL_UNLIKELY(diff)) {
            if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) {
                fullBus(code, newval, bits);
            }
        }
    }
    inline void chgQuad(vluint32_t code, const vluint64_t newval, int bits) {
        vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval;
        if (VL_UNLIKELY(diff)) {
            if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
                fullQuad(code, newval, bits);
            }
        }
    }
    inline void chgArray(vluint32_t code, const vluint32_t* newvalp, int bits) {
        for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
            if (VL_UNLIKELY(oldp(code)[word] ^ newvalp[word])) {
                fullArray(code, newvalp, bits);
                return;
            }
        }
    }
    inline void chgArray(vluint32_t code, const vluint64_t* newvalp, int bits) {
        for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) {
            if (VL_UNLIKELY(*(reinterpret_cast<vluint64_t*>(oldp(code + 2 * word)))
                            ^ newvalp[word])) {
                fullArray(code, newvalp, bits);
                return;
            }
        }
    }
    inline void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
        vluint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri));
        if (VL_UNLIKELY(diff)) {
            // Verilator 3.510 and newer provide clean input, so the below
            // is only for back compatibility
            if (VL_UNLIKELY(diff & 1)) {  // Change after clean?
                fullTriBit(code, newval, newtri);
            }
        }
    }
    inline void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri,
                          int bits) {
        vluint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri));
        if (VL_UNLIKELY(diff)) {
            if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) {
                fullTriBus(code, newval, newtri, bits);
            }
        }
    }
    inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri,
                           int bits) {
        vluint64_t diff = (((*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval)
                           | ((*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) ^ newtri));
        if (VL_UNLIKELY(diff)) {
            if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
                fullTriQuad(code, newval, newtri, bits);
            }
        }
    }
    inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
                            int bits) {
        for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
            if (VL_UNLIKELY((oldp(code)[word * 2] ^ newvalp[word])
                            | (oldp(code)[word * 2 + 1] ^ newtrip[word]))) {
                fullTriArray(code, newvalp, newtrip, bits);
                return;
            }
        }
    }
    inline void chgDouble(vluint32_t code, const double newval) {
        // cppcheck-suppress invalidPointerCast
        if (VL_UNLIKELY((*(reinterpret_cast<double*>(oldp(code)))) != newval)) {
            fullDouble(code, newval);
        }
    }

    // METHODS
    // Old/standalone API only
    void evcd(bool flag) { m_evcd = flag; }
#endif  // VL_TRACE_VCD_OLD_API
};

// Declare specializations here they are used in VerilatedVcdC just below
template <> void VerilatedTrace<VerilatedVcd>::dump(vluint64_t timeui);
template <> void VerilatedTrace<VerilatedVcd>::set_time_unit(const char* unitp);
template <> void VerilatedTrace<VerilatedVcd>::set_time_unit(const std::string& unit);
template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const char* unitp);
template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const std::string& unit);

//=============================================================================
// VerilatedVcdC
/// Create a VCD dump file in C standalone (no SystemC) simulations.
/// Also derived for use in SystemC simulations.
/// Thread safety: Unless otherwise indicated, every function is VL_MT_UNSAFE_ONE

class VerilatedVcdC {
    VerilatedVcd m_sptrace;  ///< Trace file being created

    // CONSTRUCTORS
    VL_UNCOPYABLE(VerilatedVcdC);

public:
    explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL)
        : m_sptrace(filep) {}
    ~VerilatedVcdC() { close(); }
    /// Routines can only be called from one thread; allow next call from different thread
    void changeThread() { spTrace()->changeThread(); }

public:
    // ACCESSORS
    /// Is file open?
    bool isOpen() const { return m_sptrace.isOpen(); }
    // METHODS
    /// Open a new VCD file
    /// This includes a complete header dump each time it is called,
    /// just as if this object was deleted and reconstructed.
    void open(const char* filename) VL_MT_UNSAFE_ONE { m_sptrace.open(filename); }
    /// Continue a VCD dump by rotating to a new file name
    /// The header is only in the first file created, this allows
    /// "cat" to be used to combine the header plus any number of data files.
    void openNext(bool incFilename = true) VL_MT_UNSAFE_ONE { m_sptrace.openNext(incFilename); }
    /// Set size in megabytes after which new file should be created
    void rolloverMB(size_t rolloverMB) { m_sptrace.rolloverMB(rolloverMB); }
    /// Close dump
    void close() VL_MT_UNSAFE_ONE { m_sptrace.close(); }
    /// Flush dump
    void flush() VL_MT_UNSAFE_ONE { m_sptrace.flush(); }
    /// Write one cycle of dump data
    void dump(vluint64_t timeui) { m_sptrace.dump(timeui); }
    /// Write one cycle of dump data - backward compatible and to reduce
    /// conversion warnings.  It's better to use a vluint64_t time instead.
    void dump(double timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
    void dump(vluint32_t timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
    void dump(int timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
    /// Set time units (s/ms, defaults to ns)
    /// For Verilated models, these propage from the Verilated default --timeunit
    void set_time_unit(const char* unit) { m_sptrace.set_time_unit(unit); }
    void set_time_unit(const std::string& unit) { m_sptrace.set_time_unit(unit); }
    /// Set time resolution (s/ms, defaults to ns)
    /// For Verilated models, these propage from the Verilated default --timeunit
    void set_time_resolution(const char* unit) { m_sptrace.set_time_resolution(unit); }
    void set_time_resolution(const std::string& unit) { m_sptrace.set_time_resolution(unit); }

    /// Internal class access
    inline VerilatedVcd* spTrace() { return &m_sptrace; }

#ifdef VL_TRACE_VCD_OLD_API
    //=========================================================================
    // Note: These are only for testing for backward compatibility with foreign
    // code and is not used by Verilator. Do not use these as there is no
    // guarantee of functionality.
    /// Use evcd format
    void evcd(bool flag) VL_MT_UNSAFE_ONE { m_sptrace.evcd(flag); }
#endif
};

#endif  // guard