vcd.cc revision 13245
1/* 2 * Copyright 2018 Google, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer; 8 * redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution; 11 * neither the name of the copyright holders nor the names of its 12 * contributors may be used to endorse or promote products derived from 13 * this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Authors: Gabe Black 28 */ 29 30#include "systemc/utils/vcd.hh" 31 32#include <ctime> 33#include <iomanip> 34 35#include "base/bitfield.hh" 36#include "base/cprintf.hh" 37#include "base/logging.hh" 38#include "systemc/core/scheduler.hh" 39#include "systemc/ext/core/sc_event.hh" 40#include "systemc/ext/core/sc_main.hh" 41#include "systemc/ext/core/sc_time.hh" 42#include "systemc/ext/dt/bit/sc_bv_base.hh" 43#include "systemc/ext/dt/bit/sc_logic.hh" 44#include "systemc/ext/dt/bit/sc_lv_base.hh" 45#include "systemc/ext/dt/fx/sc_fxnum.hh" 46#include "systemc/ext/dt/fx/sc_fxval.hh" 47#include "systemc/ext/dt/int/sc_int_base.hh" 48#include "systemc/ext/dt/int/sc_signed.hh" 49#include "systemc/ext/dt/int/sc_uint_base.hh" 50#include "systemc/ext/dt/int/sc_unsigned.hh" 51#include "systemc/ext/utils/functions.hh" 52 53namespace sc_gem5 54{ 55 56namespace 57{ 58 59std::string 60cleanName(std::string name) 61{ 62 for (int i = 0; i < name.length(); i++) { 63 if (name[i] == '[') 64 name[i] = '('; 65 else if (name[i] == ']') 66 name[i] = ')'; 67 } 68 return name; 69} 70 71} // anonymous namespace 72 73class VcdTraceValBase : public TraceValBase 74{ 75 protected: 76 std::string _vcdName; 77 78 const char * 79 stripLeadingBits(const char *orig) 80 { 81 const char first = orig[0]; 82 83 if (first != 'z' && first != 'x' && first != '0') 84 return orig; 85 86 const char *res = orig; 87 while (*++res == first) {} 88 89 if (first != '0' || *res != '1') 90 res--; 91 92 return res; 93 } 94 95 char 96 scLogicToVcdState(char in) 97 { 98 switch (in) { 99 case 'U': 100 case 'X': 101 case 'W': 102 case 'D': 103 return 'x'; 104 case '0': 105 case 'L': 106 return '0'; 107 case '1': 108 case 'H': 109 return '1'; 110 case 'Z': 111 return 'z'; 112 default: 113 return '?'; 114 } 115 } 116 117 void 118 printVal(std::ostream &os, const std::string &rep) 119 { 120 switch (width()) { 121 case 0: 122 return; 123 case 1: 124 os << rep << vcdName() << std::endl;; 125 return; 126 default: 127 os << "b" << stripLeadingBits(rep.c_str()) << " " << 128 vcdName() << std::endl; 129 return; 130 } 131 } 132 133 public: 134 VcdTraceValBase(int width) : TraceValBase(width) {} 135 ~VcdTraceValBase() {} 136 137 void vcdName(const std::string &vcd_name) { _vcdName = vcd_name; } 138 const std::string &vcdName() { return _vcdName; } 139 virtual std::string vcdType() { return "wire"; } 140 141 virtual void output(std::ostream &os) = 0; 142}; 143 144void 145VcdTraceScope::addValue(const std::string &name, VcdTraceValBase *value) 146{ 147 size_t pos = name.find_first_of('.'); 148 if (pos == std::string::npos) { 149 values.emplace_back(name, value); 150 } else { 151 std::string sname = name.substr(0, pos); 152 auto it = scopes.find(sname); 153 if (it == scopes.end()) 154 it = scopes.emplace(sname, new VcdTraceScope).first; 155 it->second->addValue(name.substr(pos + 1), value); 156 } 157} 158 159void 160VcdTraceScope::output(const std::string &name, std::ostream &os) 161{ 162 os << "$scope module " << name << " $end" << std::endl; 163 164 for (auto &p: values) { 165 const std::string &name = p.first; 166 VcdTraceValBase *value = p.second; 167 168 int w = value->width(); 169 if (w <= 0) { 170 std::string msg = csprintf("'%s' has 0 bits", name); 171 // The typo in this error message is intentional to match the 172 // Accellera output. 173 SC_REPORT_ERROR("(E710) object cannot not be traced", msg.c_str()); 174 return; 175 } 176 177 std::string clean_name = cleanName(name); 178 if (w == 1) { 179 ccprintf(os, "$var %s % 3d %s %s $end\n", 180 value->vcdType(), w, value->vcdName(), clean_name); 181 } else { 182 ccprintf(os, "$var %s % 3d %s %s [%d:0] $end\n", 183 value->vcdType(), w, value->vcdName(), clean_name, w - 1); 184 } 185 } 186 187 for (auto &p: scopes) 188 p.second->output(p.first, os); 189 190 os << "$upscope $end" << std::endl; 191} 192 193template <typename T> 194class VcdTraceVal : public TraceVal<T, VcdTraceValBase> 195{ 196 public: 197 typedef T TracedType; 198 199 VcdTraceVal(const T* t, const std::string &vcd_name, int width) : 200 TraceVal<T, VcdTraceValBase>(t, width) 201 { 202 this->vcdName(vcd_name); 203 } 204}; 205 206std::string 207VcdTraceFile::nextSignalName() 208{ 209 std::string name(_nextName); 210 211 bool carry = false; 212 int pos = NextNameChars - 1; 213 do { 214 carry = (_nextName[pos] == 'z'); 215 if (carry) 216 _nextName[pos--] = 'a'; 217 else 218 _nextName[pos--]++; 219 } while (carry && pos >= 0); 220 221 return name; 222} 223 224void 225VcdTraceFile::initialize() 226{ 227 finalizeTime(); 228 229 // Date. 230 stream() << "$date" << std::endl; 231 time_t long_time; 232 time(&long_time); 233 struct tm *p_tm = localtime(&long_time); 234 stream() << std::put_time(p_tm, " %b %d, %Y %H:%M:%S\n"); 235 stream() << "$end" << std::endl << std::endl; 236 237 // Version. 238 stream() << "$version" << std::endl; 239 stream() << " " << ::sc_core::sc_version() << std::endl; 240 stream() << "$end" << std::endl << std::endl; 241 242 // Timescale. 243 stream() << "$timescale" << std::endl; 244 stream() << " " << ::sc_core::sc_time::from_value(timeUnitTicks) << 245 std::endl; 246 stream() << "$end" << std::endl << std::endl; 247 248 for (auto tv: traceVals) 249 tv->finalize(); 250 251 topScope.output("SystemC", stream()); 252 253 stream() << "$enddefinitions $end" << std::endl << std::endl; 254 255 Tick now = scheduler.getCurTick(); 256 257 std::string timedump_comment = 258 csprintf("All initial values are dumped below at time " 259 "%g sec = %g timescale units.", 260 static_cast<double>(now) / SimClock::Float::s, 261 static_cast<double>(now / timeUnitTicks)); 262 writeComment(timedump_comment); 263 264 lastPrintedTime = now / timeUnitTicks; 265 266 stream() << "$dumpvars" << std::endl; 267 for (auto tv: traceVals) 268 tv->output(stream()); 269 stream() << "$end" << std::endl << std::endl; 270 271 initialized = true; 272} 273 274VcdTraceFile::~VcdTraceFile() 275{ 276 for (auto tv: traceVals) 277 delete tv; 278 traceVals.clear(); 279 280 if (timeUnitTicks) 281 ccprintf(stream(), "#%u\n", scheduler.getCurTick() / timeUnitTicks); 282} 283 284void 285VcdTraceFile::trace(bool delta) 286{ 287 if (!delta) 288 deltasAtNow = 0; 289 290 uint64_t deltaOffset = deltasAtNow; 291 292 if (delta) 293 deltaOffset = deltasAtNow++; 294 295 if (_traceDeltas != delta) 296 return; 297 298 if (!initialized) { 299 initialize(); 300 return; 301 } 302 303 Tick now = scheduler.getCurTick() / timeUnitTicks + deltaOffset; 304 305 if (now <= lastPrintedTime) { 306 // TODO warn about reversed time? 307 return; 308 } 309 310 bool time_printed = false; 311 for (auto tv: traceVals) { 312 if (tv->check()) { 313 if (!time_printed) { 314 lastPrintedTime = now; 315 ccprintf(stream(), "#%u\n", now); 316 time_printed = true; 317 } 318 319 tv->output(stream()); 320 } 321 } 322 if (time_printed) 323 stream() << std::endl; 324} 325 326class VcdTraceValBool : public VcdTraceVal<bool> 327{ 328 public: 329 using VcdTraceVal<bool>::VcdTraceVal; 330 331 void 332 output(std::ostream &os) override 333 { 334 printVal(os, this->value() ? "1" : "0"); 335 } 336}; 337 338void 339VcdTraceFile::addTraceVal(const bool *v, const std::string &name) 340{ 341 addNewTraceVal<VcdTraceValBool>(v, name); 342} 343 344template <typename T> 345class VcdTraceValFloat : public VcdTraceVal<T> 346{ 347 public: 348 using VcdTraceVal<T>::VcdTraceVal; 349 350 std::string vcdType() override { return "real"; } 351 352 void 353 output(std::ostream &os) override 354 { 355 ccprintf(os, "r%.16g %s\n", this->value(), this->vcdName()); 356 } 357}; 358 359void 360VcdTraceFile::addTraceVal(const float *v, const std::string &name) 361{ 362 addNewTraceVal<VcdTraceValFloat<float>>(v, name); 363} 364void 365VcdTraceFile::addTraceVal(const double *v, const std::string &name) 366{ 367 addNewTraceVal<VcdTraceValFloat<double>>(v, name); 368} 369 370class VcdTraceValScLogic : public VcdTraceVal<sc_dt::sc_logic> 371{ 372 public: 373 using VcdTraceVal<sc_dt::sc_logic>::VcdTraceVal; 374 375 void 376 output(std::ostream &os) override 377 { 378 char str[2] = { 379 scLogicToVcdState(value().to_char()), 380 '\0' 381 }; 382 printVal(os, str); 383 } 384}; 385 386void 387VcdTraceFile::addTraceVal(const sc_dt::sc_logic *v, const std::string &name) 388{ 389 addNewTraceVal<VcdTraceValScLogic>(v, name); 390} 391 392template <typename T> 393class VcdTraceValFinite : public VcdTraceVal<T> 394{ 395 public: 396 using VcdTraceVal<T>::VcdTraceVal; 397 398 void 399 finalize() override 400 { 401 VcdTraceVal<T>::finalize(); 402 this->_width = this->value().length(); 403 } 404 405 void 406 output(std::ostream &os) override 407 { 408 std::string str; 409 const int w = this->width(); 410 411 str.reserve(w); 412 for (int i = w - 1; i >= 0; i--) 413 str += this->value()[i].to_bool() ? '1' : '0'; 414 415 this->printVal(os, str); 416 } 417}; 418 419void 420VcdTraceFile::addTraceVal(const sc_dt::sc_int_base *v, 421 const std::string &name) 422{ 423 addNewTraceVal<VcdTraceValFinite<sc_dt::sc_int_base>>(v, name); 424} 425void 426VcdTraceFile::addTraceVal(const sc_dt::sc_uint_base *v, 427 const std::string &name) 428{ 429 addNewTraceVal<VcdTraceValFinite<sc_dt::sc_uint_base>>(v, name); 430} 431 432void 433VcdTraceFile::addTraceVal(const sc_dt::sc_signed *v, const std::string &name) 434{ 435 addNewTraceVal<VcdTraceValFinite<sc_dt::sc_signed>>(v, name); 436} 437void 438VcdTraceFile::addTraceVal(const sc_dt::sc_unsigned *v, 439 const std::string &name) 440{ 441 addNewTraceVal<VcdTraceValFinite<sc_dt::sc_unsigned>>(v, name); 442} 443 444template <typename T> 445class VcdTraceValLogic : public VcdTraceVal<T> 446{ 447 public: 448 using VcdTraceVal<T>::VcdTraceVal; 449 450 void 451 finalize() override 452 { 453 VcdTraceVal<T>::finalize(); 454 this->_width = this->value().length(); 455 } 456 457 void 458 output(std::ostream &os) override 459 { 460 this->printVal(os, this->value().to_string()); 461 } 462}; 463 464void 465VcdTraceFile::addTraceVal(const sc_dt::sc_bv_base *v, const std::string &name) 466{ 467 addNewTraceVal<VcdTraceValLogic<::sc_dt::sc_bv_base>>(v, name); 468} 469void 470VcdTraceFile::addTraceVal(const sc_dt::sc_lv_base *v, const std::string &name) 471{ 472 addNewTraceVal<VcdTraceValLogic<::sc_dt::sc_lv_base>>(v, name); 473} 474 475template <typename T> 476class VcdTraceValFxval : public VcdTraceVal<T> 477{ 478 public: 479 using VcdTraceVal<T>::VcdTraceVal; 480 481 std::string vcdType() override { return "real"; } 482 483 void 484 output(std::ostream &os) override 485 { 486 ccprintf(os, "r%.16g %s\n", 487 this->value().to_double(), this->vcdName()); 488 } 489}; 490 491void 492VcdTraceFile::addTraceVal(const sc_dt::sc_fxval *v, const std::string &name) 493{ 494 addNewTraceVal<VcdTraceValFxval<sc_dt::sc_fxval>>(v, name); 495} 496void 497VcdTraceFile::addTraceVal(const sc_dt::sc_fxval_fast *v, 498 const std::string &name) 499{ 500 addNewTraceVal<VcdTraceValFxval<sc_dt::sc_fxval_fast>>(v, name); 501} 502 503template <typename T> 504class VcdTraceValFxnum : public VcdTraceVal<T> 505{ 506 public: 507 using VcdTraceVal<T>::VcdTraceVal; 508 509 void 510 output(std::ostream &os) override 511 { 512 std::string str; 513 const int w = this->width(); 514 515 str.reserve(w); 516 for (int i = w - 1; i >= 0; i--) 517 str += this->value()[i] ? '1' : '0'; 518 519 this->printVal(os, str); 520 } 521}; 522 523void 524VcdTraceFile::addTraceVal(const sc_dt::sc_fxnum *v, const std::string &name) 525{ 526 addNewTraceVal<VcdTraceValFxnum<::sc_dt::sc_fxnum>>(v, name); 527} 528void 529VcdTraceFile::addTraceVal(const sc_dt::sc_fxnum_fast *v, 530 const std::string &name) 531{ 532 addNewTraceVal<VcdTraceValFxnum<::sc_dt::sc_fxnum_fast>>(v, name); 533} 534 535class VcdTraceValEvent : public VcdTraceVal<::sc_core::sc_event> 536{ 537 public: 538 using VcdTraceVal<::sc_core::sc_event>::VcdTraceVal; 539 540 std::string vcdType() override { return "event"; } 541 542 void 543 output(std::ostream &os) override 544 { 545 if (value()) 546 printVal(os, "1"); 547 else 548 os << std::endl; 549 } 550}; 551 552void 553VcdTraceFile::addTraceVal(const sc_core::sc_event *v, const std::string &name) 554{ 555 addNewTraceVal<VcdTraceValEvent>(v, name); 556} 557 558class VcdTraceValTime : public VcdTraceVal<::sc_core::sc_time> 559{ 560 private: 561 static const int TimeWidth = 64; 562 563 public: 564 using VcdTraceVal<::sc_core::sc_time>::VcdTraceVal; 565 566 std::string vcdType() override { return "time"; } 567 568 void 569 finalize() override 570 { 571 VcdTraceVal<::sc_core::sc_time>::finalize(); 572 _width = TimeWidth; 573 } 574 575 void 576 output(std::ostream &os) override 577 { 578 char str[TimeWidth + 1]; 579 str[TimeWidth] = '\0'; 580 581 const uint64_t val = value().value(); 582 for (int i = 0; i < TimeWidth; i++) 583 str[i] = ::bits(val, TimeWidth - i - 1) ? '1' : '0'; 584 585 printVal(os, str); 586 } 587}; 588void 589VcdTraceFile::addTraceVal(const sc_core::sc_time *v, const std::string &name) 590{ 591 addNewTraceVal<VcdTraceValTime>(v, name); 592} 593 594template <typename T> 595class VcdTraceValInt : public VcdTraceVal<T> 596{ 597 public: 598 using VcdTraceVal<T>::VcdTraceVal; 599 600 void 601 output(std::ostream &os) override 602 { 603 const int w = this->width(); 604 char str[w + 1]; 605 str[w] = '\0'; 606 607 const uint64_t val = 608 static_cast<uint64_t>(this->value()) & ::mask(sizeof(T) * 8); 609 610 if (::mask(w) < val) { 611 for (int i = 0; i < w; i++) 612 str[i] = 'x'; 613 } else { 614 for (int i = 0; i < w; i++) 615 str[i] = ::bits(val, w - i - 1) ? '1' : '0'; 616 } 617 618 this->printVal(os, str); 619 } 620}; 621 622void 623VcdTraceFile::addTraceVal(const unsigned char *v, const std::string &name, 624 int width) 625{ 626 addNewTraceVal<VcdTraceValInt<unsigned char>>(v, name, width); 627} 628void 629VcdTraceFile::addTraceVal(const char *v, const std::string &name, int width) 630{ 631 addNewTraceVal<VcdTraceValInt<char>>(v, name, width); 632} 633void 634VcdTraceFile::addTraceVal(const unsigned short *v, const std::string &name, 635 int width) 636{ 637 addNewTraceVal<VcdTraceValInt<unsigned short>>(v, name, width); 638} 639void 640VcdTraceFile::addTraceVal(const short *v, const std::string &name, int width) 641{ 642 addNewTraceVal<VcdTraceValInt<short>>(v, name, width); 643} 644void 645VcdTraceFile::addTraceVal(const unsigned int *v, const std::string &name, 646 int width) 647{ 648 addNewTraceVal<VcdTraceValInt<unsigned int>>(v, name, width); 649} 650void 651VcdTraceFile::addTraceVal(const int *v, const std::string &name, int width) 652{ 653 addNewTraceVal<VcdTraceValInt<int>>(v, name, width); 654} 655void 656VcdTraceFile::addTraceVal(const unsigned long *v, const std::string &name, 657 int width) 658{ 659 addNewTraceVal<VcdTraceValInt<unsigned long>>(v, name, width); 660} 661void 662VcdTraceFile::addTraceVal(const long *v, const std::string &name, int width) 663{ 664 addNewTraceVal<VcdTraceValInt<long>>(v, name, width); 665} 666 667void 668VcdTraceFile::addTraceVal(const sc_dt::int64 *v, const std::string &name, 669 int width) 670{ 671 addNewTraceVal<VcdTraceValInt<sc_dt::int64>>(v, name, width); 672} 673void 674VcdTraceFile::addTraceVal(const sc_dt::uint64 *v, const std::string &name, 675 int width) 676{ 677 addNewTraceVal<VcdTraceValInt<sc_dt::uint64>>(v, name, width); 678} 679 680void 681VcdTraceFile::addTraceVal(const unsigned int *v, const std::string &name, 682 const char **literals) 683{ 684 uint64_t count = 0; 685 while (*literals++) 686 count++; 687 688 int bits = 0; 689 while (count >> bits) 690 bits++; 691 692 addNewTraceVal<VcdTraceValInt<unsigned int>>(v, name, bits); 693} 694 695void 696VcdTraceFile::writeComment(const std::string &comment) 697{ 698 stream() << "$comment" << std::endl; 699 stream() << comment << std::endl; 700 stream() << "$end" << std::endl << std::endl; 701} 702 703} // namespace sc_gem5 704