7 Commits

11 changed files with 214 additions and 45 deletions

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.18)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
# ##############################################################################

View File

@ -373,7 +373,7 @@ volatile std::array<bool, 2> dummy = {
auto vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t)>*>(init_data);
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*)>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
@ -383,7 +383,7 @@ volatile std::array<bool, 2> dummy = {
auto vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t)>*>(init_data);
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*)>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};

View File

@ -293,7 +293,7 @@ public:
void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); }
void set_semihosting_callback(std::function<void(arch_if*, reg_t, reg_t)>& cb) { semihosting_cb = cb; };
void set_semihosting_callback(semihosting_cb_t<reg_t> cb) { semihosting_cb = cb; };
protected:
struct riscv_instrumentation_if : public iss::instrumentation_if {
@ -354,7 +354,7 @@ protected:
bool tohost_lower_written = false;
riscv_instrumentation_if instr_if;
std::function<void(arch_if*, reg_t, reg_t)> semihosting_cb;
semihosting_cb_t<reg_t> semihosting_cb;
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>;
using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
@ -1125,9 +1125,6 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
}
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
this->interrupt_sim = hostvar;
#ifndef WITH_TCC
// throw(iss::simulation_stopped(hostvar));
#endif
break;
case 0x0101: {
char c = static_cast<char>(hostvar & 0xff);
@ -1272,7 +1269,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
#endif
CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred ";
semihosting_callback(this, this->reg.X10 /*a0*/, this->reg.X11 /*a1*/);
semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/);
return this->reg.NEXT_PC;
}
}

View File

@ -319,7 +319,7 @@ public:
void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); }
void set_semihosting_callback(std::function<void(arch_if*, reg_t, reg_t)>& cb) { semihosting_cb = cb; };
void set_semihosting_callback(semihosting_cb_t<reg_t> cb) { semihosting_cb = cb; };
protected:
struct riscv_instrumentation_if : public iss::instrumentation_if {
@ -380,7 +380,7 @@ protected:
bool tohost_lower_written = false;
riscv_instrumentation_if instr_if;
std::function<void(arch_if*, reg_t, reg_t)> semihosting_cb;
semihosting_cb_t<reg_t> semihosting_cb;
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>;
using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
@ -1507,7 +1507,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
#endif
CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred ";
semihosting_callback(this, this->reg.X10 /*a0*/, this->reg.X11 /*a1*/);
semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/);
return this->reg.NEXT_PC;
}
}

View File

