1 // -*- mode: C++; c-file-style: "cc-mode" -*-
2 //=============================================================================
3 //
4 // Code available from: https://verilator.org
5 //
6 // Copyright 2001-2021 by Wilson Snyder. This program is free software; you
7 // can redistribute it and/or modify it under the terms of either the GNU
8 // Lesser General Public License Version 3 or the Perl Artistic License
9 // Version 2.0.
10 // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
11 //
12 //=============================================================================
13 ///
14 /// \file
15 /// \brief Verilated tracing in VCD format header
16 ///
17 /// User wrapper code should use this header when creating VCD traces.
18 ///
19 //=============================================================================
20 
21 #ifndef VERILATOR_VERILATED_VCD_C_H_
22 #define VERILATOR_VERILATED_VCD_C_H_
23 
24 #include "verilated.h"
25 #include "verilated_trace.h"
26 
27 #include <map>
28 #include <string>
29 #include <vector>
30 
31 class VerilatedVcd;
32 
33 //=============================================================================
34 // VerilatedFile
35 /// Class representing a file to write to. These virtual methods can be
36 /// overrode for e.g. socket I/O.
37 
38 class VerilatedVcdFile VL_NOT_FINAL {
39 private:
40     int m_fd = 0;  // File descriptor we're writing to
41 public:
42     // METHODS
43     /// Construct a (as yet) closed file
44     VerilatedVcdFile() = default;
45     /// Close and destruct
46     virtual ~VerilatedVcdFile() = default;
47     /// Open a file with given filename
48     virtual bool open(const std::string& name) VL_MT_UNSAFE;
49     /// Close object's file
50     virtual void close() VL_MT_UNSAFE;
51     /// Write data to file (if it is open)
52     virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE;
53 };
54 
55 //=============================================================================
56 // VerilatedVcd
57 // Base class to create a Verilator VCD dump
58 // This is an internally used class - see VerilatedVcdC for what to call from applications
59 
60 class VerilatedVcd VL_NOT_FINAL : public VerilatedTrace<VerilatedVcd> {
61 private:
62     // Give the superclass access to private bits (to avoid virtual functions)
63     friend class VerilatedTrace<VerilatedVcd>;
64 
65     //=========================================================================
66     // VCD specific internals
67 
68     VerilatedVcdFile* m_filep;  // File we're writing to
69     bool m_fileNewed;  // m_filep needs destruction
70     bool m_isOpen = false;  // True indicates open file
71     bool m_evcd = false;  // True for evcd format
72     std::string m_filename;  // Filename we're writing to (if open)
73     vluint64_t m_rolloverMB = 0;  // MB of file size to rollover at
74     int m_modDepth = 0;  // Depth of module hierarchy
75 
76     char* m_wrBufp;  // Output buffer
77     const char* m_wrFlushp;  // Output buffer flush trigger location
78     char* m_writep;  // Write pointer into output buffer
79     vluint64_t m_wrChunkSize;  // Output buffer size
80     vluint64_t m_wroteBytes = 0;  // Number of bytes written to this file
81 
82     std::vector<char> m_suffixes;  // VCD line end string codes + metadata
83 
84     using NameMap = std::map<const std::string, const std::string>;
85     NameMap* m_namemapp = nullptr;  // List of names for the header
86 
87     void bufferResize(vluint64_t minsize);
88     void bufferFlush() VL_MT_UNSAFE_ONE;
bufferCheck()89     inline void bufferCheck() {
90         // Flush the write buffer if there's not enough space left for new information
91         // We only call this once per vector, so we need enough slop for a very wide "b###" line
92         if (VL_UNLIKELY(m_writep > m_wrFlushp)) bufferFlush();
93     }
94     void openNextImp(bool incFilename);
95     void closePrev();
96     void closeErr();
97     void makeNameMap();
98     void deleteNameMap();
99     void printIndent(int level_change);
100     void printStr(const char* str);
101     void printQuad(vluint64_t n);
102     void printTime(vluint64_t timeui);
103     void declare(vluint32_t code, const char* name, const char* wirep, bool array, int arraynum,
104                  bool tri, bool bussed, int msb, int lsb);
105 
106     void dumpHeader();
107 
108     static char* writeCode(char* writep, vluint32_t code);
109 
110     void finishLine(vluint32_t code, char* writep);
111 
112     // CONSTRUCTORS
113     VL_UNCOPYABLE(VerilatedVcd);
114 
115 protected:
116     //=========================================================================
117     // Implementation of VerilatedTrace interface
118 
119     // Implementations of protected virtual methods for VerilatedTrace
120     virtual void emitTimeChange(vluint64_t timeui) override;
121 
122     // Hooks called from VerilatedTrace
preFullDump()123     virtual bool preFullDump() override { return isOpen(); }
124     virtual bool preChangeDump() override;
125 
126     // Implementations of duck-typed methods for VerilatedTrace. These are
127     // called from only one place (namely full*) so always inline them.
128     inline void emitBit(vluint32_t code, CData newval);
129     inline void emitCData(vluint32_t code, CData newval, int bits);
130     inline void emitSData(vluint32_t code, SData newval, int bits);
131     inline void emitIData(vluint32_t code, IData newval, int bits);
132     inline void emitQData(vluint32_t code, QData newval, int bits);
133     inline void emitWData(vluint32_t code, const WData* newvalp, int bits);
134     inline void emitDouble(vluint32_t code, double newval);
135 
136 public:
137     //=========================================================================
138     // External interface to client code
139 
140     explicit VerilatedVcd(VerilatedVcdFile* filep = nullptr);
141     ~VerilatedVcd();
142 
143     // ACCESSORS
144     // Set size in megabytes after which new file should be created
rolloverMB(vluint64_t rolloverMB)145     void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB = rolloverMB; }
146 
147     // METHODS
148     // Open the file; call isOpen() to see if errors
149     void open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex);
150     // Open next data-only file
151     void openNext(bool incFilename) VL_MT_SAFE_EXCLUDES(m_mutex);
152     // Close the file
153     void close() VL_MT_SAFE_EXCLUDES(m_mutex);
154     // Flush any remaining data to this file
155     void flush() VL_MT_SAFE_EXCLUDES(m_mutex);
156     // Return if file is open
isOpen()157     bool isOpen() const VL_MT_SAFE { return m_isOpen; }
158 
159     //=========================================================================
160     // Internal interface to Verilator generated code
161 
162     void declBit(vluint32_t code, const char* name, bool array, int arraynum);
163     void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
164     void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
165     void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
166     void declDouble(vluint32_t code, const char* name, bool array, int arraynum);
167 
168 #ifdef VL_TRACE_VCD_OLD_API
169     //=========================================================================
170     // Note: These are only for testing for backward compatibility with foreign
171     // code and is not used by Verilator. Do not use these as there is no
172     // guarantee of functionality.
173 
174     void declTriBit(vluint32_t code, const char* name, bool array, int arraynum);
175     void declTriBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
176     void declTriQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb,
177                      int lsb);
178     void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb,
179                       int lsb);
180 
fullBit(vluint32_t * oldp,CData newval)181     void fullBit(vluint32_t* oldp, CData newval) { fullBit(oldp - this->oldp(0), newval); }
fullCData(vluint32_t * oldp,CData newval,int bits)182     void fullCData(vluint32_t* oldp, CData newval, int bits) {
183         fullBus(oldp - this->oldp(0), newval, bits);
184     }
fullSData(vluint32_t * oldp,SData newval,int bits)185     void fullSData(vluint32_t* oldp, SData newval, int bits) {
186         fullBus(oldp - this->oldp(0), newval, bits);
187     }
fullIData(vluint32_t * oldp,IData newval,int bits)188     void fullIData(vluint32_t* oldp, IData newval, int bits) {
189         fullBus(oldp - this->oldp(0), newval, bits);
190     }
fullQData(vluint32_t * oldp,QData newval,int bits)191     void fullQData(vluint32_t* oldp, QData newval, int bits) {
192         fullQuad(oldp - this->oldp(0), newval, bits);
193     }
fullWData(vluint32_t * oldp,const WData * newvalp,int bits)194     void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
195         fullArray(oldp - this->oldp(0), newvalp, bits);
196     }
fullDouble(vluint32_t * oldp,double newval)197     void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); }
198 
chgBit(vluint32_t * oldp,CData newval)199     inline void chgBit(vluint32_t* oldp, CData newval) { chgBit(oldp - this->oldp(0), newval); }
chgCData(vluint32_t * oldp,CData newval,int bits)200     inline void chgCData(vluint32_t* oldp, CData newval, int bits) {
201         chgBus(oldp - this->oldp(0), newval, bits);
202     }
chgSData(vluint32_t * oldp,SData newval,int bits)203     inline void chgSData(vluint32_t* oldp, SData newval, int bits) {
204         chgBus(oldp - this->oldp(0), newval, bits);
205     }
chgIData(vluint32_t * oldp,IData newval,int bits)206     inline void chgIData(vluint32_t* oldp, IData newval, int bits) {
207         chgBus(oldp - this->oldp(0), newval, bits);
208     }
chgQData(vluint32_t * oldp,QData newval,int bits)209     inline void chgQData(vluint32_t* oldp, QData newval, int bits) {
210         chgQuad(oldp - this->oldp(0), newval, bits);
211     }
chgWData(vluint32_t * oldp,const WData * newvalp,int bits)212     inline void chgWData(vluint32_t* oldp, const WData* newvalp, int bits) {
213         chgArray(oldp - this->oldp(0), newvalp, bits);
214     }
chgDouble(vluint32_t * oldp,double newval)215     inline void chgDouble(vluint32_t* oldp, double newval) {
216         chgDouble(oldp - this->oldp(0), newval);
217     }
218 
219     // Inside dumping routines, dump one signal, faster when not inlined
220     // due to code size reduction.
221     void fullBit(vluint32_t code, const vluint32_t newval);
222     void fullBus(vluint32_t code, const vluint32_t newval, int bits);
223     void fullQuad(vluint32_t code, const vluint64_t newval, int bits);
224     void fullArray(vluint32_t code, const vluint32_t* newvalp, int bits);
225     void fullArray(vluint32_t code, const vluint64_t* newvalp, int bits);
226     void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
227     void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
228     void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri, int bits);
229     void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
230                       int bits);
231     void fullDouble(vluint32_t code, const double newval);
232 
233     // Inside dumping routines, dump one signal if it has changed.
234     // We do want to inline these to avoid calls when the value did not change.
chgBit(vluint32_t code,const vluint32_t newval)235     inline void chgBit(vluint32_t code, const vluint32_t newval) {
236         const vluint32_t diff = oldp(code)[0] ^ newval;
237         if (VL_UNLIKELY(diff)) fullBit(code, newval);
238     }
chgBus(vluint32_t code,const vluint32_t newval,int bits)239     inline void chgBus(vluint32_t code, const vluint32_t newval, int bits) {
240         const vluint32_t diff = oldp(code)[0] ^ newval;
241         if (VL_UNLIKELY(diff)) {
242             if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) {
243                 fullBus(code, newval, bits);
244             }
245         }
246     }
chgQuad(vluint32_t code,const vluint64_t newval,int bits)247     inline void chgQuad(vluint32_t code, const vluint64_t newval, int bits) {
248         const vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval;
249         if (VL_UNLIKELY(diff)) {
250             if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
251                 fullQuad(code, newval, bits);
252             }
253         }
254     }
chgArray(vluint32_t code,const vluint32_t * newvalp,int bits)255     inline void chgArray(vluint32_t code, const vluint32_t* newvalp, int bits) {
256         for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
257             if (VL_UNLIKELY(oldp(code)[word] ^ newvalp[word])) {
258                 fullArray(code, newvalp, bits);
259                 return;
260             }
261         }
262     }
chgArray(vluint32_t code,const vluint64_t * newvalp,int bits)263     inline void chgArray(vluint32_t code, const vluint64_t* newvalp, int bits) {
264         for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) {
265             if (VL_UNLIKELY(*(reinterpret_cast<vluint64_t*>(oldp(code + 2 * word)))
266                             ^ newvalp[word])) {
267                 fullArray(code, newvalp, bits);
268                 return;
269             }
270         }
271     }
chgTriBit(vluint32_t code,const vluint32_t newval,const vluint32_t newtri)272     inline void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
273         const vluint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri));
274         if (VL_UNLIKELY(diff)) {
275             // Verilator 3.510 and newer provide clean input, so the below
276             // is only for back compatibility
277             if (VL_UNLIKELY(diff & 1)) {  // Change after clean?
278                 fullTriBit(code, newval, newtri);
279             }
280         }
281     }
chgTriBus(vluint32_t code,const vluint32_t newval,const vluint32_t newtri,int bits)282     inline void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri,
283                           int bits) {
284         const vluint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri));
285         if (VL_UNLIKELY(diff)) {
286             if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) {
287                 fullTriBus(code, newval, newtri, bits);
288             }
289         }
290     }
chgTriQuad(vluint32_t code,const vluint64_t newval,const vluint64_t newtri,int bits)291     inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri,
292                            int bits) {
293         const vluint64_t diff = (((*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval)
294                                  | ((*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) ^ newtri));
295         if (VL_UNLIKELY(diff)) {
296             if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
297                 fullTriQuad(code, newval, newtri, bits);
298             }
299         }
300     }
chgTriArray(vluint32_t code,const vluint32_t * newvalp,const vluint32_t * newtrip,int bits)301     inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
302                             int bits) {
303         for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
304             if (VL_UNLIKELY((oldp(code)[word * 2] ^ newvalp[word])
305                             | (oldp(code)[word * 2 + 1] ^ newtrip[word]))) {
306                 fullTriArray(code, newvalp, newtrip, bits);
307                 return;
308             }
309         }
310     }
chgDouble(vluint32_t code,const double newval)311     inline void chgDouble(vluint32_t code, const double newval) {
312         // cppcheck-suppress invalidPointerCast
313         if (VL_UNLIKELY((*(reinterpret_cast<double*>(oldp(code)))) != newval)) {
314             fullDouble(code, newval);
315         }
316     }
317 
318     // METHODS
319     // Old/standalone API only
evcd(bool flag)320     void evcd(bool flag) { m_evcd = flag; }
321 #endif  // VL_TRACE_VCD_OLD_API
322 };
323 
324 #ifndef DOXYGEN
325 // Declare specializations here they are used in VerilatedVcdC just below
326 template <> void VerilatedTrace<VerilatedVcd>::dump(vluint64_t timeui);
327 template <> void VerilatedTrace<VerilatedVcd>::set_time_unit(const char* unitp);
328 template <> void VerilatedTrace<VerilatedVcd>::set_time_unit(const std::string& unit);
329 template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const char* unitp);
330 template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const std::string& unit);
331 #endif  // DOXYGEN
332 
333 //=============================================================================
334 // VerilatedVcdC
335 /// Class representing a VCD dump file in C standalone (no SystemC)
336 /// simulations.  Also derived for use in SystemC simulations.
337 
338 class VerilatedVcdC VL_NOT_FINAL {
339     VerilatedVcd m_sptrace;  // Trace file being created
340 
341     // CONSTRUCTORS
342     VL_UNCOPYABLE(VerilatedVcdC);
343 
344 public:
345     /// Construct the dump. Optional argument is a preconstructed file.
346     explicit VerilatedVcdC(VerilatedVcdFile* filep = nullptr)
347         : m_sptrace{filep} {}
348     /// Destruct, flush, and close the dump
~VerilatedVcdC()349     ~VerilatedVcdC() { close(); }
350 
351 public:
352     // METHODS - User called
353 
354     /// Return if file is open
isOpen()355     bool isOpen() const VL_MT_SAFE { return m_sptrace.isOpen(); }
356     /// Open a new VCD file
357     /// This includes a complete header dump each time it is called,
358     /// just as if this object was deleted and reconstructed.
open(const char * filename)359     void open(const char* filename) VL_MT_SAFE { m_sptrace.open(filename); }
360     /// Continue a VCD dump by rotating to a new file name
361     /// The header is only in the first file created, this allows
362     /// "cat" to be used to combine the header plus any number of data files.
363     void openNext(bool incFilename = true) VL_MT_SAFE { m_sptrace.openNext(incFilename); }
364     /// Set size in megabytes after which new file should be created
rolloverMB(size_t rolloverMB)365     void rolloverMB(size_t rolloverMB) VL_MT_SAFE { m_sptrace.rolloverMB(rolloverMB); }
366     /// Close dump
close()367     void close() VL_MT_SAFE { m_sptrace.close(); }
368     /// Flush dump
flush()369     void flush() VL_MT_SAFE { m_sptrace.flush(); }
370     /// Write one cycle of dump data
371     /// Call with the current context's time just after eval'ed,
372     /// e.g. ->dump(contextp->time())
dump(vluint64_t timeui)373     void dump(vluint64_t timeui) VL_MT_SAFE { m_sptrace.dump(timeui); }
374     /// Write one cycle of dump data - backward compatible and to reduce
375     /// conversion warnings.  It's better to use a vluint64_t time instead.
dump(double timestamp)376     void dump(double timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
dump(vluint32_t timestamp)377     void dump(vluint32_t timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
dump(int timestamp)378     void dump(int timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
379 
380     // METHODS - Internal/backward compatible
381     // \protectedsection
382 
383     // Set time units (s/ms, defaults to ns)
384     // Users should not need to call this, as for Verilated models, these
385     // propage from the Verilated default timeunit
set_time_unit(const char * unit)386     void set_time_unit(const char* unit) VL_MT_SAFE { m_sptrace.set_time_unit(unit); }
set_time_unit(const std::string & unit)387     void set_time_unit(const std::string& unit) VL_MT_SAFE { m_sptrace.set_time_unit(unit); }
388     // Set time resolution (s/ms, defaults to ns)
389     // Users should not need to call this, as for Verilated models, these
390     // propage from the Verilated default timeprecision
set_time_resolution(const char * unit)391     void set_time_resolution(const char* unit) VL_MT_SAFE { m_sptrace.set_time_resolution(unit); }
set_time_resolution(const std::string & unit)392     void set_time_resolution(const std::string& unit) VL_MT_SAFE {
393         m_sptrace.set_time_resolution(unit);
394     }
395 
396     // Internal class access
spTrace()397     inline VerilatedVcd* spTrace() { return &m_sptrace; }
398 
399 #ifdef VL_TRACE_VCD_OLD_API
400     //=========================================================================
401     // Note: These are only for testing for backward compatibility with foreign
402     // code and is not used by Verilator. Do not use these as there is no
403     // guarantee of functionality.
404 
405     // Use evcd format
evcd(bool flag)406     void evcd(bool flag) VL_MT_UNSAFE_ONE { m_sptrace.evcd(flag); }
407 #endif
408 };
409 
410 #endif  // guard
411