38 using namespace etiss;
50 "CPUArchRegListenerInterface::signalChangedRegisterValue() called from outside etiss::CPUCore::execute(). "
51 "this should not happen and indicates a faultiy CPUArch (or Plugin) implementation. This function may have "
52 "been called indirectly from ETISS_signalChangedRegisterValue()");
58 etiss::log(
etiss::ERROR,
"CPUArchRegListenerInterface::signalChangedRegisterValue() called but CPUArch didn't "
59 "provide a VirtualStruct.");
62 auto field = vs->findName(registerName);
65 field = vs->findPrettyName(registerName);
69 "CPUArchRegListenerInterface::signalChangedRegisterValue() called but the associated "
70 "VirtualStruct has not the specified field.",
78 "CPUArchRegListenerInterface::signalChangedRegisterValue() called but the field of the associated "
79 "VirtualStruct doesn't have the listerner flags set (etiss::VirtualStruct::Field::L).",
90 bool consumed =
false;
93 for (
auto iter : parent_.plugins)
101 consumed_by_interruptlistener_ =
false;
103 parent_.intvector_->setBit(bit, state);
107 consumed_by_interruptlistener_ =
true;
113 return parent_.intvector_->getBit(bit);
117 return parent_.intvector_->width();
121 return parent_.intvector_->isActive();
125 for (
unsigned i = 0; i < width(); i++)
143 ,
cpu_(arch->newCPU())
156 #if ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
164 if (!
vcpu_->findName(
"instructionPointer"))
168 *
vcpu_,
"instructionPointer",
"",
174 #if ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
175 if (!
vcpu_->findName(
"instructionCounter"))
178 *
vcpu_,
"instructionCounter",
"",
193 if (plugin.get() != 0)
196 std::lock_guard<std::mutex> lock(
mu_);
198 for (
const std::shared_ptr<etiss::Plugin> &p :
plugins)
200 if (p.get() == plugin.get())
206 if (plugin->plugin_core_)
209 *
this, *(plugin.get()));
213 plugin->plugin_core_ =
this;
214 plugin->setCorrespondingCPUCoreName(this->
getName());
215 plugin->addedToCPUCore(
this);
226 bool removed =
false;
228 std::lock_guard<std::mutex> lock(
mu_);
231 if (iter->get() == plugin.get())
250 std::shared_ptr<CPUCore>
CPUCore::create(std::string archname, std::string instancename,
251 std::map<std::string, std::string> archoptions)
257 std::shared_ptr<etiss::CPUArch> arch =
getCPUArch(archname, archoptions);
266 std::shared_ptr<CPUCore> ret(
new CPUCore(arch));
278 std::list<std::string> ret;
283 auto ptr = iter->lock();
286 ret.push_back(ptr->getName() +
" [" + ptr->getArch()->getArchName() +
"," + ptr->getJITName() +
310 std::string prefix = std::string())
316 std::string code = std::string(prefix +
"\n#include \"etiss/jit/CPU.h\"\n#include "
317 "\"etiss/jit/System.h\"\n#include \"etiss/jit/ReturnCode.h\"\n "
318 "#include \"etiss/jit/types.h\"\n#include "
319 "\"etiss/jit/fpu/softfloat.h\"\n etiss_int32 get_size(){ return "
323 std::set<std::string> headers;
326 void *handle = jit->
translate(code, headers, std::set<std::string>(), std::set<std::string>(), error,
true);
330 std::string(
"Failed to compile test code [") + code +
"] to check struct size: " + error);
335 get_size gs = (get_size)jit->
getFunction(handle,
"get_size", error);
340 std::string(
"Failed to get compiled function [get_size] to check struct size: ") + error);
345 if (r != expected_size)
347 std::stringstream ss;
348 ss <<
"Unexpected size of " << structname <<
";";
349 ss <<
" Expected: " << expected_size;
364 std::stringstream stru;
368 std::vector<const char *> types;
369 std::vector<etiss::int32> typeslen;
370 types.push_back(
"etiss_int8");
372 types.push_back(
"etiss_uint8");
374 types.push_back(
"etiss_int16");
376 types.push_back(
"etiss_uint16");
378 types.push_back(
"etiss_int32");
380 types.push_back(
"etiss_uint32");
382 types.push_back(
"etiss_int64");
384 types.push_back(
"etiss_uint64");
386 types.push_back(
"void*");
387 typeslen.push_back(
sizeof(
void *));
389 stru <<
"struct _etiss_test_struct {\n";
391 for (
size_t i = 0; i < types.size(); i++)
393 stru << types[i] <<
" var_" << i <<
";\n";
394 expected_size += typeslen[i];
395 for (
size_t j = 0; j < types.size(); j++)
399 stru << types[j] <<
" var_" << i <<
"_" << j <<
";\n";
400 expected_size += typeslen[j];
407 std::string code = std::string(
"\n#include \"etiss/jit/types.h\"\n#pragma pack(push, 1)\n") + stru.str() +
408 "\n#pragma pack(pop)\n etiss_int32 get_size(){ return sizeof(struct "
409 "_etiss_test_struct);}";
411 std::set<std::string> headers;
414 void *handle = jit->
translate(code, headers, std::set<std::string>(), std::set<std::string>(), error,
true);
418 std::string(
"Failed to compile test code [") + code +
"] to check struct size: " + error);
423 get_size gs = (get_size)jit->
getFunction(handle,
"get_size", error);
428 std::string(
"Failed to get compiled function [get_size] to check struct size: ") + error);
433 if (r != expected_size)
435 std::stringstream ss;
436 ss <<
"Unexpected size of test structure;";
437 ss <<
" Expected: " << expected_size;
462 case RETURNCODE::RELOADBLOCKS:
467 case RETURNCODE::RELOADCURRENTBLOCK:
469 block_ptr->
valid =
false;
473 case RETURNCODE::GDBNOERROR:
476 case RETURNCODE::CPUFINISHED:
487 std::list<etiss::RegisterDevicePlugin *>
plugins;
492 std::string name = field.
name_;
493 const char *cname = name.c_str();
494 for (
auto plugin : plugins)
498 plugin->changedRegister(cname);
510 return RETURNCODE::INVALIDSYSTEM;
513 std::lock_guard<std::mutex> lock(
mu_);
518 return RETURNCODE::GENERALERROR;
524 return RETURNCODE::GENERALERROR;
532 std::shared_ptr<JIT> jiti =
jit_;
536 return RETURNCODE::JITERROR;
541 if (
etiss::cfg().get<bool>(
"jit.verify",
true))
544 return RETURNCODE::JITCOMPILATIONERROR;
546 return RETURNCODE::JITCOMPILATIONERROR;
548 return RETURNCODE::JITCOMPILATIONERROR;
550 return RETURNCODE::JITCOMPILATIONERROR;
552 return RETURNCODE::JITCOMPILATIONERROR;
554 return RETURNCODE::JITCOMPILATIONERROR;
556 " has passed the verification tests (tested by CPUCore " +
name_ +
")");
565 return RETURNCODE::GENERALERROR;
570 auto local_arch =
arch_;
571 plugins.push_back(std::shared_ptr<etiss::Plugin>(timerInstance, [local_arch](
etiss::Plugin *p) {
573 local_arch->deleteTimer(p);
591 plugins.push_back(std::make_shared<etiss::mm::DMMUWrapper>(
mmu_));
595 std::list<SystemWrapperPlugin *> syswrappers;
598 auto c = plugin->getSystemWrapperPlugin();
604 syswrappers.push_front(
c);
609 std::stringstream stream;
610 stream <<
"SystemWrapperPlugin \"" <<
c->getPluginName() <<
"\" failed to wrap ETISS_System instance";
622 p->plugin_cpu_ =
cpu_;
623 p->plugin_system_ = system;
624 p->plugin_arch_ =
arch_.get();
628 m <<
"Init Plugin " << p->getPluginName();
633 std::vector<CoroutinePlugin *> cor_array;
634 for (
const auto &plugin :
plugins)
636 auto c = plugin->getCoroutinePlugin();
638 cor_array.push_back(
c);
646 void **plugins_handle_ = translation.
init();
647 if (!plugins_handle_)
655 std::list<RegisterDevicePlugin *> regdevices;
658 auto rdp = plugin->getRegisterDevicePlugin();
660 regdevices.push_back(rdp);
662 if (!regdevices.empty())
666 "etiss::RegisterDevicePlugin is a legacy convenience plugin. it may become deprecated later on. "
667 "consider using etiss::VirtualStruct::Field::Listener to directly listen only for relevant fields.");
673 vcpu_->foreachField([listener](std::shared_ptr<etiss::VirtualStruct::Field> f) {
674 f->addListener(listener);
683 "etiss::RegisterDevicePlugin added to a CPUCore that doesn't have a VirtualStruct.",
name_);
690 bool exit_on_loop =
etiss::cfg().
get<
bool>(
"etiss.exit_on_loop",
false);
692 float startTime = (
float)
clock() / CLOCKS_PER_SEC;
703 #if ETISS_DBG_ICOUNT_LIMIT > 0 && ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
712 for (
auto &cor_plugin : cor_array)
714 exception = cor_plugin->execute();
726 for (
unsigned bc = 0; bc <
bcc_; bc++)
740 if (
mmu_->cache_flush_pending)
745 mmu_->cache_flush_pending =
false;
753 if ((exception =
arch_->handleException(exception,
cpu_)))
772 exception = RETURNCODE::ARCHERROR;
777 std::stringstream stream;
778 stream <<
"CPU execution stopped: Cannot execute from instruction index " << std::hex
781 exception = RETURNCODE::JITCOMPILATIONERROR;
788 #if ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
794 exception = (*(blptr->
execBlock))(
cpu_, system, plugins_handle_);
797 if (exit_on_loop && !exception &&
801 exception = RETURNCODE::CPUFINISHED;
804 #if ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
806 blptr->
end - oldinstrptr;
830 float endTime = (
float)
clock() / CLOCKS_PER_SEC;
834 for (
auto &cor_plugin : cor_array)
836 cor_plugin->executionEnd(exception);
841 double simulation_time = endTime - startTime;
844 std::cout <<
"CPU Time: " << (cpu_time) <<
"s Simulation Time: " << (simulation_time) <<
"s"
846 std::cout <<
"CPU Cycles (estimated): " << (cpu_cycle) << std::endl;
847 std::cout <<
"MIPS (estimated): " << (mips) << std::endl;
851 std::string valid_json_output_path =
etiss::cfg().
get<std::string>(
"vp.stats_file_path",
"");
854 if(output_json==
true)
856 std::ofstream json_output(valid_json_output_path);
857 json_output <<
"{\"mips\": " << mips <<
", \"Simulation_Time\": " << simulation_time <<
", \"CPU_Time\": " << cpu_time <<
", \"CPU_cycle\": " << cpu_cycle <<
"}" << std::endl;
860 #ifndef ETISS_USE_COREDSL_COVERAGE
861 if (
etiss::cfg().isSet(
"vp.coredsl_coverage_path")) {
862 etiss::log(
etiss::WARNING,
"Coverage Analysis is disabled but vp.coredsl_coverage_path is set. To enable coverage analysis, build ETISS with -DETISS_USE_COREDSL_COVERAGE");
866 std::string coverage_output_path =
etiss::cfg().
get<std::string>(
"vp.coredsl_coverage_path",
"coverage.csv");
868 std::ofstream coverage_output(coverage_output_path);
869 coverage_output <<
arch_->getArchName() << std::endl;
870 coverage_output <<
"ID;Count" << std::endl;
872 coverage_output << it.first <<
";" << it.second << std::endl;
890 std::cout <<
"CPU Cycles (with pipeline): " <<
max << std::endl;
900 #if ETISS_CPUCORE_DBG_APPROXIMATE_INSTRUCTION_COUNTER
913 p->plugin_cpu_ =
nullptr;
914 p->plugin_system_ =
nullptr;
915 p->plugin_arch_ =
nullptr;
920 for (
auto &syswrapper : syswrappers)
922 auto psys = syswrapper->unwrap(
cpu_, system);
929 std::stringstream stream;
930 stream <<
"SERVE WARNING: SystemWrapperPlugin \"" << syswrapper->getPluginName()
931 <<
"\" failed to unwrap ETISS_System instance. Most likely results in a memory leak.";
940 [listener](std::shared_ptr<etiss::VirtualStruct::Field> f) { f->removeListener(listener); });
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
Header file of the ETISS library.
__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.
CPUCore(std::shared_ptr< etiss::CPUArch > arch)
Private constructor of CPUCore.
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
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_
InterruptVectorWrapper * intwrapper_
cpu interrupt vector derived from cpu_ and allocated by arch_
friend class InterruptVectorWrapper
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< 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 * 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...
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 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.
InterruptListenerPlugin * getInterruptListenerPlugin()
virtual void removedFromCPUCore(etiss::CPUCore *core)
called as soon a plugin has been removed from its CPUCore.
std::string getPluginName() const
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
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.
MM_EXPORT const int32_t NOERROR
Page Table Entry (PTE) defines the composition of Page Frame Number (PFN) and relavant flags.
std::string jitFiles()
Get ETISS JIT files path.
std::string toString(const T &val)
conversion of type T to std::string.
Configuration & cfg(const std::string &cfgName)
Get reference of the global ETISS configuration object.
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