33 "CPUArchRegListenerInterface::signalChangedRegisterValue() called from outside etiss::CPUCore::execute(). "
34 "this should not happen and indicates a faultiy CPUArch (or Plugin) implementation. This function may have "
35 "been called indirectly from ETISS_signalChangedRegisterValue()");
41 etiss::log(
etiss::ERROR,
"CPUArchRegListenerInterface::signalChangedRegisterValue() called but CPUArch didn't "
42 "provide a VirtualStruct.");
45 auto field = vs->findName(registerName);
48 field = vs->findPrettyName(registerName);
52 "CPUArchRegListenerInterface::signalChangedRegisterValue() called but the associated "
53 "VirtualStruct has not the specified field.",
61 "CPUArchRegListenerInterface::signalChangedRegisterValue() called but the field of the associated "
62 "VirtualStruct doesn't have the listerner flags set (etiss::VirtualStruct::Field::L).",
73 bool consumed =
false;
76 for (
auto iter : parent_.plugins)
84 consumed_by_interruptlistener_ =
false;
86 parent_.intvector_->setBit(bit, state);
90 consumed_by_interruptlistener_ =
true;
96 return parent_.intvector_->getBit(bit);
100 return parent_.intvector_->width();
104 return parent_.intvector_->isActive();
108 for (
unsigned i = 0; i < width(); i++)
126 ,
cpu_(arch->newCPU())
139#if ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
147 if (!
vcpu_->findName(
"instructionPointer"))
151 *
vcpu_,
"instructionPointer",
"",
157#if ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
158 if (!
vcpu_->findName(
"instructionCounter"))
161 *
vcpu_,
"instructionCounter",
"",
177 if (plugin.get() != 0)
180 std::lock_guard<std::mutex> lock(
mu_);
182 for (
const std::shared_ptr<etiss::Plugin> &p :
plugins)
184 if (p.get() == plugin.get())
190 if (plugin->plugin_core_)
193 *
this, *(plugin.get()));
197 plugin->plugin_core_ =
this;
198 plugin->setCorrespondingCPUCoreName(this->
getName());
199 plugin->addedToCPUCore(
this);
210 bool removed =
false;
212 std::lock_guard<std::mutex> lock(
mu_);
215 if (iter->get() == plugin.get())
234std::shared_ptr<CPUCore>
CPUCore::create(std::string archname, std::string instancename,
235 std::map<std::string, std::string> archoptions)
241 std::shared_ptr<etiss::CPUArch> arch =
getCPUArch(archname, archoptions);
250 std::shared_ptr<CPUCore> ret{
nullptr };
251 if (instancename !=
"")
252 ret.reset(
new CPUCore(arch, instancename));
266 std::list<std::string> ret;
271 auto ptr = iter->lock();
274 ret.push_back(ptr->getName() +
" [" + ptr->getArch()->getArchName() +
"," + ptr->getJITName() +
298 std::string prefix = std::string())
304 std::string code = std::string(prefix + R
"V0G0N(
305#include "etiss/jit/CPU.h"
306#include "etiss/jit/System.h"
307#include "etiss/jit/ReturnCode.h"
308#include "etiss/jit/types.h"
309etiss_int32 get_size() { return sizeof()V0G0N" +
310 structname + "); };");
312 std::set<std::string> headers;
316 void *handle = jit->
translate(code, headers, std::set<std::string>(), std::set<std::string>(), error, jit_debug);
320 std::string(
"Failed to compile test code [") + code +
"] to check struct size: " + error);
324 typedef etiss::int32 (*get_size)(void);
325 get_size gs = (get_size)jit->
getFunction(handle,
"get_size", error);
330 std::string(
"Failed to get compiled function [get_size] to check struct size: ") + error);
333 etiss::int32 r = gs();
335 if (r != expected_size)
337 std::stringstream ss;
338 ss <<
"Unexpected size of " << structname <<
";";
339 ss <<
" Expected: " << expected_size;
354 std::stringstream stru;
355 etiss::int32 expected_size = 0;
358 std::vector<const char *> types;
359 std::vector<etiss::int32> typeslen;
360 types.push_back(
"etiss_int8");
362 types.push_back(
"etiss_uint8");
364 types.push_back(
"etiss_int16");
366 types.push_back(
"etiss_uint16");
368 types.push_back(
"etiss_int32");
370 types.push_back(
"etiss_uint32");
372 types.push_back(
"etiss_int64");
374 types.push_back(
"etiss_uint64");
376 types.push_back(
"void*");
377 typeslen.push_back(
sizeof(
void *));
379 stru <<
"struct _etiss_test_struct {\n";
381 for (
size_t i = 0; i < types.size(); i++)
383 stru << types[i] <<
" var_" << i <<
";\n";
384 expected_size += typeslen[i];
385 for (
size_t j = 0; j < types.size(); j++)
389 stru << types[j] <<
" var_" << i <<
"_" << j <<
";\n";
390 expected_size += typeslen[j];
397 std::string code = std::string(
"\n#include \"etiss/jit/types.h\"\n#pragma pack(push, 1)\n") + stru.str() +
398 "\n#pragma pack(pop)\n etiss_int32 get_size(){ return sizeof(struct "
399 "_etiss_test_struct);}";
401 std::set<std::string> headers;
405 void *handle = jit->
translate(code, headers, std::set<std::string>(), std::set<std::string>(), error, jit_debug);
409 std::string(
"Failed to compile test code [") + code +
"] to check struct size: " + error);
412 typedef etiss::int32 (*get_size)(void);
414 get_size gs = (get_size)jit->
getFunction(handle,
"get_size", error);
419 std::string(
"Failed to get compiled function [get_size] to check struct size: ") + error);
422 etiss::int32 r = gs();
424 if (r != expected_size)
426 std::stringstream ss;
427 ss <<
"Unexpected size of test structure;";
428 ss <<
" Expected: " << expected_size;
445 if (
unlikely(code == RETURNCODE::NOERROR))
453 case RETURNCODE::RELOADBLOCKS:
456 code = RETURNCODE::NOERROR;
458 case RETURNCODE::RELOADCURRENTBLOCK:
460 block_ptr->
valid =
false;
462 code = RETURNCODE::NOERROR;
464 case RETURNCODE::GDBNOERROR:
465 code = RETURNCODE::NOERROR;
467 case RETURNCODE::CPUFINISHED:
478 std::list<etiss::RegisterDevicePlugin *>
plugins;
483 std::string name = field.
name_;
484 const char *cname = name.c_str();
485 for (
auto plugin : plugins)
489 plugin->changedRegister(cname);
501 return RETURNCODE::INVALIDSYSTEM;
504 std::lock_guard<std::mutex> lock(
mu_);
509 return RETURNCODE::GENERALERROR;
515 return RETURNCODE::GENERALERROR;
523 std::shared_ptr<JIT> jiti =
jit_;
527 return RETURNCODE::JITERROR;
531 if (
etiss::cfg().get<bool>(
"jit.verify",
true))
534 return RETURNCODE::JITCOMPILATIONERROR;
536 return RETURNCODE::JITCOMPILATIONERROR;
538 return RETURNCODE::JITCOMPILATIONERROR;
540 return RETURNCODE::JITCOMPILATIONERROR;
542 return RETURNCODE::JITCOMPILATIONERROR;
544 return RETURNCODE::JITCOMPILATIONERROR;
546 " has passed the verification tests (tested by CPUCore " +
name_ +
")");
555 return RETURNCODE::GENERALERROR;
560 auto local_arch =
arch_;
561 plugins.push_back(std::shared_ptr<etiss::Plugin>(timerInstance,
565 local_arch->deleteTimer(p);
583 plugins.push_back(std::make_shared<etiss::mm::DMMUWrapper>(
mmu_));
587 std::list<SystemWrapperPlugin *> syswrappers;
590 auto c = plugin->getSystemWrapperPlugin();
596 syswrappers.push_front(
c);
601 std::stringstream stream;
602 stream <<
"SystemWrapperPlugin \"" <<
c->getPluginName() <<
"\" failed to wrap ETISS_System instance";
614 p->plugin_cpu_ =
cpu_;
615 p->plugin_system_ = system;
616 p->plugin_arch_ =
arch_.get();
620 m <<
"Init Plugin " << p->getPluginName();
625 std::vector<CoroutinePlugin *> cor_array;
626 for (
const auto &plugin :
plugins)
628 auto c = plugin->getCoroutinePlugin();
630 cor_array.push_back(
c);
638 void **plugins_handle_ = translation.
init();
639 if (!plugins_handle_)
647 std::list<RegisterDevicePlugin *> regdevices;
650 auto rdp = plugin->getRegisterDevicePlugin();
652 regdevices.push_back(rdp);
654 if (!regdevices.empty())
658 "etiss::RegisterDevicePlugin is a legacy convenience plugin. it may become deprecated later on. "
659 "consider using etiss::VirtualStruct::Field::Listener to directly listen only for relevant fields.");
665 vcpu_->foreachField([listener](std::shared_ptr<etiss::VirtualStruct::Field> f)
666 { f->addListener(listener); });
674 "etiss::RegisterDevicePlugin added to a CPUCore that doesn't have a VirtualStruct.",
name_);
681 bool exit_on_loop =
etiss::cfg().
get<
bool>(
"etiss.exit_on_loop",
false);
683 struct timespec start, finish;
685 clock_gettime(CLOCK_MONOTONIC, &start);
689 etiss::int32 exception = RETURNCODE::NOERROR;
696#if ETISS_DBG_ICOUNT_LIMIT > 0 && ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
705 for (
auto &cor_plugin : cor_array)
707 exception = cor_plugin->execute();
708 if (
unlikely(exception != RETURNCODE::NOERROR))
711 if (
unlikely(exception != RETURNCODE::NOERROR))
719 for (
unsigned bc = 0; bc <
bcc_; bc++)
733 if (
mmu_->cache_flush_pending)
738 mmu_->cache_flush_pending =
false;
746 if ((exception =
arch_->handleException(exception,
cpu_)))
765 exception = RETURNCODE::ARCHERROR;
770 std::stringstream stream;
771 stream <<
"CPU execution stopped: Cannot execute from instruction index " << std::hex
774 exception = RETURNCODE::JITCOMPILATIONERROR;
781#if ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
787 exception = (*(blptr->
execBlock))(
cpu_, system, plugins_handle_);
793 exception = RETURNCODE::CPUFINISHED;
796#if ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
798 blptr->
end - oldinstrptr;
805 if (
unlikely(exception != RETURNCODE::NOERROR))
808 if (
unlikely(exception != RETURNCODE::NOERROR))
821 clock_gettime(CLOCK_MONOTONIC, &finish);
824 for (
auto &cor_plugin : cor_array)
826 cor_plugin->executionEnd(exception);
831 double simulation_time = (finish.tv_sec - start.tv_sec) + (finish.tv_nsec - start.tv_nsec) / 1000000000.0;
836 std::cout <<
"CPU Time: " << (cpu_time) <<
"s Simulation Time: " << (simulation_time) <<
"s" << std::endl;
838 std::cout <<
"CPU Cycles (estimated): " << (cpu_cycle) << std::endl;
840 std::cout <<
"MIPS (estimated): " << (mips) << std::endl;
844 std::string valid_json_output_path =
etiss::cfg().
get<std::string>(
"vp.stats_file_path",
"");
847 if (output_json ==
true)
849 std::ofstream json_output(valid_json_output_path);
850 json_output <<
"{\"mips\": " << mips <<
", \"Simulation_Time\": " << simulation_time
851 <<
", \"CPU_Time\": " << cpu_time <<
", \"CPU_cycle\": " << cpu_cycle <<
"}" << std::endl;
854#ifndef ETISS_USE_COREDSL_COVERAGE
855 if (
etiss::cfg().isSet(
"vp.coredsl_coverage_path"))
858 "coverage analysis, build ETISS with -DETISS_USE_COREDSL_COVERAGE");
862 std::string coverage_output_path =
etiss::cfg().
get<std::string>(
"vp.coredsl_coverage_path",
"coverage.csv");
865 std::ofstream coverage_output(coverage_output_path);
866 coverage_output <<
arch_->getArchName() << std::endl;
867 coverage_output <<
"ID;Count" << std::endl;
870 coverage_output << it.first <<
";" << it.second << std::endl;
887 std::cout <<
"CPU Cycles (with pipeline): " <<
max << std::endl;
897#if ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
910 p->plugin_cpu_ =
nullptr;
911 p->plugin_system_ =
nullptr;
912 p->plugin_arch_ =
nullptr;
917 for (
auto &syswrapper : syswrappers)
919 auto psys = syswrapper->unwrap(
cpu_, system);
926 std::stringstream stream;
927 stream <<
"SERVE WARNING: SystemWrapperPlugin \"" << syswrapper->getPluginName()
928 <<
"\" failed to unwrap ETISS_System instance. Most likely results in a memory leak.";
936 vcpu_->foreachField([listener](std::shared_ptr<etiss::VirtualStruct::Field> f)
937 { f->removeListener(listener); });
947 std::shared_ptr<ETISS_System> sys =
etiss::wrap(&system);
949 return RETURNCODE::GENERALERROR;
950 etiss::uint32 ret =
execute(*(sys.get()));
956 std::shared_ptr<etiss::JIT> jit =
jit_;
977 if (iter->_getPluginName() == name)
contains neccesary interfaces for instruction translation.
static void etiss_CPUCore_handleException(ETISS_CPU *cpu, etiss::int32 &code, BlockLink *&block_ptr, Translation &translator, CPUArch *arch)
small helper function to handle exceptions.
static bool verifyJITPragmaPack(etiss::JIT *jit)
generates test code to check alignment of structures in the just in time compiler
static bool verifyJITSizeOf(std::string structname, etiss::int32 expected_size, etiss::JIT *jit, std::string prefix=std::string())
generates and compiles test code for the just in time compiler to check size of basic types
defines main cpu core interface
std::map< int, int > coverage_map
Wrapper class to wrap aroud data MMU.
Header file of the ETISS library.
JIT compiler interface definition.
Modeling hardware memory management for virtual memory -> physical memory translation and protection.
__DEVICE__ int max(int __a, int __b)
__device__ __2f16 float c
static __inline__ uint64_t
#define ETISS_MAX_RESOURCES
int ETISS_System_isvalid(ETISS_System *sys)
LegacyRegisterDevicePluginListener(const std::list< etiss::RegisterDevicePlugin * > &plugins_)
std::list< etiss::RegisterDevicePlugin * > plugins
virtual ~LegacyRegisterDevicePluginListener()
virtual void write(etiss::VirtualStruct::Field &field, uint64_t val)
structure to store additional information with a function pointer to the translated code
const etiss::uint64 end
end instruction index (excluded)
const ExecBlockCall execBlock
function pointer
bool valid
true if the associated function implements current code
static void signalChangedRegisterValue(ETISS_CPU *cpu, const char *registerName)
call this function to inform RegisterDevicePlugins about changed special register values.
the interface to translate instructions of and processor architecture
virtual etiss::int32 handleException(etiss::int32 code, ETISS_CPU *cpu)
translate/process exceptions that occur at runtime
virtual void setBit(unsigned bit, bool state)
set the bit of an interrupt line to state (true = raised)
virtual unsigned width() const
number of interrupt bits
virtual bool getBit(unsigned bit) const
get the bit of an interrupt line
virtual bool isActive() const
InterruptVectorWrapper(CPUCore &parent)
virtual void clear()
sets every bit to false
CPUCore is responsible for the simulation of a CPU core in ETISS.
std::shared_ptr< etiss::mm::MMU > mmu_
std::mutex mu_
JIT instance to use. may be 0 (etiss::getDefaultJIT() will be used in that case)
const int id_
name of the cpu core
std::string getJITName()
Get the name of the JIT plug-in used by the CPUCore instance.
etiss::InterruptVector * intvector_
std::list< std::shared_ptr< Plugin > > plugins
mutex to lock the configuration of this cpu core.
unsigned exception_skip_count_
etiss::int32 execute(ETISS_System &system)
Start the simulation of the CPU core for the system model.
static std::mutex instances_mu_
this field is always present to maintain API compatibility but it is only used if ETISS_CPUCORE_DBG_A...
bool mmu_enabled_
TODO: possibility to limit the cache size.
std::shared_ptr< etiss::JIT > jit_
if true the a timer plugin allocated by arch_ will be added in CPUCore::execute
static std::list< std::string > list()
returns a list of currently present CPU cores
std::shared_ptr< etiss::CPUArch > arch_
CPUCore(std::shared_ptr< etiss::CPUArch > arch, std::string const &name)
Private constructor of CPUCore.
InterruptVectorWrapper * intwrapper_
cpu interrupt vector derived from cpu_ and allocated by arch_
void reset(etiss::uint64 *startindex)
Reset the CPU state.
static std::shared_ptr< CPUCore > create(std::string archname, std::string instancename="", std::map< std::string, std::string > archoptions=std::map< std::string, std::string >())
Create a CPUCore instance.
unsigned bcc_
list of all plugins
std::string name_
cpu architecture of this cpu core. may never be 0 or changed
ETISS_CPU * cpu_
ID of the cpu core.
void addPlugin(std::shared_ptr< etiss::Plugin > plugin)
Adds a plug-in to the core simulator.
std::shared_ptr< Plugin > getPlugin(std::string name)
returns the plugin with the given name.
std::shared_ptr< etiss::VirtualStruct > vcpu_
cpu state structure allocated by arch_
static std::list< std::weak_ptr< CPUCore > > instances_
mutext for access to a list of cpu core instances
void removePlugin(std::shared_ptr< etiss::Plugin > plugin)
Remove a plug-in from the core simulator.
virtual std::shared_ptr< VirtualStruct > getStruct()
Get the virtual structure of this CPUCore instance.
const std::string & getName()
Get the name of the CPUCore instance.
etiss::InterruptEnable * intenable_
wrapped interrupt vector to allow interrupt listening
bool isSet(std::string val)
return true if the value of an configuration key has been set
T get(const std::string &key, T default_, bool *default_used=0)
template function to read the value of a configuration key.
virtual bool interruptWrite(unsigned bit, bool value)=0
gets called whenever an external write to the interrrupt vector takes place
compiler interface for just in time compilation of generated C code
virtual void * getFunction(void *handle, std::string name, std::string &error)=0
returns a function pointer to a compiled function from the handle returned by etiss::JIT::translate
virtual void * translate(std::string code, std::set< std::string > headerpaths, std::set< std::string > librarypaths, std::set< std::string > libraries, std::string &error, bool debug=true)=0
translate C code to executable code and return a handle/pointer that identifies the compilation resul...
std::string getName()
returns the JIT instance name previously passed to the constructor
virtual void free(void *handle)=0
clean up handled returned by etiss::JIT::translate
base plugin class that provides access to different plugin functions if present
CPUCore * plugin_core_
holds a pointer to the associated CPUCore instance.
virtual void removedFromCPUCore(etiss::CPUCore *core)
called as soon a plugin has been removed from its CPUCore.
InterruptListenerPlugin * getInterruptListenerPlugin()
std::string getPluginName() const
System Interface for the basic system IO operations and time synchronization.
void unloadBlocks(etiss::uint64 startindex=0, etiss::uint64 endindex=((etiss::uint64)((etiss::int64) -1)))
BlockLink * getBlockFast(BlockLink *prev, const etiss::uint64 &instructionindex)
CALL THIS function NOT getBlock(...) since getBlock will not check next/branch references.
NOTE: etiss::CPUArch should implement support for Listeners by either using the etiss::VirtualStruct:...
a Field instance represents e.g.
static const int W
write flag
const std::string name_
name of the field.
static const int L
supports listener plugins; used for etiss::RegisterDevicePlugins to determine access to a variable/fi...
static const int P
private field: this flag indicates that this field is an implementation specific field that e....
static const int R
read flag
conatins a convinience class that can be wrapped as a ETISS_System structure
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.
void forceInitialization()
Force the initialization of ETISS.
std::string jitFiles()
Get ETISS JIT files path.
std::string toString(const T &val)
conversion of type T to std::string.
std::shared_ptr< ETISS_System > wrap(etiss::System *sys)
wraps a etiss::System in a ETISS_System structure.
void log(Verbosity level, std::string msg)
write log message at the given level.
basic cpu state structure needed for execution of any cpu architecture.
etiss_uint64 instructionPointer
pointer to next instruction.
const char * resources[ETISS_MAX_RESOURCES]
names of resources
etiss_uint64 cpuCycleTime_ps
frequency of the cpu. use to allign e.g. memory delays
etiss_uint64 cpuTime_ps
simulation time of cpu
etiss_uint64 resourceUsages[ETISS_MAX_RESOURCES]
how many cycles each resource is used
void * _etiss_private_handle_
private helper handle for plugins
etiss_uint64 cycles[ETISS_MAX_RESOURCES]
how many cycles in each resource (including waiting)
memory access and time synchronization functions.
void * handle
custom handle that will be passed to the functions of this structure
void(* syncTime)(void *handle, ETISS_CPU *cpu)
called after a block to synchronize the time