ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ETISS.cpp
Go to the documentation of this file.
1
36#include "etiss/ETISS.h"
38
39#include <csignal>
40#include <cstring>
41#include <fstream>
42#include <functional>
43
44#include <boost/program_options/options_description.hpp>
45#include <boost/program_options/parsers.hpp>
46#include <boost/program_options/variables_map.hpp>
47#include <boost/algorithm/string.hpp>
48
49#include "SimpleIni.h"
50// SimpleIni includes windows.h which defines NOERROR, clashing with our ReturnCode.
51#ifdef NOERROR
52#undef NOERROR
53#endif
54
55#if ETISS_USE_DLSYM
56#include <dlfcn.h>
57#endif
58
59using namespace etiss;
60
62
63std::list<std::shared_ptr<etiss::LibraryInterface>> etiss_libraries_;
64std::recursive_mutex etiss_libraries_mu_;
65
66boost::program_options::variables_map vm;
67std::vector<std::string> pluginOptions = {"plugin.logger.logaddr", "plugin.logger.logmask", "plugin.gdbserver.port"};
68
69std::set<std::string> etiss::listCPUArchs()
70{
71 std::set<std::string> ret;
72 std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
73 for (auto iter = etiss_libraries_.begin(); iter != etiss_libraries_.end(); iter++)
74 {
75 if ((*iter).get() != 0)
76 {
77 if (!(*iter)->isEmpty())
78 {
79 for (unsigned i = 0; i < (*iter)->countCPUArchs(); i++)
80 {
81 std::string jit = (*iter)->nameCPUArch(i);
82 if (ret.find(jit) != ret.end())
83 {
84 etiss::log(etiss::ERROR, "CPUArch provided by multiple libraries: \"" + jit + "\"");
85 }
86 else
87 {
88 ret.insert(jit);
89 }
90 }
91 }
92 }
93 }
94 return ret;
95}
96
97std::set<std::string> etiss::listJITs()
98{
99 std::set<std::string> ret;
100 std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
101 for (auto iter = etiss_libraries_.begin(); iter != etiss_libraries_.end(); iter++)
102 {
103 if ((*iter).get() != 0)
104 {
105 if (!(*iter)->isEmpty())
106 {
107 for (unsigned i = 0; i < (*iter)->countJITs(); i++)
108 {
109 std::string jit = (*iter)->nameJIT(i);
110 if (ret.find(jit) != ret.end())
111 {
112 etiss::log(etiss::ERROR, "JIT provided by multiple libraries: \"" + jit + "\"");
113 }
114 else
115 {
116 ret.insert(jit);
117 }
118 }
119 }
120 }
121 }
122 return ret;
123}
124
125std::set<std::string> etiss::listPlugins()
126{
127 std::set<std::string> ret;
128 std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
129 for (auto iter = etiss_libraries_.begin(); iter != etiss_libraries_.end(); iter++)
130 {
131 if ((*iter).get() != 0)
132 {
133 if (!(*iter)->isEmpty())
134 {
135 for (unsigned i = 0; i < (*iter)->countPlugins(); i++)
136 {
137 std::string jit = (*iter)->namePlugin(i);
138 if (ret.find(jit) != ret.end())
139 {
140 etiss::log(etiss::ERROR, "JIT provided by multiple libraries: \"" + jit + "\"");
141 }
142 else
143 {
144 ret.insert(jit);
145 }
146 }
147 }
148 }
149 }
150 return ret;
151}
152
153std::shared_ptr<JIT> etiss::getJIT(std::string name, std::map<std::string, std::string> options)
154{
155 std::shared_ptr<JIT> jit;
156 std::string ujit;
157 std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
158 for (auto iter = etiss_libraries_.begin(); iter != etiss_libraries_.end(); iter++)
159 {
160 std::shared_ptr<LibraryInterface> lib = *iter;
161 if (lib.get() != 0)
162 {
163 if (!lib->isEmpty())
164 {
165 for (unsigned i = 0; i < lib->countJITs(); i++)
166 {
167 if (lib->nameJIT(i) == name)
168 {
169 if (jit.get() != 0)
170 {
171 etiss::log(etiss::ERROR, "JIT provided by multiple libraries: using \"" + name +
172 "\" from library \"" + ujit +
173 "\" [also provided by library \"" + lib->getName() + "\"]");
174 }
175 else
176 {
177 etiss::JIT *ca = lib->createJIT(i, options);
178 if (ca == 0)
179 {
181 "Failed to create JIT via library interface \"" + lib->getName() + "\"");
182 }
183 else
184 {
185 jit = std::shared_ptr<JIT>(ca, [lib](JIT *j) { lib->deleteJIT(j); });
186 ujit = lib->getName();
187 }
188 }
189 }
190 }
191 }
192 }
193 }
194 return jit;
195}
196
197std::shared_ptr<CPUArch> etiss::getCPUArch(std::string name, std::map<std::string, std::string> options)
198{
199 std::shared_ptr<CPUArch> arch;
200 std::string uarch;
201 std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
202 for (auto iter = etiss_libraries_.begin(); iter != etiss_libraries_.end(); iter++)
203 {
204 std::shared_ptr<LibraryInterface> lib = *iter;
205 if (lib.get() != 0)
206 {
207 if (!lib->isEmpty())
208 {
209 for (unsigned i = 0; i < lib->countCPUArchs(); i++)
210 {
211 if (lib->nameCPUArch(i) == name)
212 {
213 if (arch.get() != 0)
214 {
215 etiss::log(etiss::ERROR, "CPU Architecture provided by multiple libraries: using \"" +
216 name + "\" from library \"" + uarch +
217 "\" [also provided by library \"" + lib->getName() + "\"]");
218 }
219 else
220 {
221 etiss::CPUArch *ca = lib->createCPUArch(i, options);
222 if (ca == 0)
223 {
225 "Failed to create CPUArch via library interface \"" + lib->getName() + "\"");
226 }
227 else
228 {
229 arch = std::shared_ptr<CPUArch>(ca, [lib](CPUArch *a) { lib->deleteCPUArch(a); });
230 uarch = lib->getName();
231 }
232 }
233 }
234 }
235 }
236 }
237 }
238 return arch;
239}
240
241std::shared_ptr<Plugin> etiss::getPlugin(std::string name, std::map<std::string, std::string> options)
242{
243 std::shared_ptr<Plugin> ptrPlugin;
244 std::string strPluginName;
245 std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
246 for (auto iter = etiss_libraries_.begin(); iter != etiss_libraries_.end(); iter++)
247 {
248 std::shared_ptr<LibraryInterface> lib = *iter;
249 if (lib.get() != 0)
250 {
251 if (!lib->isEmpty())
252 {
253 for (unsigned i = 0; i < lib->countPlugins(); i++)
254 {
255 if (lib->namePlugin(i) == name)
256 {
257 if (ptrPlugin.get() != 0)
258 {
259 etiss::log(etiss::ERROR, "Plugin provided by multiple libraries: using \"" + name +
260 "\" from library \"" + strPluginName +
261 "\" [also provided by library \"" + lib->getName() + "\"]");
262 }
263 else
264 {
265 etiss::Plugin *ca = lib->createPlugin(i, options);
266 if (ca == 0)
267 {
269 "Failed to create Plugin via library interface \"" + lib->getName() + "\"");
270 }
271 else
272 {
273 ptrPlugin = std::shared_ptr<Plugin>(ca, [lib](Plugin *p) { lib->deletePlugin(p); });
274 strPluginName = lib->getName();
275 etiss::log(etiss::INFO, "Plugin \"" + name + "\" loaded via library interface \"" +
276 strPluginName + "\"\n");
277 }
278 }
279 break;
280 }
281 }
282 }
283 }
284 }
285 return ptrPlugin;
286}
287
288bool etiss::loadLibrary(std::string path, std::string name)
289{
290 auto lib = etiss::LibraryInterface::openSharedLibrary(path, name);
291
292 if (lib.get())
293 {
294 addLibrary(lib);
295 return true;
296 }
297
298 return false;
299}
300
301void etiss::addLibrary(std::shared_ptr<etiss::LibraryInterface> libInterface)
302{
303 etiss::LibraryInterface *lif = libInterface.get();
304
305 if (lif == 0)
306 {
307 return;
308 }
309
311
312 {
313 std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
314 etiss_libraries_.push_back(libInterface);
315 }
316 // if no default jit is present, try to use one from this library
317 for (unsigned i = 0; (etiss_defaultjit_.size() <= 0) && (i < libInterface->countJITs()); i++)
318 {
319 etiss_defaultjit_ = libInterface->nameJIT(i);
320 }
321}
322std::set<std::string> etiss::listLibraries()
323{
324 std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
325 std::set<std::string> ret;
326 for (auto iter = etiss_libraries_.begin(); iter != etiss_libraries_.end(); iter++)
327 {
328 ret.insert((*iter)->getName() + "[" + (*iter)->versionInfo() + "]");
329 }
330 return ret;
331}
332
333std::set<std::string> etiss::listLibraryPrefixes()
334{
335 std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
336 std::set<std::string> ret;
337 for (auto iter = etiss_libraries_.begin(); iter != etiss_libraries_.end(); iter++)
338 {
339 ret.insert((*iter)->getName());
340 }
341 return ret;
342}
343
344std::shared_ptr<etiss::JIT> etiss::getDefaultJIT()
345{
347}
348
349// transfer controll to etiss console on SIGINT
352
354{
355 if (sig == SIGINT)
356 {
357 std::cout << std::endl << "\033[0;31m" << std::endl;
359 std::cout << std::endl << "\033[0m" << std::endl;
360 }
361 else
362 { // false handler assignment
363 signal(sig, SIG_DFL);
364 raise(sig);
365 return;
366 }
367}
368
369//__attribute__((destructor))
371{
373 {
376 }
377}
384
385// initialize
386CSimpleIniA *po_simpleIni;
387void etiss_loadIni(std::string fileName)
388{
389 if (po_simpleIni == NULL)
390 po_simpleIni = new CSimpleIniA(true, true, true);
391
392 SI_Error rc = po_simpleIni->LoadFile(fileName.c_str());
393 if (rc < 0)
394 std::cout << "Initializer::loadIni(): Failed to load Ini: " << fileName << std::endl;
395 else
396 std::cout << "Initializer::loadIni(): Ini sucessfully loaded " << fileName << std::endl;
397}
398
399void etiss::Initializer::loadIni(std::list<std::string> *files)
400{
401 std::cout << " Load ini file." << std::endl;
402 // create ini parser
403 if (po_simpleIni == NULL)
404 po_simpleIni = new CSimpleIniA(true, true, true);
405 else
406 std::cout << "Info: simpleIni already exists!" << std::endl;
407
408 // load file
409 for (auto it_files : *files)
410 {
411 // the check above is sufficient no need for this / checked for previous cases false and last true gives true not the case based on files structure
412 etiss_loadIni(it_files);
413 }
414}
415
417{
418 if (!po_simpleIni) // no .ini files were given.
419 {
420 return;
421 }
422 std::cout << " Load Configs from .ini files:" << std::endl;
423
424 // preload loglevel
425 if (!etiss::cfg().isSet("etiss.loglevel"))
426 {
427 etiss::cfg().set<int>("etiss.loglevel", po_simpleIni->GetLongValue("IntConfigurations", "etiss.loglevel", etiss::WARNING));
428 }
429 {
430 int ll = cfg().get<int>("etiss.loglevel", etiss::WARNING);
431 if (ll >= 0 && ll <= etiss::VERBOSE)
432 { // valid log level
433 // dnm
434 // etiss::verbosity() = etiss::VERBOSE;
436 etiss::log(etiss::VERBOSE, "Log level set to VERBOSE");
437 }
438 else
439 {
441 etiss::log(etiss::ERROR, "Specified log level is not valid. must range between 0 (= "
442 "silent) and 5 (= verbose)");
443 }
444 }
445
446 // get all sections
447 CSimpleIniA::TNamesDepend sections;
448 po_simpleIni->GetAllSections(sections);
449 for (auto iter_section : sections)
450 {
451 // only load config sections
452 if (std::string(iter_section.pItem) != "StringConfigurations" &&
453 std::string(iter_section.pItem) != "BoolConfigurations" &&
454 std::string(iter_section.pItem) != "IntConfigurations")
455 {
456 continue;
457 }
458 etiss::log(etiss::INFO, std::string(" [") + iter_section.pItem + ']');
459
460 // get all keys in a section
461 CSimpleIniA::TNamesDepend keys;
462 po_simpleIni->GetAllKeys(iter_section.pItem, keys);
463 for (auto iter_key : keys)
464 {
465 std::stringstream message;
466 bool warning = false;
467
468 // skip loglevel
469 if (std::string(iter_key.pItem) == "etiss.loglevel")
470 continue;
471
472 // check if cfg is already set
473 if (etiss::cfg().isSet(iter_key.pItem))
474 {
475 message << " cfg already set on command line. ";
476 message << " " << iter_key.pItem << "=";
477 const ::std::type_info& type = vm[std::string(iter_key.pItem)].value().type() ;
478 if (type == typeid(::std::string))
479 message << vm[std::string(iter_key.pItem)].as<std::string>() << ",";
480 else if (type == typeid(int))
481 message << vm[std::string(iter_key.pItem)].as<int>() << ",";
482 else if (type == typeid(bool))
483 message << std::boolalpha << vm[std::string(iter_key.pItem)].as<bool>() << ",";
484 warning = true;
485 }
486 else
487 {
488 // write key (=option) to message.
489 message << " " << iter_key.pItem << "=";
490
491 // get all values of a key with multiple values
492 CSimpleIniA::TNamesDepend values;
493 po_simpleIni->GetAllValues(iter_section.pItem, iter_key.pItem, values);
494 for (auto iter_value : values)
495 {
496 // Handle configurations
497 if (std::string(iter_section.pItem) == "StringConfigurations")
498 {
499 etiss::cfg().set<std::string>(iter_key.pItem, iter_value.pItem);
500 }
501 else if (std::string(iter_section.pItem) == "BoolConfigurations")
502 {
503 std::string itemval = iter_value.pItem;
504 boost::algorithm::to_lower(itemval); // converts itemval to lower case string
505 bool val;
506
507 if ((itemval == "true") | (itemval == "yes") | (itemval == "1") | (itemval == "t")) val = true;
508 else if ((itemval == "false") | (itemval == "no") | (itemval == "0") | (itemval == "f")) val = false;
509 else etiss::log(etiss::FATALERROR, std::string("Configuration value ") + iter_key.pItem + " could not be parsed as boolean");
510
511 etiss::cfg().set<bool>(iter_key.pItem, val);
512 }
513 else if (std::string(iter_section.pItem) == "IntConfigurations") // already load!
514 {
515 std::string itemval = iter_value.pItem;
516 std::size_t sz = 0;
517 long long val;
518 try {
519 val = std::stoll(itemval, &sz, 0);
520 }
521 // catch invalid_argument exception.
522 catch (std::invalid_argument const&){
523 etiss::log(etiss::FATALERROR, std::string("Configuration value ") + iter_key.pItem + " could not be parsed as integer");
524 }
525 etiss::cfg().set<long long>(iter_key.pItem, val);
526 // we use double, as long could have only 32 Bit (e.g. on Windows)
527 // and long long is not offered by the ini library
528 }
529 else
530 // we don't add a DoubleConfigurations section, as converting them
531 // to and from strings could provoke accuracy issues.
532 // To support double, a Configuration::get<double>() has to be
533 // added to Misc.cpp
534 {
535 message << " Section not found for Value:";
536 warning = true;
537 }
538
539 // write item (=option value) to message.
540 message << iter_value.pItem << ",";
541 }
542
543 // check if more than one value is set in the ini file
544 if (values.size() > 1)
545 {
546 warning = true;
547 message << " Multi values. Take only LAST one!";
548 }
549 }
550 // add message to etiss log.
551 etiss::log(warning ? etiss::WARNING : etiss::INFO, message.str());
552 }
553 }
554}
555
556void etiss::Initializer::loadIniPlugins(std::shared_ptr<etiss::CPUCore> cpu)
557{
558 std::map<std::string, std::string> options;
559 for (auto iter = pluginOptions.begin(); iter != pluginOptions.end(); iter++)
560 {
561 if (etiss::cfg().isSet(*iter))
562 {
563 options[*iter] = std::string(vm[std::string(*iter)].as<std::string>());
564 etiss::log(etiss::INFO, *iter + " written from command line\n" + " options[" +
565 std::string(*iter) +
566 "] = " + std::string(vm[std::string(*iter)].as<std::string>()) + "\n");
567 }
568 }
569 if (vm.count("pluginToLoad"))
570 {
571 const std::vector<std::string> pluginList = vm["pluginToLoad"].as<std::vector<std::string>>();
572 for (auto pluginName = pluginList.begin(); pluginName != pluginList.end(); pluginName++)
573 {
574 std::string::size_type pos = std::string(*pluginName).length();
575 bool pluginAlreadyPresent = false;
576 for (auto iter : *cpu->getPlugins())
577 {
578 std::string pluginNamecpu = iter->getPluginName();
579 if (pos != std::string::npos)
580 {
581 pluginNamecpu = pluginNamecpu.substr(0, pos);
582 }
583 if (pluginNamecpu == *pluginName)
584 {
585 pluginAlreadyPresent = true;
586 break;
587 }
588 }
589 if (pluginAlreadyPresent)
590 {
591 etiss::log(etiss::WARNING, " Warning: Plugin already present. Skipping it: " + *pluginName + "\n");
592 continue;
593 }
594 etiss::log(etiss::INFO, " Adding Plugin " + *pluginName + "\n");
595 std::shared_ptr<Plugin> plugin = etiss::getPlugin(*pluginName, options);
596 if (!plugin)
597 etiss::log(etiss::FATALERROR, "Plugin not found: " + *pluginName + "\n");
598 cpu->addPlugin(plugin);
599 }
600 }
601 if (!po_simpleIni)
602 {
603 etiss::log(etiss::WARNING, "Ini file not loaded. Can't load plugins from simpleIni!");
604 return;
605 }
606 // get all sections
607 CSimpleIniA::TNamesDepend sections;
608 po_simpleIni->GetAllSections(sections);
609 for (auto iter_section : sections)
610 {
611 // only load Plugin sections
612 if (std::string(iter_section.pItem).substr(0, 6) != std::string("Plugin"))
613 continue;
614 std::string pluginName = std::string(iter_section.pItem).substr(7);
615 std::string::size_type pos = pluginName.length();
616 // check if Plugin is already present
617 bool pluginAlreadyPresent = false;
618 for (auto iter : *cpu->getPlugins())
619 {
620 std::string pluginNamecpu = iter->getPluginName();
621 if (pos != std::string::npos)
622 {
623 pluginNamecpu = pluginNamecpu.substr(0, pos);
624 }
625 if (pluginNamecpu == pluginName)
626 {
627 pluginAlreadyPresent = true;
628 break;
629 }
630 }
631 if (pluginAlreadyPresent)
632 {
633 etiss::log(etiss::WARNING, " Warning: Plugin already present. Skipping it: " + pluginName + "\n");
634 continue;
635 }
636
637 etiss::log(etiss::INFO, " Adding Plugin " + pluginName + "\n");
638
639 // get all keys in a section = plugin option
640 CSimpleIniA::TNamesDepend keys;
641 po_simpleIni->GetAllKeys(iter_section.pItem, keys);
642 for (auto iter_key : keys)
643 {
644 // get all values of a key with multiple values = value of option
645 CSimpleIniA::TNamesDepend values;
646 po_simpleIni->GetAllValues(iter_section.pItem, iter_key.pItem, values);
647 if (!etiss::cfg().isSet(iter_key.pItem))
648 {
649 std::stringstream ss;
650 ss << iter_key.pItem << " not set on the command line. Checking in .ini file.";
651 etiss::log(etiss::INFO, ss.str());
652
653 for (auto iter_value : values)
654 {
655 options[iter_key.pItem] = iter_value.pItem;
657 " options[" + std::string(iter_key.pItem) + "] = " + std::string(iter_value.pItem) + "\n\n");
658 }
659 // check if more than one value is set in the ini file
660 if (values.size() > 1)
661 etiss::log(etiss::WARNING, "Multiple values for option. Took only last one!");
662 }
663 }
664 std::shared_ptr<Plugin> plugin = etiss::getPlugin(pluginName, options);
665 if (!plugin)
666 etiss::log(etiss::FATALERROR, "Plugin not found: " + pluginName + "\n");
667 cpu->addPlugin(plugin);
668 }
669}
670
671void etiss::Initializer::loadIniJIT(std::shared_ptr<etiss::CPUCore> cpu)
672{
673 // check if JIT is set
674 if (!etiss::cfg().isSet("jit.type"))
675 {
676 etiss::log(etiss::INFO, "No JIT configured. Will use default JIT. \n");
677 cpu->set(etiss::getDefaultJIT());
678 return;
679 }
680 if (cpu->getJITName() != "")
681 {
683 "etiss::Initializer::loadIniJIT:" + std::string(" JIT already present. Overwriting it."));
684 }
685 etiss::log(etiss::INFO, " Adding JIT \"" + cfg().get<std::string>("jit.type", "") + '\"');
686 cpu->set(getJIT(cfg().get<std::string>("jit.type", "")));
687}
688
689std::pair<std::string, std::string> inifileload(const std::string& s)
690{
691 if (s.find("-i") == 0)
692 {
693 std::string inifile;
694 inifile = s.substr(2);
695 etiss_loadIni(inifile);
696 }
697 return make_pair(std::string(), std::string());
698}
699
700void etiss_initialize(const std::vector<std::string>& args, bool forced = false)
701{
702 static std::mutex mu_;
703 static bool initialized_(false);
704 {
705 std::lock_guard<std::mutex> lock(mu_);
706 if (initialized_)
707 {
708 if (!forced)
709 {
710 etiss::log(etiss::WARNING, "Multiple calls to etiss::initialize");
711 }
712 else
713 {
714 return;
715 }
716 }
717 else
718 {
719 if (forced)
720 {
721 etiss::log(etiss::WARNING, "etiss::initialize has not been called before using ETISS library "
722 "functions. Please add the line \'etiss::initialize(argc,argv);\' "
723 "at the beginning of \'int main(int argc, char**argv);\'");
724 }
725 }
726 initialized_ = true;
727 }
728
729 {
730 namespace po = boost::program_options;
731 try
732 {
733 po::options_description desc("Allowed options");
734 desc.add_options()
735 ("help", "Produce a help message that lists all supported options.")
736 ("arch.cpu", po::value<std::string>(), "The CPU Architecture to simulate.")
737 ("arch.or1k.ignore_sr_iee", po::value<bool>(), "Ignore exception on OpenRISC.")
738 ("arch.or1k.if_stall_cycles", po::value<int>(), "Add instruction stall cycles on OpenRISC.")
739 ("arch.cpu_cycle_time_ps", po::value<int>(), "Sets CPU cycles time on OpenRISC and ARM.")
740 ("arch.enable_semihosting", po::value<bool>(), "Enables semihosting operations")
741 ("etiss.enable_dmi", po::value<bool>(), "Enables the Direct Memory Interface feature of SystemC to speed up memory accesses. This needs to be disabled for memory tracing.")
742 ("etiss.log_pc", po::value<bool>(), "Enables logging of the program counter.")
743 ("etiss.max_block_size", po::value<int>(), "Sets maximum amount of instructions in a block.")
744 ("etiss.output_path_prefix", po::value<std::string>(), "Path prefix to use when writing output files.")
745 ("etiss.loglevel", po::value<int>(), "Verbosity of logging output.")
746 ("jit.gcc.cleanup", po::value<bool>(), "Cleans up temporary files in GCCJIT. ")
747 ("jit.verify", po::value<bool>(), "Run some basic checks to verify the functionality of the JIT engine.")
748 ("jit.debug", po::value<bool>(), "Causes the JIT Engines to compile in debug mode.")
749 ("jit.type", po::value<std::string>(), "The JIT compiler to use.")
750 ("jit.external_headers", po::value<std::string>(), "List of semicolon-separated paths to headers for the JIT to include.")
751 ("jit.external_libs", po::value<std::string>(), "List of semicolon-separated library names for the JIT to link.")
752 ("jit.external_header_paths", po::value<std::string>(), "List of semicolon-separated headers paths for the JIT.")
753 ("jit.external_lib_paths", po::value<std::string>(), "List of semicolon-separated library paths for the JIT.")
754 ("vp.sw_binary_ram", po::value<std::string>(), "Path to binary file to be loaded into RAM.")
755 ("vp.sw_binary_rom", po::value<std::string>(), "Path to binary file to be loaded into ROM.")
756 ("vp.elf_file", po::value<std::string>(), "Load ELF file.")
757 ("vp.stats_file_path", po::value<std::string>(), "Path where the output json file gets stored after bare processor is run.")
758 ("simple_mem_system.print_dbus_access", po::value<bool>(), "Traces accesses to the data bus.")
759 ("simple_mem_system.print_ibus_access", po::value<bool>(), "Traces accesses to the instruction bus.")
760 ("simple_mem_system.print_dbgbus_access", po::value<bool>(), "Traces accesses to the debug bus.")
761 ("simple_mem_system.print_to_file", po::value<bool>(), "Write all tracing to a file instead of the terminal. The file will be located at etiss.output_path_prefix.")
762 ("plugin.logger.logaddr", po::value<std::string>(), "Provides the compare address that is used to check for memory accesses that are redirected to the logger.")
763 ("plugin.logger.logmask", po::value<std::string>(), "Provides the mask that is used to check for memory accesses that are redirected to the logger.")
764 ("plugin.gdbserver.port", po::value<std::string>(), "Option for gdbserver")
765 ("pluginToLoad,p", po::value<std::vector<std::string>>()->multitoken(), "List of plugins to be loaded.")
766 ;
767
768 po::command_line_parser parser{args};
769 po::command_line_parser iniparser{args};
770 iniparser.options(desc).allow_unregistered().extra_parser(inifileload).run();
771 parser.options(desc).allow_unregistered().extra_parser(etiss::Configuration::set_cmd_line_boost);
772 po::parsed_options parsed_options = parser.run();
773 po::store(parsed_options, vm);
774
775 if (vm.count("help"))
776 {
777 std::cout << "\nPlease begin all options with --\n\n";
778 std::cout << desc << "\n";
779 etiss::log(etiss::FATALERROR, std::string("Please choose the right configurations from the list and re-run.\n"));
780 }
781
782 auto unregistered = po::collect_unrecognized(parsed_options.options, po::include_positional);
783 for (auto iter_unreg : unregistered)
784 {
785 if (iter_unreg.find("-i") != 0 && iter_unreg.find("-p"))
786 {
787 etiss::log(etiss::FATALERROR, std::string("Unrecognised option ") + iter_unreg +
788 "\n\t Please use --help to list all recognised options. \n");
789 }
790 }
791
792 for (po::variables_map::iterator i = vm.begin() ; i != vm.end() ; ++ i)
793 {
794 const po::variable_value& v = i->second;
795 if (!v.empty())
796 {
797 const ::std::type_info& type = v.value().type();
798 if (type == typeid(::std::string))
799 {
800 const ::std::string& val = v.as<::std::string>() ;
801 etiss::cfg().set<std::string>(std::string(i->first), val);
802 }
803 else if (type == typeid(int))
804 {
805 int val = v.as<int>();
806 etiss::cfg().set<int>(std::string(i->first), val);
807 }
808 else if (type == typeid(bool))
809 {
810 bool val = v.as<bool>();
811 etiss::cfg().set<bool>(std::string(i->first), val);
812 }
813 }
814 }
815 }
816 catch(std::exception& e)
817 {
818 etiss::log(etiss::FATALERROR, std::string(e.what()) +
819 "\n\t Please use --help to list all recognised options. \n");
820 }
821 }
823
824 // log level
825 {
826 int ll = cfg().get<int>("etiss.loglevel", etiss::WARNING);
827 if (ll >= 0 && ll <= etiss::VERBOSE)
828 { // valid log level
829 // dnm
830 // etiss::verbosity() = etiss::VERBOSE;
832 etiss::log(etiss::VERBOSE, "Log level set to VERBOSE");
833 }
834 else
835 {
837 etiss::log(etiss::ERROR, "Specified log level is not valid. must range between 0 (= "
838 "silent) and 5 (= verbose)");
839 }
840 }
841
842 etiss::py::init(); // init python
843
846
847 // load integrated library
848 if (cfg().get<bool>("etiss.load_integrated_libraries", true))
849 {
851 }
852
853 // check if some required files can be found
854 {
855 std::string path = etiss::installDir();
856 std::vector<std::string> requiredFiles;
857
858 // required files
859 requiredFiles.push_back(path + "/include/jit/etiss/jit/CPU.h");
860
861 // check
862 for (auto iter = requiredFiles.begin(); iter != requiredFiles.end(); iter++)
863 {
864 std::ifstream f(iter->c_str());
865 if (!f)
866 {
867 etiss::log(etiss::WARNING, std::string("Could not find file: ") + *iter + "\n" +
868 "\t The installation seems broken");
869 }
870 }
871 }
872
873 // load fault files
874 {
875 std::string faults = cfg().get<std::string>("faults.xml", "");
876 if (!faults.empty())
877 {
878 std::list<std::string> ffs = etiss::split(faults, ';');
879 for (auto ff : ffs)
880 {
882 }
883 }
884 }
885}
886
887void etiss::initialize(std::vector<std::string>& args)
888{
889 etiss_initialize(args, false);
890}
891
893{
894 std::vector<std::string> args{};
895 etiss_initialize(args, true);
896}
897
898//__attribute__((destructor))
899static void etiss_shutdown()
900{
901 etiss::shutdown(); // TODO: verify with spec. assuming shared library close
902 // after __attribute__((destructor)) functions have been
903 // called
904
905 // force close open libraries
906 //{
907 // std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
908 // etiss_libraries_.clear();
909 //}
910}
917
918bool etiss_shutdownOk = false;
919
921{
922 if (etiss_shutdownOk) // only on shutdown
923 return;
924
925 etiss_shutdownOk = true;
926
928
929 // unload libraries
930 {
931 std::list<std::weak_ptr<LibraryInterface>> libraries_weak;
932 {
933 std::lock_guard<std::recursive_mutex> lock(etiss_libraries_mu_);
934 for (auto iter = etiss_libraries_.begin(); iter != etiss_libraries_.end(); iter++)
935 {
936 libraries_weak.push_back(std::weak_ptr<LibraryInterface>(*iter));
937 }
938 etiss_libraries_.clear();
939 }
940 for (auto iter = libraries_weak.begin(); iter != libraries_weak.end(); iter++)
941 {
942 std::shared_ptr<LibraryInterface> li = iter->lock();
943 if (li.get() != 0)
944 {
945 std::stringstream ss;
946 ss << "Failed to unload library \"" << li.get()->getName() << "\": ";
947 ss << li.use_count() - 1 << " references " << std::endl;
948 etiss::log(etiss::ERROR, ss.str());
949 }
950 }
951 }
952
953 // check for existing cpu core instances
954 {
955 std::list<std::string> cores = CPUCore::list();
956 if (cores.size() > 0)
957 {
958 for (auto iter = cores.begin(); iter != cores.end(); iter++)
959 {
960 etiss::log(etiss::ERROR, std::string("CPU core has not been deleted before "
961 "etiss::shutdown() call: ") +
962 *iter);
963 }
964 }
965 }
966
968}
969
973//__attribute__((destructor))
975{
976 if (!etiss_shutdownOk)
977 {
978 etiss::log(etiss::ERROR, "To prevent segmentation faults it is neccessary to call "
979 "\"etiss::shutdown();\" at the end of main and free any "
980 "resource acquired through ETISS.");
981 }
982}
989
996
997std::string etiss::errorMessage(etiss::int32 code, CPUArch *arch)
998{
999 if (code <= 0)
1000 { // global code
1001 const char *msg = etiss::RETURNCODE::getErrorMessages()[code];
1002 if (msg == 0)
1003 return std::string();
1004 return std::string(msg);
1005 }
1006 else
1007 { // cpu arch dependent code
1008 if (arch != 0)
1009 {
1010 std::string ret = arch->getName() + ": ";
1012 return ret;
1013 }
1014 else
1015 {
1016 return "Unknown CPU architecture dependent error code.";
1017 }
1018 }
1019}
1020
ETISS_PLUGIN_EXPORT etiss::CPUArch std::map< std::string, std::string > options
create new instance of the CPUArch type at index
void etiss_loadIni(std::string fileName)
Definition ETISS.cpp:387
boost::program_options::variables_map vm
Definition ETISS.cpp:66
bool etiss_SIGINT_handler_enabled
Definition ETISS.cpp:351
static void etiss_shutdown()
Definition ETISS.cpp:899
void(* etiss_prev_SIGINT_handler)(int)=0
Definition ETISS.cpp:350
bool etiss_shutdownOk
Definition ETISS.cpp:918
CSimpleIniA * po_simpleIni
Definition ETISS.cpp:386
std::pair< std::string, std::string > inifileload(const std::string &s)
Definition ETISS.cpp:689
std::string etiss_defaultjit_
Definition ETISS.cpp:61
static void etiss_check_shutdown()
check if etiss::shutdown() was called before exiting main.
Definition ETISS.cpp:974
std::recursive_mutex etiss_libraries_mu_
Definition ETISS.cpp:64
void etiss_SIGINT_handler(int sig)
Definition ETISS.cpp:353
static void etiss_remove_SIGINT()
Definition ETISS.cpp:370
std::list< std::shared_ptr< etiss::LibraryInterface > > etiss_libraries_
Definition ETISS.cpp:63
void etiss_loadIniConfigs()
Definition ETISS.cpp:416
std::vector< std::string > pluginOptions
Definition ETISS.cpp:67
void etiss_initialize(const std::vector< std::string > &args, bool forced=false)
Definition ETISS.cpp:700
Header file of the ETISS library.
contains the stressor class that loads and activates faults.
__device__ __2f16 float bool s
do v
Definition arm_acle.h:76
the interface to translate instructions of and processor architecture
Definition CPUArch.h:162
std::string getName() const
returns the name of this architecture.
Definition CPUArch.h:184
static std::list< std::string > list()
returns a list of currently present CPU cores
Definition CPUCore.cpp:276
static std::pair< std::string, std::string > set_cmd_line_boost(const std::string &s)
Definition Misc.cpp:388
bool isSet(std::string val)
return true if the value of an configuration key has been set
Definition Misc.cpp:382
bool set(const std::string &key, T value)
template function to set the value of a configuration key.
Definition Misc.h:372
T get(const std::string &key, T default_, bool *default_used=0)
template function to read the value of a configuration key.
Definition Misc.h:349
void loadIni(std::list< std::string > *files)
creates a simpleIni object which holds the data of the given .ini file.
Definition ETISS.cpp:399
void loadIniPlugins(std::shared_ptr< etiss::CPUCore > cpu)
loads the plugins given with the previous loaded .ini files
Definition ETISS.cpp:556
void loadIniJIT(std::shared_ptr< etiss::CPUCore > cpu)
sets the JIT given with the previous loaded .ini files
Definition ETISS.cpp:671
~Initializer()
Destructor that shutdowns ETISS.
Definition ETISS.cpp:990
compiler interface for just in time compilation of generated C code
Definition JIT.h:67
interface class for libraries.
static std::shared_ptr< LibraryInterface > openIntegratedLibrary()
static std::shared_ptr< LibraryInterface > openSharedLibrary(std::string path, std::string name)
base plugin class that provides access to different plugin functions if present
Definition Plugin.h:77
static bool loadXML(const std::string &file, const int coreID=0)
extracts faults out of the given xml file.
Definition Stressor.cpp:80
static void clear()
clears the fault map.
Definition Stressor.cpp:274
replaces __attribute__((destructor)) in a portable way
Definition ETISS.cpp:913
replaces __attribute__((destructor)) in a portable way
Definition ETISS.cpp:380
replaces __attribute__((destructor)) in a portable way
Definition ETISS.cpp:985
std::shared_ptr< etiss::JIT > getDefaultJIT()
Get the default JIT implementation.
Definition ETISS.cpp:344
bool loadLibrary(std::string path, std::string name)
Load a library.
Definition ETISS.cpp:288
std::shared_ptr< Plugin > getPlugin(std::string name, std::map< std::string, std::string > options=std::map< std::string, std::string >())
Get a present Plugin plug-in by name.
Definition ETISS.cpp:241
std::string errorMessage(etiss::int32 code, CPUArch *arch=0)
Get the error message for an error code for a specific CPUArch plug-in.
Definition ETISS.cpp:997
std::set< std::string > listLibraryPrefixes()
Create a set with strings of the library names.
Definition ETISS.cpp:333
std::set< std::string > listJITs()
Create a set with all identifier names of the known JIT plug-ins.
Definition ETISS.cpp:97
void preloadLibraries()
Search and try to load libraries.
std::set< std::string > listPlugins()
Create a set with all identifier names of the known plug-ins.
Definition ETISS.cpp:125
std::shared_ptr< JIT > getJIT(std::string name, std::map< std::string, std::string > options=std::map< std::string, std::string >())
Get a present JIT plug-in by name.
Definition ETISS.cpp:153
std::shared_ptr< CPUArch > getCPUArch(std::string name, std::map< std::string, std::string > options=std::map< std::string, std::string >())
Get a present CPUArch plug-in by name.
Definition ETISS.cpp:197
void shutdown()
Shutdown ETISS.
Definition ETISS.cpp:920
std::set< std::string > listCPUArchs()
Create a set with all identifier names of the known CPUArch plug-ins.
Definition ETISS.cpp:69
void addLibrary(std::shared_ptr< etiss::LibraryInterface > libInterface)
Add a LibraryInterface to the ETISS environment.
Definition ETISS.cpp:301
void initialize(std::vector< std::string > &args)
Initialize and configure ETISS.
Definition ETISS.cpp:887
std::set< std::string > listLibraries()
Create a set with strings of the library names and some information appended in square brackets.
Definition ETISS.cpp:322
void forceInitialization()
Force the initialization of ETISS.
Definition ETISS.cpp:892
void shutdown()
Page Table Entry (PTE) defines the composition of Page Frame Number (PFN) and relavant flags.
Definition Benchmark.h:53
std::list< std::string > split(const std::string &str, std::function< size_t(const std::string &, size_t, size_t &)> findsplit)
Definition Misc.cpp:91
std::string Configuration::get< std::string >(const std::string &key, std::string default_, bool *default_used)
Definition Misc.cpp:255
std::string installDir()
Get ETISS installation directory.
Definition Misc.cpp:583
Verbosity
Enumeration type for the log levels.
Definition Misc.h:124
@ INFO
Definition Misc.h:129
@ VERBOSE
Definition Misc.h:130
@ WARNING
Definition Misc.h:128
@ ERROR
Definition Misc.h:127
@ FATALERROR
Definition Misc.h:126
Configuration & cfg()
Definition Misc.cpp:577
Verbosity & verbosity()
Get log level reference.
Definition Misc.cpp:120
void log(Verbosity level, std::string msg)
write log message at the given level.
Definition Misc.cpp:125
#define NULL