11 #include <QCoreApplication>
12 #include <QDataStream>
16 #include <QRegularExpression>
52 retval += (char)(firstChar + z % 92);
65 if (!mWorkdir.
isEmpty() && !saleae_cli)
72 mSaleaeDirectoryFilename = workdir +
"/saleae.json";
76 void VcdSerializer::deleteFiles()
79 mAbbrevByName.
clear();
80 memset(mErrorCount, 0,
sizeof(mErrorCount));
83 void VcdSerializer::writeVcdEvent(
QFile& of)
85 if (mTime < mFirstTimestamp || mTime > mLastTimestamp)
90 for (VcdSerializerElement* vse : mWriteElements)
94 qulonglong ts = (vse->time() == 0) ? 0 : vse->time() - mTimeShift;
121 int n = waves.
size();
123 int* values =
new int [n];
124 memset(values, 0, n*
sizeof(
int));
127 for (
int i = 0; i < n; i++)
134 [
this,&of,values,n](
const void* obj, uint64_t t,
int val) {
137 of.write(QByteArray::number((qulonglong)mTime));
138 for (int j=0; j<n; j++)
141 of.write(QByteArray::number(values[j]));
151 while (parser.next_event())
157 for (
int j=0; j<n; j++)
174 mTimeShift = timeSift;
175 mFirstTimestamp = startTime;
176 mLastTimestamp = endTime - mTimeShift;
181 SaleaeParser parser(mSaleaeDirectoryFilename.toStdString());
191 int n = waves.
size();
193 for (
int i = 0; i < n; i++)
197 mWriteElements.append(vse);
201 [
this, &of](
const void* obj, uint64_t t,
int val) {
202 VcdSerializerElement* vse = (VcdSerializerElement*)obj;
203 if ((int)t - (int)mTimeShift < 0)
205 vse->setEvent(0, val);
212 mTime = t - mTimeShift;
224 while (parser.next_event())
228 for (VcdSerializerElement* vse : mWriteElements)
232 mWriteElements.clear();
237 bool VcdSerializer::parseVcdDataNonDecimal(
const QByteArray& line,
int base)
245 int val = sl.
at(0).toUInt(&ok, base);
250 log_warning(
"waveform_viewer",
"Cannot parse VCD data value '{}'", std::string(sl.
at(0).data()));
254 storeValue(val, sl.
at(1));
259 bool VcdSerializer::parseVcdDataline(
char* buf,
int len)
265 switch (*(buf + pos))
301 val = *(buf + pos) -
'0';
304 qDebug() <<
"cannot parse dataline entries starting with" << *(buf + pos) << buf;
308 while (p < len && buf[p] >
' ')
312 Q_ASSERT(p > pos + 1);
313 int abbrevLen = p - pos - 1;
314 storeValue(val,
QByteArray(buf + pos + 1, abbrevLen));
316 len -= (abbrevLen + 1);
317 while (buf[pos] ==
' ' && len > 0)
326 void VcdSerializer::storeValue(
int val,
const QByteArray& abrev)
328 SaleaeOutputFile* sof = mSaleaeFiles.value(abrev);
334 sof->writeTimeValue(mTime, val);
337 bool VcdSerializer::parseCsvHeader(
char* buf)
341 bool loop = (*pos != 0);
346 while (*pos && *pos !=
',' && *pos !=
'\n')
350 loop = (*(pos++) ==
',');
374 int n =
name.size() - 1;
375 if (n < 2 ||
name.at(0) !=
'"' ||
name.at(n) !=
'"')
382 if (!
name.isEmpty() ||
id)
384 SaleaeOutputFile* sof = mSaleaeWriter->add_or_replace_waveform(
name.toStdString(),
id);
389 mSaleaeFiles.insert(abbrev, sof);
402 bool VcdSerializer::parseCsvDataline(
char* buf,
int dataLineIndex)
407 bool loop = (*pos != 0);
411 while (*pos && *pos !=
',' && *pos !=
'\n')
415 loop = (*(pos++) ==
',');
422 if (value.
size() == 1)
445 bool wdInsert =
false;
446 if (icol >= mLastValue.size())
448 while (icol > mLastValue.size())
450 mLastValue.append(-99);
452 mLastValue.append(ival);
455 else if (mLastValue.at(icol) != ival)
457 mLastValue[icol] = ival;
468 sof->writeTimeValue(mTime, ival);
474 double tDouble = value.
toDouble(&ok);
479 u64 tInt = (
u64)floor(tDouble * SaleaeParser::sTimeScaleFactor + 0.5);
482 mFirstTimestamp = tInt;
487 mTime = tInt - mFirstTimestamp;
504 SaleaeParser::sTimeScaleFactor = timeScale;
513 createSaleaeDirectory();
514 mSaleaeWriter =
new SaleaeWriter(mSaleaeDirectoryFilename.toStdString());
516 bool retval = parseCsvInternal(
ff, onlyNets);
518 delete mSaleaeWriter;
519 mSaleaeWriter =
nullptr;
520 mSaleaeFiles.clear();
529 void VcdSerializer::emitProgress(
double step,
double max)
536 int percent = floor(step * 100 / max + 0.5);
537 if (percent == mLastProgress)
542 mLastProgress = percent;
543 qApp->processEvents();
546 void VcdSerializer::emitImportDone()
548 NetlistSimulatorController* nsc =
static_cast<NetlistSimulatorController*
>(parent());
557 void VcdSerializer::createSaleaeDirectory()
559 QDir saleaeDir(
QDir(mWorkdir).absoluteFilePath(
"saleae"));
560 saleaeDir.mkpath(saleaeDir.absolutePath());
561 mSaleaeDirectoryFilename = saleaeDir.absoluteFilePath(
"saleae.json");
567 for (
const Net* n : onlyNets)
572 static const int bufsize = 65535;
573 char buf[bufsize + 1];
575 bool parseHeader =
true;
576 int dataLineIndex = 0;
579 int sizeRead =
ff.readLine(buf, bufsize);
580 if (sizeRead >= bufsize)
584 log_warning(
"waveform_viewer",
"CSV line {} exceeds buffer size {}.", dataLineIndex, bufsize);
593 log_warning(
"waveform_viewer",
"CSV parse error reading line {} from file '{}'.", dataLineIndex,
ff.fileName().toStdString());
604 if (!parseCsvHeader(buf))
608 log_warning(
"waveform_viewer",
"Cannot parse CSV header line '{}'.", buf);
616 if (!parseCsvDataline(buf, dataLineIndex++))
620 log_warning(
"waveform_viewer",
"Cannot parse CSV data line '{}'.", buf);
642 createSaleaeDirectory();
643 mSaleaeWriter =
new SaleaeWriter(mSaleaeDirectoryFilename.toStdString());
645 bool retval = parseVcdInternal(
ff, onlyNets);
647 delete mSaleaeWriter;
648 mSaleaeWriter =
nullptr;
649 mSaleaeFiles.clear();
650 mAbbrevByName.clear();
661 bool parseHeader =
true;
664 for (
const Net* n : onlyNets)
672 quint64 fileSize = ff.size();
673 quint64 totalRead = 0;
675 static const int bufsize = 4095;
676 char buf[bufsize + 1];
681 int sizeRead = ff.readLine(buf, bufsize);
683 totalRead += sizeRead;
684 emitProgress(totalRead, fileSize);
685 if (sizeRead >= bufsize)
689 log_warning(
"waveform_viewer",
"VCD line {} exceeds buffer size {}.", iline, bufsize);
698 log_warning(
"waveform_viewer",
"VCD parse error reading line {} from file '{}'.", iline,
ff.fileName().toStdString());
702 if (sizeRead > 0 && buf[sizeRead - 1] ==
'\n')
706 if (sizeRead > 0 && buf[sizeRead - 1] ==
'\r')
721 if (mHead.
captured(1) ==
"enddefinitions")
725 else if (mHead.
captured(1) ==
"var")
730 if (!wireName.
isEmpty() && wireName.
at(0) ==
'\\')
742 if (mAbbrevByName.contains(wireName))
746 log_warning(
"waveform_viewer",
"Waveform duplicate for '{}' in VCD file '{}'.", wireName.
toStdString(),
ff.fileName().toStdString());
751 mAbbrevByName.
insert(wireName, wireAbbrev);
764 SaleaeOutputFile* sof =
nullptr;
765 if (mSaleaeFiles.contains(wireAbbrev))
768 sof = mSaleaeFiles.value(wireAbbrev);
771 mSaleaeWriter->add_directory_entry(sof->index(), wireName.
toStdString(), netId);
776 sof = mSaleaeWriter->add_or_replace_waveform(wireName.
toStdString(), netId);
779 mSaleaeFiles.insert(wireAbbrev, sof);
787 if (!parseVcdDataline(buf, sizeRead))
800 bool VcdSerializer::importSaleae(
const QString& saleaeDirecotry,
const std::unordered_map<hal::Net*, int>& lookupTable,
const QString& workdir,
u64 timeScale)
805 SaleaeParser::sTimeScaleFactor = timeScale;
806 int nstep = lookupTable.size() + 1;
809 emitProgress(istep++, nstep);
810 createSaleaeDirectory();
813 QDir sourceDir(saleaeDirecotry);
815 emitProgress(istep++, nstep);
817 for (
auto it = lookupTable.begin(); it != lookupTable.end(); ++it)
820 bool removeOldFile =
false;
829 removeOldFile =
true;
849 emitProgress(istep++, nstep);
void emitLoadProgress(int percent)
static const int sReadError
Fake data value to indicate all kind of errors.
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....
The SaleaeParser class is an engine which allows to parse any number of SALEAE files into a sequence ...
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...
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)
#define log_warning(channel,...)
bool save(std::filesystem::path file_path, GateLibrary *gate_lib, bool overwrite=false)
const int maxErrorMessages
char at(int i) const const
bool isEmpty() const const
QByteArray number(int n, int base)
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
bool copy(const QString &newName)
virtual bool open(QIODevice::OpenMode mode) override
qint64 write(const char *data, qint64 maxSize)
const T & at(int i) const const
bool isEmpty() const const
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
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