@ -1,16 +1,61 @@
#include "semihosting.h"
#include <cstdint>
#include <map>
#include <iss/vm_types.h>
#include <stdexcept>
#include <chrono>
// explanation of syscalls can be found at https://github.com/SpinalHDL/openocd_riscv/blob/riscv_spinal/src/target/semihosting_common.h
template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T call_number, T parameter) {
switch(static_cast<semihosting_syscalls>(call_number)) {
const char *SYS_OPEN_MODES_STRS[] = { "r", "rb", "r+", "r+b", "w", "wb", "w+", "w+b", "a", "ab", "a+", "a+b" };
template <typename T> T sh_read_field(iss::arch_if* arch_if_ptr, T addr, int len=4) {
uint8_t bytes[4];
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, addr, 4, &bytes[0]);
//auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character);
if(res != iss::Ok){
return 0; //TODO THROW ERROR
} else return static_cast<T>(bytes[0]) | (static_cast<T>(bytes[1]) << 8) | (static_cast<T>(bytes[2]) << 16) | (static_cast<T>(bytes[3]) << 24);
}
template <typename T> std::string sh_read_string(iss::arch_if* arch_if_ptr, T addr, T str_len){
std::vector<uint8_t> buffer(str_len);
for (int i = 0; i < str_len; i++ ) {
buffer[i] = sh_read_field(arch_if_ptr, addr + i, 1);
}
std::string str(buffer.begin(), buffer.end());
return str;
}
template <typename T> void semihosting_callback<T>::operator()(iss::arch_if* arch_if_ptr, T* call_number, T* parameter) {
static std::map<T, FILE *> openFiles;
static T file_count = 3;
static T semihostingErrno;
switch(static_cast<semihosting_syscalls>(*call_number)) {
case semihosting_syscalls::SYS_CLOCK: {
throw std::runtime_error("Semihosting Call not Implemented");
auto end = std::chrono::high_resolution_clock::now(); // end measurement
auto elapsed = end - timeVar;
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
*call_number = millis; //TODO get time now
break;
}
case semihosting_syscalls::SYS_CLOSE: {
throw std::runtime_error("Semihosting Call not Implemented");
T file_handle = *parameter;
if (openFiles.size() <= file_handle && file_handle < 0) {
semihostingErrno = EBADF;
return;
}
auto file = openFiles[file_handle];
openFiles.erase(file_handle);
if (!(file == stdin || file == stdout || file == stderr)) {
int i = fclose(file);
*call_number = i;
} else {
*call_number = -1;
semihostingErrno = EINTR;
}
break;
}
case semihosting_syscalls::SYS_ELAPSED: {
@ -18,7 +63,7 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal
break;
}
case semihosting_syscalls::SYS_ERRNO: {
throw std::runtime_error("Semihosting Call not Implemented");
*call_number = semihostingErrno;
break;
}
case semihosting_syscalls::SYS_EXIT: {
@ -31,7 +76,15 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal
break;
}
case semihosting_syscalls::SYS_FLEN: {
throw std::runtime_error("Semihosting Call not Implemented");
T file_handle = *parameter;
auto file = openFiles[file_handle];
size_t currentPos = ftell(file);
if (currentPos < 0) throw std::runtime_error("SYS_FLEN negative value");
fseek(file, 0, SEEK_END);
size_t length = ftell(file);
fseek(file, currentPos, SEEK_SET);
*call_number = (T)length;
break;
}
case semihosting_syscalls::SYS_GET_CMDLINE: {
@ -43,39 +96,127 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal
break;
}
case semihosting_syscalls::SYS_ISERROR: {
throw std::runtime_error("Semihosting Call not Implemented");
T value = *parameter;
*call_number = (value != 0);
break;
}
case semihosting_syscalls::SYS_ISTTY: {
throw std::runtime_error("Semihosting Call not Implemented");
T file_handle = *parameter;
*call_number = (file_handle == 0 || file_handle == 1 || file_handle == 2);
break;
}
case semihosting_syscalls::SYS_OPEN: {
throw std::runtime_error("Semihosting Call not Implemented");
T path_str_addr = sh_read_field<T>(arch_if_ptr, *parameter);
T mode = sh_read_field<T>(arch_if_ptr, 4+(*parameter));
T path_len = sh_read_field<T>(arch_if_ptr, 8+(*parameter));
std::string path_str = sh_read_string<T>(arch_if_ptr, path_str_addr, path_len);
//TODO LOG INFO
if (mode >= 12) {
//TODO throw ERROR
return;
}
FILE *file = nullptr;
if(path_str == ":tt") {
if (mode < 4)
file = stdin;
else if (mode < 8)
file = stdout;
else
file = stderr;
} else {
file = fopen(path_str.c_str(), SYS_OPEN_MODES_STRS[mode]);
if (file == nullptr) {
//TODO throw error
return;
}
}
T file_handle = file_count++;
openFiles[file_handle] = file;
*call_number = file_handle;
break;
}
case semihosting_syscalls::SYS_READ: {
throw std::runtime_error("Semihosting Call not Implemented");
T file_handle = sh_read_field<T>(arch_if_ptr, (*parameter)+4);
T addr = sh_read_field<T>(arch_if_ptr, *parameter);
T count = sh_read_field<T>(arch_if_ptr, (*parameter)+8);
auto file = openFiles[file_handle];
std::vector<uint8_t> buffer(count);
size_t num_read = 0;
if (file == stdin)
{
// when reading from stdin: mimic behaviour from read syscall
// and return on newline.
while (num_read < count)
{
char c = fgetc(file);
buffer[num_read] = c;
num_read++;
if (c == '\n')
break;
}
} else {
num_read = fread(buffer.data(), 1, count, file);
}
buffer.resize(num_read);
for(int i = 0; i<num_read; i++) {
auto res = arch_if_ptr->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, addr+i, 1, &buffer[i]);
if(res != iss::Ok)
return;
}
*call_number = count - num_read;
break;
}
case semihosting_syscalls::SYS_READC: {
throw std::runtime_error("Semihosting Call not Implemented");
uint8_t character = getchar();
//character = getchar();
/*if(character != iss::Ok)
std::cout << "Not OK";
return;*/
*call_number = character;
break;
}
case semihosting_syscalls::SYS_REMOVE: {
throw std::runtime_error("Semihosting Call not Implemented");
T path_str_addr = sh_read_field<T>(arch_if_ptr, *parameter);
T path_len = sh_read_field<T>(arch_if_ptr, (*parameter)+4);
std::string path_str = sh_read_string<T>(arch_if_ptr, path_str_addr, path_len);
if(remove(path_str.c_str())<0) *call_number = -1;
break;
}
case semihosting_syscalls::SYS_RENAME: {
throw std::runtime_error("Semihosting Call not Implemented");
T path_str_addr_old = sh_read_field<T>(arch_if_ptr, *parameter);
T path_len_old = sh_read_field<T>(arch_if_ptr, (*parameter)+4);
T path_str_addr_new = sh_read_field<T>(arch_if_ptr, (*parameter)+8);
T path_len_new = sh_read_field<T>(arch_if_ptr, (*parameter)+12);
std::string path_str_old = sh_read_string<T>(arch_if_ptr, path_str_addr_old, path_len_old);
std::string path_str_new = sh_read_string<T>(arch_if_ptr, path_str_addr_new, path_len_new);
rename(path_str_old.c_str(), path_str_new.c_str());
break;
}
case semihosting_syscalls::SYS_SEEK: {
throw std::runtime_error("Semihosting Call not Implemented");
T file_handle = sh_read_field<T>(arch_if_ptr, *parameter);
T pos = sh_read_field<T>(arch_if_ptr, (*parameter)+1);
auto file = openFiles[file_handle];
int retval = fseek(file, pos, SEEK_SET);
if(retval<0) throw std::runtime_error("SYS_SEEK negative return value");
break;
}
case semihosting_syscalls::SYS_SYSTEM: {
throw std::runtime_error("Semihosting Call not Implemented");
T cmd_addr = sh_read_field<T>(arch_if_ptr, *parameter);
T cmd_len = sh_read_field<T>(arch_if_ptr, (*parameter)+1);
std::string cmd = sh_read_string<T>(arch_if_ptr, cmd_addr, cmd_len);
system(cmd.c_str());
break;
}
case semihosting_syscalls::SYS_TICKFREQ: {
@ -83,20 +224,43 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal
break;
}
case semihosting_syscalls::SYS_TIME: {
throw std::runtime_error("Semihosting Call not Implemented");
//returns time in seconds scince 01.01.1970 00:00
*call_number = time(NULL);
break;
}
case semihosting_syscalls::SYS_TMPNAM: {
throw std::runtime_error("Semihosting Call not Implemented");
T buffer_addr = sh_read_field<T>(arch_if_ptr, *parameter);
T identifier = sh_read_field<T>(arch_if_ptr, (*parameter)+1);
T buffer_len = sh_read_field<T>(arch_if_ptr, (*parameter)+2);
if (identifier > 255) {
*call_number = -1;
return;
}
std::stringstream ss;
ss << "tmp/file-" << std::setfill('0') << std::setw(3) << identifier;
std::string filename = ss.str();
for(int i = 0; i < buffer_len; i++) {
uint8_t character = filename[i];
auto res = arch_if_ptr->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, (*parameter)+i, 1, &character);
if(res != iss::Ok) return;
}
break;
}
case semihosting_syscalls::SYS_WRITE: {
throw std::runtime_error("Semihosting Call not Implemented");
T file_handle = sh_read_field<T>(arch_if_ptr, (*parameter)+4);
T addr = sh_read_field<T>(arch_if_ptr, *parameter);
T count = sh_read_field<T>(arch_if_ptr, (*parameter)+8);
auto file = openFiles[file_handle];
std::string str = sh_read_string<T>(arch_if_ptr, addr, count);
fwrite(&str[0], 1, count, file);
break;
}
case semihosting_syscalls::SYS_WRITEC: {
uint8_t character;
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, parameter, 1, &character);
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character);
if(res != iss::Ok)
return;
putchar(character);
@ -105,13 +269,13 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal
case semihosting_syscalls::SYS_WRITE0: {
uint8_t character;
while(1) {
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, parameter, 1, &character);
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character);
if(res != iss::Ok)
return;
if(character == 0)
break;
putchar(character);
parameter++;
(*parameter)++;
}
break;
}
@ -128,5 +292,5 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal
break;
}
}
template void semihosting_callback<uint32_t>(iss::arch_if* arch_if_ptr, uint32_t call_number, uint32_t parameter);
template void semihosting_callback<uint64_t>(iss::arch_if* arch_if_ptr, uint64_t call_number, uint64_t parameter);
template class semihosting_callback<uint32_t>;
template class semihosting_callback<uint64_t>;

