HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
saleae_file.cpp
Go to the documentation of this file.
1 #ifdef STANDALONE_PARSER
2 #include "saleae_file.h"
3 #include "saleae_parser.h"
4 #else
7 #endif
8 
9 #include <stdio.h>
10 #include <iostream>
11 #include <math.h>
12 #include <string.h>
13 
14 namespace hal
15 {
16 
17  const char* SaleaeHeader::sIdent = "<SALEAE>";
18 
20  : mCount(cnt), mTimeArray(nullptr), mValueArray(nullptr)
21  {
22  if (mCount)
23  {
24  mTimeArray = new uint64_t[mCount];
25  mValueArray = new int[mCount];
26  }
27  }
28 
30  {
31  if (mTimeArray) delete [] mTimeArray;
32  if (mValueArray) delete [] mValueArray;
33  }
34 
36  : mVersion(0), mStorageFormat(Uint64),
37  mValue(-1), mBeginTime(0), mEndTime(0), mNumTransitions(0)
38  {
39  strcpy(mIdent,sIdent);
40  }
41 
43  {
44  ff.read(mIdent,8);
45  mIdent[8] = 0;
46  if (mIdent != std::string(sIdent))
48 
49  ff.read((char*)&mVersion,sizeof(mVersion));
50 
51  uint32_t type;
52  ff.read((char*)&type,sizeof(type));
53 
54  switch (type)
55  {
56  case Double:
57  case Uint64:
58  case Coded:
60  break;
61  default:
63  }
64 
65  ff.read((char*)&mValue,sizeof(mValue));
66 
67  if (mStorageFormat != Double)
68  {
69  ff.read((char*)&mBeginTime,sizeof(mBeginTime));
70  ff.read((char*)&mEndTime,sizeof(mEndTime));
71  }
72  else
73  {
74  double tmp;
75  ff.read((char*)&tmp,sizeof(tmp));
76  mBeginTime = floor(tmp * SaleaeParser::sTimeScaleFactor + 0.5);
77  ff.read((char*)&tmp,sizeof(tmp));
78  mEndTime = floor(tmp * SaleaeParser::sTimeScaleFactor + 0.5);
79  }
80  ff.read((char*)&mNumTransitions,sizeof(mNumTransitions));
81 
82  return SaleaeStatus::Ok;
83  }
84 
86  {
87  uint32_t type = mStorageFormat;
88  of.write(mIdent,8);
89  of.write((char*)&mVersion,sizeof(mVersion));
90  of.write((char*)&type,sizeof(type));
91  of.write((char*)&mValue,sizeof(mValue));
92  of.write((char*)&mBeginTime,sizeof(mBeginTime));
93  of.write((char*)&mEndTime,sizeof(mEndTime));
94  of.write((char*)&mNumTransitions,sizeof(mNumTransitions));
95  return SaleaeStatus::Ok;
96  }
97 
98  SaleaeInputFile::SaleaeInputFile(const std::string &filename)
99  : std::ifstream(filename, std::ios::binary), mReadPointer(0),
100  mStatus(SaleaeStatus::Ok)
101  {
102  if (good())
103  mStatus = mHeader.read(*this);
104  else
105  mStatus = SaleaeStatus::ErrorOpenFile;
106 
107  if (mStatus)
108  setstate(failbit);
109 
110  switch (mHeader.storageFormat())
111  {
113  mReader = [this](bool* ok) {
114  double timeVal;
115  if (this->read((char*)&timeVal,sizeof(timeVal)))
116  *ok = true;
117  else
118  *ok = false;
119  return (uint64_t) floor(timeVal * SaleaeParser::sTimeScaleFactor + 0.5) - this->mHeader.beginTime();
120  };
121  break;
123  case SaleaeHeader::Coded:
124  mReader = [this](bool* ok) {
125  uint64_t timeVal;
126  if (this->read((char*)&timeVal,sizeof(timeVal)))
127  *ok = true;
128  else
129  *ok = false;
130  return timeVal;
131  };
132  break;
133  }
134 
135  // printf("<%s> %d %d %d %.7f %.7f %lu\n", mIdent, mVersion, mType, mValue, mBeginTime, mEndTime, mNumTransitions );
136  }
137 
139  {
140  uint64_t n = nread;
141  if (mReadPointer + n > mHeader.numTransitions() + 1)
142  n = mHeader.numTransitions() + 1 - mReadPointer;
143  if (!n) return nullptr;
144 
145  SaleaeDataBuffer* retval = new SaleaeDataBuffer;
146  retval->mCount = n;
147  retval->mTimeArray = new uint64_t[n];
148  retval->mValueArray = new int[n];
149 
150  uint64_t i = 0;
151  int val = (mReadPointer % 2 == 0) ? mHeader.value() : 1-mHeader.value();
152  if (!mReadPointer)
153  {
154  retval->mTimeArray[0] = mHeader.beginTime();
155  retval->mValueArray[0] = val;
156  val = val ? 0 : 1;
157  mReadPointer = 1;
158  i = 1;
159  --n;
160  if (!n) return retval;
161  }
162 
163  switch (mHeader.storageFormat())
164  {
166  {
167  double* tmp = new double[n];
168  this->read((char*)tmp,sizeof(double)*n);
169  for (uint64_t j=0; j<n; j++)
170  {
171  retval->mValueArray[i+j] = val;
172  retval->mTimeArray[i+j] = floor(tmp[j] * SaleaeParser::sTimeScaleFactor + 0.5) - mHeader.beginTime();
173  val = val ? 0 : 1;
174  }
175  delete [] tmp;
176  }
177  break;
179  this->read((char*)(retval->mTimeArray+i),sizeof(uint64_t)*n);
180  for (uint64_t j=0; j<n; j++)
181  {
182  retval->mValueArray[i+j] = val;
183  val = val ? 0 : 1;
184  }
185  break;
186  case SaleaeHeader::Coded:
187  this->read((char*)(retval->mTimeArray+i),sizeof(uint64_t)*n);
188  for (uint64_t j=0; j<n; j++)
189  {
190  retval->mValueArray[i+j] = ((retval->mTimeArray[i+j] >> 62) & 0x3) -2;
191  retval->mTimeArray[i+j] &= 0x3fffffffffffffffull;
192  }
193  break;
194  }
195 
196  mReadPointer += n;
197  if (mReadPointer > mHeader.numTransitions()) setstate(eofbit);
198  return retval;
199  }
200 
201 
203  {
204  switch (mStatus) {
206  return "Error opening SALEAE file";
208  return "No <SALEAE> identifier found";
210  return "Expected SALEAE type 0 (digital data)";
211  default:
212  break;
213  }
214  return std::string();
215  }
216 
218  {
219  SaleaeDataTuple retval;
220  if (!mReadPointer)
221  {
222  retval.mTime = mHeader.beginTime();
223  retval.mValue = mHeader.value();
224  ++mReadPointer;
225  seekTransition(0);
226  return retval;
227  }
228 
229  bool ok = true;
230  retval.mTime = mReader(&ok);
231  if (!ok)
232  {
234  return retval;
235  }
236 
237  if (mHeader.storageFormat() == SaleaeHeader::Coded)
238  {
239  retval.mValue = ((retval.mTime >> 62) & 0x3) - 2;
240  retval.mTime &= 0x3fffffffffffffffull;
241  }
242  else
243  retval.mValue = (mReadPointer%2==0) ? mHeader.value() : 1-mHeader.value();
244 
245  ++mReadPointer;
246  if (mReadPointer > mHeader.numTransitions()) setstate(eofbit);
247 
248  return retval;
249  }
250 
252  {
253  if (!delta) return;
254  if (delta < 0)
255  {
256  if ((uint64_t)-delta > mReadPointer)
257  mReadPointer = 0;
258  else
259  mReadPointer += delta;
260  }
261  else
262  {
263  if (delta + mReadPointer > mHeader.numTransitions())
264  mReadPointer = mHeader.numTransitions();
265  else
266  mReadPointer += delta;
267  }
268 
269  if (mReadPointer)
270  seekTransition(mReadPointer-1);
271  else
272  seekTransition(0);
273  }
274 
276  {
277  mReadPointer = pos;
278  seekTransition(pos ? pos-1 : 0);
279  }
280 
281  int64_t SaleaeInputFile::get_file_position(double t, bool successor)
282  {
283  uint64_t max = mHeader.numTransitions();
284  uint64_t t0 = mHeader.beginTime();
285  uint64_t t1 = mHeader.endTime();
286  mReadPointer = 0;
287  if (t < t0) return -1;
288  if (t == t0) return 0;
289  if (t >= t1)
290  {
291  mReadPointer = max;
292  if (successor && t > t1)
293  {
294  // attempt to get successor pos of last transition
295  setstate(eofbit);
296  return -1;
297  }
298  return max;
299  }
300 
301  int64_t pos = 0;
302  int64_t delta = max > 4 ? max / 4 : 1;
303  bool loop = true;
304  bool ok = true;
305  while (loop)
306  {
307  pos += delta;
308  if (pos < 0) pos = 0;
309  if (pos >= (int64_t) max-1) pos = max-1;
310  if (pos)
311  {
312  seekTransition(pos-1);
313  t0 = mReader(&ok) & 0x3fffffffffffffffull;
314  }
315  else
316  {
317  seekTransition(pos);
318  t0 = mHeader.beginTime();
319  }
320  t1 = mReader(&ok) & 0x3fffffffffffffffull;
321  if (t0 <= t && t1 > t)
322  {
323  if (successor && t0 < t) ++pos;
324  mReadPointer = pos;
325  seekTransition(pos ? pos-1 : 0);
326  return pos;
327  }
328  else if (t1 <= t)
329  {
330  if (delta < 0) delta = - delta/2;
331  if (!delta) delta = 1;
332  }
333  else if (t0 > t)
334  {
335  if (delta > 0) delta = - delta/2;
336  if (!delta) delta = -1;
337  }
338  }
339  return -1;
340  }
341 
343  {
344  int64_t pos = get_file_position(t);
345  if (pos < 0) return -1;
346  bool ok = true;
347 
348  if (mHeader.storageFormat() == SaleaeHeader::Coded)
349  {
350  seekTransition(pos);
351  uint64_t tuple = mReader(&ok);
352  return ((tuple >> 62) & 0x3) - 2;
353  }
354 
355  return (pos%2==0) ? mHeader.value() : 1 - mHeader.value();
356  }
357 
358  SaleaeOutputFile::SaleaeOutputFile(const std::string &filename, int index_)
359  : std::ofstream(filename, std::ios::binary), mIndex(index_), mFilename(filename), mStatus(SaleaeStatus::Ok),
360  mFirstValue(true), mLastWrittenValue(0), mLastWrittenTime(0)
361  {
362  if (!good())
363  mStatus = SaleaeStatus::ErrorOpenFile;
364  else
365  mHeader.write(*this);
366  }
367 
368  void SaleaeOutputFile::convertToCoded()
369  {
370  flush();
371  seekp(std::ios_base::beg);
372  mHeader.write(*this);
373  flush();
374  SaleaeInputFile sif(mFilename);
375  SaleaeDataBuffer* sdf = sif.get_buffered_data(sif.header()->numTransitions()+1);
376  sif.close();
377  seekp(std::ios_base::beg);
379  mHeader.write(*this);
380  put_data(sdf);
381  delete sdf;
382  }
383 
385  {
386  if (!buf->mCount) return;
388  for (uint64_t i = 0; i<buf->mCount; i++)
389  {
390  if (buf->mValueArray[i] < 0)
391  {
392  sf = SaleaeHeader::Coded;
393  break;
394  }
395  }
396  uint64_t n = buf->mCount - 1;
397  mHeader.setStorageFormat(sf);
398  mHeader.setValue(buf->mValueArray[0]);
399  mHeader.setEndTime(buf->mTimeArray[n]);
400  mHeader.setNumTransitions(n);
401  if (sf == SaleaeHeader::Coded)
402  buf->convertCoded();
403  this->write((char*) (buf->mTimeArray+1), n * sizeof(uint64_t));
404  // close will write header info
405  }
406 
407  void SaleaeOutputFile::writeTimeValue(uint64_t t, int32_t val)
408  {
409  if (mFirstValue)
410  {
411  mHeader.setValue(val);
412  mHeader.setBeginTime(t);
413  mHeader.setEndTime(t);
414  mFirstValue = false;
415  mLastWrittenValue = val;
416  mLastWrittenTime = t;
417  }
418  else
419  {
420  if (val < 0 && mHeader.storageFormat() == SaleaeHeader::Uint64)
421  convertToCoded();
422 
423  if(t < mLastWrittenTime || val == mLastWrittenValue) return;
424  mLastWrittenValue = val;
425  mLastWrittenTime = t;
426 
427  if (mHeader.storageFormat() == SaleaeHeader::Coded)
428  {
429  uint64_t buf = val + 2;
430  buf <<= 62;
431  buf |= (t & 0xfffffffffffffffull);
432  write((char*)&buf,sizeof(buf));
433  }
434  else
435  write((char*)&t,sizeof(t));
436  mHeader.incrementTransitions();
437  mHeader.setEndTime(t);
438  }
439  }
440 
442  {
443  // qDebug() << good() << "~SaleaeOutputFile" << hex << (quintptr) this;
444  if (good()) close();
445  }
446 
448  {
449  if (!good()) return;
450  seekp(std::ios_base::beg);
451  mHeader.write(*this);
452  std::ofstream::close();
453  }
454 
456  {
458  mIndex,
459  mHeader.beginTime(),
460  mHeader.endTime(),
461  mHeader.numTransitions()+1);
462  }
463 
465  {
466  for (uint64_t i = 1; i<mCount; i++)
467  {
468  uint64_t mask = mValueArray[i] + 2;
469  mask <<= 62;
470  mTimeArray[i] = (mTimeArray[i] & 0xfffffffffffffffull) | mask;
471  }
472  }
473 
475  {
476  std::cout << mCount << " :";
477  for (uint64_t i = 0; i<mCount; i++)
478  {
479  std::cout << " <" << mTimeArray[i] << "," << (mValueArray[i] < 0 ? 'X' : ((char) ('0'+mValueArray[i]))) << ">";
480  }
481  std::cout << std::endl;
482  }
483 }
void convertCoded()
Convert data buffer from "hal " format to "halx".
uint64_t mCount
Number of elements in buffer.
Definition: saleae_file.h:137
SaleaeDataBuffer(uint64_t cnt=0)
Constructor. Generates null instance when no argument is given.
Definition: saleae_file.cpp:19
~SaleaeDataBuffer()
Destructor takes care of disposing allocated memory.
Definition: saleae_file.cpp:29
uint64_t * mTimeArray
Buffer for mCount transition time values.
Definition: saleae_file.h:140
int * mValueArray
Buffer for mCount data values.
Definition: saleae_file.h:143
void dump() const
Dump buffer content to stdout.
int mValue
Data value.
Definition: saleae_file.h:171
static const int sReadError
Fake data value to indicate all kind of errors.
Definition: saleae_file.h:165
uint64_t mTime
Transition time.
Definition: saleae_file.h:168
The SaleaeDirectoryFileIndex class represents a single SALEAE data file. The class comprises the inde...
uint64_t mNumTransitions
Definition: saleae_file.h:70
StorageFormat
SALEAE storage format for transition time values.
Definition: saleae_file.h:61
@ Uint64
Double values,.
Definition: saleae_file.h:62
void setEndTime(uint64_t t)
Setter for time of last event.
Definition: saleae_file.h:112
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
StorageFormat mStorageFormat
Definition: saleae_file.h:66
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
uint64_t mEndTime
Definition: saleae_file.h:69
int32_t value() const
Getter for initial value.
Definition: saleae_file.h:97
StorageFormat storageFormat() const
Getter for storage format, see above.
Definition: saleae_file.h:91
void setNumTransitions(uint64_t n)
Setter for number of transitions stored in file.
Definition: saleae_file.h:118
static const char * sIdent
Definition: saleae_file.h:72
SaleaeStatus::ErrorCode write(std::ofstream &of) const
Definition: saleae_file.cpp:85
SaleaeStatus::ErrorCode read(std::ifstream &ff)
Definition: saleae_file.cpp:42
uint64_t mBeginTime
Definition: saleae_file.h:68
void setBeginTime(uint64_t t)
Setter for time of first event.
Definition: saleae_file.h:106
void setValue(int32_t v)
Setter for initial value.
Definition: saleae_file.h:100
void incrementTransitions()
Increment number of transitions by one.
Definition: saleae_file.h:121
void setStorageFormat(StorageFormat sf)
Setter for storage format, see above.
Definition: saleae_file.h:94
int64_t get_file_position(double t, bool successor=false)
SaleaeDataTuple get_next_value()
Getter for next (time,value) tuple in sequential read.
void skip_transitions(int64_t delta)
Goto position for next read access, skip number of transitions indicated by 'delta',...
SaleaeDataBuffer * get_buffered_data(uint64_t nread)
Returns pointer to data buffer reading from current file position up to nread events....
SaleaeInputFile(const std::string &filename)
Definition: saleae_file.cpp:98
int get_int_value(double t)
Get waveform value for time t.
std::string get_last_error() const
Get verbose error message based on internal status, empty string if no error.
void set_file_position(int64_t pos)
Goto position for next read access. Pos=0 is start value from header.
void writeTimeValue(uint64_t t, int32_t val)
Write single data tuple to disk.
void close()
Update header on disk and close file.
SaleaeOutputFile(const std::string &filename, int index_)
SaleaeDirectoryFileIndex fileIndex() const
File index summary for saleae directory.
void put_data(SaleaeDataBuffer *buf)
Write buffered data.
static uint64_t sTimeScaleFactor
conversion factor to be applied when converting double values from original SALEAE file to integer va...
bool write(const GateLibrary *gate_lib, const std::filesystem::path &file_path)
Definition: defines.h:45
PinType type