ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
|
ETISS itself (libETISS.so/.a) is a framework that uses implementations of etiss::CPUArch,etiss::JIT and etiss::Plugin to translate instructions to C code, compile the generated code and extend simulation capabilities.
These implementations are provided by libraries (shared or integrated)
Shared libraries and the integrated library of ETISS are wrapped in a etiss::LibraryInterface object. Those objects are then added with etiss::addLibrary .etiss::CPUArch,etiss::JIT and etiss::Plugin implementations from added libraries can then be instantiated with etiss::getCPUArch , etiss::getJIT and etiss::getPlugin. This concept allows to combine different library sources under one interface and even add new libraries at runtime. In case of implementing a shared library consider Removing symbols from a shared library
For each of the 3 base classes (etiss::CPUArch,etiss::JIT and etiss::Plugin) etiss::LibraryInterface provides a method to count,name,instantiate and delete an implementation:
In case of a shared library a special implementation of etiss::LibraryInterface loads a lib*.so file with dlopen (RTLD_GLOBAL flag is set) and looks for symbols of functions that implement the above shown methods. Use etiss::loadLibrary to open a shared library manually. To avoid name clashed between multiple loaded libraries the symbols are expected to be prefixed with the library name. An example header file for those functions of a library called libYOURLIB.so could look like this:
"extern int YOURLIB_etissversion()" allows to prevent loading of incompatible libraries. Other functions are defined similar to the methods of the etiss::LibraryInterface. Only the functions for the type of implementations a shared library provides need to be implemented (note the missing functions for etiss::JIT in above example). It is also possible to bundle a static library with libETISS.so/.a . In this case no change to the code needs to be made since ETISS will fist try to load a shared library and then falls back to the current application to load these functions (Integrate a Library into an executable using ETISS).
Refer to How to implement a cpu architecture for ETISS , How to implement a just in time compiler for ETISS and How to implement a plugin for ETISS for step by step examples of how to implement a shared library.
Due to the compilation of C code at runtime various files (mostly headers) are needed at runtime. The scrip includeHeaderCodegen.py allows to generate c/c++ code that contains those files together with a relative path in arrays. For a list of options that can be passed to the script run "$ python includeHeaderCodegen.py -h":
Example command as used by ETISS itself:
Shortened example output for the files stored within ETISS:
Apart from using includeHeaderCodegen.py any custom storage/generation mechanism can be used to ensure availability of files at runtime.
When a etiss::LibraryInterface is added via etiss::addLibrary then etiss::LibraryInterface::getFileCount,etiss::LibraryInterface::getFileName and etiss::LibraryInterface::getFileData are used to create those files. In case of a shared library these function need to be implemented for libYOURLIB.so like this:
Those files will be extracted relative to the path specified by the configuration option "etiss_wd" (can be changed before etiss::initialize with etiss::cfg.set("etiss_wd","/some/path")). By default the path is set to "~/.etiss/" ETISS_VERSION_STRING "/" (e.g. ~/.etiss/0.2/). Since the relative file paths are simply appended the etiss_wd value must end with "/".
If the target file already exists it will not be overwritten. Libraries need to consider using version numbers in their relative paths to prevent file version conflicts.