View File

@ -1,6 +1,8 @@
#ifndef _SEMIHOSTING_H_
#define _SEMIHOSTING_H_
#include <iss/arch_if.h>
#include <functional>
#include <chrono>
/*
* According to:
* "Semihosting for AArch32 and AArch64, Release 2.0"
@ -48,6 +50,11 @@ enum class semihosting_syscalls {
USER_CMD_0x1FF = 0x1FF,
};
template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T call_number, T parameter);
template <typename T> struct semihosting_callback{
std::chrono::high_resolution_clock::time_point timeVar;
semihosting_callback(): timeVar(std::chrono::high_resolution_clock::now()) {}
void operator()(iss::arch_if* arch_if_ptr, T* call_number, T* parameter);
};
template <typename T> using semihosting_cb_t = std::function<void(iss::arch_if*, T*, T*)>;
#endif

View File

@ -119,7 +119,8 @@ int main(int argc, char* argv[]) {
// instantiate the simulator
iss::vm_ptr vm{nullptr};
iss::cpu_ptr cpu{nullptr};
std::function<void(iss::arch_if*, uint32_t, uint32_t)> semihosting_cb = &semihosting_callback<uint32_t>;
semihosting_callback<uint32_t> cb{};
semihosting_cb_t<uint32_t> semihosting_cb = [&cb](iss::arch_if* i, uint32_t* a0, uint32_t* a1) {cb(i,a0,a1);};
std::string isa_opt(clim["isa"].as<std::string>());
if(isa_opt.size() == 0 || isa_opt == "?") {
auto list = f.get_names();

View File

@ -4795,7 +4795,7 @@ volatile std::array<bool, 2> dummy = {
auto vm = new asmjit::tgc5c::vm_impl<arch::tgc5c>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data);
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
@ -4805,7 +4805,7 @@ volatile std::array<bool, 2> dummy = {
auto vm = new asmjit::tgc5c::vm_impl<arch::tgc5c>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data);
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};

View File

@ -2700,7 +2700,7 @@ volatile std::array<bool, 2> dummy = {
auto vm = new interp::tgc5c::vm_impl<arch::tgc5c>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data);
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
@ -2710,7 +2710,7 @@ volatile std::array<bool, 2> dummy = {
auto vm = new interp::tgc5c::vm_impl<arch::tgc5c>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data);
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};

View File

@ -4722,7 +4722,7 @@ volatile std::array<bool, 2> dummy = {
auto vm = new llvm::tgc5c::vm_impl<arch::tgc5c>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data);
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t*, arch::traits<arch::tgc5c>::reg_t*)>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
@ -4732,7 +4732,7 @@ volatile std::array<bool, 2> dummy = {
auto vm = new llvm::tgc5c::vm_impl<arch::tgc5c>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data);
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t*, arch::traits<arch::tgc5c>::reg_t*)>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};

View File

@ -3653,7 +3653,7 @@ volatile std::array<bool, 2> dummy = {
auto vm = new tcc::tgc5c::vm_impl<arch::tgc5c>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data);
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};
@ -3663,7 +3663,7 @@ volatile std::array<bool, 2> dummy = {
auto vm = new tcc::tgc5c::vm_impl<arch::tgc5c>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
if(init_data){
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::tgc5c>::reg_t, arch::traits<arch::tgc5c>::reg_t)>*>(init_data);
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::tgc5c>::reg_t>*>(init_data);
cpu->set_semihosting_callback(*cb);
}
return {cpu_ptr{cpu}, vm_ptr{vm}};