15#include "etiss/jit/CPU.h"
20#include <unordered_map>
22#include "elfio/elfio.hpp"
27#define ARMv6M_DEBUG_PRINT 0
38 std::cout << message <<
" (" << (count + 1) <<
"x)" << std::endl;
43 etiss::uint8 *mem, std::string initString,
bool InitEleSet, uint64_t randomRoot)
44 : name_(name), start_addr_(start_addr), end_addr_(start_addr + size - 1), size_(size), mode_(mode)
52 mem_ =
new etiss::uint8[size];
55 memInit(initString, randomRoot);
60 etiss::fmt::format(
"The memory segment is allocated uninitialized with length {:#x} !",
size_));
68 if (initString.find(
"0x") == 0)
71 etiss::fmt::format(
"The memory segment is initialized with {:#x} elements with value: 0x{:s}",
size_,
75 initString.erase(initString.begin(), initString.begin() + 2);
78 for (etiss::uint64 i = 0; i <
size_; ++i)
80 std::string hexStr =
"";
81 if (j != (initString.length() - 1))
83 hexStr = initString.substr(j, 2);
87 hexStr = initString.substr(j, 1);
90 j = (j + 2 <= initString.length() - 1) ? j + 2 : 0;
94 uint8_t hexVal =
static_cast<uint8_t>(std::stoi(hexStr.c_str(), 0, 16));
97 catch (std::invalid_argument
const &
exp)
99 std::stringstream memMsg;
100 memMsg <<
"\n Hex Value MemSegment input is erronous (typo?) at " <<
exp.what();
106 else if (initString.find(
"random") == 0 || initString.find(
"RANDOM") == 0)
109 etiss::fmt::format(
"The memory segment is initialized with {:#x} random bytes and root: {:d}",
size_,
112 static std::default_random_engine generator{ randomRoot };
113 std::uniform_int_distribution<int> random_char_{ 0, 255 };
114 for (etiss::uint64 i = 0; i <
size_; ++i)
116 mem_[i] = random_char_(generator);
123 etiss::fmt::format(
"The memory segment is initialized with {:#x} elements with the string: {:s}",
126 const char *data = initString.c_str();
127 for (etiss::uint64 i = 0; i <
size_; ++i)
129 mem_[i] = data[i % strlen(data)];
136 if (data !=
nullptr && (offset + file_size_bytes) <=
size_)
151 return (((addr + payload_size - 1) <=
end_addr_) ?
true :
false);
160 std::sort(
msegs_.begin(),
msegs_.end(), [](std::unique_ptr<MemSegment> &a, std::unique_ptr<MemSegment> &
b)
161 { return a->start_addr_ < b->start_addr_; });
166 std::stringstream ss;
180 auto cfgstr = etiss::fmt::format(
"simple_mem_system.memseg_initelement_{:02d}", i);
181 std::string initString =
etiss::cfg().
get<std::string>(cfgstr,
"");
185 etiss::fmt::format(
"simple_mem_system.memseg_initelement_random_root_{:02d}", i), 0);
188 etiss::cfg().
get<std::string>(etiss::fmt::format(
"simple_mem_system.memseg_image_{:02d}", i),
"");
191 etiss::cfg().
get<std::string>(etiss::fmt::format(
"simple_mem_system.memseg_mode_{:02d}", i),
"");
193 if (origin != (etiss::uint64)-1 &&
length != (etiss::uint64)-1)
198 std::string modestr =
"";
199 if (mode.find(
'R') != mode.npos)
204 if (mode.find(
'W') != mode.npos)
209 if (mode.find(
'X') != mode.npos)
216 etiss::fmt::format(
"{} - {:s}[{:#016x} - {:#016x}]", i + 1, modestr, origin +
length - 1, origin);
218 etiss::uint8 *buf =
nullptr;
223 std::ifstream ifs(image, std::ifstream::binary | std::ifstream::ate);
227 etiss::fmt::format(
"Error during read of segment image file {:s}!", image));
230 ifs.seekg(0, std::ifstream::beg);
232 buf =
new etiss::uint8[fsize];
234 ifs.read((
char *)buf, fsize);
238 "The memory segment {:d} is initialized with {:#x} bytes from input_image!", i,
length)
244 buf, initString, initEleSet, randomRoot);
256 std::string elf_file =
etiss::cfg().
get<std::string>(
"vp.elf_file",
"");
260 if (!reader.load(elf_file))
267 std::stringstream ss;
268 ss <<
"Assuming CPU architecture " <<
etiss::cfg().
get<std::string>(
"arch.cpu",
"")
269 <<
" as set in configuration file. ELF architecture field will be ignored";
275 if (reader.get_machine() == EM_RISCV)
277 if ((reader.get_class() == ELFCLASS64))
281 else if ((reader.get_class() == ELFCLASS32))
293 std::stringstream ss;
294 ss <<
"Target architecture with code 0x" << std::hex << std::setw(2) << std::setfill(
'0')
295 << reader.get_machine()
296 <<
" was not automatically recognized, please set the arch.cpu parameter manually!";
299 std::stringstream ss;
300 ss <<
"Set ETISS architecture to " <<
etiss::cfg().
get<std::string>(
"arch.cpu",
"")
301 <<
" as specified in ELF-file.";
305 for (
auto &seg : reader.segments)
307 etiss::uint64 start_addr = seg->get_physical_address();
308 etiss::uint64 size = seg->get_memory_size();
311 size_t file_size = seg->get_file_size();
312 if (seg->get_type() != PT_LOAD)
316 std::string modestr =
"";
317 if (seg->get_flags() & PF_R)
322 if (seg->get_flags() & PF_W)
327 if (seg->get_flags() & PF_X)
333 std::string sname = etiss::fmt::format(
"{} - {:s}[{:#016x} - {:#016x}]", seg->get_index(), modestr,
334 start_addr + size - 1, start_addr);
338 if (mseg_it !=
msegs_.end())
340 auto &mseg = *mseg_it;
345 mseg->load(seg->get_data(), start_addr - mseg->start_addr_, file_size);
347 std::stringstream msg;
348 msg <<
"Initialized the memory segment " << mseg->name_ <<
" from ELF-file";
354 std::stringstream msg;
355 msg << etiss::fmt::format(
"Found no matching memory segments at {:#016x}", start_addr);
359 msg <<
"! As you turned on error_on_seg_mismatch, ETISS will now terminate.";
364 msg <<
", creating one. WARNING: the segment will be created with the size information present in the "
365 "ELF-file, the resulting segment may be too small to fit dynamic data (cache, heap)!";
369 auto mseg = std::make_unique<MemSegment>(start_addr, size,
static_cast<MemSegment::access_t>(mode), sname);
379 std::stringstream msg;
380 msg <<
"New Memory segment added: " << mseg->name_;
383 mseg->load(raw_data, 0, file_size_bytes);
385 msegs_.push_back(std::move(mseg));
389 : print_ibus_access_(
etiss::
cfg().get<
bool>(
"simple_mem_system.print_ibus_access",
false))
390 , print_dbus_access_(
etiss::
cfg().get<
bool>(
"simple_mem_system.print_dbus_access",
false))
391 , print_dbgbus_access_(
etiss::
cfg().get<
bool>(
"simple_mem_system.print_dbgbus_access",
false))
392 , print_to_file_(
etiss::
cfg().get<
bool>(
"simple_mem_system.print_to_file",
false))
393 , error_on_seg_mismatch_(
etiss::
cfg().get<
bool>(
"simple_mem_system.error_on_seg_mismatch",
false))
394 , message_max_cnt_(
etiss::
cfg().get<
int>(
"simple_mem_system.message_max_cnt", 100))
407 etiss::fmt::format(
"{:s}, PC = {:#016x}, address {:#016x}, length {:#x}", error, pc, addr, len));
414 return RETURNCODE::NOERROR;
417 return RETURNCODE::IBUS_READ_ERROR;
423 return RETURNCODE::IBUS_WRITE_ERROR;
426static void trace(
ETISS_CPU *cpu, etiss::uint64 addr, etiss::uint32 len,
bool isWrite,
bool toFile, std::ofstream &file)
436 auto text = etiss::fmt::format(
"{:d};{:#08x};{};{:#08x};{:#x}", time, pc, (isWrite ?
'w' :
'r'), addr, len);
439 file << text << std::endl;
441 std::cout << text << std::endl;
449 if (mseg_it !=
msegs_.end())
451 auto &mseg = *mseg_it;
454 if (!(mseg->mode_ & access))
456 access_error(cpu, addr, len, std::string(
"dbus ") + (write ?
"write" :
"read") +
" forbidden",
460 size_t offset = addr - mseg->start_addr_;
462 void *dest = write ? mseg->mem_ + offset : buf;
463 const void *src = write ? buf : mseg->mem_ + offset;
470 return RETURNCODE::NOERROR;
475 return write ? RETURNCODE::DBUS_WRITE_ERROR : RETURNCODE::DBUS_READ_ERROR;
480 return dbus_access<false>(cpu, addr, buf, len);
485 return dbus_access<true>(cpu, addr, buf, len);
490 return dread(
nullptr, addr, buf, len);
495 return dwrite(
nullptr, addr, buf, len);
general configuration and logging
std::unordered_map< std::string, uint32_t > map_messageCounter
void global_sync_time(uint64 time_ps)
uint32_t printMessage(std::string key, std::string message, uint32_t maxCount)
static void trace(ETISS_CPU *cpu, etiss::uint64 addr, etiss::uint32 len, bool isWrite, bool toFile, std::ofstream &file)
simple test system implementation
void access_error(ETISS_CPU *cpu, etiss::uint64 addr, etiss::uint32 len, std::string error, etiss::Verbosity verbosity)
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
static __inline__ uint32_t
static __inline__ uint64_t
static __inline__ uint8_t
bool isSet(std::string val)
return true if the value of an configuration key has been set
bool set(const std::string &key, T value)
template function to set the value of a configuration key.
T get(const std::string &key, T default_, bool *default_used=0)
template function to read the value of a configuration key.
bool payload_in_range(etiss::uint64 addr, etiss::uint64 payload_size) const
void memInit(std::string initString, uint64_t randomRoot=0)
bool addr_in_range(etiss::uint64 addr) const
const etiss::uint64 start_addr_
const etiss::uint64 end_addr_
void load(const void *data, size_t offset, size_t file_size_bytes)
MemSegment(etiss::uint64 start_addr, etiss::uint64 size, access_t mode, const std::string name, etiss::uint8 *mem=nullptr, std::string initString="", bool InitEleSet=false, uint64_t randomRoot=0)
Constructor of Memory Segment.
const etiss::uint64 size_
etiss::uint64 start_addr_
std::map< etiss::uint64, etiss::uint64 > configured_address_spaces_
etiss::int32 dread(ETISS_CPU *cpu, etiss::uint64 addr, etiss::uint8 *buf, etiss::uint32 len)
Data read operation.
bool error_on_seg_mismatch_
std::vector< std::unique_ptr< MemSegment > > msegs_
etiss::int32 dwrite(ETISS_CPU *cpu, etiss::uint64 addr, etiss::uint8 *buf, etiss::uint32 len)
Data write operation.
etiss::int32 dbus_access(ETISS_CPU *cpu, etiss::uint64 addr, etiss::uint8 *buf, etiss::uint32 len)
void add_memsegment(std::unique_ptr< MemSegment > &mseg, const void *raw_data, size_t file_size_bytes)
etiss::int32 dbg_write(etiss::uint64 addr, etiss::uint8 *buf, etiss::uint32 len)
Debug write operation.
etiss::int32 dbg_read(etiss::uint64 addr, etiss::uint8 *buf, etiss::uint32 len)
Debug read operation.
etiss::int32 iread(ETISS_CPU *cpu, etiss::uint64 addr, etiss::uint32 len)
Instruction read operation.
etiss::int32 iwrite(ETISS_CPU *cpu, etiss::uint64 addr, etiss::uint8 *buf, etiss::uint32 len)
Instruction write operation.
std::ofstream trace_file_dbus_
void syncTime(ETISS_CPU *cpu)
Synchronize simulation time.
std::string Configuration::get< std::string >(const std::string &key, std::string default_, bool *default_used)
Verbosity
Enumeration type for the log levels.
Verbosity & verbosity()
Get log level reference.
void log(Verbosity level, std::string msg)
write log message at the given level.
float __ovld __cnfn length(float p)
Return the length of vector p, i.e., sqrt(p.x2 + p.y 2 + ...)
basic cpu state structure needed for execution of any cpu architecture.
etiss_uint64 instructionPointer
pointer to next instruction.
etiss_uint64 cpuTime_ps
simulation time of cpu