HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
vcd_serializer.cpp
Go to the documentation of this file.
2 
3 #include "hal_core/netlist/net.h"
10 
11 #include <QCoreApplication>
12 #include <QDataStream>
13 #include <QDebug>
14 #include <QDir>
15 #include <QFileInfo>
16 #include <QRegularExpression>
17 #include <math.h>
18 
19 namespace hal
20 {
21 
22  const int maxErrorMessages = 3;
23 
24  VcdSerializerElement::VcdSerializerElement(int inx, const WaveData* wd) : mIndex(inx), mData(wd), mTime(0), mValue(SaleaeDataTuple::sReadError)
25  {
26  ;
27  }
28 
30  {
31  return mData->name();
32  }
33 
35  {
36  return mValue != SaleaeDataTuple::sReadError;
37  }
38 
40  {
42  mTime = 0;
43  }
44 
46  {
47  QByteArray retval;
48  int z = mIndex;
49  char firstChar = '!';
50  do
51  {
52  retval += (char)(firstChar + z % 92);
53  z /= 92;
54  if (z < 92)
55  {
56  firstChar = ' '; // most significant digit must be non-zero
57  }
58  } while (z > 0);
59  return retval;
60  }
61 
62  //----------------------------------
63  VcdSerializer::VcdSerializer(const QString& workdir, bool saleae_cli, QObject* parent) : QObject(parent), mSaleaeWriter(nullptr), mWorkdir(workdir), mLastProgress(-1)
64  {
65  if (!mWorkdir.isEmpty() && !saleae_cli)
66  {
67  QDir saleaeDir = QDir(mWorkdir).absoluteFilePath("saleae");
68  mSaleaeDirectoryFilename = saleaeDir.absoluteFilePath("saleae.json");
69  }
70  else
71  {
72  mSaleaeDirectoryFilename = workdir + "/saleae.json";
73  }
74  }
75 
76  void VcdSerializer::deleteFiles()
77  {
78  mSaleaeFiles.clear();
79  mAbbrevByName.clear();
80  memset(mErrorCount, 0, sizeof(mErrorCount));
81  }
82 
83  void VcdSerializer::writeVcdEvent(QFile& of)
84  {
85  if (mTime < mFirstTimestamp || mTime > mLastTimestamp)
86  {
87  return;
88  }
89  bool first = true;
90  for (VcdSerializerElement* vse : mWriteElements)
91  {
92  if (vse->hasData())
93  {
94  qulonglong ts = (vse->time() == 0) ? 0 : vse->time() - mTimeShift;
95  if (first)
96  {
97  of.write('#' + QByteArray::number(ts) + '\n');
98  first = false;
99  }
100  of.write(QByteArray::number(vse->value()) + vse->charCode() + '\n');
101  vse->value();
102  vse->reset();
103  }
104  }
105  }
106 
107  bool VcdSerializer::exportCsv(const QString& filename, const QList<const WaveData*>& waves)
108  {
109  if (waves.isEmpty())
110  {
111  return false;
112  }
113  SaleaeParser parser(mSaleaeDirectoryFilename.toStdString());
114  QFile of(filename);
115  if (!of.open(QIODevice::WriteOnly))
116  {
117  return false;
118  }
119 
120  mTime = 0;
121  int n = waves.size();
122 
123  int* values = new int [n];
124  memset(values, 0, n*sizeof(int));
125 
126  of.write("Time");
127  for (int i = 0; i < n; i++)
128  {
129  const WaveData* wd = waves.at(i);
130  of.write(QString(",\"%1\"").arg(wd->name()).toUtf8());
131  parser.register_callback(
132  wd->name().toStdString(),
133  wd->id(),
134  [this,&of,values,n](const void* obj, uint64_t t, int val) {
135  if (t != mTime)
136  {
137  of.write(QByteArray::number((qulonglong)mTime));
138  for (int j=0; j<n; j++)
139  {
140  of.write(",");
141  of.write(QByteArray::number(values[j]));
142  }
143  of.write("\n");
144  mTime = t;
145  }
146  *((int*)obj) = val;
147  },
148  values+i);
149  }
150 
151  while (parser.next_event())
152  {;}
153 
154  if (mTime)
155  {
156  of.write(QByteArray::number((qulonglong)mTime));
157  for (int j=0; j<n; j++)
158  {
159  of.write(",");
160  of.write(QByteArray::number(values[j]));
161  }
162  }
163 
164  of.write("\n");
165 
166  delete [] values;
167 
168  return true;
169  }
170 
171 
172  bool VcdSerializer::exportVcd(const QString& filename, const QList<const WaveData*>& waves, u32 startTime, u32 endTime, u32 timeSift)
173  {
174  mTimeShift = timeSift;
175  mFirstTimestamp = startTime;
176  mLastTimestamp = endTime - mTimeShift;
177  if (waves.isEmpty())
178  {
179  return false;
180  }
181  SaleaeParser parser(mSaleaeDirectoryFilename.toStdString());
182  QFile of(filename);
183  if (!of.open(QIODevice::WriteOnly))
184  {
185  return false;
186  }
187 
188  mTime = 0;
189  of.write(QByteArray("$scope module top_module $end\n"));
190 
191  int n = waves.size();
192 
193  for (int i = 0; i < n; i++)
194  {
195  const WaveData* wd = waves.at(i);
196  VcdSerializerElement* vse = new VcdSerializerElement(i, wd);
197  mWriteElements.append(vse);
198  parser.register_callback(
199  wd->name().toStdString(),
200  wd->id(),
201  [this, &of](const void* obj, uint64_t t, int val) {
202  VcdSerializerElement* vse = (VcdSerializerElement*)obj;
203  if ((int)t - (int)mTimeShift < 0)
204  {
205  vse->setEvent(0, val);
206  }
207  else
208  {
209  if (t != mTime)
210  {
211  writeVcdEvent(of);
212  mTime = t - mTimeShift;
213  }
214  vse->setEvent(t, val);
215  }
216  },
217  vse);
218  QString line = QString("$var wire 1 %1 %2 $end\n").arg(QString::fromUtf8(vse->charCode())).arg(vse->name());
219  of.write(line.toUtf8());
220  }
221 
222  of.write(QByteArray("$upscope $end\n$enddefinitions $end\n"));
223 
224  while (parser.next_event())
225  {
226  ;
227  }
228  for (VcdSerializerElement* vse : mWriteElements)
229  {
230  delete vse;
231  }
232  mWriteElements.clear();
233 
234  return true;
235  }
236 
237  bool VcdSerializer::parseVcdDataNonDecimal(const QByteArray& line, int base)
238  {
239  QList<QByteArray> sl = line.split(' ');
240  if (sl.size() != 2)
241  {
242  return false;
243  }
244  bool ok;
245  int val = sl.at(0).toUInt(&ok, base);
246  if (!ok)
247  {
248  if (mErrorCount[0]++ < maxErrorMessages)
249  {
250  log_warning("waveform_viewer", "Cannot parse VCD data value '{}'", std::string(sl.at(0).data()));
251  }
252  val = 0;
253  }
254  storeValue(val, sl.at(1));
255  // [return ok] return statement if we want to bail out upon data parse error
256  return true; // ignore parse errors
257  }
258 
259  bool VcdSerializer::parseVcdDataline(char* buf, int len)
260  {
261  int pos = 0;
262  while (len)
263  {
264  int val = -1;
265  switch (*(buf + pos))
266  {
267  case 'b':
268  return true; // parseVcdDataNonDecimal(QByteArray(buf+pos+1,len-1),2);
269  case 'o':
270  return true; //parseVcdDataNonDecimal(QByteArray(buf+pos+1,len-1),8);
271  case 'h':
272  return true; // parseVcdDataNonDecimal(QByteArray(buf+pos+1,len-1),16);
273  case '$': {
274  QByteArray testKeyword = QByteArray(buf + pos + 1, len - 1);
275  if (testKeyword.startsWith("dumpvars") || testKeyword.startsWith("end"))
276  {
277  return true;
278  }
279  return false;
280  }
281  case '#': {
282  bool ok;
283  mTime = QByteArray(buf + pos + 1, len - 1).toULongLong(&ok);
284  Q_ASSERT(ok);
285  return true;
286  }
287  case 'x':
288  val = -1;
289  break;
290  case 'z':
291  val = -2;
292  break;
293  case '0':
294  case '1':
295  case '2':
296  case '3':
297  case '4':
298  case '5':
299  case '6':
300  case '7':
301  val = *(buf + pos) - '0';
302  break;
303  default:
304  qDebug() << "cannot parse dataline entries starting with" << *(buf + pos) << buf;
305  return false;
306  }
307  int p = pos + 1;
308  while (p < len && buf[p] > ' ')
309  {
310  ++p;
311  }
312  Q_ASSERT(p > pos + 1);
313  int abbrevLen = p - pos - 1;
314  storeValue(val, QByteArray(buf + pos + 1, abbrevLen));
315  pos = p;
316  len -= (abbrevLen + 1);
317  while (buf[pos] == ' ' && len > 0)
318  {
319  pos++;
320  len--;
321  }
322  }
323  return true;
324  }
325 
326  void VcdSerializer::storeValue(int val, const QByteArray& abrev)
327  {
328  SaleaeOutputFile* sof = mSaleaeFiles.value(abrev);
329  if (!sof)
330  {
331  return;
332  }
333  // Q_ASSERT(wd);
334  sof->writeTimeValue(mTime, val);
335  }
336 
337  bool VcdSerializer::parseCsvHeader(char* buf)
338  {
339  int icol = 0;
340  char* pos = buf;
341  bool loop = (*pos != 0);
342  QString abbrev;
343  while (loop)
344  {
345  QByteArray header;
346  while (*pos && *pos != ',' && *pos != '\n')
347  {
348  header += *(pos++);
349  }
350  loop = (*(pos++) == ',');
351  if (!icol)
352  {
353  if (mSaleae)
354  {
355  abbrev = QString::fromUtf8(header);
356  }
357  }
358  else
359  {
360  bool ok;
361  if (!mSaleae)
362  {
363  abbrev = QString::number(icol);
364  }
365  QString name;
366  u32 id = header.trimmed().toUInt(&ok);
367  if (ok && id)
368  {
369  name = QString("net[%1]").arg(id);
370  }
371  else
372  {
373  name = QString::fromUtf8(header.trimmed());
374  int n = name.size() - 1;
375  if (n < 2 || name.at(0) != '"' || name.at(n) != '"')
376  {
377  return false;
378  }
379  name = name.mid(1, n - 1);
380  id = 0;
381  }
382  if (!name.isEmpty() || id)
383  {
384  SaleaeOutputFile* sof = mSaleaeWriter->add_or_replace_waveform(name.toStdString(), id);
385  if (!sof)
386  {
387  return false;
388  }
389  mSaleaeFiles.insert(abbrev, sof);
390  }
391  else
392  {
393  return false;
394  }
395  }
396  icol++;
397  }
398 
399  return true;
400  }
401 
402  bool VcdSerializer::parseCsvDataline(char* buf, int dataLineIndex)
403  {
404  int icol = 0;
405  bool ok;
406  char* pos = buf;
407  bool loop = (*pos != 0);
408  while (loop)
409  {
410  QByteArray value;
411  while (*pos && *pos != ',' && *pos != '\n')
412  {
413  value += *(pos++);
414  }
415  loop = (*(pos++) == ',');
416  if (!value.isEmpty())
417  {
418  if (icol)
419  {
420  int ival = 0;
421  ok = true;
422  if (value.size() == 1)
423  {
424  switch (value.at(0))
425  {
426  case '0':
427  break;
428  case '1':
429  ival = 1;
430  break;
431  default:
432  ival = value.trimmed().toInt(&ok);
433  break;
434  }
435  }
436  else
437  {
438  ival = value.trimmed().toInt(&ok);
439  }
440  if (!ok)
441  {
442  return false;
443  }
444 
445  bool wdInsert = false;
446  if (icol >= mLastValue.size())
447  {
448  while (icol > mLastValue.size())
449  {
450  mLastValue.append(-99);
451  }
452  mLastValue.append(ival);
453  wdInsert = true;
454  }
455  else if (mLastValue.at(icol) != ival)
456  {
457  mLastValue[icol] = ival;
458  wdInsert = true;
459  }
460 
461  if (wdInsert)
462  {
463  SaleaeOutputFile* sof = mSaleaeFiles.value(QString::number(icol));
464  if (!sof)
465  {
466  return false;
467  }
468  sof->writeTimeValue(mTime, ival);
469  }
470  }
471  else
472  {
473  // time
474  double tDouble = value.toDouble(&ok);
475  if (!ok)
476  {
477  return false;
478  }
479  u64 tInt = (u64)floor(tDouble * SaleaeParser::sTimeScaleFactor + 0.5);
480  if (!dataLineIndex)
481  {
482  mFirstTimestamp = tInt;
483  mTime = 0;
484  }
485  else
486  {
487  mTime = tInt - mFirstTimestamp;
488  }
489  }
490  }
491  icol++;
492  }
493  return true;
494  }
495 
496  bool VcdSerializer::importCsv(const QString& csvFilename, const QString& workdir, const QList<const Net*>& onlyNets, u64 timeScale)
497  {
498  mWorkdir = workdir.isEmpty() ? QDir::currentPath() : workdir;
499  mLastValue.clear();
500  deleteFiles();
501  mTime = 0;
502  mSaleae = false;
503 
504  SaleaeParser::sTimeScaleFactor = timeScale;
505 
506  QFile ff(csvFilename);
507  if (!ff.open(QIODevice::ReadOnly))
508  {
509  log_warning("waveform_viewer", "Cannot open CSV input file '{}'.", csvFilename.toStdString());
510  return false;
511  }
512 
513  createSaleaeDirectory();
514  mSaleaeWriter = new SaleaeWriter(mSaleaeDirectoryFilename.toStdString());
515 
516  bool retval = parseCsvInternal(ff, onlyNets);
517 
518  delete mSaleaeWriter;
519  mSaleaeWriter = nullptr;
520  mSaleaeFiles.clear();
521 
522  if (retval)
523  {
524  emitImportDone();
525  }
526  return retval;
527  }
528 
529  void VcdSerializer::emitProgress(double step, double max)
530  {
531  NetlistSimulatorController* nsc = static_cast<NetlistSimulatorController*>(parent());
532  if (!nsc)
533  {
534  return;
535  }
536  int percent = floor(step * 100 / max + 0.5);
537  if (percent == mLastProgress)
538  {
539  return;
540  }
541  nsc->emitLoadProgress(percent);
542  mLastProgress = percent;
543  qApp->processEvents();
544  }
545 
546  void VcdSerializer::emitImportDone()
547  {
548  NetlistSimulatorController* nsc = static_cast<NetlistSimulatorController*>(parent());
549  if (!nsc)
550  {
551  return;
552  }
553  nsc->emitLoadProgress(-1);
554  mLastProgress = -1;
555  }
556 
557  void VcdSerializer::createSaleaeDirectory()
558  {
559  QDir saleaeDir(QDir(mWorkdir).absoluteFilePath("saleae"));
560  saleaeDir.mkpath(saleaeDir.absolutePath());
561  mSaleaeDirectoryFilename = saleaeDir.absoluteFilePath("saleae.json");
562  }
563 
564  bool VcdSerializer::parseCsvInternal(QFile& ff, const QList<const Net*>& onlyNets)
565  {
566  QMap<QString, const Net*> netNames;
567  for (const Net* n : onlyNets)
568  {
569  netNames.insert(QString::fromStdString(n->get_name()), n);
570  }
571 
572  static const int bufsize = 65535;
573  char buf[bufsize + 1];
574 
575  bool parseHeader = true;
576  int dataLineIndex = 0;
577  while (!ff.atEnd())
578  {
579  int sizeRead = ff.readLine(buf, bufsize);
580  if (sizeRead >= bufsize)
581  {
582  if (mErrorCount[1]++ < maxErrorMessages)
583  {
584  log_warning("waveform_viewer", "CSV line {} exceeds buffer size {}.", dataLineIndex, bufsize);
585  }
586  return false;
587  }
588 
589  if (sizeRead < 0)
590  {
591  if (mErrorCount[2]++ < maxErrorMessages)
592  {
593  log_warning("waveform_viewer", "CSV parse error reading line {} from file '{}'.", dataLineIndex, ff.fileName().toStdString());
594  }
595  return false;
596  }
597  if (!sizeRead)
598  {
599  continue;
600  }
601 
602  if (parseHeader)
603  {
604  if (!parseCsvHeader(buf))
605  {
606  if (mErrorCount[3]++ < maxErrorMessages)
607  {
608  log_warning("waveform_viewer", "Cannot parse CSV header line '{}'.", buf);
609  }
610  return false;
611  }
612  parseHeader = false;
613  }
614  else
615  {
616  if (!parseCsvDataline(buf, dataLineIndex++))
617  {
618  if (mErrorCount[4]++ < maxErrorMessages)
619  {
620  log_warning("waveform_viewer", "Cannot parse CSV data line '{}'.", buf);
621  }
622  return false;
623  }
624  }
625  }
626 
627  return true;
628  }
629 
630  bool VcdSerializer::importVcd(const QString& vcdFilename, const QString& workdir, const QList<const Net*>& onlyNets)
631  {
632  mWorkdir = workdir.isEmpty() ? QDir::currentPath() : workdir;
633  deleteFiles();
634  mTime = 0;
635  QFile ff(vcdFilename);
636  if (!ff.open(QIODevice::ReadOnly))
637  {
638  log_warning("waveform_viewer", "Cannot open VCD input file '{}'.", vcdFilename.toStdString());
639  return false;
640  }
641 
642  createSaleaeDirectory();
643  mSaleaeWriter = new SaleaeWriter(mSaleaeDirectoryFilename.toStdString());
644 
645  bool retval = parseVcdInternal(ff, onlyNets);
646 
647  delete mSaleaeWriter;
648  mSaleaeWriter = nullptr;
649  mSaleaeFiles.clear();
650  mAbbrevByName.clear();
651 
652  if (retval)
653  {
654  emitImportDone();
655  }
656  return retval;
657  }
658 
659  bool VcdSerializer::parseVcdInternal(QFile& ff, const QList<const Net*>& onlyNets)
660  {
661  bool parseHeader = true;
662 
663  QMap<QString, const Net*> netNames;
664  for (const Net* n : onlyNets)
665  {
666  netNames.insert(QString::fromStdString(n->get_name()), n);
667  }
668 
669  QRegularExpression reHead("\\$(\\w*) (.*)\\$end");
670  QRegularExpression reWire("wire\\s+(\\d+) ([^ ]+) (.*)$");
671 
672  quint64 fileSize = ff.size();
673  quint64 totalRead = 0;
674 
675  static const int bufsize = 4095;
676  char buf[bufsize + 1];
677 
678  int iline = 0;
679  while (!ff.atEnd())
680  {
681  int sizeRead = ff.readLine(buf, bufsize);
682  ++iline;
683  totalRead += sizeRead;
684  emitProgress(totalRead, fileSize);
685  if (sizeRead >= bufsize)
686  {
687  if (mErrorCount[5]++ < maxErrorMessages)
688  {
689  log_warning("waveform_viewer", "VCD line {} exceeds buffer size {}.", iline, bufsize);
690  }
691  return false;
692  }
693 
694  if (sizeRead < 0)
695  {
696  if (mErrorCount[6]++ < maxErrorMessages)
697  {
698  log_warning("waveform_viewer", "VCD parse error reading line {} from file '{}'.", iline, ff.fileName().toStdString());
699  }
700  return false;
701  }
702  if (sizeRead > 0 && buf[sizeRead - 1] == '\n')
703  {
704  --sizeRead;
705  }
706  if (sizeRead > 0 && buf[sizeRead - 1] == '\r')
707  {
708  --sizeRead;
709  }
710  if (!sizeRead)
711  {
712  continue;
713  }
714 
715  if (parseHeader)
716  {
717  QByteArray line(buf, sizeRead);
718  QRegularExpressionMatch mHead = reHead.match(line);
719  if (mHead.hasMatch())
720  {
721  if (mHead.captured(1) == "enddefinitions")
722  {
723  parseHeader = false;
724  }
725  else if (mHead.captured(1) == "var")
726  {
727  QRegularExpressionMatch mWire = reWire.match(mHead.captured(2));
728  bool ok;
729  QString wireName = mWire.captured(3);
730  if (!wireName.isEmpty() && wireName.at(0) == '\\')
731  {
732  wireName.remove(0, 1);
733  }
734  wireName = wireName.trimmed();
735  const Net* net = netNames.value(wireName);
736 
737  if (!netNames.isEmpty() && !net)
738  {
739  continue; // net not found in given name list
740  }
741 
742  if (mAbbrevByName.contains(wireName))
743  {
744  if (mErrorCount[7]++ < maxErrorMessages)
745  {
746  log_warning("waveform_viewer", "Waveform duplicate for '{}' in VCD file '{}'.", wireName.toStdString(), ff.fileName().toStdString());
747  }
748  continue;
749  }
750  QString wireAbbrev = mWire.captured(2);
751  mAbbrevByName.insert(wireName, wireAbbrev);
752  int wireBits = mWire.captured(1).toUInt(&ok);
753  if (!ok)
754  {
755  wireBits = 1;
756  }
757  if (wireBits > 1)
758  {
759  continue; // TODO : decision whether we will be able to handle VCD with more bits
760  }
761 
762  u32 netId = net ? net->get_id() : 0;
763 
764  SaleaeOutputFile* sof = nullptr;
765  if (mSaleaeFiles.contains(wireAbbrev))
766  {
767  // output file already exists, need name entry
768  sof = mSaleaeFiles.value(wireAbbrev);
769  if (sof)
770  {
771  mSaleaeWriter->add_directory_entry(sof->index(), wireName.toStdString(), netId);
772  }
773  }
774  else
775  {
776  sof = mSaleaeWriter->add_or_replace_waveform(wireName.toStdString(), netId);
777  if (sof)
778  {
779  mSaleaeFiles.insert(wireAbbrev, sof);
780  }
781  }
782  }
783  }
784  }
785  else
786  {
787  if (!parseVcdDataline(buf, sizeRead))
788  {
789  if (mErrorCount[8]++ < maxErrorMessages)
790  {
791  log_warning("waveform_viewer", "Cannot parse VCD data line '{}'.", QByteArray(buf, sizeRead).data());
792  }
793  return false;
794  }
795  }
796  }
797  return true;
798  }
799 
800  bool VcdSerializer::importSaleae(const QString& saleaeDirecotry, const std::unordered_map<hal::Net*, int>& lookupTable, const QString& workdir, u64 timeScale)
801  {
802  mWorkdir = workdir.isEmpty() ? QDir::currentPath() : workdir;
803  deleteFiles();
804  mTime = 0;
805  SaleaeParser::sTimeScaleFactor = timeScale;
806  int nstep = lookupTable.size() + 1;
807  int istep = 0;
808 
809  emitProgress(istep++, nstep);
810  createSaleaeDirectory();
811  SaleaeDirectory sd(get_saleae_directory_filename());
813  QDir sourceDir(saleaeDirecotry);
814  QDir targetDir(QFileInfo(mSaleaeDirectoryFilename).path());
815  emitProgress(istep++, nstep);
816 
817  for (auto it = lookupTable.begin(); it != lookupTable.end(); ++it)
818  {
819  Q_ASSERT(it->first);
820  bool removeOldFile = false;
821  int inx = sd.get_datafile_index(it->first->get_name(), it->first->get_id());
822  if (inx < 0)
823  {
824  // create new file in import direcotry
825  inx = sd.get_next_available_index();
826  }
827  else
828  {
829  removeOldFile = true;
830  }
831  QString source = sourceDir.absoluteFilePath(QString("digital_%1.bin").arg(it->second));
832  QString target = targetDir.absoluteFilePath(QString("digital_%1.bin").arg(inx));
833  if (removeOldFile)
834  {
835  QFile::remove(target);
836  }
837  if (!QFile::copy(source, target))
838  {
839  return false;
840  }
841  SaleaeInputFile sif(target.toStdString());
842  if (!sif.header())
843  {
844  return false;
845  }
846  SaleaeDirectoryNetEntry sdne(it->first->get_name(), it->first->get_id());
847  sdne.addIndex(SaleaeDirectoryFileIndex(inx, sif.header()->beginTime(), sif.header()->endTime(), sif.header()->numTransitions() + 1));
848  sd.add_or_replace_net(sdne);
849  emitProgress(istep++, nstep);
850  }
851  emitImportDone();
852  return true;
853  }
854 } // namespace hal
Definition: net.h:58
static const int sReadError
Fake data value to indicate all kind of errors.
Definition: saleae_file.h:165
The SaleaeDirectoryFileIndex class represents a single SALEAE data file. The class comprises the inde...
The SaleaeDirectory class provides the API for the SALEAE directory file. The SALEAE directory file w...
int get_datafile_index(const std::string &nam, uint32_t id) const
Get waveform datafile index for net identified by name and id.
void add_or_replace_net(SaleaeDirectoryNetEntry &sdne)
Add net entry if not yet existing, replace existing entry otherwise.
int get_next_available_index() const
Getter for next available file index ('digital_XXX.bin' with lowest number XXX not in use)
The SaleaeDirectoryNetEntry class represents a regular waveform for a single simulated net....
void addIndex(const SaleaeDirectoryFileIndex &sdfe)
Add index for binary file to net entry instance.
The SaleaeDirectoryStoreRequest class is useful to bundle requests for updating SALEAE directory....
uint64_t endTime() const
Getter for time of last event.
Definition: saleae_file.h:109
uint64_t beginTime() const
Getter for time of first event.
Definition: saleae_file.h:103
uint64_t numTransitions() const
Getter for number of transitions stored in file. Remember that the total number of events is numTrans...
Definition: saleae_file.h:115
const SaleaeHeader * header() const
Getter for header information.
Definition: saleae_file.h:214
The SaleaeParser class is an engine which allows to parse any number of SALEAE files into a sequence ...
Definition: saleae_parser.h:74
bool register_callback(const std::string &name, uint32_t id, std::function< void(void *, uint64_t, int)> callback, void *obj)
Registers callback which gets executed upon next_event()
The SaleaeWriter class is a helper class which provides utility methods when importing data to SALEAE...
Definition: saleae_writer.h:42
void setEvent(u64 t, int val)
QByteArray charCode() const
VcdSerializerElement(int inx, const WaveData *wd)
VcdSerializer(const QString &workdir=QString(), bool saleae_cli=false, QObject *parent=nullptr)
bool exportCsv(const QString &filename, const QList< const WaveData * > &waves)
QString name() const
Definition: wave_data.h:104
u32 id() const
Definition: wave_data.h:103
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
#define log_warning(channel,...)
Definition: log.h:76
bool save(std::filesystem::path file_path, GateLibrary *gate_lib, bool overwrite=false)
Definition: defines.h:45
const int maxErrorMessages
Net * net
std::string name
char at(int i) const const
bool isEmpty() const const
QByteArray number(int n, int base)
int size() const const
QList< QByteArray > split(char sep) const const
bool startsWith(const QByteArray &ba) const const
double toDouble(bool *ok) const const
int toInt(bool *ok, int base) const const
uint toUInt(bool *ok, int base) const const
qulonglong toULongLong(bool *ok, int base) const const
QByteArray trimmed() const const
QString absoluteFilePath(const QString &fileName) const const
QString currentPath()
bool copy(const QString &newName)
virtual bool open(QIODevice::OpenMode mode) override
bool remove()
qint64 write(const char *data, qint64 maxSize)
const T & at(int i) const const
bool isEmpty() const const
int size() const const
void clear()
QMap::iterator insert(const Key &key, const T &value)
bool isEmpty() const const
const T value(const Key &key, const T &defaultValue) const const
QString captured(int nth) const const
bool hasMatch() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
const QChar at(int position) const const
void clear()
QString fromStdString(const std::string &str)
QString fromUtf8(const char *str, int size)
QString & insert(int position, QChar ch)
bool isEmpty() const const
QString number(int n, int base)
QString & remove(int position, int n)
std::string toStdString() const const
uint toUInt(bool *ok, int base) const const
QByteArray toUtf8() const const
QString trimmed() const const