HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
wave_form_painted.cpp
Go to the documentation of this file.
9 #include <math.h>
10 #include <QDebug>
11 
12 namespace hal {
13 
14  bool TimeInterval::operator< (const TimeInterval& other) const
15  {
16  if (other.mCenterTime == 0) return true; // other invalid, this is better (=smaller)
17  if (mCenterTime == 0) return false; // this invalid, other is better (=smaller)
18  return mDuration < other.mDuration; // both valid, smaller wins
19  }
20 
22  : mCursorTime(0), mCursorValue(SaleaeDataTuple::sReadError)
23  {;}
24 
26  {
27  clonePrimitives(other);
28  }
29 
30  void WaveFormPainted::clonePrimitives(const WaveFormPainted &other)
31  {
32  for (const WaveFormPrimitive* wfp : other.mPrimitives)
33  {
34  if (const WaveFormPrimitiveHline* wfph = dynamic_cast<const WaveFormPrimitiveHline*>(wfp); wfph)
35  mPrimitives.append(new WaveFormPrimitiveHline(*wfph));
36  else if (const WaveFormPrimitiveTransition* wfpt = dynamic_cast<const WaveFormPrimitiveTransition*>(wfp); wfpt)
37  mPrimitives.append(new WaveFormPrimitiveTransition(*wfpt));
38  else if (const WaveFormPrimitiveTrigger* wfpg = dynamic_cast<const WaveFormPrimitiveTrigger*>(wfp); wfpg)
39  mPrimitives.append(new WaveFormPrimitiveTrigger(*wfpg));
40  else if (const WaveFormPrimitiveUndefined* wfpu = dynamic_cast<const WaveFormPrimitiveUndefined*>(wfp); wfpu)
41  mPrimitives.append(new WaveFormPrimitiveUndefined(*wfpu));
42  else if (const WaveFormPrimitiveFilled* wfpf = dynamic_cast<const WaveFormPrimitiveFilled*>(wfp); wfpf)
43  mPrimitives.append(new WaveFormPrimitiveFilled(*wfpf));
44  else if (const WaveFormPrimitiveValue* wfpv = dynamic_cast<const WaveFormPrimitiveValue*>(wfp); wfpv)
45  mPrimitives.append(new WaveFormPrimitiveValue(*wfpv));
46  else
47  qDebug() << "Programming error, copy constructor failed due to unknown primitive type";
48  }
49  }
50 
52  {
54  }
55 
57  {
58  clonePrimitives(other);
59  mValidity = other.mValidity;
60  mShortestToggle = other.shortestToggle();
61  mCursorTime = other.mCursorTime;
62  mCursorXpos = other.mCursorXpos;
63  mCursorValue = other.mCursorValue;
64  return *this;
65  }
66 
68  {
69  QMutexLocker lock(&mMutex);
70  for (WaveFormPrimitive* wfp : mPrimitives)
71  delete wfp;
72  mPrimitives.clear();
73  mValidity = WaveZoomShift();
74  mShortestToggle = TimeInterval();
75  }
76 
77  void WaveFormPainted::paint(int y0, QPainter& painter)
78  {
79  QMutexLocker lock(&mMutex);
80  for (WaveFormPrimitive* wfp : mPrimitives)
81  wfp->paint(y0,painter);
82  }
83 
85  {
86  QMutexLocker lock(&mMutex);
87  for (const WaveFormPrimitive* wfp : mPrimitives)
88  if (wfp->isInRange(xpos))
89  {
90  return wfp->value();
91  }
93  }
94 
96  {
97  QMap<float,int> retval;
98  QMutexLocker lock(&mMutex);
99  for (const WaveFormPrimitive* wfp : mPrimitives)
100  {
101  if (wfp->x1() <= wfp->x0()) continue;
102  retval.insert(wfp->x0(),wfp->value());
103  }
104  return retval;
105  }
106 
108  {
109  clearPrimitives();
110 
111  QMap<float,WaveGroupValue> transitionValue;
112  const WaveDataGroup* grp = dynamic_cast<const WaveDataGroup*>(wd);
113  if (!grp) return false;
114  bool firstWave = true;
115 
116  float xmax = 0;
117  int nbits = 0;
118  for (int iwave : grp->childrenWaveIndex())
119  {
120  if (iwave<0) return false;
121  WaveItemIndex wii(iwave, WaveItemIndex::Wire, grp->id());
122  WaveItem* wi = hash->value(wii);
123  if (!wi || wi->mPainted.isEmpty()) return false;
124 
125  QMutexLocker lock(&wi->mMutex);
126  // validity must be the same for all child elements
127  if (firstWave)
128  {
129  mValidity = wi->mPainted.validity();
130  xmax = wi->mPainted.x1();
131  firstWave = false;
132  }
133  else
134  {
135  float testXmax = wi->mPainted.x1();
136  if (testXmax > xmax) xmax = testXmax;
137  if (mValidity != wi->mPainted.validity())
138  return false;
139  }
140  QMap<float,int> pValues = wi->mPainted.primitiveValues();
141  u32 mask = 1<<nbits;
142  for (auto it = pValues.constBegin(); it != pValues.constEnd(); ++it)
143  {
144  transitionValue[it.key()].setValue(mask,it.value());
145  }
146  ++nbits;
147  }
148 
149  float lastX = -1;
150  bool firstLoop = true;
151  WaveGroupValue lastValue(nbits);
152 
153  transitionValue[xmax] = lastValue;
154 
155  bool refreshCursor = transitionValue.isEmpty() ? false : mCursorTime >= transitionValue.constBegin().key();
156  for (auto it = transitionValue.constBegin(); it != transitionValue.constEnd(); ++it)
157  {
158  int nextX = it.key();
159  WaveGroupValue nextValue = it.value().mergePrevious(lastValue);
160  bool updateX = true;
161  if (!firstLoop) // not first loop -> valid lastX value
162  {
163  int val = lastValue.value();
165  mPrimitives.append(new WaveFormPrimitiveFilled(lastX,nextX,0));
166  else if (val < 0)
167  mPrimitives.append(new WaveFormPrimitiveUndefined(lastX,nextX));
168  else if (val != nextValue.value())
169  mPrimitives.append(new WaveFormPrimitiveValue(lastX,nextX,val,grp->bits(),grp->valueBase()));
170  else
171  updateX = false; // same value, will be painted at next transition
172 
173  if (refreshCursor && nextX > 0 && (u64) nextX > mCursorTime)
174  {
176  mCursorValue = val;
177  refreshCursor = false;
178  }
179 
180  }
181  if (updateX) lastX = nextX;
182  lastValue = nextValue;
183  firstLoop = false;
184  }
185  return true;
186  }
187 
188  bool WaveFormPainted::generateBoolean(const WaveData* wd, const WaveDataList *wdList, const WaveItemHash *hash)
189  {
190  clearPrimitives();
191 
192  QMap<float,WaveGroupValue> transitionValue;
193  const WaveDataBoolean* wdBool = dynamic_cast<const WaveDataBoolean*>(wd);
194  if (!wdBool) return false;
195  bool firstWave = true;
196 
197  float xmax = 0;
198  int nbits = 0;
199  for (WaveData* wdChild : wdBool->children())
200  {
201  int iwave = wdChild->dataIndex();
202  if (iwave<0) return false;
203  WaveItem* wi = nullptr;
204  for (u32 grpId = 0; grpId <= wdList->maxGroupId(); ++grpId)
205  {
206  WaveItemIndex wii(iwave, WaveItemIndex::Wire, grpId);
207  WaveItem* wi = hash->value(wii);
208  if (wi) break;
209  }
210  if (!wi || wi->mPainted.isEmpty()) return false;
211 
212  QMutexLocker lock(&wi->mMutex);
213  // validity must be the same for all child elements
214  if (firstWave)
215  {
216  mValidity = wi->mPainted.validity();
217  xmax = wi->mPainted.x1();
218  firstWave = false;
219  }
220  else
221  {
222  float testXmax = wi->mPainted.x1();
223  if (testXmax > xmax) xmax = testXmax;
224  if (mValidity != wi->mPainted.validity())
225  return false;
226  }
227  QMap<float,int> pValues = wi->mPainted.primitiveValues();
228  u32 mask = 1<<nbits;
229  for (auto it = pValues.constBegin(); it != pValues.constEnd(); ++it)
230  {
231  transitionValue[it.key()].setValue(mask,it.value());
232  }
233  ++nbits;
234  }
235 
236  float lastX = -1;
237  bool firstLoop = true;
238  WaveGroupValue lastValue(nbits);
239 
240  transitionValue[xmax] = lastValue;
241 
242  bool refreshCursor = transitionValue.isEmpty() ? false : mCursorTime >= transitionValue.constBegin().key();
243  for (auto it = transitionValue.constBegin(); it != transitionValue.constEnd(); ++it)
244  {
245  int nextX = it.key();
246  WaveGroupValue nextValue = it.value().mergePrevious(lastValue);
247  bool updateX = true;
248  if (!firstLoop) // not first loop -> valid lastX value
249  {
250  int val = lastValue.value();
252  mPrimitives.append(new WaveFormPrimitiveFilled(lastX,nextX,0));
253  else if (val < 0)
254  mPrimitives.append(new WaveFormPrimitiveUndefined(lastX,nextX));
255  else if (val != nextValue.value())
256  {
257  const char* tt = wdBool->truthTable();
258  int j = val/8;
259  int k = val%8;
260  int val = (tt[j] & (1<<k)) ? 1 : 0;
261  mPrimitives.append(new WaveFormPrimitiveHline(lastX,nextX,val));
262  }
263  else
264  updateX = false; // same value, will be painted at next transition
265 
266  if (refreshCursor && nextX > 0 && (u64) nextX > mCursorTime)
267  {
269  mCursorValue = val;
270  refreshCursor = false;
271  }
272 
273  }
274  if (updateX) lastX = nextX;
275  lastValue = nextValue;
276  firstLoop = false;
277  }
278  return true;
279  }
280 
281  void WaveFormPainted::generateTrigger(WaveDataProvider *wdp, const WaveTransform *trans, const WaveScrollbar *sbar, bool *loop)
282  {
283  mValidity = WaveZoomShift(trans, sbar);
284  *loop = true;
285 
286  quint64 tleft = sbar->tLeftI();
287  bool refreshCursor = (mCursorTime >= tleft);
288  int width = sbar->viewportWidth();
289 
290  SaleaeDataTuple tuple = wdp->startValue(tleft);
291  float xpos = sbar->xPosF(tuple.mTime);
292 
293  while(*loop && tuple.mValue != SaleaeDataTuple::sReadError && xpos <= width && tuple.mTime <= trans->tMax())
294  {
295  if (xpos >= 0 && tuple.mValue==1) mPrimitives.append(new WaveFormPrimitiveTrigger(xpos));
296  if (refreshCursor && tuple.mTime >= mCursorTime)
297  {
298  if (tuple.mTime == mCursorTime)
299  mCursorValue = 1;
300  else
301  mCursorValue = 0;
302  refreshCursor = false;
303  }
304  tuple = wdp->nextPoint();
305  xpos = sbar->xPosF(tuple.mTime);
306  }
307  }
308 
309  void WaveFormPainted::generate(WaveDataProvider* wdp, const WaveTransform* trans, const WaveScrollbar* sbar, bool *loop)
310  {
311  if (wdp->isTrigger())
312  {
313  generateTrigger(wdp,trans,sbar,loop);
314  return;
315  }
316  mValidity = WaveZoomShift(trans, sbar);
317  *loop = true;
318  WaveFormPrimitive* pendingTransition = nullptr;
319 
320  quint64 tleft = sbar->tLeftI();
321  bool refreshCursor = (mCursorTime >= tleft);
322  int width = sbar->viewportWidth();
323 
324  SaleaeDataTuple startval = wdp->startValue(tleft);
325  int valNext = startval.mValue;
326  float xNext = sbar->xPosF(startval.mTime);
327  quint64 tNext = trans->tMin();
328  if (valNext == SaleaeDataTuple::sReadError) *loop = false;
329  float xMax = width;
330 
331  // max time within visibible t window
332  if (sbar->xPosF(trans->tMax()) < xMax)
333  xMax = sbar->xPosF(trans->tMax());
334 
335  while (*loop && xNext <= xMax)
336  {
337  quint64 tLast = tNext;
338  float xLast = xNext;
339  int valLast = valNext;
340 
341  SaleaeDataTuple sdt = wdp->nextPoint();
342 
343  if (sdt.readError())
344  {
345  xNext = xMax;
346  *loop = false;
347  }
348  else
349  {
350  tNext = sdt.mTime;
351  xNext = sbar->xPosF(tNext);
352  valNext = sdt.mValue;
353  if (xNext > xMax)
354  {
355  xNext = xMax;
356  *loop = false;
357  }
358  }
359 
360  if (refreshCursor && (tNext > mCursorTime || !loop))
361  {
362  mCursorValue = valLast;
363  refreshCursor = false;
364  }
365 
366  if (tNext > tLast)
367  {
368  TimeInterval dt(tLast, tNext);
369  if (dt < mShortestToggle) mShortestToggle = dt;
370  }
371 
372  if (xNext - xLast > 2.)
373  {
374  if (pendingTransition)
375  {
376  mPrimitives.append(pendingTransition);
377  pendingTransition = nullptr;
378  }
379  if (valLast < 0)
380  mPrimitives.append(new WaveFormPrimitiveUndefined(xLast,xNext));
381  else if (wdp->isGroup())
382  mPrimitives.append(new WaveFormPrimitiveValue(xLast,xNext,valLast,wdp->bits(),wdp->valueBase()));
383  else
384  mPrimitives.append(new WaveFormPrimitiveHline(xLast,xNext,valLast));
385  }
386  else
387  {
388 
390  = new WaveFormPrimitiveFilled(pendingTransition?pendingTransition->x0():xLast, xNext, valLast);
391  if (pendingTransition)
392  {
393  const WaveFormPrimitiveFilled* lastFilled = dynamic_cast<const WaveFormPrimitiveFilled*>(pendingTransition);
394  if (lastFilled) filled->add(*lastFilled);
395  delete pendingTransition;
396  }
397  pendingTransition = filled;
398  }
399  if (loop && valLast >= 0 && valNext >= 0 && valLast != valNext && !pendingTransition && !wdp->isGroup())
400  {
401  pendingTransition = new WaveFormPrimitiveTransition(xNext);
402  }
403  }
404  if (pendingTransition)
405  mPrimitives.append(pendingTransition);
406  }
407 
408  float WaveFormPainted::x0() const
409  {
410  if (mPrimitives.isEmpty()) return -1;
411  auto it = mPrimitives.constBegin();
412  float retval = (*it)->x0();
413  while (++it != mPrimitives.constEnd())
414  if ((*it)->x0() < retval)
415  retval = (*it)->x0();
416  return retval;
417  }
418 
419  float WaveFormPainted::x1() const
420  {
421  if (mPrimitives.isEmpty()) return -1;
422  auto it = mPrimitives.constBegin();
423  float retval = (*it)->x1();
424  while (++it != mPrimitives.constEnd())
425  if ((*it)->x1() > retval)
426  retval = (*it)->x1();
427  return retval;
428  }
429 
430  void WaveFormPainted::setCursorValue(u64 tCursor, int xpos, int val)
431  {
432  mCursorTime = tCursor;
433  mCursorXpos = xpos;
434  mCursorValue = val;
435  }
436 
437  int WaveFormPainted::cursorValueStored(u64 tCursor, int xpos) const
438  {
439  // stored value not valid
440  if (tCursor != mCursorTime || xpos != mCursorXpos)
442 
443  // can deliver value - might be invalid though
444  return mCursorValue;
445  }
446 
448  {
449  QMutexLocker lock(&mMutex);
450  mCursorValue = 0;
451  for (const WaveFormPrimitive* wfp : mPrimitives)
452  {
453  if (fabs(wfp->x0()-xpos)<0.5)
454  mCursorValue = 1;
455  }
456  mCursorTime = tCursor;
457  mCursorXpos = xpos;
458  return mCursorValue;
459  }
460 
462  {
463  // try get from painted primitives
464  int tmpValue = valueXpos(xpos);
465  if (tmpValue == WaveGroupValue::sTooManyTransitions)
466  tmpValue = SaleaeDataTuple::sReadError;
467 
468  if (tmpValue >= BooleanFunction::Z)
469  {
470  mCursorTime = tCursor;
471  mCursorXpos = xpos;
472  mCursorValue = tmpValue;
473  }
474  return tmpValue;
475  }
476 }
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
bool readError() const
Indicates that there was an error and no data was returned.
Definition: saleae_file.h:174
bool operator<(const TimeInterval &other) const
QList< WaveData * > children() const
Definition: wave_data.cpp:738
const char * truthTable() const
Definition: wave_data.h:296
QList< int > childrenWaveIndex() const
Definition: wave_data.cpp:1052
virtual int bits() const override
Definition: wave_data.cpp:1083
int valueBase() const
Definition: wave_data.h:111
int dataIndex() const
Definition: wave_data.cpp:178
u32 id() const
Definition: wave_data.h:103
u32 maxGroupId() const
Definition: wave_data.h:210
virtual SaleaeDataTuple nextPoint()=0
virtual SaleaeDataTuple startValue(u64 t)=0
QMap< float, int > primitiveValues()
void setCursorValue(u64 tCursor, int xpos, int val)
const WaveZoomShift & validity() const
void generateTrigger(WaveDataProvider *wdp, const WaveTransform *trans, const WaveScrollbar *sbar, bool *loop)
void paint(int y0, QPainter &painter)
int cursorValuePainted(u64 tCursor, int xpos)
bool generateBoolean(const WaveData *wd, const WaveDataList *wdList, const WaveItemHash *hash)
WaveFormPainted & operator=(const WaveFormPainted &other)
int cursorValueTrigger(u64 tCursor, int xpos)
void generate(WaveDataProvider *wdp, const WaveTransform *trans, const WaveScrollbar *sbar, bool *loop)
int cursorValueStored(u64 tCursor, int xpos) const
bool generateGroup(const WaveData *wd, const WaveItemHash *hash)
TimeInterval shortestToggle() const
void add(const WaveFormPrimitiveFilled &other)
virtual void paint(int y0, QPainter &painter)=0
bool isInRange(int x) const
virtual int value() const
static const int sTooManyTransitions
WaveFormPainted mPainted
Definition: wave_item.h:83
QMutex mMutex
Definition: wave_item.h:85
quint64 tLeftI() const
int viewportWidth() const
double xPosF(double t) const
quint64 tMin() const
quint64 tMax() const
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
Definition: defines.h:45
const T value(const Key &key) const const
const Key & key() const const
QMap::const_iterator constBegin() const const
QMap::const_iterator constEnd() const const
QMap::iterator insert(const Key &key, const T &value)
bool isEmpty() const const