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