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