From 23c7028b2acf2bc18e657d6613e7ebfd42b6a6eb Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 2 Feb 2015 12:14:49 +0300 Subject: [PATCH] ARMv7: ARM encoding introduced; bugfixes --- Utilities/GNU.h | 6 + Utilities/Log.h | 2 +- Utilities/StrFmt.cpp | 3 +- Utilities/StrFmt.h | 11 +- rpcs3/Emu/ARMv7/ARMv7Context.h | 2 +- rpcs3/Emu/ARMv7/ARMv7Decoder.cpp | 132 ++++++++++++++------ rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp | 31 ++--- rpcs3/Emu/ARMv7/ARMv7Thread.cpp | 8 +- rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp | 4 +- rpcs3/Emu/ARMv7/Modules/sceRtc.cpp | 4 +- rpcs3/Emu/Memory/vm.cpp | 7 +- rpcs3/Emu/SysCalls/LogBase.h | 14 +-- rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp | 12 +- rpcs3/Emu/SysCalls/Modules/cellSync.cpp | 4 +- rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp | 13 +- rpcs3/Loader/ELF32.cpp | 17 ++- 16 files changed, 161 insertions(+), 109 deletions(-) diff --git a/Utilities/GNU.h b/Utilities/GNU.h index b1988b4dfa..a8db7f8703 100644 --- a/Utilities/GNU.h +++ b/Utilities/GNU.h @@ -14,6 +14,12 @@ #define __noinline __attribute__((noinline)) #endif +#ifdef _WIN32 +#define __safebuffers __declspec(safebuffers) +#else +#define __safebuffers +#endif + template void strcpy_trunc(char(&dst)[size], const std::string& src) { diff --git a/Utilities/Log.h b/Utilities/Log.h index d1710f05cf..5ff8504ce7 100644 --- a/Utilities/Log.h +++ b/Utilities/Log.h @@ -132,5 +132,5 @@ void log_message(Log::LogType type, Log::LogSeverity sev, std::string text); template __noinline void log_message(Log::LogType type, Log::LogSeverity sev, const char* fmt, Targs... args) { - log_message(type, sev, fmt::detail::format(fmt, strlen(fmt), fmt::do_unveil(args)...)); + log_message(type, sev, fmt::detail::format(fmt, fmt::do_unveil(args)...)); } diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 0b8410e2f4..2de4fc889f 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -144,8 +144,9 @@ size_t fmt::detail::get_fmt_precision(const char* fmt, size_t len) return 1; } -std::string fmt::detail::format(const char* fmt, size_t len) +std::string fmt::detail::format(const char* fmt) { + const size_t len = strlen(fmt); const size_t fmt_start = get_fmt_start(fmt, len); if (fmt_start != len) { diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index 3bc464fcb8..f7474efa25 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -429,16 +429,17 @@ namespace fmt } }; - std::string format(const char* fmt, size_t len); // terminator + std::string format(const char* fmt); // terminator template - std::string format(const char* fmt, size_t len, const T& arg, Args... args) + std::string format(const char* fmt, const T& arg, Args... args) { + const size_t len = strlen(fmt); const size_t fmt_start = get_fmt_start(fmt, len); const size_t fmt_len = get_fmt_len(fmt + fmt_start, len - fmt_start); const size_t fmt_end = fmt_start + fmt_len; - return std::string(fmt, fmt_start) + get_fmt::text(fmt + fmt_start, fmt_len, arg) + format(fmt + fmt_end, len - fmt_end, args...); + return std::string(fmt, fmt_start) + get_fmt::text(fmt + fmt_start, fmt_len, arg) + format(fmt + fmt_end, args...); } }; @@ -551,9 +552,9 @@ namespace fmt Other features are not supported. */ template - __forceinline std::string format(const char* fmt, Args... args) + __forceinline __safebuffers std::string format(const char* fmt, Args... args) { - return detail::format(fmt, strlen(fmt), do_unveil(args)...); + return detail::format(fmt, do_unveil(args)...); } //convert a wxString to a std::string encoded in utf8 diff --git a/rpcs3/Emu/ARMv7/ARMv7Context.h b/rpcs3/Emu/ARMv7/ARMv7Context.h index fa9e04c64d..5ca662939f 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Context.h +++ b/rpcs3/Emu/ARMv7/ARMv7Context.h @@ -137,7 +137,7 @@ struct ARMv7Context } else { - write_pc(value & ~1); + write_pc(value); } } diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp b/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp index ce2dbb6914..2c0c976697 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp @@ -1159,9 +1159,44 @@ struct ARMv7_op4t_table_t } } } + + const ARMv7_opcode_t* HACK() + { + for (auto& opcode : table) + { + if (opcode->func == ARMv7_instrs::HACK) + { + return opcode; + } + } + + throw "HACK instruction not found"; + } } g_op4t; +struct ARMv7_op4arm_table_t +{ + std::vector table; + + ARMv7_op4arm_table_t() + { + for (auto& opcode : ARMv7_opcode_table) + { + if (opcode.type >= A1) + { + if (opcode.code & ~opcode.mask) + { + LOG_ERROR(GENERAL, "%s: wrong opcode mask (mask=0x%08x, code=0x%08x)", opcode.name, opcode.mask, opcode.code); + } + + table.push_back(&opcode); + } + } + } + +} g_op4arm; + std::unordered_map g_opct; void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump) @@ -1231,16 +1266,21 @@ void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump) const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1; const u32 target = (addr + 4 & ~3) + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); - // possibly a call to imported function: - if (target >= end_addr && ((target - end_addr) % 16) == 0 && vm::psv::read16(target) == 0xf870) - { - const u32 instr = vm::psv::read32(target); + const u32 instr = vm::psv::read32(target); - // check if not "unimplemented" - if (instr >> 16) + // possibly a call to imported function: + if (target >= end_addr && ((target - end_addr) % 16) == 0 && (instr & 0xfff000f0) == 0xe0700090) + { + // check if implemented + if (const u32 func = (instr & 0xfff00) >> 4 | (instr & 0xf)) { - // replace BLX with "hack" instruction directly, it can help to see where it was called from - vm::psv::write32(addr, instr); + // replace BLX with "HACK" instruction directly (in Thumb form), it can help to see where it was called from + vm::psv::write32(addr, 0xf870 | func << 16); + g_opct[0xf8700000 | func] = g_op4t.HACK(); + } + else + { + // leave as is if unimplemented } } else @@ -1257,50 +1297,60 @@ void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump) addr += found->length; } - while (vm::psv::read16(addr) == 0xf870) - { - g_opct[0xf8700000 | vm::psv::read16(addr + 2)] = g_op4t.table[0]; - addr += 16; - } - LOG_NOTICE(ARMv7, "armv7_decoder_initialize() finished, g_opct.size() = %lld", (u64)g_opct.size()); } u32 ARMv7Decoder::DecodeMemory(const u32 address) { - if (address & 0x1) - { - throw "ARMv7Decoder::DecodeMemory() failed (something is wrong with instruction set)"; - } - ARMv7Code code = {}; - code.code0 = vm::psv::read16(address); - if (auto opcode = g_op2t.data[code.code0]) + if (m_ctx.ISET == Thumb) { - (*opcode->func)(m_ctx, code, opcode->type); - return 2; + code.code0 = vm::psv::read16(address); + + if (auto opcode = g_op2t.data[code.code0]) + { + (*opcode->func)(m_ctx, code, opcode->type); + return 2; + } + + code.code1 = code.code0; + code.code0 = vm::psv::read16(address + 2); + + auto op = g_opct.find(code.data); + if (op != g_opct.end()) + { + (*op->second->func)(m_ctx, code, op->second->type); + return 4; + } + + //for (auto opcode : g_op4t.table) + //{ + // if ((code.data & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(code.data))) + // { + // (*opcode->func)(m_ctx, code, opcode->type); + // return 4; + // } + //} } - - code.code1 = code.code0; - code.code0 = vm::psv::read16(address + 2); - - auto op = g_opct.find(code.data); - if (op != g_opct.end()) + else if (m_ctx.ISET == ARM) { - (*op->second->func)(m_ctx, code, op->second->type); - return 4; + code.data = vm::psv::read32(address); + + for (auto opcode : g_op4arm.table) + { + if ((code.data & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(code.data))) + { + (*opcode->func)(m_ctx, code, opcode->type); + return 4; + } + } } - - //for (auto opcode : g_op4t.table) - //{ - // if ((code.data & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(code.data))) - // { - // (*opcode->func)(m_ctx, code, opcode->type); - // return 4; - // } - //} - + else + { + throw "ARMv7Decoder::DecodeMemory() failed (invalid instruction set set)"; + } + ARMv7_instrs::UNK(m_ctx, code); return 4; diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp index c204351616..d7b1c9adf8 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp @@ -280,7 +280,14 @@ namespace ARMv7_instrs void ARMv7_instrs::UNK(ARMv7Context& context, const ARMv7Code code) { - throw fmt::format("Unknown/illegal opcode: 0x%04x 0x%04x", code.code1, code.code0); + if (context.ISET == Thumb) + { + throw fmt::format("Unknown/illegal opcode: 0x%04x 0x%04x", code.code1, code.code0); + } + else + { + throw fmt::format("Unknown/illegal opcode: 0x%08x", code.data); + } } void ARMv7_instrs::HACK(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -976,16 +983,7 @@ void ARMv7_instrs::BLX(ARMv7Context& context, const ARMv7Code code, const ARMv7_ if (ConditionPassed(context, cond)) { context.LR = newLR; - if (target & 1) - { - context.ISET = Thumb; - context.thread.SetBranch(target & ~1); - } - else - { - context.ISET = ARM; - context.thread.SetBranch(target); - } + context.write_pc(target); } } @@ -1014,16 +1012,7 @@ void ARMv7_instrs::BX(ARMv7Context& context, const ARMv7Code code, const ARMv7_e if (ConditionPassed(context, cond)) { - if (target & 1) - { - context.ISET = Thumb; - context.thread.SetBranch(target & ~1); - } - else - { - context.ISET = ARM; - context.thread.SetBranch(target); - } + context.write_pc(target); } } diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 6e1cec6fa8..9fe72a3d49 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -12,7 +12,8 @@ void ARMv7Context::write_pc(u32 value) { - thread.SetBranch(value); + ISET = value & 1 ? Thumb : ARM; + thread.SetBranch(value & ~1); } u32 ARMv7Context::read_pc() @@ -109,10 +110,11 @@ ARMv7Thread::~ARMv7Thread() void ARMv7Thread::InitRegs() { - memset(context.GPR, 0, sizeof(context.GPR[0]) * 15); + memset(context.GPR, 0, sizeof(context.GPR)); context.APSR.APSR = 0; context.IPSR.IPSR = 0; - //context.ISET = Thumb; + context.ISET = PC & 1 ? Thumb : ARM; // select instruction set + context.thread.SetPc(PC & ~1); // and fix PC context.ITSTATE.IT = 0; context.SP = m_stack_addr + m_stack_size; context.TLS = armv7_get_tls(GetId()); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index dbbce2e151..d7bd58c79a 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -48,12 +48,12 @@ s32 sceKernelCreateThread( ARMv7Thread& new_thread = static_cast(Emu.GetCPU().AddThread(CPU_THREAD_ARMv7)); const auto id = new_thread.GetId(); - new_thread.SetEntry(entry.addr() ^ 1); + new_thread.SetEntry(entry.addr()); new_thread.SetPrio(initPriority); new_thread.SetStackSize(stackSize); new_thread.SetName(pName.get_ptr()); - sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x)^1: id -> 0x%x", pName.get_ptr(), entry, id); + sceLibKernel.Warning("*** New ARMv7 Thread [%s] (entry=0x%x): id -> 0x%x", pName.get_ptr(), entry, id); new_thread.Run(); return id; diff --git a/rpcs3/Emu/ARMv7/Modules/sceRtc.cpp b/rpcs3/Emu/ARMv7/Modules/sceRtc.cpp index 96d44a3686..9b81d86072 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceRtc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceRtc.cpp @@ -59,7 +59,7 @@ s32 sceRtcCheckValid(vm::psv::ptr pTime) throw __FUNCTION__; } -s32 sceRtcSetTime_t(vm::psv::ptr pTime, time_t iTime) +s32 sceRtcSetTime_t(vm::psv::ptr pTime, u32 iTime) { throw __FUNCTION__; } @@ -69,7 +69,7 @@ s32 sceRtcSetTime64_t(vm::psv::ptr pTime, u64 ullTime) throw __FUNCTION__; } -s32 sceRtcGetTime_t(vm::psv::ptr pTime, vm::psv::ptr piTime) +s32 sceRtcGetTime_t(vm::psv::ptr pTime, vm::psv::ptr piTime) { throw __FUNCTION__; } diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 69e42e62cb..04d3a0f90a 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -69,7 +69,7 @@ namespace vm void error(const u64 addr, const char* func) { - throw fmt::format("%s(): invalid address 0x%llx", func, addr); + throw fmt::format("%s(): failed to cast 0x%llx (too big value)", func, addr); } namespace ps3 @@ -249,7 +249,10 @@ namespace vm case CPU_THREAD_ARMv7: { - assert(!"stack_pop(): ARMv7 not supported"); + ARMv7Context& context = static_cast(CPU).context; + + assert(context.SP == addr); + context.SP = old_pos; return; } diff --git a/rpcs3/Emu/SysCalls/LogBase.h b/rpcs3/Emu/SysCalls/LogBase.h index 7f496d6c6e..82e569e808 100644 --- a/rpcs3/Emu/SysCalls/LogBase.h +++ b/rpcs3/Emu/SysCalls/LogBase.h @@ -17,9 +17,9 @@ class LogBase void LogOutput(LogType type, const std::string& text) const; template - __noinline void LogPrepare(LogType type, const char* fmt, size_t len, Targs... args) const + __noinline void LogPrepare(LogType type, const char* fmt, Targs... args) const { - LogOutput(type, fmt::detail::format(fmt, len, args...)); + LogOutput(type, fmt::detail::format(fmt, args...)); } public: @@ -38,7 +38,7 @@ public: template __forceinline void Notice(const char* fmt, Targs... args) const { - LogPrepare(LogNotice, fmt, strlen(fmt), fmt::do_unveil(args)...); + LogPrepare(LogNotice, fmt, fmt::do_unveil(args)...); } template @@ -53,25 +53,25 @@ public: template __forceinline void Success(const char* fmt, Targs... args) const { - LogPrepare(LogSuccess, fmt, strlen(fmt), fmt::do_unveil(args)...); + LogPrepare(LogSuccess, fmt, fmt::do_unveil(args)...); } template __forceinline void Warning(const char* fmt, Targs... args) const { - LogPrepare(LogWarning, fmt, strlen(fmt), fmt::do_unveil(args)...); + LogPrepare(LogWarning, fmt, fmt::do_unveil(args)...); } template __forceinline void Error(const char* fmt, Targs... args) const { - LogPrepare(LogError, fmt, strlen(fmt), fmt::do_unveil(args)...); + LogPrepare(LogError, fmt, fmt::do_unveil(args)...); } template __forceinline void Todo(const char* fmt, Targs... args) const { - LogPrepare(LogTodo, fmt, strlen(fmt), fmt::do_unveil(args)...); + LogPrepare(LogTodo, fmt, fmt::do_unveil(args)...); } }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp index 18724020af..79ad2d72bc 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp @@ -372,7 +372,7 @@ s32 cellSaveDataListSave2( for (u32 i=0; iresult < 0) { @@ -629,7 +629,7 @@ s32 cellSaveDataFixedLoad2( for (u32 i = 0; iresult < 0) { @@ -826,7 +826,7 @@ s32 cellSaveDataListAutoSave( //for (u32 i = 0; i queue, vm::ptr buffer, u32 siz queue->m_depth = depth; queue->m_buffer = buffer; queue->m_direction = direction; - *queue->m_hs1 = {}; - *queue->m_hs2 = {}; + memset(queue->m_hs1, 0, sizeof(queue->m_hs1)); + memset(queue->m_hs2, 0, sizeof(queue->m_hs2)); queue->m_eaSignal = eaSignal; if (direction == CELL_SYNC_QUEUE_ANY2ANY) diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp index 99555c70cf..f38865db09 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp @@ -217,6 +217,7 @@ int cellVideoOutGetConfiguration(u32 videoOut, vm::ptrresolutionId = Emu.GetGSManager().GetInfo().mode.resolutionId; config->format = Emu.GetGSManager().GetInfo().mode.format; config->aspect = Emu.GetGSManager().GetInfo().mode.aspect; - *config->reserved = {}; config->pitch = Emu.GetGSManager().GetInfo().mode.pitch; return CELL_VIDEO_OUT_SUCCEEDED; case CELL_VIDEO_OUT_SECONDARY: - *config = {}; // ??? return CELL_VIDEO_OUT_SUCCEEDED; } @@ -478,22 +477,25 @@ int cellAudioOutGetState(u32 audioOut, u32 deviceIndex, vm::ptrWarning("cellAudioOutGetState(audioOut=0x%x, deviceIndex=0x%x, state_addr=0x%x)", audioOut, deviceIndex, state.addr()); + *state = {}; + switch(audioOut) { case CELL_AUDIO_OUT_PRIMARY: state->state = Emu.GetAudioManager().GetState(); state->encoder = Emu.GetAudioManager().GetInfo().mode.encoder; - *state->reserved = {}; state->downMixer = Emu.GetAudioManager().GetInfo().mode.downMixer; state->soundMode.type = Emu.GetAudioManager().GetInfo().mode.type; state->soundMode.channel = Emu.GetAudioManager().GetInfo().mode.channel; state->soundMode.fs = Emu.GetAudioManager().GetInfo().mode.fs; state->soundMode.reserved = 0; state->soundMode.layout = Emu.GetAudioManager().GetInfo().mode.layout; + return CELL_AUDIO_OUT_SUCCEEDED; case CELL_AUDIO_OUT_SECONDARY: - *state = { CELL_AUDIO_OUT_OUTPUT_STATE_DISABLED }; + state->state = CELL_AUDIO_OUT_OUTPUT_STATE_DISABLED; + return CELL_AUDIO_OUT_SUCCEEDED; } @@ -534,19 +536,18 @@ int cellAudioOutGetConfiguration(u32 audioOut, vm::ptrWarning("cellAudioOutGetConfiguration(audioOut=%d, config_addr=0x%x, option_addr=0x%x)", audioOut, config.addr(), option.addr()); if (option) *option = {}; + *config = {}; switch(audioOut) { case CELL_AUDIO_OUT_PRIMARY: config->channel = Emu.GetAudioManager().GetInfo().mode.channel; config->encoder = Emu.GetAudioManager().GetInfo().mode.encoder; - *config->reserved = {}; config->downMixer = Emu.GetAudioManager().GetInfo().mode.downMixer; return CELL_AUDIO_OUT_SUCCEEDED; case CELL_AUDIO_OUT_SECONDARY: - *config = {}; return CELL_AUDIO_OUT_SUCCEEDED; } diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index bf36001a51..89112c8692 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -104,6 +104,10 @@ namespace loader vm::psv::ptr sceLibcHeapDelayedAlloc; u32 unk2; + u32 unk3; + + vm::psv::ptr __sce_libcmallocreplace; + vm::psv::ptr __sce_libcnewreplace; }; struct psv_process_param_t @@ -233,18 +237,14 @@ namespace loader LOG_NOTICE(LOADER, "Imported function %s (nid=0x%08x, addr=0x%x)", func->name, nid, addr); } - // writing Thumb code (temporarily, because it should be ARM) - vm::psv::write16(addr + 0, 0xf870); // HACK instruction (Thumb) - vm::psv::write16(addr + 2, (u16)get_psv_func_index(func)); // function index - vm::psv::write16(addr + 4, 0x4770); // BX LR - vm::psv::write16(addr + 6, 0); // null + const u32 code = get_psv_func_index(func); + vm::psv::write32(addr + 0, 0xe0700090 | (code & 0xfff0) << 4 | (code & 0xf)); // HACK instruction (ARM) } else { LOG_ERROR(LOADER, "Unknown function 0x%08x (addr=0x%x)", nid, addr); - vm::psv::write16(addr + 0, 0xf870); // HACK instruction (Thumb) - vm::psv::write16(addr + 2, 0); // index 0 (unimplemented stub) + vm::psv::write32(addr + 0, 0xe0700090); // HACK instruction (ARM), unimplemented stub (code 0) vm::psv::write32(addr + 4, nid); // nid } @@ -404,8 +404,7 @@ namespace loader const u32 stack_size = proc_param->sceUserMainThreadStackSize ? *proc_param->sceUserMainThreadStackSize : 0; const u32 priority = proc_param->sceUserMainThreadPriority ? *proc_param->sceUserMainThreadPriority : 0; - /* TODO: Thumb/ARM encoding selection */ - armv7_thread(entry & ~1, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run(); + armv7_thread(entry, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run(); break; } case MACHINE_SPU: spu_thread(m_ehdr.is_le() ? m_ehdr.data_le.e_entry : m_ehdr.data_be.e_entry, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); break;