ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
Trigger.cpp
Go to the documentation of this file.
1 /*
2 
3  @copyright
4 
5  <pre>
6 
7  Copyright 2018 Infineon Technologies AG
8 
9  This file is part of ETISS tool, see <https://github.com/tum-ei-eda/etiss>.
10 
11  The initial version of this software has been created with the funding support by the German Federal
12  Ministry of Education and Research (BMBF) in the project EffektiV under grant 01IS13022.
13 
14  Redistribution and use in source and binary forms, with or without modification, are permitted
15  provided that the following conditions are met:
16 
17  1. Redistributions of source code must retain the above copyright notice, this list of conditions and
18  the following disclaimer.
19 
20  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
21  and the following disclaimer in the documentation and/or other materials provided with the distribution.
22 
23  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse
24  or promote products derived from this software without specific prior written permission.
25 
26  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
27  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
28  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
29  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  POSSIBILITY OF SUCH DAMAGE.
34 
35  </pre>
36 
37  @author Chair of Electronic Design Automation, TUM
38 
39  @version 0.1
40 
41 */
42 
43 #ifndef NO_ETISS
44 #include "etiss/fault/Trigger.h"
45 #include "etiss/Misc.h"
46 #include "etiss/fault/Injector.h"
47 #else
48 #include "fault/Injector.h"
49 #include "fault/Trigger.h"
50 #endif
51 
52 #include <iostream>
53 
54 namespace etiss
55 {
56 
57 namespace fault
58 {
59 
61 {
62  if (type_ != type)
63  {
64  etiss::log(etiss::FATALERROR, std::string("etiss::fault::Trigger::ensure: Type mismatch type=") +
65  std::to_string(type) + " type_=" + std::to_string(type_));
66  throw "called function of different trigger type";
67  }
68 }
69 
70 Trigger::Trigger() : type_(NOP)
71 {
72  etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::Trigger() : type_ (NOP)"));
73 }
74 Trigger::Trigger(const Trigger &sub, uint64_t count)
75  : type_(META_COUNTER), sub_(new Trigger(sub)), param1_(count), param2_(0)
76 {
77  etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::Trigger() : type_ (META_COUNTER)"));
78 }
79 Trigger::Trigger(const InjectorAddress &target_injector, const std::string &field, uint64_t value)
80  : type_(VARIABLEVALUE), field_(field), inj_(target_injector), fieldptr_(0), param1_(value)
81 {
82  etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::Trigger() : type_ (VARIABLEVALUE)"));
83 }
84 Trigger::Trigger(const InjectorAddress &target_injector, uint64_t time_ps, bool relative)
85  : type_(relative ? TIMERELATIVE : TIME), inj_(target_injector), param1_(time_ps), param2_(0)
86 {
87  relative ? etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::Trigger() : type_ (TIMERELATIVE)"))
88  : etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::Trigger() : type_ (TIME)"));
89 }
90 
91 Trigger::Trigger(const Trigger &cpy) : type_(NOP)
92 {
93  *this = cpy;
94 }
96 {
97  if (type_ == META_COUNTER)
98  delete sub_;
99  if (type_ == VARIABLEVALUE)
100  {
101  if (inj_.isResolved() && fieldptr_)
102  {
103  inj_.getInjector()->freeFastFieldAccessPtr(fieldptr_);
104  }
105  }
106  type_ = cpy.type_;
107  switch (type_)
108  {
109  case META_COUNTER:
110  sub_ = new Trigger(*cpy.sub_);
111  param1_ = cpy.param1_;
112  param2_ = cpy.param2_;
113  break;
114  case VARIABLEVALUE:
115  field_ = cpy.field_;
116  inj_ = cpy.inj_;
117  fieldptr_ = 0;
118  param1_ = cpy.param1_;
119  break;
120  case TIMERELATIVE: [[fallthrough]];
121  case TIME:
122  inj_ = cpy.inj_;
123  param1_ = cpy.param1_;
124  param2_ = cpy.param2_;
125  break;
126  case NOP:
127  break;
128  }
129  return *this;
130 }
131 
132 #if CXX0X_UP_SUPPORTED
133 Trigger::Trigger(Trigger &&cpy) : type_(NOP)
134 {
135  operator=(cpy);
136 }
137 Trigger &Trigger::operator=(Trigger &&cpy)
138 {
139  operator=((const Trigger &)cpy);
140  return *this;
141 }
142 #endif
143 
145 {
146  if (type_ == META_COUNTER)
147  delete sub_;
148  if (type_ == VARIABLEVALUE)
149  {
150  if (inj_.isResolved() && fieldptr_)
151  {
152  inj_.getInjector()->freeFastFieldAccessPtr(fieldptr_);
153  }
154  }
155 }
156 
157 bool Trigger::fired(uint64_t time_ps, etiss::fault::Injector *target_injector)
158 {
159  etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::fired(time_ps=") + std::to_string(time_ps) +
160  std::string(", Injector*)"));
161  // std::cout << "Trigger::fired called at " << time_ps << " ps" << std::endl;
162  switch (type_)
163  {
164  case META_COUNTER:
165  if (sub_->fired(time_ps, target_injector))
166  {
167  ++param2_; // increase count
168  if (param1_ == param2_)
169  {
170  return true; // count reached -> fire event
171  }
172  }
173  break;
174  case VARIABLEVALUE:
175  {
176  if (fieldptr_ == 0)
177  {
178  std::string errmsg;
179  fieldptr_ = target_injector->fastFieldAccessPtr(field_, errmsg);
180  if (fieldptr_ == 0)
181  {
182 #ifdef NO_ETISS
183  std::cout << "Trigger::fired: Failed to get field" << std::endl;
184 #else
185  etiss::log(etiss::ERROR, "Trigger::fired: Failed to get field", *this);
186 #endif
187  return false;
188  }
189  }
190  uint64_t val = 0;
191  std::string errmsg;
192  if (inj_.getInjector())
193  {
194  if (!inj_.getInjector()->readField(fieldptr_, val, errmsg))
195  {
196 #ifdef NO_ETISS
197  std::cout << "Trigger::fired: Failed to read field: " << errmsg << std::endl;
198 #else
199  etiss::log(etiss::ERROR, "Trigger::fired: Failed to get field", *this, errmsg);
200 #endif
201  return false;
202  }
203  }
204  else
205  {
206 #ifdef NO_ETISS
207  std::cout << "Trigger::fired: Failed get injector: " << inj_.getInjectorPath() << std::endl;
208 #else
209  etiss::log(etiss::ERROR, "Trigger::fired: Failed get injector", *this, inj_);
210 #endif
211  }
212  return val == param1_;
213  }
214  break;
215  case TIMERELATIVE:
216  etiss::log(etiss::WARNING, "Trigger::fired: Unresolved TIMERELATIVE - resolving now", *this, inj_);
217  resolveTime(time_ps);
218  [[fallthrough]];
219  case TIME:
220  /* TODO: Why doing it like this ? this would always fire after time_ps has reached */
221  // Possibly because might be called not exaclty but later than excact trigger time, then late triggering should
222  // be done
223 
224  // if (time_ps >= param1_ && param2_ <= time_ps)
225  if (param1_ <= time_ps && param2_ == 0) // testing alternative param2_ says if trigger has already fired
226  {
228 
229  // param2_ = time_ps+1;
230  param2_ = 1; // testing alternative: param2_ says if trigger has already fired
231  return true;
232  }
233  // param2_ = time_ps;
234  // testing alternative param2_ says if trigger has already fired
235 
236  // DO NOT DO IT LIKE THIS, MIGHT NOT BE CALLED EXACTLY WITH TIME OF TRIGGER
237  // if (time_ps == param1_)
238  // return true;
239  break;
240  case NOP:
241  break;
242  }
243 
244  return false;
245 }
246 
248 {
250  std::string("etiss::fault::Trigger::resolveTime(time=") + std::to_string(time) + std::string(")"));
251  if (type_ == TIMERELATIVE)
252  {
253  type_ = TIME;
254  param1_ = param1_ + time;
255  }
256  else if (type_ == META_COUNTER)
257  {
258  return getSubTrigger().resolveTime(time);
259  }
260 }
262 {
263  if (type_ == META_COUNTER)
264  {
265  return getSubTrigger().isResolved();
266  }
267  return type_ != TIMERELATIVE;
268 }
269 
271 {
273  return param1_;
274 }
276 {
278  return *sub_;
279 }
281 {
283  return *sub_;
284 }
286 {
287  if (type_ == META_COUNTER)
288  {
289  return getSubTrigger().getTriggerTime();
290  }
291  try
292  {
293  ensure(TIME);
294  }
295  catch (char const *)
296  {
298  }
299  return param1_;
300 }
302 {
303  return inj_;
304 }
306 {
307  if (type_ == META_COUNTER)
308  {
309  return sub_->getInjector();
310  }
311  else
312  {
313  return inj_.getInjector();
314  }
315 }
316 bool Trigger::isNOP() const
317 {
318  if (type_ == META_COUNTER)
319  {
320  return sub_->isNOP();
321  }
322  else
323  {
324  return type_ == NOP;
325  }
326 }
327 const std::string &Trigger::getTriggerField() const
328 {
329  // std::cout << "Trigger::getTriggerField() called" << std::endl;
330  if (type_ == META_COUNTER)
331  {
332  return getSubTrigger().getTriggerField();
333  }
335  return field_;
336 }
338 {
339  // std::cout << "Trigger::getTriggerFieldValue() called" << std::endl;
340  if (type_ == META_COUNTER)
341  {
343  }
345  return param1_;
346 }
348 {
349  return type_;
350 }
351 
352 std::string Trigger::toString() const
353 {
354  std::stringstream ss;
355  ss << "Trigger {";
356  switch (type_)
357  {
358  case META_COUNTER:
359  ss << " type=META_COUNTER triggerCount=" << +param1_ << " currentCount=" << +param2_;
360  break;
361  case VARIABLEVALUE:
362  ss << " type=VARIABLEVALUE field=" << field_ << " triggerValue=" << +param1_;
363  break;
364  case TIME:
365  ss << " type=TIME triggerTime=" << +param1_;
366  break;
367  case TIMERELATIVE:
368  ss << " type=TIMERELATIVE triggerTime=" << +param1_;
369  break;
370  case NOP:
371  ss << " type=NOP";
372  break;
373  }
374  ss << "}";
375  return ss.str();
376 }
377 
378 #if ETISS_FAULT_XML
379 namespace xml
380 {
381 template <>
382 bool parse<etiss::fault::Trigger *>(pugi::xml_node node, etiss::fault::Trigger *&f, Diagnostics &diag)
383 {
384  etiss::log(etiss::VERBOSE, std::string("Called etiss::fault::xml::parse<etiss::fault::Trigger*>") +
385  std::string("(node, Trigger*&, Diagnostics)"));
386  f = 0;
387  std::string type;
388  if (!parse_attr(node, "type", type, diag))
389  {
390  return false;
391  }
392 
393  if (type == "META_COUNTER")
394  {
395  uint64_t count;
396  if (!parse<uint64_t>(findSingleNode(node, "count", diag), count, diag))
397  {
398  return false;
399  }
400  etiss::fault::Trigger *sub = 0;
401  if ((!parse<etiss::fault::Trigger *>(findSingleNode(node, "trigger", diag), sub, diag)) || (sub == 0))
402  {
403  diag.unexpectedNode(node, "Failed to parse sub trigger");
404  return false;
405  }
406  f = new etiss::fault::Trigger(*sub, count);
407  delete sub;
408  return true;
409  }
410 
411  if (type == "VARIABLEVALUE")
412  {
413  uint64_t value;
414  if (!parse_hex(findSingleNode(node, "value", diag), value, diag))
415  {
416  return false;
417  }
418  std::string field;
419  if (!parse<std::string>(findSingleNode(node, "field", diag), field, diag))
420  {
421  return false;
422  }
423  setCoreName(field);
425  if (!parse<etiss::fault::InjectorAddress>(findSingleNode(node, "injector", diag), injector, diag))
426  {
427  return false;
428  }
429  f = new Trigger(injector, field, value);
430  return true;
431  }
432 
433  if (type == "TIME")
434  {
435  uint64_t count;
436  if (!parse<uint64_t>(findSingleNode(node, "time_ps", diag), count, diag))
437  {
438  return false;
440  }
442  if (!parse<etiss::fault::InjectorAddress>(findSingleNode(node, "injector", diag), injector, diag))
443  {
444  return false;
445  }
446  f = new Trigger(injector, count);
447  return true;
448  }
449 
450  if (type == "TIMERELATIVE")
451  {
452  uint64_t count;
453  if (!parse<uint64_t>(findSingleNode(node, "time_ps", diag), count, diag))
454  {
455  return false;
457  }
459  if (!parse<etiss::fault::InjectorAddress>(findSingleNode(node, "injector", diag), injector, diag))
460  {
461  return false;
462  }
463  f = new Trigger(injector, count, true);
464  std::cout << "Injector2: " << f->getInjectorAddress().getInjectorPath() << std::endl;
465  return true;
466  }
467 
468  return false;
469 }
470 template <>
471 bool write<const etiss::fault::Trigger *>(pugi::xml_node node, const etiss::fault::Trigger *const &f, Diagnostics &diag)
472 {
473  etiss::log(etiss::VERBOSE, std::string("Called etiss::fault::xml::write<etiss::fault::Trigger*>") +
474  std::string("(node, Trigger*&, Diagnostics)"));
475  if (f == 0)
476  return false;
477  return write<etiss::fault::Trigger>(node, *f, diag);
478 }
479 
480 template <>
481 bool parse<etiss::fault::Trigger>(pugi::xml_node node, etiss::fault::Trigger &f, Diagnostics &diag)
482 {
483  etiss::log(etiss::VERBOSE, std::string("Called etiss::fault::xml::parse<etiss::fault::Trigger>") +
484  std::string("(node, Trigger&, Diagnostics)"));
485  etiss::fault::Trigger *t = 0;
486  if (!parse<etiss::fault::Trigger *>(node, t, diag))
487  return false;
488  f = *t;
489  delete t;
490  return true;
491 }
492 template <>
493 bool write<etiss::fault::Trigger>(pugi::xml_node node, const etiss::fault::Trigger &f, Diagnostics &diag)
494 {
495  etiss::log(etiss::VERBOSE, std::string("Called etiss::fault::xml::write<etiss::fault::Trigger>") +
496  std::string("(node, Trigger&, Diagnostics)"));
497  // std::cout << "write<etiss::fault::Trigger> called " << std::endl;
498  switch (f.getType())
499  {
501  {
502  write_attr<std::string>(node, "type", "META_COUNTER", diag);
503  write<uint64_t>(node.append_child("count"), f.getTriggerCount(), diag);
504  write<etiss::fault::Trigger>(node.append_child("trigger"), f.getSubTrigger(), diag);
505  }
506  return true;
508  {
509  write_attr<std::string>(node, "type", "VARIABLEVALUE", diag);
510  write<std::string>(node.append_child("field"), f.getTriggerField(), diag);
511  write<uint64_t>(node.append_child("count"), f.getTriggerFieldValue(), diag);
512  Injector_ptr ptr = f.getInjector();
513  if (!ptr)
514  {
515  diag.errors.push_back("A fault trigger has no target_injector. failed to "
516  "get path of trigger");
517  return false;
518  }
519  write<std::string>(node.append_child("injector"), ptr->getInjectorPath(), diag);
520  }
521  return true;
524  {
525  write_attr<std::string>(node, "type",
526  (f.getType() == etiss::fault::Trigger::TIMERELATIVE) ? "TIMERELATIVE" : "TIME", diag);
527  write<uint64_t>(node.append_child("time_ps"), f.getTriggerTime(), diag);
528  Injector_ptr ptr = f.getInjector();
529  if (!ptr)
530  {
531  diag.errors.push_back("A fault trigger has no target_injector. failed to "
532  "get path of trigger");
533  return false;
534  }
535  write<std::string>(node.append_child("injector"), ptr->getInjectorPath(), diag);
536  }
537  return true;
539  {
540  write_attr<std::string>(node, "type", "NOP", diag);
541  }
542  return true;
543  }
544 
545  diag.errors.push_back("etiss::fault::xml::write<etiss::fault::Trigger> "
546  "encountered an unknown type of trigger");
547 
548  return false;
549 }
550 
551 } // namespace xml
552 #endif
553 
554 } // namespace fault
555 
556 } // namespace etiss
contains the fault injector interface class.
general configuration and logging
contains the Trigger class that defines conditions under which actions of a Fault need to be applied.
static __inline__ uint64_t
Definition: arm_cde.h:31
const std::string & getInjectorPath() const
bool isResolved() const
> Calls Injector::get (implemented in VirtualStruct) to resolve path_ and get iptr_
const Injector_ptr & getInjector() const
virtual void * fastFieldAccessPtr(const std::string &name, std::string &errormsg)=0
std::string toString() const
operator<< can be used.
Definition: Trigger.cpp:352
const std::string & getTriggerField() const
Definition: Trigger.cpp:327
void ensure(Type type) const
Definition: Trigger.cpp:60
Trigger & getSubTrigger()
Definition: Trigger.cpp:275
const uint64_t & getTriggerFieldValue() const
Definition: Trigger.cpp:337
uint64_t getTriggerCount() const
Definition: Trigger.cpp:270
const Injector_ptr & getInjector() const
Definition: Trigger.cpp:305
Type getType() const
Definition: Trigger.cpp:347
bool fired(uint64_t time_ps, etiss::fault::Injector *target_injector)
this function checks if the Trigger has just fired.
Definition: Trigger.cpp:157
InjectorAddress inj_
Definition: Trigger.h:166
const InjectorAddress & getInjectorAddress() const
Definition: Trigger.cpp:301
Trigger()
Type: NOP (no operation)
Definition: Trigger.cpp:70
std::string field_
Definition: Trigger.h:164
Trigger & operator=(const Trigger &cpy)
Definition: Trigger.cpp:95
bool isNOP() const
Definition: Trigger.cpp:316
uint64_t getTriggerTime() const
Definition: Trigger.cpp:285
bool isResolved() const
returns if the translation from TIMERELATIVE to TIME trigger has taken place
Definition: Trigger.cpp:261
void resolveTime(uint64_t time)
this function calculates in case of a TIMERELATIVE Trigger a constant TIME trigger
Definition: Trigger.cpp:247
@ TIMERELATIVE
needs to be resolved.
Definition: Trigger.h:94
xml_node append_child(xml_node_type type=node_element)
Definition: pugixml.cpp:4983
void setCoreName(std::string &str)
Definition: XML.cpp:62
std::shared_ptr< Injector > Injector_ptr
Definition: Defs.h:83
Page Table Entry (PTE) defines the composition of Page Frame Number (PFN) and relavant flags.
Definition: Benchmark.h:53
@ VERBOSE
Definition: Misc.h:130
@ WARNING
Definition: Misc.h:128
@ ERROR
Definition: Misc.h:127
@ FATALERROR
Definition: Misc.h:126
void log(Verbosity level, std::string msg)
write log message at the given level.
Definition: Misc.cpp:125