diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index 44ed7dedf7..5aaf98579d 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -109,7 +109,15 @@ struct FileListener : LogListener if (mPrependChannelName) { text.insert(0, gTypeNameTable[static_cast(msg.mType)].mName); - + + if (msg.mType == Log::TTY) + { + text = fmt::escape(text); + if (text[text.length() - 1] != '\n') + { + text += '\n'; + } + } } mFile.Write(text); } diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 6ae236b922..f3f74a327d 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -179,7 +179,7 @@ std::string fmt::replace_all(const std::string &src, const std::string& from, co pos += to.length(); } - return src; + return target; } //TODO: move this wx Stuff somewhere else @@ -339,3 +339,34 @@ std::string fmt::tolower(std::string source) return source; } + +std::string fmt::toupper(std::string source) +{ + std::transform(source.begin(), source.end(), source.begin(), ::toupper); + + return source; +} + +std::string fmt::escape(std::string source) +{ + const std::pair escape_list[] = + { + { "\\", "\\\\" }, + { "\a", "\\a" }, + { "\b", "\\b" }, + { "\f", "\\f" }, + { "\n", "\\n\n" }, + { "\r", "\\r" }, + { "\t", "\\t" }, + { "\v", "\\v" }, + }; + + source = fmt::replace_all(source, escape_list); + + for (char c = 0; c < 32; c++) + { + if (c != '\n') source = fmt::replace_all(source, std::string(1, c), fmt::Format("\\x%02X", c)); + } + + return source; +} diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index bd4059ab86..bdc99a83af 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -177,6 +177,8 @@ namespace fmt std::string to_udec(u64 value); std::string to_sdec(s64 value); + std::string toupper(std::string source); + namespace detail { size_t get_fmt_start(const char* fmt, size_t len); @@ -198,6 +200,10 @@ namespace fmt { return to_hex(arg, get_fmt_precision(fmt, len)); } + else if (fmt[len - 1] == 'X') + { + return fmt::toupper(to_hex(arg, get_fmt_precision(fmt, len))); + } else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u') { return to_udec(arg); @@ -218,6 +224,10 @@ namespace fmt { return to_hex(arg, get_fmt_precision(fmt, len)); } + else if (fmt[len - 1] == 'X') + { + return fmt::toupper(to_hex(arg, get_fmt_precision(fmt, len))); + } else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u') { return to_udec(arg); @@ -238,6 +248,10 @@ namespace fmt { return to_hex(arg, get_fmt_precision(fmt, len)); } + else if (fmt[len - 1] == 'X') + { + return fmt::toupper(to_hex(arg, get_fmt_precision(fmt, len))); + } else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u') { return to_udec(arg); @@ -258,6 +272,10 @@ namespace fmt { return to_hex(arg, get_fmt_precision(fmt, len)); } + else if (fmt[len - 1] == 'X') + { + return fmt::toupper(to_hex(arg, get_fmt_precision(fmt, len))); + } else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u') { return to_udec(arg); @@ -278,6 +296,10 @@ namespace fmt { return to_hex((u8)arg, get_fmt_precision(fmt, len)); } + else if (fmt[len - 1] == 'X') + { + return fmt::toupper(to_hex((u8)arg, get_fmt_precision(fmt, len))); + } else if (fmt[len - 1] == 'd') { return to_sdec(arg); @@ -298,6 +320,10 @@ namespace fmt { return to_hex((u16)arg, get_fmt_precision(fmt, len)); } + else if (fmt[len - 1] == 'X') + { + return fmt::toupper(to_hex((u16)arg, get_fmt_precision(fmt, len))); + } else if (fmt[len - 1] == 'd') { return to_sdec(arg); @@ -318,6 +344,10 @@ namespace fmt { return to_hex((u32)arg, get_fmt_precision(fmt, len)); } + else if (fmt[len - 1] == 'X') + { + return fmt::toupper(to_hex((u32)arg, get_fmt_precision(fmt, len))); + } else if (fmt[len - 1] == 'd') { return to_sdec(arg); @@ -338,6 +368,10 @@ namespace fmt { return to_hex((u64)arg, get_fmt_precision(fmt, len)); } + else if (fmt[len - 1] == 'X') + { + return fmt::toupper(to_hex((u64)arg, get_fmt_precision(fmt, len))); + } else if (fmt[len - 1] == 'd') { return to_sdec(arg); @@ -358,6 +392,10 @@ namespace fmt { return to_hex((u32&)arg, get_fmt_precision(fmt, len)); } + else if (fmt[len - 1] == 'X') + { + return fmt::toupper(to_hex((u32&)arg, get_fmt_precision(fmt, len))); + } else if (fmt[len - 1] == 'f') { return std::to_string(arg); @@ -378,6 +416,10 @@ namespace fmt { return to_hex((u64&)arg, get_fmt_precision(fmt, len)); } + else if (fmt[len - 1] == 'X') + { + return fmt::toupper(to_hex((u64&)arg, get_fmt_precision(fmt, len))); + } else if (fmt[len - 1] == 'f') { return std::to_string(arg); @@ -394,7 +436,7 @@ namespace fmt { static std::string text(const char* fmt, size_t len, bool arg) { - if (fmt[len - 1] == 'x') + if (fmt[len - 1] == 'x' || fmt[len - 1] == 'X') { return to_hex(arg, get_fmt_precision(fmt, len)); } @@ -579,4 +621,6 @@ namespace fmt std::string merge(std::vector source, const std::string& separator); std::string merge(std::initializer_list> sources, const std::string& separator); std::string tolower(std::string source); + std::string toupper(std::string source); + std::string escape(std::string source); } diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 2539c791cd..25d5981e23 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -213,9 +213,10 @@ static const reg_table_t reg_table[17] = #endif -bool handle_access_violation(const u32 addr, x64_context* context) +bool handle_access_violation(const u32 addr, bool is_writing, x64_context* context) { - if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) // RawSPU MMIO registers + // check if address is RawSPU MMIO register + if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) { // one x64 instruction is manually decoded and interpreted x64_op_t op; @@ -277,6 +278,12 @@ bool handle_access_violation(const u32 addr, x64_context* context) return true; } + // check if fault is caused by reservation + if (vm::reservation_query(addr, is_writing)) + { + return true; + } + // TODO: allow recovering from a page fault as a feature of PS3 virtual memory return false; } @@ -285,38 +292,49 @@ bool handle_access_violation(const u32 addr, x64_context* context) void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp) { - const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr(); + const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::g_base_addr; const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0; + if (u == EXCEPTION_ACCESS_VIOLATION && (u32)addr64 == addr64) { - if (handle_access_violation((u32)addr64, pExp->ContextRecord)) - { - // restore context (further code shouldn't be reached) - RtlRestoreContext(pExp->ContextRecord, nullptr); - - // it's dangerous because destructors won't be executed - } - throw fmt::format("Access violation %s location 0x%llx", is_writing ? "writing" : "reading", addr64); } - - // else some fatal error (should crash) } +const PVOID exception_handler = (atexit([]{ RemoveVectoredExceptionHandler(exception_handler); }), AddVectoredExceptionHandler(1, [](PEXCEPTION_POINTERS pExp) -> LONG +{ + const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::g_base_addr; + const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0; + + if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && + (u32)addr64 == addr64 && + GetCurrentNamedThread() && + handle_access_violation((u32)addr64, is_writing, pExp->ContextRecord)) + { + return EXCEPTION_CONTINUE_EXECUTION; + } + else + { + return EXCEPTION_CONTINUE_SEARCH; + } +})); + #else void signal_handler(int sig, siginfo_t* info, void* uct) { - const u64 addr64 = (u64)info->si_addr - (u64)Memory.GetBaseAddr(); + const u64 addr64 = (u64)info->si_addr - (u64)vm::g_base_addr; + const bool is_writing = ((ucontext_t*)uct)->uc_mcontext.gregs[REG_ERR] & 0x2; + if ((u32)addr64 == addr64 && GetCurrentNamedThread()) { - if (handle_access_violation((u32)addr64, (ucontext_t*)uct)) + if (handle_access_violation((u32)addr64, is_writing, (ucontext_t*)uct)) { return; // proceed execution } // TODO: this may be wrong - throw fmt::format("Access violation at location 0x%llx", addr64); + throw fmt::format("Access violation %s location 0x%llx", is_writing ? "writing" : "reading", addr64); } // else some fatal error @@ -352,6 +370,11 @@ void SetCurrentNamedThread(NamedThreadBase* value) return; } + if (old_value) + { + vm::reservation_free(); + } + if (value && value->m_tls_assigned.exchange(true)) { LOG_ERROR(GENERAL, "Thread '%s' was already assigned to g_tls_this_thread of another thread", value->GetThreadName()); @@ -421,8 +444,17 @@ void ThreadBase::Start() #ifdef _WIN32 auto old_se_translator = _set_se_translator(_se_translator); + if (!exception_handler) + { + LOG_ERROR(GENERAL, "exception_handler not set"); + return; + } #else - if (sigaction_result == -1) assert(!"sigaction() failed"); + if (sigaction_result == -1) + { + printf("sigaction() failed"); + exit(EXIT_FAILURE); + } #endif SetCurrentNamedThread(this); @@ -560,8 +592,6 @@ void thread_t::start(std::function func) #ifdef _WIN32 auto old_se_translator = _set_se_translator(_se_translator); -#else - if (sigaction_result == -1) assert(!"sigaction() failed"); #endif NamedThreadBase info(name); diff --git a/rpcs3/Emu/ARMv7/ARMv7Context.h b/rpcs3/Emu/ARMv7/ARMv7Context.h index 5ca662939f..9200cd5752 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Context.h +++ b/rpcs3/Emu/ARMv7/ARMv7Context.h @@ -10,17 +10,15 @@ enum ARMv7InstructionSet ThumbEE }; +enum armv7_debug_flags : u32 +{ + DF_DISASM = 1 << 0, + DF_PRINT = 1 << 1, + DF_NO_EXE = 1 << 2, +}; + struct ARMv7Context { - ARMv7Thread& thread; - - ARMv7Context(ARMv7Thread& thread) : thread(thread) {} - - void write_pc(u32 value); - u32 read_pc(); - u32 get_stack_arg(u32 pos); - void fast_call(u32 addr); - union { u32 GPR[15]; @@ -116,9 +114,6 @@ struct ARMv7Context u32 TLS; - u32 R_ADDR; - u64 R_DATA; - struct perf_counter { u32 event; @@ -127,6 +122,18 @@ struct ARMv7Context std::array counters; + ARMv7Thread& thread; + + u32 debug; // debug flags + std::string debug_str; + + ARMv7Context(ARMv7Thread& thread) : thread(thread), debug(/*DF_DISASM | DF_PRINT*/ 0) {} + + void write_pc(u32 value); + u32 read_pc(); + u32 get_stack_arg(u32 pos); + void fast_call(u32 addr); + void write_gpr(u32 n, u32 value) { assert(n < 16); diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp b/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp index 2c0c976697..70ccd9f240 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp @@ -30,137 +30,147 @@ struct ARMv7_opcode_t const ARMv7_opcode_t ARMv7_opcode_table[] = { - ARMv7_OP4(0xffff, 0x0000, 0xf870, 0x0000, T1, HACK), // "Undefined" Thumb opcode used + ARMv7_OP4(0xffff, 0x0000, 0xf870, 0x0000, T1, HACK, nullptr), // "Undefined" Thumb opcode used ARMv7_OP4(0x0ff0, 0x00f0, 0x0070, 0x0090, A1, HACK), // "Undefined" ARM opcode used - ARMv7_OP4(0xfbe0, 0x8000, 0xf140, 0x0000, T1, ADC_IMM), + ARMv7_OP4(0xfbe0, 0x8000, 0xf140, 0x0000, T1, ADC_IMM, nullptr), ARMv7_OP4(0x0fe0, 0x0000, 0x02a0, 0x0000, A1, ADC_IMM), - ARMv7_OP2(0xffc0, 0x4040, T1, ADC_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xeb40, 0x0000, T2, ADC_REG), + ARMv7_OP2(0xffc0, 0x4140, T1, ADC_REG, nullptr), + ARMv7_OP4(0xffe0, 0x8000, 0xeb40, 0x0000, T2, ADC_REG, nullptr), ARMv7_OP4(0x0fe0, 0x0010, 0x00a0, 0x0000, A1, ADC_REG), ARMv7_OP4(0x0fe0, 0x0090, 0x00a0, 0x0010, A1, ADC_RSR), - ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM), - ARMv7_OP2(0xf800, 0x3000, T2, ADD_IMM), + ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM, nullptr), + ARMv7_OP2(0xf800, 0x3000, T2, ADD_IMM, nullptr), ARMv7_OP4(0xfbe0, 0x8000, 0xf100, 0x0000, T3, ADD_IMM, SKIP_IF( (BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13 )), ARMv7_OP4(0xfbf0, 0x8000, 0xf200, 0x0000, T4, ADD_IMM, SKIP_IF( (BF(16, 19) & 13) == 13 )), ARMv7_OP4(0x0fe0, 0x0000, 0x0280, 0x0000, A1, ADD_IMM), - ARMv7_OP2(0xfe00, 0x1800, T1, ADD_REG), + ARMv7_OP2(0xfe00, 0x1800, T1, ADD_REG, nullptr), ARMv7_OP2(0xff00, 0x4400, T2, ADD_REG, SKIP_IF( (c & 0x87) == 0x85 || BF(3, 6) == 13 )), ARMv7_OP4(0xffe0, 0x8000, 0xeb00, 0x0000, T3, ADD_REG, SKIP_IF( (BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13 )), ARMv7_OP4(0x0fe0, 0x0010, 0x0080, 0x0000, A1, ADD_REG), ARMv7_OP4(0x0fe0, 0x0090, 0x0080, 0x0010, A1, ADD_RSR), - ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI), - ARMv7_OP2(0xff80, 0xb000, T2, ADD_SPI), + ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI, nullptr), + ARMv7_OP2(0xff80, 0xb000, T2, ADD_SPI, nullptr), ARMv7_OP4(0xfbef, 0x8000, 0xf10d, 0x0000, T3, ADD_SPI, SKIP_IF( BF(8, 11) == 15 && BT(20) )), - ARMv7_OP4(0xfbff, 0x8000, 0xf20d, 0x0000, T4, ADD_SPI), + ARMv7_OP4(0xfbff, 0x8000, 0xf20d, 0x0000, T4, ADD_SPI, nullptr), ARMv7_OP4(0x0fef, 0x0000, 0x028d, 0x0000, A1, ADD_SPI), - ARMv7_OP2(0xff78, 0x4468, T1, ADD_SPR), + ARMv7_OP2(0xff78, 0x4468, T1, ADD_SPR, nullptr), ARMv7_OP2(0xff87, 0x4485, T2, ADD_SPR, SKIP_IF( BF(3, 6) == 13 )), - ARMv7_OP4(0xffef, 0x8000, 0xeb0d, 0x0000, T3, ADD_SPR), + ARMv7_OP4(0xffef, 0x8000, 0xeb0d, 0x0000, T3, ADD_SPR, nullptr), ARMv7_OP4(0x0fef, 0x0010, 0x008d, 0x0000, A1, ADD_SPR), - ARMv7_OP2(0xf800, 0xa000, T1, ADR), - ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR), - ARMv7_OP4(0xfbff, 0x8000, 0xf20f, 0x0000, T3, ADR), + ARMv7_OP2(0xf800, 0xa000, T1, ADR, nullptr), + ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR, nullptr), + ARMv7_OP4(0xfbff, 0x8000, 0xf20f, 0x0000, T3, ADR, nullptr), ARMv7_OP4(0x0fff, 0x0000, 0x028f, 0x0000, A1, ADR), ARMv7_OP4(0x0fff, 0x0000, 0x024f, 0x0000, A2, ADR), - ARMv7_OP4(0xfbe0, 0x8000, 0xf000, 0x0000, T1, AND_IMM), + ARMv7_OP4(0xfbe0, 0x8000, 0xf000, 0x0000, T1, AND_IMM, SKIP_IF( BF(8, 11) == 15 && BT(20) )), ARMv7_OP4(0x0fe0, 0x0000, 0x0200, 0x0000, A1, AND_IMM), - ARMv7_OP2(0xffc0, 0x4000, T1, AND_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xea00, 0x0000, T2, AND_REG), + ARMv7_OP2(0xffc0, 0x4000, T1, AND_REG, nullptr), + ARMv7_OP4(0xffe0, 0x8000, 0xea00, 0x0000, T2, AND_REG, SKIP_IF( BF(8, 11) == 15 && BT(20) )), ARMv7_OP4(0x0fe0, 0x0010, 0x0000, 0x0000, A1, AND_REG), ARMv7_OP4(0x0fe0, 0x0090, 0x0000, 0x0010, A1, AND_RSR), - ARMv7_OP2(0xf800, 0x1000, T1, ASR_IMM), - ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0020, T2, ASR_IMM), + ARMv7_OP2(0xf800, 0x1000, T1, ASR_IMM, nullptr), + ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0020, T2, ASR_IMM, nullptr), ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0040, A1, ASR_IMM), - ARMv7_OP2(0xffc0, 0x4100, T1, ASR_REG), - ARMv7_OP4(0xffe0, 0xf0f0, 0xfa40, 0xf000, T2, ASR_REG), + ARMv7_OP2(0xffc0, 0x4100, T1, ASR_REG, nullptr), + ARMv7_OP4(0xffe0, 0xf0f0, 0xfa40, 0xf000, T2, ASR_REG, nullptr), ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0050, A1, ASR_REG), - ARMv7_OP2(0xf000, 0xd000, T1, B), - ARMv7_OP2(0xf800, 0xe000, T2, B), - ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x8000, T3, B), - ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x9000, T4, B), + ARMv7_OP2(0xf000, 0xd000, T1, B, SKIP_IF( BF(9, 11) == 0x7 )), + ARMv7_OP2(0xf800, 0xe000, T2, B, nullptr), + ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x8000, T3, B, SKIP_IF( BF(23, 25) == 0x7 )), + ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x9000, T4, B, nullptr), ARMv7_OP4(0x0f00, 0x0000, 0x0a00, 0x0000, A1, B), - ARMv7_OP4(0xffff, 0x8020, 0xf36f, 0x0000, T1, BFC), + ARMv7_OP4(0xffff, 0x8020, 0xf36f, 0x0000, T1, BFC, nullptr), ARMv7_OP4(0x0fe0, 0x007f, 0x07c0, 0x001f, A1, BFC), - ARMv7_OP4(0xfff0, 0x8020, 0xf360, 0x0000, T1, BFI), + + ARMv7_OP4(0xfff0, 0x8020, 0xf360, 0x0000, T1, BFI, SKIP_IF( BF(16, 19) == 15 )), ARMv7_OP4(0x0fe0, 0x0070, 0x07c0, 0x0010, A1, BFI), - ARMv7_OP4(0xfbe0, 0x8000, 0xf020, 0x0000, T1, BIC_IMM), + ARMv7_OP4(0xfbe0, 0x8000, 0xf020, 0x0000, T1, BIC_IMM, nullptr), ARMv7_OP4(0x0fe0, 0x0000, 0x03c0, 0x0000, A1, BIC_IMM), - ARMv7_OP2(0xffc0, 0x4380, T1, BIC_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xea20, 0x0000, T2, BIC_REG), + ARMv7_OP2(0xffc0, 0x4380, T1, BIC_REG, nullptr), + ARMv7_OP4(0xffe0, 0x8000, 0xea20, 0x0000, T2, BIC_REG, nullptr), ARMv7_OP4(0x0fe0, 0x0010, 0x01c0, 0x0000, A1, BIC_REG), ARMv7_OP4(0x0fe0, 0x0090, 0x01c0, 0x0010, A1, BIC_RSR), - ARMv7_OP2(0xff00, 0xbe00, T1, BKPT), + ARMv7_OP2(0xff00, 0xbe00, T1, BKPT, nullptr), ARMv7_OP4(0x0ff0, 0x00f0, 0x0120, 0x0070, A1, BKPT), - ARMv7_OP4(0xf800, 0xd000, 0xf000, 0xd000, T1, BL), + ARMv7_OP4(0xf800, 0xd000, 0xf000, 0xd000, T1, BL, nullptr), ARMv7_OP4(0x0f00, 0x0000, 0x0b00, 0x0000, A1, BL), - ARMv7_OP2(0xff80, 0x4780, T1, BLX), - ARMv7_OP4(0xf800, 0xc001, 0xf000, 0xc000, T2, BLX), + ARMv7_OP2(0xff80, 0x4780, T1, BLX, nullptr), + ARMv7_OP4(0xf800, 0xc001, 0xf000, 0xc000, T2, BLX, nullptr), ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff30, A1, BLX), ARMv7_OP4(0xfe00, 0x0000, 0xfa00, 0x0000, A2, BLX), - ARMv7_OP2(0xff87, 0x4700, T1, BX), + ARMv7_OP2(0xff87, 0x4700, T1, BX, nullptr), ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff10, A1, BX), - ARMv7_OP2(0xf500, 0xb100, T1, CB_Z), + ARMv7_OP2(0xf500, 0xb100, T1, CB_Z, nullptr), - ARMv7_OP4(0xfff0, 0xf0f0, 0xfab0, 0xf080, T1, CLZ), + ARMv7_OP4(0xfff0, 0xf0f0, 0xfab0, 0xf080, T1, CLZ, nullptr), ARMv7_OP4(0x0fff, 0x0ff0, 0x016f, 0x0f10, A1, CLZ), - ARMv7_OP4(0xfbf0, 0x8f00, 0xf110, 0x0f00, T1, CMN_IMM), + ARMv7_OP4(0xfbf0, 0x8f00, 0xf110, 0x0f00, T1, CMN_IMM, nullptr), ARMv7_OP4(0x0ff0, 0xf000, 0x0370, 0x0000, A1, CMN_IMM), - ARMv7_OP2(0xffc0, 0x42c0, T1, CMN_REG), - ARMv7_OP4(0xfff0, 0x8f00, 0xeb10, 0x0f00, T2, CMN_REG), + ARMv7_OP2(0xffc0, 0x42c0, T1, CMN_REG, nullptr), + ARMv7_OP4(0xfff0, 0x8f00, 0xeb10, 0x0f00, T2, CMN_REG, nullptr), ARMv7_OP4(0x0ff0, 0xf010, 0x0170, 0x0000, A1, CMN_REG), ARMv7_OP4(0x0ff0, 0xf090, 0x0170, 0x0010, A1, CMN_RSR), - ARMv7_OP2(0xf800, 0x2800, T1, CMP_IMM), - ARMv7_OP4(0xfbf0, 0x8f00, 0xf1b0, 0x0f00, T2, CMP_IMM), + ARMv7_OP2(0xf800, 0x2800, T1, CMP_IMM, nullptr), + ARMv7_OP4(0xfbf0, 0x8f00, 0xf1b0, 0x0f00, T2, CMP_IMM, nullptr), ARMv7_OP4(0x0ff0, 0xf000, 0x0350, 0x0000, A1, CMP_IMM), - ARMv7_OP2(0xffc0, 0x4280, T1, CMP_REG), - ARMv7_OP2(0xff00, 0x4500, T2, CMP_REG), - ARMv7_OP4(0xfff0, 0x8f00, 0xebb0, 0x0f00, T3, CMP_REG), + ARMv7_OP2(0xffc0, 0x4280, T1, CMP_REG, nullptr), + ARMv7_OP2(0xff00, 0x4500, T2, CMP_REG, nullptr), + ARMv7_OP4(0xfff0, 0x8f00, 0xebb0, 0x0f00, T3, CMP_REG, nullptr), ARMv7_OP4(0x0ff0, 0xf010, 0x0150, 0x0000, A1, CMP_REG), ARMv7_OP4(0x0ff0, 0xf090, 0x0150, 0x0010, A1, CMP_RSR), - ARMv7_OP4(0xfbe0, 0x8000, 0xf080, 0x0000, T1, EOR_IMM), + ARMv7_OP4(0xffff, 0xfff0, 0xf3af, 0x80f0, T1, DBG, nullptr), + ARMv7_OP4(0x0fff, 0xfff0, 0x0320, 0xf0f0, A1, DBG), + + ARMv7_OP4(0xffff, 0xfff0, 0xf3bf, 0x8f50, T1, DMB, nullptr), + ARMv7_OP4(0xffff, 0xfff0, 0xf57f, 0xf050, A1, DMB), + + ARMv7_OP4(0xffff, 0xfff0, 0xf3bf, 0x8f40, T1, DSB, nullptr), + ARMv7_OP4(0xffff, 0xfff0, 0xf57f, 0xf040, A1, DSB), + + ARMv7_OP4(0xfbe0, 0x8000, 0xf080, 0x0000, T1, EOR_IMM, SKIP_IF( BF(8, 11) == 15 && BT(20) )), ARMv7_OP4(0x0fe0, 0x0000, 0x0220, 0x0000, A1, EOR_IMM), - ARMv7_OP2(0xffc0, 0x4040, T1, EOR_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xea80, 0x0000, T2, EOR_REG), + ARMv7_OP2(0xffc0, 0x4040, T1, EOR_REG, nullptr), + ARMv7_OP4(0xffe0, 0x8000, 0xea80, 0x0000, T2, EOR_REG, SKIP_IF( BF(8, 11) == 15 && BT(20) )), ARMv7_OP4(0x0fe0, 0x0010, 0x0020, 0x0000, A1, EOR_REG), ARMv7_OP4(0x0fe0, 0x0090, 0x0020, 0x0010, A1, EOR_RSR), ARMv7_OP2(0xff00, 0xbf00, T1, IT, SKIP_IF( BF(0, 3) == 0 )), - ARMv7_OP2(0xf800, 0xc800, T1, LDM), - ARMv7_OP4(0xffd0, 0x2000, 0xe890, 0x0000, T2, LDM), + ARMv7_OP2(0xf800, 0xc800, T1, LDM, nullptr), + ARMv7_OP4(0xffd0, 0x2000, 0xe890, 0x0000, T2, LDM, SKIP_IF( BT(21) && BF(16, 19) == 13 )), ARMv7_OP4(0x0fd0, 0x0000, 0x0890, 0x0000, A1, LDM), ARMv7_OP4(0x0fd0, 0x0000, 0x0810, 0x0000, A1, LDMDA), - ARMv7_OP4(0xffd0, 0x2000, 0xe910, 0x0000, T1, LDMDB), + ARMv7_OP4(0xffd0, 0x2000, 0xe910, 0x0000, T1, LDMDB, nullptr), ARMv7_OP4(0x0fd0, 0x0000, 0x0910, 0x0000, A1, LDMDB), ARMv7_OP4(0x0fd0, 0x0000, 0x0990, 0x0000, A1, LDMIB), - ARMv7_OP2(0xf800, 0x6800, T1, LDR_IMM), - ARMv7_OP2(0xf800, 0x9800, T2, LDR_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf8d0, 0x0000, T3, LDR_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf850, 0x0800, T4, LDR_IMM), + ARMv7_OP2(0xf800, 0x6800, T1, LDR_IMM, nullptr), + ARMv7_OP2(0xf800, 0x9800, T2, LDR_IMM, nullptr), + ARMv7_OP4(0xfff0, 0x0000, 0xf8d0, 0x0000, T3, LDR_IMM, SKIP_IF( BF(16, 19) == 15 )), + ARMv7_OP4(0xfff0, 0x0800, 0xf850, 0x0800, T4, LDR_IMM, SKIP_IF( BF(16, 19) == 15 || BF(8, 10) == 6 || (c & 0xf07ff) == 0xd0304 || (c & 0x500) == 0 )), ARMv7_OP4(0x0e50, 0x0000, 0x0410, 0x0000, A1, LDR_IMM), - ARMv7_OP2(0xf800, 0x4800, T1, LDR_LIT), - ARMv7_OP4(0xff7f, 0x0000, 0xf85f, 0x0000, T2, LDR_LIT), + ARMv7_OP2(0xf800, 0x4800, T1, LDR_LIT, nullptr), + ARMv7_OP4(0xff7f, 0x0000, 0xf85f, 0x0000, T2, LDR_LIT, nullptr), ARMv7_OP4(0x0f7f, 0x0000, 0x051f, 0x0000, A1, LDR_LIT), - ARMv7_OP2(0xfe00, 0x5800, T1, LDR_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf850, 0x0000, T2, LDR_REG), + ARMv7_OP2(0xfe00, 0x5800, T1, LDR_REG, nullptr), + ARMv7_OP4(0xfff0, 0x0fc0, 0xf850, 0x0000, T2, LDR_REG, SKIP_IF( BF(16, 19) == 15 )), ARMv7_OP4(0x0e50, 0x0010, 0x0610, 0x0000, A1, LDR_REG), - + ARMv7_OP2(0xf800, 0x7800, T1, LDRB_IMM), ARMv7_OP4(0xfff0, 0x0000, 0xf890, 0x0000, T2, LDRB_IMM), ARMv7_OP4(0xfff0, 0x0800, 0xf810, 0x0800, T3, LDRB_IMM), @@ -280,7 +290,7 @@ const ARMv7_opcode_t ARMv7_opcode_table[] = ARMv7_OP4(0xfbe0, 0x8000, 0xf040, 0x0000, T1, ORR_IMM), ARMv7_OP4(0x0fe0, 0x0000, 0x0380, 0x0000, A1, ORR_IMM), ARMv7_OP2(0xffc0, 0x4300, T1, ORR_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xea40, 0x0000, T2, ORR_REG), + ARMv7_OP4(0xffe0, 0x8000, 0xea40, 0x0000, T2, ORR_REG, SKIP_IF( BF(16, 19) == 15 )), ARMv7_OP4(0x0fe0, 0x0010, 0x0180, 0x0000, A1, ORR_REG), ARMv7_OP4(0x0fe0, 0x0090, 0x0180, 0x0010, A1, ORR_RSR), @@ -1105,6 +1115,7 @@ const ARMv7_opcode_t ARMv7_opcode_table[] = struct ARMv7_op2_table_t { const ARMv7_opcode_t* data[0x10000]; + u32 null_ops; ARMv7_op2_table_t() { @@ -1123,6 +1134,8 @@ struct ARMv7_op2_table_t } } + null_ops = 0x10000; + for (u32 i = 0; i < 0x10000; i++) { data[i] = nullptr; @@ -1132,6 +1145,7 @@ struct ARMv7_op2_table_t if (((i << 16) & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(i))) { data[i] = opcode; + null_ops--; break; } } @@ -1201,11 +1215,12 @@ std::unordered_map g_opct; void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump) { - // 1. Find every 4-byte thumb instruction and cache it + // 1. Find every 4-byte Thumb instruction and cache it // 2. If some instruction is not recognized, print the error // 3. Possibly print disasm - g_opct.clear(); + //g_opct.clear(); + //g_opct.reserve(end_addr - addr); while (addr < end_addr) { @@ -1266,7 +1281,7 @@ 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); - const u32 instr = vm::psv::read32(target); + const u32 instr = Memory.IsGoodAddr(target, 4) ? vm::psv::read32(target) : 0; // possibly a call to imported function: if (target >= end_addr && ((target - end_addr) % 16) == 0 && (instr & 0xfff000f0) == 0xe0700090) @@ -1297,7 +1312,7 @@ void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump) addr += found->length; } - LOG_NOTICE(ARMv7, "armv7_decoder_initialize() finished, g_opct.size() = %lld", (u64)g_opct.size()); + LOG_NOTICE(ARMv7, "armv7_decoder_initialize() finished, g_opct.size() = %lld, g_op2t.null_ops=0x%x", (u64)g_opct.size(), g_op2t.null_ops); } u32 ARMv7Decoder::DecodeMemory(const u32 address) diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp index d7b1c9adf8..e07bbaa00b 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include #include "Utilities/Log.h" #include "Emu/System.h" #include "Emu/Memory/Memory.h" @@ -10,6 +11,8 @@ #define reject(cond, info) { if (cond) Error(__FUNCTION__, code, type, #cond, info); } +std::map g_armv7_dump; + namespace ARMv7_instrs { template @@ -63,7 +66,7 @@ namespace ARMv7_instrs SRType DecodeImmShift(u32 type, u32 imm5, u32* shift_n) { - SRType shift_t = SRType_None; + SRType shift_t; switch (type) { @@ -80,25 +83,28 @@ namespace ARMv7_instrs shift_t = SRType_ROR; if (shift_n) *shift_n = imm5; } break; + + default: throw __FUNCTION__; } return shift_t; } - SRType DecodeRegShift(u8 type) - { - SRType shift_t = SRType_None; + //SRType DecodeRegShift(u8 type) + //{ + // SRType shift_t; - switch (type) - { - case 0: shift_t = SRType_LSL; break; - case 1: shift_t = SRType_LSR; break; - case 2: shift_t = SRType_ASR; break; - case 3: shift_t = SRType_ROR; break; - } + // switch (type) + // { + // case 0: shift_t = SRType_LSL; break; + // case 1: shift_t = SRType_LSR; break; + // case 2: shift_t = SRType_ASR; break; + // case 3: shift_t = SRType_ROR; break; + // default: throw __FUNCTION__; + // } - return shift_t; - } + // return shift_t; + //} u32 LSL_C(u32 x, s32 shift, bool& carry_out) { @@ -129,7 +135,7 @@ namespace ARMv7_instrs s32 ASR_C(s32 x, s32 shift, bool& carry_out) { assert(shift > 0); - carry_out = shift <= 32 ? x & (1 << (shift - 1)) : false; + carry_out = shift <= 32 ? x & (1 << (shift - 1)) : x < 0; return shift < 32 ? x >> shift : x >> 31; } @@ -142,8 +148,9 @@ namespace ARMv7_instrs u32 ROR_C(u32 x, s32 shift, bool& carry_out) { assert(shift); - carry_out = x & (1 << (shift - 1)); - return x >> shift | x << (32 - shift); + const u32 result = x >> shift | x << (32 - shift); + carry_out = result >> 31; + return result; } u32 ROR_(u32 x, s32 shift) @@ -228,9 +235,9 @@ namespace ARMv7_instrs } } - u32 ThumbExpandImm(ARMv7Context& context, u32 imm12) + u32 ThumbExpandImm(u32 imm12) { - bool carry = context.APSR.C; + bool carry = false; return ThumbExpandImm_C(imm12, carry, carry); } @@ -240,13 +247,13 @@ namespace ARMv7_instrs switch (cond >> 1) { - case 0: result = context.APSR.Z == 1; break; - case 1: result = context.APSR.C == 1; break; - case 2: result = context.APSR.N == 1; break; - case 3: result = context.APSR.V == 1; break; - case 4: result = context.APSR.C == 1 && context.APSR.Z == 0; break; - case 5: result = context.APSR.N == context.APSR.V; break; - case 6: result = context.APSR.N == context.APSR.V && context.APSR.Z == 0; break; + case 0: result = (context.APSR.Z == 1); break; + case 1: result = (context.APSR.C == 1); break; + case 2: result = (context.APSR.N == 1); break; + case 3: result = (context.APSR.V == 1); break; + case 4: result = (context.APSR.C == 1) && (context.APSR.Z == 0); break; + case 5: result = (context.APSR.N == context.APSR.V); break; + case 6: result = (context.APSR.N == context.APSR.V) && (context.APSR.Z == 0); break; case 7: return true; } @@ -276,17 +283,221 @@ namespace ARMv7_instrs throw fmt::format("%s(%s) error: %s (%s)", func, format_encoding(type), info, cond); } + + bool process_debug(ARMv7Context& context) + { + if (context.debug & DF_PRINT) + { + auto pos = context.debug_str.find(' '); + if (pos != std::string::npos && pos < 8) + { + context.debug_str.insert(pos, 8 - pos, ' '); + } + + context.debug_str = fmt::format("0x%08x: %s", context.thread.PC, context.debug_str); + + LV2_LOCK(0); + + auto found = g_armv7_dump.find(context.thread.PC); + if (found != g_armv7_dump.end()) + { + if (found->second != context.debug_str) + { + throw context.debug_str; + } + } + else + { + g_armv7_dump[context.thread.PC] = context.debug_str; + } + } + + if (context.debug & DF_NO_EXE) + { + return true; + } + + return false; + } + + const char* fmt_cond(u32 cond) + { + switch (cond) + { + case 0: return "eq"; + case 1: return "ne"; + case 2: return "cs"; + case 3: return "cc"; + case 4: return "mi"; + case 5: return "pl"; + case 6: return "vs"; + case 7: return "vc"; + case 8: return "hi"; + case 9: return "ls"; + case 10: return "ge"; + case 11: return "lt"; + case 12: return "gt"; + case 13: return "le"; + case 14: return ""; + default: return "???"; + } + } + + const char* fmt_it(u32 state) + { + switch (state & ~0x10) + { + case 0x8: return ""; + + case 0x4: return state & 0x10 ? "e" : "t"; + case 0xc: return state & 0x10 ? "t" : "e"; + + case 0x2: return state & 0x10 ? "ee" : "tt"; + case 0x6: return state & 0x10 ? "et" : "te"; + case 0xa: return state & 0x10 ? "te" : "et"; + case 0xe: return state & 0x10 ? "tt" : "ee"; + + case 0x1: return state & 0x10 ? "eee" : "ttt"; + case 0x3: return state & 0x10 ? "eet" : "tte"; + case 0x5: return state & 0x10 ? "ete" : "tet"; + case 0x7: return state & 0x10 ? "ett" : "tee"; + case 0x9: return state & 0x10 ? "tee" : "ett"; + case 0xb: return state & 0x10 ? "tet" : "ete"; + case 0xd: return state & 0x10 ? "tte" : "eet"; + case 0xf: return state & 0x10 ? "ttt" : "eee"; + + default: return "???"; + } + } + + const char* fmt_reg(u32 reg) + { + switch (reg) + { + case 0: return "r0"; + case 1: return "r1"; + case 2: return "r2"; + case 3: return "r3"; + case 4: return "r4"; + case 5: return "r5"; + case 6: return "r6"; + case 7: return "r7"; + case 8: return "r8"; + case 9: return "r9"; + case 10: return "r10"; + case 11: return "r11"; + case 12: return "r12"; + case 13: return "sp"; + case 14: return "lr"; + case 15: return "pc"; + default: return "r???"; + } + } + + std::string fmt_shift(u32 type, u32 amount) + { + assert(type != SRType_RRX || amount == 1); + assert(amount <= 32); + + if (amount) + { + switch (type) + { + case SRType_LSL: return ",lsl #" + fmt::to_udec(amount); + case SRType_LSR: return ",lsr #" + fmt::to_udec(amount); + case SRType_ASR: return ",asr #" + fmt::to_udec(amount); + case SRType_ROR: return ",ror #" + fmt::to_udec(amount); + case SRType_RRX: return ",rrx"; + default: return ",?????"; + } + } + + return{}; + } + + std::string fmt_reg_list(u32 reg_list) + { + std::vector> lines; + + for (u32 i = 0; i < 13; i++) + { + if (reg_list & (1 << i)) + { + if (lines.size() && lines.rbegin()->second == i - 1) + { + lines.rbegin()->second = i; + } + else + { + lines.push_back({ i, i }); + } + } + } + + if (reg_list & 0x2000) lines.push_back({ 13, 13 }); // sp + if (reg_list & 0x4000) lines.push_back({ 14, 14 }); // lr + if (reg_list & 0x8000) lines.push_back({ 15, 15 }); // pc + + std::string result; + + if (reg_list >> 16) result = "???"; // invalid bits + + for (auto& line : lines) + { + if (!result.empty()) + { + result += ","; + } + + if (line.first == line.second) + { + result += fmt_reg(line.first); + } + else + { + result += fmt_reg(line.first); + result += '-'; + result += fmt_reg(line.second); + } + } + + return result; + } + + std::string fmt_mem_imm(u32 reg, u32 imm, bool index, bool add, bool wback) + { + if (index) + { + return fmt::format("[%s,#%s0x%X]%s", fmt_reg(reg), add ? "" : "-", imm, wback ? "!" : ""); + } + else + { + return fmt::format("[%s],#%s0x%X%s", fmt_reg(reg), add ? "" : "-", imm, wback ? "" : "???"); + } + } + + std::string fmt_mem_reg(u32 n, u32 m, bool index, bool add, bool wback, u32 shift_t = SRType_LSL, u32 shift_n = 0) + { + if (index) + { + return fmt::format("[%s,%s%s%s]%s", fmt_reg(n), add ? "" : "-", fmt_reg(m), fmt_shift(shift_t, shift_n), wback ? "!" : ""); + } + else + { + return fmt::format("[%s],%s%s%s%s", fmt_reg(n), add ? "" : "-", fmt_reg(m), fmt_shift(shift_t, shift_n), wback ? "" : "???"); + } + } } void ARMv7_instrs::UNK(ARMv7Context& context, const ARMv7Code code) { if (context.ISET == Thumb) { - throw fmt::format("Unknown/illegal opcode: 0x%04x 0x%04x", code.code1, code.code0); + 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); + throw fmt::format("Unknown/illegal opcode: 0x%08X", code.data); } } @@ -311,6 +522,12 @@ void ARMv7_instrs::HACK(ARMv7Context& context, const ARMv7Code code, const ARMv7 default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("hack%s %s", fmt_cond(cond), get_psv_func_by_index(func)->name); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { execute_psv_func_by_index(context, func); @@ -341,6 +558,12 @@ void ARMv7_instrs::MRC_(ARMv7Context& context, const ARMv7Code code, const ARMv7 default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("mrc%s p%d,%d,r%d,c%d,c%d,%d", fmt_cond(cond), cp, opc1, t, cn, cm, opc2); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { // APSR flags are written if t = 15 @@ -358,26 +581,107 @@ void ARMv7_instrs::MRC_(ARMv7Context& context, const ARMv7Code code, const ARMv7 return; } - throw fmt::format("Bad instruction: mrc p%d,%d,r%d,c%d,c%d,%d", cp, opc1, t, cn, cm, opc2); + throw fmt::format("Bad instruction: mrc%s p%d,%d,r%d,c%d,c%d,%d", fmt_cond(cond), cp, opc1, t, cn, cm, opc2); } } void ARMv7_instrs::ADC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, d, n, imm32; + bool set_flags; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + set_flags = (code.data & 0x100000); + imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); + + reject(d == 13 || d == 15 || n == 13 || n == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("adc%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + bool carry, overflow; + const u32 result = AddWithCarry(context.read_gpr(n), imm32, context.APSR.C, carry, overflow); + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + context.APSR.V = overflow; + } + } } void ARMv7_instrs::ADC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + bool set_flags = !context.ITSTATE; + u32 cond, d, n, m, shift_t, shift_n; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = n = (code.data & 0x7); + m = (code.data & 0x38) >> 3; + shift_t = SRType_LSL; + shift_n = 0; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + m = (code.data & 0xf); + set_flags = (code.data & 0x100000); + shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); + + reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("adc%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + bool carry, overflow; + const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); + const u32 result = AddWithCarry(context.read_gpr(n), shifted, context.APSR.C, carry, overflow); + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + context.APSR.V = overflow; + } + } } void ARMv7_instrs::ADC_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -418,7 +722,7 @@ void ARMv7_instrs::ADD_IMM(ARMv7Context& context, const ARMv7Code code, const AR d = (code.data & 0xf00) >> 8; n = (code.data & 0xf0000) >> 16; set_flags = (code.data & 0x100000); - imm32 = ThumbExpandImm(context, (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); + imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); reject(d == 15 && set_flags, "CMN (immediate)"); reject(n == 13, "ADD (SP plus immediate)"); @@ -442,22 +746,25 @@ void ARMv7_instrs::ADD_IMM(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("add%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { + bool carry, overflow; + const u32 result = AddWithCarry(context.read_gpr(n), imm32, false, carry, overflow); + context.write_gpr(d, result); + if (set_flags) { - bool carry, overflow; - const u32 res = AddWithCarry(context.read_gpr(n), imm32, false, carry, overflow); - context.write_gpr(d, res); - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; context.APSR.V = overflow; } - else - { - context.write_gpr(d, context.read_gpr(n) + imm32); - } } } @@ -510,23 +817,26 @@ void ARMv7_instrs::ADD_REG(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("add%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { + bool carry, overflow; const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, true); + const u32 result = AddWithCarry(context.read_gpr(n), shifted, false, carry, overflow); + context.write_gpr(d, result); + if (set_flags) { - bool carry, overflow; - const u32 res = AddWithCarry(context.read_gpr(n), shifted, false, carry, overflow); - context.write_gpr(d, res); - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; context.APSR.V = overflow; } - else - { - context.write_gpr(d, context.read_gpr(n) + shifted); - } } } @@ -567,7 +877,7 @@ void ARMv7_instrs::ADD_SPI(ARMv7Context& context, const ARMv7Code code, const AR cond = context.ITSTATE.advance(); d = (code.data & 0xf00) >> 8; set_flags = (code.data & 0x100000); - imm32 = ThumbExpandImm(context, (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); + imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); reject(d == 15 && set_flags, "CMN (immediate)"); reject(d == 15, "UNPREDICTABLE"); @@ -587,22 +897,25 @@ void ARMv7_instrs::ADD_SPI(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("add%s%s %s,sp,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { + bool carry, overflow; + const u32 result = AddWithCarry(context.SP, imm32, false, carry, overflow); + context.write_gpr(d, result); + if (set_flags) { - bool carry, overflow; - const u32 res = AddWithCarry(context.SP, imm32, false, carry, overflow); - context.write_gpr(d, res); - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; context.APSR.V = overflow; } - else - { - context.write_gpr(d, context.SP + imm32); - } } } @@ -650,44 +963,126 @@ void ARMv7_instrs::ADD_SPR(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("add%s%s %s,sp,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), fmt_shift(shift_t, shift_n)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { + bool carry, overflow; const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); + const u32 result = AddWithCarry(context.SP, shifted, false, carry, overflow); + context.write_gpr(d, result); + if (set_flags) { - bool carry, overflow; - const u32 res = AddWithCarry(context.SP, shifted, false, carry, overflow); - context.write_gpr(d, res); - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; context.APSR.V = overflow; } - else - { - context.write_gpr(d, context.SP + context.read_gpr(m)); - } } } void ARMv7_instrs::ADR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, d, imm32; + bool add; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0x700) >> 8; + imm32 = (code.data & 0xff) << 2; + add = true; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + imm32 = (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); + add = false; + + reject(d == 13 || d == 15, "UNPREDICTABLE"); + break; + } + case T3: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + imm32 = (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); + add = true; + + reject(d == 13 || d == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + const u32 base = context.read_pc() & ~3; + const u32 result = add ? base + imm32 : base - imm32; + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("adr%s r%d, 0x%08X", fmt_cond(cond), d, result); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + context.write_gpr(d, result); + } } void ARMv7_instrs::AND_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, d, n, imm32; + bool set_flags, carry = context.APSR.C; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + set_flags = (code.data & 0x100000); + imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); + + reject(d == 15 && set_flags, "TST (immediate)"); + reject(d == 13 || d == 15 || n == 13 || n == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("and%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 result = context.read_gpr(n) & imm32; + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } } void ARMv7_instrs::AND_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -723,6 +1118,12 @@ void ARMv7_instrs::AND_REG(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("and%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { bool carry; @@ -770,14 +1171,14 @@ void ARMv7_instrs::ASR_REG(ARMv7Context& context, const ARMv7Code code, const AR void ARMv7_instrs::B(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { - u32 cond, jump; + u32 cond, imm32; switch (type) { case T1: { cond = (code.data >> 8) & 0xf; - jump = 4 + sign<9, u32>((code.data & 0xff) << 1); + imm32 = sign<9, u32>((code.data & 0xff) << 1); reject(cond == 14, "UNDEFINED"); reject(cond == 15, "SVC"); @@ -787,7 +1188,7 @@ void ARMv7_instrs::B(ARMv7Context& context, const ARMv7Code code, const ARMv7_en case T2: { cond = context.ITSTATE.advance(); - jump = 4 + sign<12, u32>((code.data & 0x7ff) << 1); + imm32 = sign<12, u32>((code.data & 0x7ff) << 1); reject(context.ITSTATE, "UNPREDICTABLE"); break; @@ -799,7 +1200,7 @@ void ARMv7_instrs::B(ARMv7Context& context, const ARMv7Code code, const ARMv7_en const u32 s = (code.data >> 26) & 0x1; const u32 j1 = (code.data >> 13) & 0x1; const u32 j2 = (code.data >> 11) & 0x1; - jump = 4 + sign<21, u32>(s << 20 | j2 << 19 | j1 << 18 | (code.data & 0x3f0000) >> 4 | (code.data & 0x7ff) << 1); + imm32 = sign<21, u32>(s << 20 | j2 << 19 | j1 << 18 | (code.data & 0x3f0000) >> 4 | (code.data & 0x7ff) << 1); } reject(cond >= 14, "Related encodings"); @@ -813,7 +1214,7 @@ void ARMv7_instrs::B(ARMv7Context& context, const ARMv7Code code, const ARMv7_en const u32 s = (code.data >> 26) & 0x1; const u32 i1 = (code.data >> 13) & 0x1 ^ s ^ 1; const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1; - jump = 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); + imm32 = sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); } reject(context.ITSTATE, "UNPREDICTABLE"); @@ -822,16 +1223,21 @@ void ARMv7_instrs::B(ARMv7Context& context, const ARMv7Code code, const ARMv7_en case A1: { cond = code.data >> 28; - jump = 1 + 4 + sign<26, u32>((code.data & 0xffffff) << 2); + imm32 = sign<26, u32>((code.data & 0xffffff) << 2); break; } default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("b%s 0x%08X", fmt_cond(cond), context.read_pc() + imm32); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { - //LOG_NOTICE(ARMv7, "Branch to 0x%x (cond=0x%x)", context.thread.PC + jump, cond); - context.thread.SetBranch(context.thread.PC + jump); + context.thread.SetBranch(context.read_pc() + imm32); } } @@ -857,20 +1263,98 @@ void ARMv7_instrs::BFI(ARMv7Context& context, const ARMv7Code code, const ARMv7_ void ARMv7_instrs::BIC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + bool set_flags, carry = context.APSR.C; + u32 cond, d, n, imm32; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + set_flags = (code.data & 0x100000); + imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); + + reject(d == 13 || d == 15 || n == 13 || n == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("bic%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 result = context.read_gpr(n) & ~imm32; + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } } void ARMv7_instrs::BIC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + bool set_flags = !context.ITSTATE; + u32 cond, d, n, m, shift_t, shift_n; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = n = (code.data & 0x7); + m = (code.data & 0x38) >> 3; + shift_t = SRType_LSL; + shift_n = 0; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + m = (code.data & 0xf); + set_flags = (code.data & 0x100000); + shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); + + reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("bic%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + bool carry; + const u32 shifted = Shift_C(context.read_gpr(m), shift_t, shift_n, context.APSR.C, carry); + const u32 result = context.read_gpr(n) & ~shifted; + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } } void ARMv7_instrs::BIC_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -895,19 +1379,18 @@ void ARMv7_instrs::BKPT(ARMv7Context& context, const ARMv7Code code, const ARMv7 void ARMv7_instrs::BL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { - u32 cond, imm32, newLR; + u32 cond, imm32; switch (type) { case T1: { cond = context.ITSTATE.advance(); - newLR = (context.thread.PC + 4) | 1; { const u32 s = (code.data >> 26) & 0x1; const u32 i1 = (code.data >> 13) & 0x1 ^ s ^ 1; const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1; - imm32 = 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); + imm32 = sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); } reject(context.ITSTATE, "UNPREDICTABLE"); @@ -916,17 +1399,25 @@ void ARMv7_instrs::BL(ARMv7Context& context, const ARMv7Code code, const ARMv7_e case A1: { cond = code.data >> 28; - newLR = (context.thread.PC + 4) - 4; - imm32 = 4 + sign<26, u32>((code.data & 0xffffff) << 2); + imm32 = sign<26, u32>((code.data & 0xffffff) << 2); break; } default: throw __FUNCTION__; } + const u32 lr = context.ISET == ARM ? context.read_pc() - 4 : context.read_pc() | 1; + const u32 pc = context.ISET == ARM ? (context.read_pc() & ~3) + imm32 : context.read_pc() + imm32; + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("bl%s 0x%08X", fmt_cond(cond), pc); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { - context.LR = newLR; - context.thread.SetBranch(context.thread.PC + imm32); + context.LR = lr; + context.thread.SetBranch(pc); } } @@ -939,7 +1430,7 @@ void ARMv7_instrs::BLX(ARMv7Context& context, const ARMv7Code code, const ARMv7_ case T1: { cond = context.ITSTATE.advance(); - newLR = (context.thread.PC + 2) | 1; // ??? + newLR = (context.thread.PC + 2) | 1; { const u32 m = (code.data >> 3) & 0xf; reject(m == 15, "UNPREDICTABLE"); @@ -957,7 +1448,7 @@ void ARMv7_instrs::BLX(ARMv7Context& context, const ARMv7Code code, const ARMv7_ const u32 s = (code.data >> 26) & 0x1; const u32 i1 = (code.data >> 13) & 0x1 ^ s ^ 1; const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1; - target = (context.thread.PC + 4 & ~3) + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); + target = ~3 & context.thread.PC + 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); } reject(context.ITSTATE, "UNPREDICTABLE"); @@ -966,20 +1457,36 @@ void ARMv7_instrs::BLX(ARMv7Context& context, const ARMv7Code code, const ARMv7_ case A1: { cond = code.data >> 28; - newLR = (context.thread.PC + 4) - 4; + newLR = context.thread.PC + 4; target = context.read_gpr(code.data & 0xf); break; } case A2: { cond = 0xe; // always true - newLR = (context.thread.PC + 4) - 4; - target = (context.thread.PC + 4 | 1) + sign<25, u32>((code.data & 0xffffff) << 2 | (code.data & 0x1000000) >> 23); + newLR = context.thread.PC + 4; + target = 1 | context.thread.PC + 8 + sign<25, u32>((code.data & 0xffffff) << 2 | (code.data & 0x1000000) >> 23); break; } default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) + { + context.debug_str = fmt::format("blx%s ", fmt_cond(cond)); + switch (type) + { + case T1: context.debug_str += fmt_reg((code.data >> 3) & 0xf); break; + case T2: context.debug_str += fmt::format("0x%08X", target); break; + case A1: context.debug_str += fmt_reg(code.data & 0xf); break; + default: context.debug_str += "???"; + } + } + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { context.LR = newLR; @@ -989,14 +1496,14 @@ void ARMv7_instrs::BLX(ARMv7Context& context, const ARMv7Code code, const ARMv7_ void ARMv7_instrs::BX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { - u32 cond, target; + u32 cond, m; switch (type) { case T1: { cond = context.ITSTATE.advance(); - target = context.read_gpr((code.data >> 3) & 0xf); + m = (code.data >> 3) & 0xf; reject(context.ITSTATE, "UNPREDICTABLE"); break; @@ -1004,15 +1511,21 @@ void ARMv7_instrs::BX(ARMv7Context& context, const ARMv7Code code, const ARMv7_e case A1: { cond = code.data >> 28; - target = context.read_gpr(code.data & 0xf); + m = (code.data & 0xf); break; } default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("bx%s %s", fmt_cond(cond), fmt_reg(m)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { - context.write_pc(target); + context.write_pc(context.read_gpr(m)); } } @@ -1036,9 +1549,15 @@ void ARMv7_instrs::CB_Z(ARMv7Context& context, const ARMv7Code code, const ARMv7 default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("cb%sz 0x%08X", nonzero ? "n" : "", context.read_pc() + imm32); + if (process_debug(context)) return; + } + if ((context.read_gpr(n) == 0) ^ nonzero) { - context.thread.SetBranch(context.thread.PC + 2 + imm32); + context.thread.SetBranch(context.read_pc() + imm32); } } @@ -1055,7 +1574,7 @@ void ARMv7_instrs::CLZ(ARMv7Context& context, const ARMv7Code code, const ARMv7_ d = (code.data & 0xf00) >> 8; m = (code.data & 0xf); - reject((code.data & 0xf0000) >> 16 != m, "UNPREDICTABLE"); + reject(m != (code.data & 0xf0000) >> 16, "UNPREDICTABLE"); reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); break; } @@ -1063,6 +1582,12 @@ void ARMv7_instrs::CLZ(ARMv7Context& context, const ARMv7Code code, const ARMv7_ default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("clz%s %s,%s", fmt_cond(cond), fmt_reg(d), fmt_reg(m)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { context.write_gpr(d, cntlz32(context.read_gpr(m))); @@ -1115,7 +1640,7 @@ void ARMv7_instrs::CMP_IMM(ARMv7Context& context, const ARMv7Code code, const AR { cond = context.ITSTATE.advance(); n = (code.data & 0xf0000) >> 16; - imm32 = ThumbExpandImm(context, (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); + imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); reject(n == 15, "UNPREDICTABLE"); break; @@ -1124,14 +1649,23 @@ void ARMv7_instrs::CMP_IMM(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("cmp%s %s,#0x%X", fmt_cond(cond), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { bool carry, overflow; - const u32 res = AddWithCarry(context.read_gpr(n), ~imm32, true, carry, overflow); - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + const u32 n_value = context.read_gpr(n); + const u32 result = AddWithCarry(n_value, ~imm32, true, carry, overflow); + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; context.APSR.V = overflow; + + //LOG_NOTICE(ARMv7, "CMP: r%d=0x%08x <> 0x%08x, res=0x%08x", n, n_value, imm32, res); } } @@ -1176,15 +1710,21 @@ void ARMv7_instrs::CMP_REG(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("cmp%s %s,%s%s", fmt_cond(cond), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { + bool carry, overflow; const u32 m_value = context.read_gpr(m); const u32 n_value = context.read_gpr(n); - bool carry, overflow; const u32 shifted = Shift(m_value, shift_t, shift_n, true); - const u32 res = AddWithCarry(n_value, ~shifted, true, carry, overflow); - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + const u32 result = AddWithCarry(n_value, ~shifted, true, carry, overflow); + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; context.APSR.V = overflow; @@ -1202,7 +1742,7 @@ void ARMv7_instrs::CMP_RSR(ARMv7Context& context, const ARMv7Code code, const AR } -void ARMv7_instrs::EOR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +void ARMv7_instrs::DBG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { switch (type) { @@ -1211,7 +1751,7 @@ void ARMv7_instrs::EOR_IMM(ARMv7Context& context, const ARMv7Code code, const AR } } -void ARMv7_instrs::EOR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +void ARMv7_instrs::DMB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { switch (type) { @@ -1220,6 +1760,114 @@ void ARMv7_instrs::EOR_REG(ARMv7Context& context, const ARMv7Code code, const AR } } +void ARMv7_instrs::DSB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +{ + switch (type) + { + case A1: throw __FUNCTION__; + default: throw __FUNCTION__; + } +} + + +void ARMv7_instrs::EOR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +{ + bool set_flags, carry = context.APSR.C; + u32 cond, d, n, imm32; + + switch (type) + { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + set_flags = (code.data & 0x100000); + imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); + + reject(d == 15 && set_flags, "TEQ (immediate)"); + reject(d == 13 || d == 15 || n == 13 || n == 15, "UNPREDICTABLE"); + break; + } + case A1: throw __FUNCTION__; + default: throw __FUNCTION__; + } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("eor%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 result = context.read_gpr(n) ^ imm32; + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } +} + +void ARMv7_instrs::EOR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +{ + bool set_flags = !context.ITSTATE; + u32 cond, d, n, m, shift_t, shift_n; + + switch (type) + { + case T1: + { + cond = context.ITSTATE.advance(); + d = n = (code.data & 0x7); + m = (code.data & 0x38) >> 3; + shift_t = SRType_LSL; + shift_n = 0; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + m = (code.data & 0xf); + set_flags = (code.data & 0x100000); + shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); + + reject(d == 15 && set_flags, "TEQ (register)"); + reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } + case A1: throw __FUNCTION__; + default: throw __FUNCTION__; + } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("eor%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + bool carry; + const u32 shifted = Shift_C(context.read_gpr(m), shift_t, shift_n, context.APSR.C, carry); + const u32 result = context.read_gpr(n) ^ shifted; + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } +} + void ARMv7_instrs::EOR_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { switch (type) @@ -1236,29 +1884,85 @@ void ARMv7_instrs::IT(ARMv7Context& context, const ARMv7Code code, const ARMv7_e { case T1: { - const u32 mask = code.data & 0xf; + const u32 mask = (code.data & 0xf); const u32 first = (code.data & 0xf0) >> 4; reject(mask == 0, "Related encodings"); reject(first == 15, "UNPREDICTABLE"); - reject(first == 14 && BitCount(mask) != 1, "UNPREDICTABLE"); + reject(first == 14 && BitCount(mask, 4) != 1, "UNPREDICTABLE"); reject(context.ITSTATE, "UNPREDICTABLE"); + + context.ITSTATE.IT = code.data & 0xff; break; } default: throw __FUNCTION__; } - context.ITSTATE.IT = code.data & 0xff; + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("IT%s %s", fmt_it(context.ITSTATE.shift_state), fmt_cond(context.ITSTATE.condition)); + if (process_debug(context)) return; + } } void ARMv7_instrs::LDM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, n, reg_list; + bool wback; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + n = (code.data & 0x700) >> 8; + reg_list = (code.data & 0xff); + wback = !(reg_list & (1 << n)); + + reject(reg_list == 0, "UNPREDICTABLE"); + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + n = (code.data & 0xf0000) >> 16; + reg_list = (code.data & 0xdfff); + wback = (code.data & 0x200000); + + reject(wback && n == 13, "POP"); + reject(n == 15 || BitCount(reg_list, 16) < 2 || reg_list >= 0xc000, "UNPREDICTABLE"); + reject(reg_list & 0x8000 && context.ITSTATE, "UNPREDICTABLE"); + reject(wback && reg_list & (1 << n), "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldm%s %s%s,{%s}", fmt_cond(cond), fmt_reg(n), wback ? "!" : "", fmt_reg_list(reg_list)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + auto memory = vm::psv::ptr::make(context.read_gpr(n)); + + for (u32 i = 0; i < 16; i++) + { + if (reg_list & (1 << i)) + { + context.write_gpr(i, *memory++); + } + } + + if (wback) + { + context.write_gpr(n, memory.addr()); + } + } } void ARMv7_instrs::LDMDA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -1353,11 +2057,16 @@ void ARMv7_instrs::LDR_IMM(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldr%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; const u32 addr = index ? offset_addr : context.read_gpr(n); - context.write_gpr(t, vm::psv::read32(addr)); if (wback) @@ -1369,11 +2078,47 @@ void ARMv7_instrs::LDR_IMM(ARMv7Context& context, const ARMv7Code code, const AR void ARMv7_instrs::LDR_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, t, imm32; + bool add; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0x700) >> 8; + imm32 = (code.data & 0xff) << 2; + add = true; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + imm32 = (code.data & 0xfff); + add = (code.data & 0x800000); + + reject(t == 15 && context.ITSTATE, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + const u32 base = context.read_pc() & ~3; + const u32 addr = add ? base + imm32 : base - imm32; + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldr%s %s,0x%08X", fmt_cond(cond), fmt_reg(t), addr); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 data = vm::psv::read32(addr); + context.write_gpr(t, data); + } } void ARMv7_instrs::LDR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -1405,8 +2150,8 @@ void ARMv7_instrs::LDR_REG(ARMv7Context& context, const ARMv7Code code, const AR index = true; add = true; wback = false; - shift_t = (code.data & 0x30) >> 4; - shift_n = 0; + shift_t = SRType_LSL; + shift_n = (code.data & 0x30) >> 4; reject(n == 15, "LDR (literal)"); reject(m == 13 || m == 15, "UNPREDICTABLE"); @@ -1417,19 +2162,23 @@ void ARMv7_instrs::LDR_REG(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldr%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; const u32 addr = index ? offset_addr : context.read_gpr(n); - const u32 data = vm::psv::read32(addr); + context.write_gpr(t, vm::psv::read32(addr)); if (wback) { context.write_gpr(n, offset_addr); } - - context.write_gpr(t, data); } } @@ -1446,7 +2195,7 @@ void ARMv7_instrs::LDRB_IMM(ARMv7Context& context, const ARMv7Code code, const A cond = context.ITSTATE.advance(); t = (code.data & 0x7); n = (code.data & 0x38) >> 3; - imm32 = (code.data & 0x7c0) >> 4; + imm32 = (code.data & 0x7c0) >> 6; index = true; add = true; wback = false; @@ -1488,11 +2237,16 @@ void ARMv7_instrs::LDRB_IMM(ARMv7Context& context, const ARMv7Code code, const A default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldrb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; const u32 addr = index ? offset_addr : context.read_gpr(n); - context.write_gpr(t, vm::psv::read8(addr)); if (wback) @@ -1513,11 +2267,63 @@ void ARMv7_instrs::LDRB_LIT(ARMv7Context& context, const ARMv7Code code, const A void ARMv7_instrs::LDRB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, t, n, m, shift_t, shift_n; + bool index, add, wback; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0x7); + n = (code.data & 0x38) >> 3; + m = (code.data & 0x1c0) >> 6; + index = true; + add = true; + wback = false; + shift_t = SRType_LSL; + shift_n = 0; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + m = (code.data & 0xf); + index = true; + add = true; + wback = false; + shift_t = SRType_LSL; + shift_n = (code.data & 0x30) >> 4; + + reject(t == 15, "PLD"); + reject(n == 15, "LDRB (literal)"); + reject(t == 13 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldrb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); + const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; + const u32 addr = index ? offset_addr : context.read_gpr(n); + context.write_gpr(t, vm::psv::read8(addr)); + + if (wback) + { + context.write_gpr(n, offset_addr); + } + } } @@ -1549,12 +2355,17 @@ void ARMv7_instrs::LDRD_IMM(ARMv7Context& context, const ARMv7Code code, const A default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldrd%s %s,%s,%s", fmt_cond(cond), fmt_reg(t), fmt_reg(t2), fmt_mem_imm(n, imm32, index, add, wback)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; const u32 addr = index ? offset_addr : context.read_gpr(n); const u64 value = vm::psv::read64(addr); - context.write_gpr(t, (u32)(value)); context.write_gpr(t2, (u32)(value >> 32)); @@ -1567,11 +2378,42 @@ void ARMv7_instrs::LDRD_IMM(ARMv7Context& context, const ARMv7Code code, const A void ARMv7_instrs::LDRD_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, t, t2, imm32; + bool add; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + t2 = (code.data & 0xf00) >> 8; + imm32 = (code.data & 0xff) << 2; + add = (code.data & 0x800000); + + reject(!(code.data & 0x1000000), "Related encodings"); // ??? + reject(t == 13 || t == 15 || t2 == 13 || t2 == 15 || t == t2, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + const u32 base = context.read_pc() & ~3; + const u32 addr = add ? base + imm32 : base - imm32; + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldrd%s %s,%s,0x%08X", fmt_cond(cond), fmt_reg(t), fmt_reg(t2), addr); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u64 value = vm::psv::read64(addr); + context.write_gpr(t, (u32)(value)); + context.write_gpr(t2, (u32)(value >> 32)); + } } void ARMv7_instrs::LDRD_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -1586,11 +2428,75 @@ void ARMv7_instrs::LDRD_REG(ARMv7Context& context, const ARMv7Code code, const A void ARMv7_instrs::LDRH_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, t, n, imm32; + bool index, add, wback; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0x7); + n = (code.data & 0x38) >> 3; + imm32 = (code.data & 0x7c0) >> 5; + index = true; + add = true; + wback = false; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + imm32 = (code.data & 0xfff); + index = true; + add = true; + wback = false; + + reject(t == 15, "Unallocated memory hints"); + reject(n == 15, "LDRH (literal)"); + reject(t == 13, "UNPREDICTABLE"); + break; + } + case T3: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + imm32 = (code.data & 0xff); + index = (code.data & 0x400); + add = (code.data & 0x200); + wback = (code.data & 0x100); + + reject(n == 15, "LDRH (literal)"); + reject(t == 15 && index && !add && !wback, "Unallocated memory hints"); + reject(index && add && !wback, "LDRHT"); + reject(!index && !wback, "UNDEFINED"); + reject(t == 13 || t == 15 || (wback && n == t), "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldrh%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : context.read_gpr(n); + context.write_gpr(t, vm::psv::read16(addr)); + + if (wback) + { + context.write_gpr(n, offset_addr); + } + } } void ARMv7_instrs::LDRH_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -1655,12 +2561,17 @@ void ARMv7_instrs::LDRSB_IMM(ARMv7Context& context, const ARMv7Code code, const default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldrsb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; const u32 addr = index ? offset_addr : context.read_gpr(n); const s8 value = vm::psv::read8(addr); - context.write_gpr(t, value); // sign-extend if (wback) @@ -1737,13 +2648,19 @@ void ARMv7_instrs::LDREX(ARMv7Context& context, const ARMv7Code code, const ARMv default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ldrex%s %s,[%s,#0x%X]", fmt_cond(cond), fmt_reg(t), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 addr = context.read_gpr(n) + imm32; - const u32 value = vm::psv::read32(addr); - - context.R_ADDR = addr; - context.R_DATA = value; + + u32 value; + vm::reservation_acquire(&value, addr, sizeof(value)); + context.write_gpr(t, value); } } @@ -1788,7 +2705,7 @@ void ARMv7_instrs::LSL_IMM(ARMv7Context& context, const ARMv7Code code, const AR cond = context.ITSTATE.advance(); d = (code.data & 0x7); m = (code.data & 0x38) >> 3; - shift_n = (code.data & 0x7c0) >> 6; + DecodeImmShift(0, (code.data & 0x7c0) >> 6, &shift_n); reject(!shift_n, "MOV (register)"); break; @@ -1799,7 +2716,7 @@ void ARMv7_instrs::LSL_IMM(ARMv7Context& context, const ARMv7Code code, const AR d = (code.data & 0xf00) >> 8; m = (code.data & 0xf); set_flags = (code.data & 0x100000); - shift_n = (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6; + DecodeImmShift(0, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); reject(!shift_n, "MOV (register)"); reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); @@ -1809,15 +2726,22 @@ void ARMv7_instrs::LSL_IMM(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("lsl%s%s %s,%s,#%d", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), shift_n); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { bool carry; - const u32 res = Shift_C(context.read_gpr(m), SRType_LSL, shift_n, context.APSR.C, carry); - context.write_gpr(d, res); + const u32 result = Shift_C(context.read_gpr(m), SRType_LSL, shift_n, context.APSR.C, carry); + context.write_gpr(d, result); + if (set_flags) { - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; } } @@ -1852,15 +2776,22 @@ void ARMv7_instrs::LSL_REG(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("lsl%s%s %s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { bool carry; - const u32 res = Shift_C(context.read_gpr(n), SRType_LSL, (context.read_gpr(m) & 0xff), context.APSR.C, carry); - context.write_gpr(d, res); + const u32 result = Shift_C(context.read_gpr(n), SRType_LSL, (context.read_gpr(m) & 0xff), context.APSR.C, carry); + context.write_gpr(d, result); + if (set_flags) { - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; } } @@ -1869,11 +2800,53 @@ void ARMv7_instrs::LSL_REG(ARMv7Context& context, const ARMv7Code code, const AR void ARMv7_instrs::LSR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + bool set_flags = !context.ITSTATE; + u32 cond, d, m, shift_n; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0x7); + m = (code.data & 0x38) >> 3; + DecodeImmShift(1, (code.data & 0x7c0) >> 6, &shift_n); + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + m = (code.data & 0xf); + set_flags = (code.data & 0x100000); + DecodeImmShift(1, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); + + reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("lsr%s%s %s,%s,#%d", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), shift_n); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + bool carry; + const u32 result = Shift_C(context.read_gpr(m), SRType_LSR, shift_n, context.APSR.C, carry); + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } } void ARMv7_instrs::LSR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -1923,7 +2896,7 @@ void ARMv7_instrs::MOV_IMM(ARMv7Context& context, const ARMv7Code code, const AR case T2: { cond = context.ITSTATE.advance(); - set_flags = code.data & 0x100000; + set_flags = (code.data & 0x100000); d = (code.data >> 8) & 0xf; imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); @@ -1943,13 +2916,28 @@ void ARMv7_instrs::MOV_IMM(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) + { + switch (type) + { + case T3: case A2: context.debug_str = fmt::format("movw%s%s %s,#0x%04X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); break; + default: context.debug_str = fmt::format("mov%s%s %s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); + } + } + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { - context.write_gpr(d, imm32); + const u32 result = imm32; + context.write_gpr(d, result); + if (set_flags) { - context.APSR.N = imm32 >> 31; - context.APSR.Z = imm32 == 0; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; } } @@ -1997,15 +2985,22 @@ void ARMv7_instrs::MOV_REG(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("mov%s%s %s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { - const u32 res = context.read_gpr(m); - context.write_gpr(d, res); + const u32 result = context.read_gpr(m); + context.write_gpr(d, result); + if (set_flags) { - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; - //context.APSR.C = ? + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + //context.APSR.C = carry; } } } @@ -2020,7 +3015,7 @@ void ARMv7_instrs::MOVT(ARMv7Context& context, const ARMv7Code code, const ARMv7 { cond = context.ITSTATE.advance(); d = (code.data & 0xf00) >> 8; - imm16 = (code.data & 0xf0000) >> 4 | (code.data & 0x4000000) >> 14 | (code.data & 0x7000) >> 4 | (code.data & 0xff); + imm16 = (code.data & 0xf0000) >> 4 | (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); reject(d == 13 || d == 15, "UNPREDICTABLE"); break; @@ -2029,6 +3024,12 @@ void ARMv7_instrs::MOVT(ARMv7Context& context, const ARMv7Code code, const ARMv7 default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("movt%s %s,#0x%04X", fmt_cond(cond), fmt_reg(d), imm16); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { context.write_gpr(d, (context.read_gpr(d) & 0xffff) | (imm16 << 16)); @@ -2095,6 +3096,12 @@ void ARMv7_instrs::MUL(ARMv7Context& context, const ARMv7Code code, const ARMv7_ default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("mul%s%s %s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 op1 = context.read_gpr(n); @@ -2132,6 +3139,12 @@ void ARMv7_instrs::MVN_IMM(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("mvn%s%s %s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 result = ~imm32; @@ -2148,11 +3161,55 @@ void ARMv7_instrs::MVN_IMM(ARMv7Context& context, const ARMv7Code code, const AR void ARMv7_instrs::MVN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + bool set_flags = !context.ITSTATE; + u32 cond, d, m, shift_t, shift_n; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0x7); + m = (code.data & 0x38) >> 3; + shift_t = SRType_LSL; + shift_n = 0; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + m = (code.data & 0xf); + set_flags = (code.data & 0x100000); + shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); + + reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("mvn%s%s %s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), fmt_shift(shift_t, shift_n)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + bool carry; + const u32 shifted = Shift_C(context.read_gpr(m), shift_t, shift_n, context.APSR.C, carry); + const u32 result = ~shifted; + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } } void ARMv7_instrs::MVN_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -2189,6 +3246,12 @@ void ARMv7_instrs::NOP(ARMv7Context& context, const ARMv7Code code, const ARMv7_ default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("nop%s", fmt_cond(cond)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { } @@ -2216,20 +3279,100 @@ void ARMv7_instrs::ORN_REG(ARMv7Context& context, const ARMv7Code code, const AR void ARMv7_instrs::ORR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, d, n, imm32; + bool set_flags, carry = context.APSR.C; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + set_flags = (code.data & 0x100000); + imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); + + reject(n == 15, "MOV (immediate)"); + reject(d == 13 || d == 15 || n == 13, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("orr%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 result = context.read_gpr(n) | imm32; + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } } void ARMv7_instrs::ORR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + bool set_flags = !context.ITSTATE; + u32 cond, d, n, m, shift_t, shift_n; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = n = (code.data & 0x7); + m = (code.data & 0x38) >> 3; + shift_t = SRType_LSL; + shift_n = 0; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + m = (code.data & 0xf); + set_flags = (code.data & 0x100000); + shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); + + reject(n == 15, "ROR (immediate)"); + reject(d == 13 || d == 15 || n == 13 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("orr%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + bool carry; + const u32 shifted = Shift_C(context.read_gpr(m), shift_t, shift_n, context.APSR.C, carry); + const u32 result = context.read_gpr(n) | shifted; + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } } void ARMv7_instrs::ORR_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -2303,19 +3446,25 @@ void ARMv7_instrs::POP(ARMv7Context& context, const ARMv7Code code, const ARMv7_ default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("pop%s {%s}", fmt_cond(cond), fmt_reg_list(reg_list)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { - u32 written = 0; - for (u16 mask = 1, i = 0; mask; mask <<= 1, i++) + auto stack = vm::psv::ptr::make(context.SP); + + for (u32 i = 0; i < 16; i++) { - if (reg_list & mask) + if (reg_list & (1 << i)) { - context.write_gpr(i, vm::psv::read32(context.SP + written)); - written += 4; + context.write_gpr(i, *stack++); } } - context.SP += written; + context.SP = stack.addr(); } } @@ -2368,19 +3517,25 @@ void ARMv7_instrs::PUSH(ARMv7Context& context, const ARMv7Code code, const ARMv7 default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("push%s {%s}", fmt_cond(cond), fmt_reg_list(reg_list)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { - u32 read = 0; - for (u16 mask = 1 << 15, i = 15; mask; mask >>= 1, i--) + auto memory = vm::psv::ptr::make(context.SP); + + for (u32 i = 15; ~i; i--) { - if (reg_list & mask) + if (reg_list & (1 << i)) { - read += 4; - vm::psv::write32(context.SP - read, context.read_gpr(i)); + *--memory = context.read_gpr(i); } } - context.SP -= read; + context.SP = memory.addr(); } } @@ -2487,11 +3642,41 @@ void ARMv7_instrs::RBIT(ARMv7Context& context, const ARMv7Code code, const ARMv7 void ARMv7_instrs::REV(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, d, m; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0x7); + m = (code.data & 0x38) >> 3; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + m = (code.data & 0xf); + + reject(m != (code.data & 0xf0000) >> 16, "UNPREDICTABLE"); + reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("rev%s %s,%s", fmt_cond(cond), fmt_reg(d), fmt_reg(m)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + context.write_gpr(d, re32(context.read_gpr(m))); + } } void ARMv7_instrs::REV16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -2515,20 +3700,97 @@ void ARMv7_instrs::REVSH(ARMv7Context& context, const ARMv7Code code, const ARMv void ARMv7_instrs::ROR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, d, m, shift_n; + bool set_flags; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + m = (code.data & 0xf); + set_flags = (code.data & 0x100000); + const u32 shift_t = DecodeImmShift(3, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); + + reject(shift_t == SRType_RRX, "RRX"); + reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ror%s%s %s,%s,#%d", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), shift_n); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + bool carry; + const u32 result = Shift_C(context.read_gpr(m), SRType_ROR, shift_n, context.APSR.C, carry); + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } } void ARMv7_instrs::ROR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + bool set_flags = !context.ITSTATE; + u32 cond, d, n, m; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = n = (code.data & 0x7); + m = (code.data & 0x38) >> 3; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + m = (code.data & 0xf); + set_flags = (code.data & 0x100000); + + reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("ror%s%s %s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + bool carry; + const u32 shift_n = context.read_gpr(m) & 0xff; + const u32 result = Shift_C(context.read_gpr(n), SRType_ROR, shift_n, context.APSR.C, carry); + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } + } } @@ -2544,11 +3806,54 @@ void ARMv7_instrs::RRX(ARMv7Context& context, const ARMv7Code code, const ARMv7_ void ARMv7_instrs::RSB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + bool set_flags = !context.ITSTATE; + u32 cond, d, n, imm32; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0x7); + n = (code.data & 0x38) >> 3; + imm32 = 0; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + d = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + set_flags = (code.data & 0x100000); + imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); + + reject(d == 13 || d == 15 || n == 13 || n == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("rsb%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + bool carry, overflow; + const u32 result = AddWithCarry(~context.read_gpr(n), imm32, true, carry, overflow); + context.write_gpr(d, result); + + if (set_flags) + { + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + context.APSR.V = overflow; + } + } } void ARMv7_instrs::RSB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -2932,11 +4237,59 @@ void ARMv7_instrs::SSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv void ARMv7_instrs::STM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, n, reg_list; + bool wback; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + n = (code.data & 0x700) >> 8; + reg_list = (code.data & 0xff); + wback = true; + + reject(reg_list == 0, "UNPREDICTABLE"); + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + n = (code.data & 0xf0000) >> 16; + reg_list = (code.data & 0x5fff); + wback = (code.data & 0x200000); + + reject(n == 15 || BitCount(reg_list, 16) < 2, "UNPREDICTABLE"); + reject(wback && reg_list & (1 << n), "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("stm%s %s%s,{%s}", fmt_cond(cond), fmt_reg(n), wback ? "!" : "", fmt_reg_list(reg_list)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + auto memory = vm::psv::ptr::make(context.read_gpr(n)); + + for (u32 i = 0; i < 16; i++) + { + if (reg_list & (1 << i)) + { + *memory++ = context.read_gpr(i); + } + } + + if (wback) + { + context.write_gpr(n, memory.addr()); + } + } } void ARMv7_instrs::STMDA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -3030,11 +4383,16 @@ void ARMv7_instrs::STR_IMM(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("str%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; const u32 addr = index ? offset_addr : context.read_gpr(n); - vm::psv::write32(addr, context.read_gpr(t)); if (wback) @@ -3084,12 +4442,17 @@ void ARMv7_instrs::STR_REG(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("str%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; const u32 addr = index ? offset_addr : context.read_gpr(n); - vm::psv::write32(addr, context.read_gpr(t)); if (wback) @@ -3112,7 +4475,7 @@ void ARMv7_instrs::STRB_IMM(ARMv7Context& context, const ARMv7Code code, const A cond = context.ITSTATE.advance(); t = (code.data & 0x7); n = (code.data & 0x38) >> 3; - imm32 = (code.data & 0x7c0) >> 4; + imm32 = (code.data & 0x7c0) >> 6; index = true; add = true; wback = false; @@ -3151,11 +4514,16 @@ void ARMv7_instrs::STRB_IMM(ARMv7Context& context, const ARMv7Code code, const A default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("strb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; const u32 addr = index ? offset_addr : context.read_gpr(n); - vm::psv::write8(addr, (u8)context.read_gpr(t)); if (wback) @@ -3167,21 +4535,110 @@ void ARMv7_instrs::STRB_IMM(ARMv7Context& context, const ARMv7Code code, const A void ARMv7_instrs::STRB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, t, n, m, shift_t, shift_n; + bool index, add, wback; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0x7); + n = (code.data & 0x38) >> 3; + m = (code.data & 0x1c0) >> 6; + index = true; + add = true; + wback = false; + shift_t = SRType_LSL; + shift_n = 0; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + m = (code.data & 0xf); + index = true; + add = true; + wback = false; + shift_t = SRType_LSL; + shift_n = (code.data & 0x30) >> 4; + + reject(n == 15, "UNDEFINED"); + reject(t == 13 || t == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("strb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); + const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; + const u32 addr = index ? offset_addr : context.read_gpr(n); + vm::psv::write8(addr, (u8)context.read_gpr(t)); + + if (wback) + { + context.write_gpr(n, offset_addr); + } + } } void ARMv7_instrs::STRD_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, t, t2, n, imm32; + bool index, add, wback; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + t2 = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + imm32 = (code.data & 0xff) << 2; + index = (code.data & 0x1000000); + add = (code.data & 0x800000); + wback = (code.data & 0x200000); + + reject(!index && !wback, "Related encodings"); + reject(wback && (n == t || n == t2), "UNPREDICTABLE"); + reject(n == 15 || t == 13 || t == 15 || t2 == 13 || t2 == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("strd%s %s,%s,%s", fmt_cond(cond), fmt_reg(t), fmt_reg(t2), fmt_mem_imm(n, imm32, index, add, wback)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 n_value = context.read_gpr(n); + const u32 offset = add ? n_value + imm32 : n_value - imm32; + const u32 addr = index ? offset : n_value; + vm::psv::write64(addr, (u64)context.read_gpr(t2) << 32 | (u64)context.read_gpr(t)); + + if (wback) + { + context.write_gpr(n, offset); + } + } } void ARMv7_instrs::STRD_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -3196,20 +4653,132 @@ void ARMv7_instrs::STRD_REG(ARMv7Context& context, const ARMv7Code code, const A void ARMv7_instrs::STRH_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, t, n, imm32; + bool index, add, wback; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0x7); + n = (code.data & 0x38) >> 3; + imm32 = (code.data & 0x7c0) >> 5; + index = true; + add = true; + wback = false; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + imm32 = (code.data & 0xfff); + index = true; + add = true; + wback = false; + + reject(n == 15, "UNDEFINED"); + reject(t == 13 || t == 15, "UNPREDICTABLE"); + break; + } + case T3: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + imm32 = (code.data & 0xff); + index = (code.data & 0x400); + add = (code.data & 0x200); + wback = (code.data & 0x100); + + reject(index && add && !wback, "STRHT"); + reject(n == 15 || (!index && !wback), "UNDEFINED"); + reject(t == 13 || t == 15 || (wback && n == t), "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("strh%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : context.read_gpr(n); + vm::psv::write16(addr, (u16)context.read_gpr(t)); + + if (wback) + { + context.write_gpr(n, offset_addr); + } + } } void ARMv7_instrs::STRH_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, t, n, m, shift_t, shift_n; + bool index, add, wback; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0x7); + n = (code.data & 0x38) >> 3; + m = (code.data & 0x1c0) >> 6; + index = true; + add = true; + wback = false; + shift_t = SRType_LSL; + shift_n = 0; + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + m = (code.data & 0xf); + index = true; + add = true; + wback = false; + shift_t = SRType_LSL; + shift_n = (code.data & 0x30) >> 4; + + reject(n == 15, "UNDEFINED"); + reject(t == 13 || t == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("strh%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); + const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; + const u32 addr = index ? offset_addr : context.read_gpr(n); + vm::psv::write16(addr, (u16)context.read_gpr(t)); + + if (wback) + { + context.write_gpr(n, offset_addr); + } + } } @@ -3235,14 +4804,17 @@ void ARMv7_instrs::STREX(ARMv7Context& context, const ARMv7Code code, const ARMv default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("strex%s %s,%s,[%s,#0x%x]", fmt_cond(cond), fmt_reg(d), fmt_reg(t), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { const u32 addr = context.read_gpr(n) + imm32; const u32 value = context.read_gpr(t); - - auto& sync_obj = vm::get_ref>(addr); - context.write_gpr(d, addr != context.R_ADDR || sync_obj.compare_and_swap((u32)context.R_DATA, value) != context.R_DATA); - context.R_ADDR = 0; + context.write_gpr(d, !vm::reservation_update(addr, &value, sizeof(value))); } } @@ -3302,7 +4874,7 @@ void ARMv7_instrs::SUB_IMM(ARMv7Context& context, const ARMv7Code code, const AR d = (code.data & 0xf00) >> 8; n = (code.data & 0xf0000) >> 16; set_flags = (code.data & 0x100000); - imm32 = ThumbExpandImm(context, (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); + imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); reject(d == 15 && set_flags, "CMP (immediate)"); reject(n == 13, "SUB (SP minus immediate)"); @@ -3326,22 +4898,25 @@ void ARMv7_instrs::SUB_IMM(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("sub%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { + bool carry, overflow; + const u32 result = AddWithCarry(context.read_gpr(n), ~imm32, true, carry, overflow); + context.write_gpr(d, result); + if (set_flags) { - bool carry, overflow; - const u32 res = AddWithCarry(context.read_gpr(n), ~imm32, true, carry, overflow); - context.write_gpr(d, res); - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; context.APSR.V = overflow; } - else - { - context.write_gpr(d, context.read_gpr(n) - imm32); - } } } @@ -3380,23 +4955,26 @@ void ARMv7_instrs::SUB_REG(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("sub%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { + bool carry, overflow; const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); + const u32 result = AddWithCarry(context.read_gpr(n), ~shifted, true, carry, overflow); + context.write_gpr(d, result); + if (set_flags) { - bool carry, overflow; - const u32 res = AddWithCarry(context.read_gpr(n), ~shifted, true, carry, overflow); - context.write_gpr(d, res); - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; context.APSR.V = overflow; } - else - { - context.write_gpr(d, context.read_gpr(n) - shifted); - } } } @@ -3429,7 +5007,7 @@ void ARMv7_instrs::SUB_SPI(ARMv7Context& context, const ARMv7Code code, const AR cond = context.ITSTATE.advance(); d = (code.data & 0xf00) >> 8; set_flags = (code.data & 0x100000); - imm32 = ThumbExpandImm(context, (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); + imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); reject(d == 15 && set_flags, "CMP (immediate)"); reject(d == 15, "UNPREDICTABLE"); @@ -3449,22 +5027,25 @@ void ARMv7_instrs::SUB_SPI(ARMv7Context& context, const ARMv7Code code, const AR default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("sub%s%s %s,sp,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { + bool carry, overflow; + const u32 result = AddWithCarry(context.SP, ~imm32, true, carry, overflow); + context.write_gpr(d, result); + if (set_flags) { - bool carry, overflow; - const u32 res = AddWithCarry(context.SP, ~imm32, true, carry, overflow); - context.write_gpr(d, res); - context.APSR.N = res >> 31; - context.APSR.Z = res == 0; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; context.APSR.C = carry; context.APSR.V = overflow; } - else - { - context.write_gpr(d, context.SP - imm32); - } } } @@ -3583,11 +5164,37 @@ void ARMv7_instrs::TEQ_RSR(ARMv7Context& context, const ARMv7Code code, const AR void ARMv7_instrs::TST_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + bool carry = context.APSR.C; + u32 cond, n, imm32; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + n = (code.data & 0xf0000) >> 16; + imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); + + reject(n == 13 || n == 15, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("tst%s %s,#0x%X", fmt_cond(cond), fmt_reg(n), imm32); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u32 result = context.read_gpr(n) & imm32; + context.APSR.N = result >> 31; + context.APSR.Z = result == 0; + context.APSR.C = carry; + } } void ARMv7_instrs::TST_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -3728,11 +5335,46 @@ void ARMv7_instrs::UMLAL(ARMv7Context& context, const ARMv7Code code, const ARMv void ARMv7_instrs::UMULL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, d0, d1, n, m; + bool set_flags; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + d0 = (code.data & 0xf000) >> 12; + d1 = (code.data & 0xf00) >> 8; + n = (code.data & 0xf0000) >> 16; + m = (code.data & 0xf); + set_flags = false; + + reject(d0 == 13 || d0 == 15 || d1 == 13 || d1 == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); + reject(d0 == d1, "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("umull%s%s %s,%s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d0), fmt_reg(d1), fmt_reg(n), fmt_reg(m)); + if (process_debug(context)) return; + } + + if (ConditionPassed(context, cond)) + { + const u64 result = (u64)context.read_gpr(n) * (u64)context.read_gpr(m); + context.write_gpr(d1, (u32)(result >> 32)); + context.write_gpr(d0, (u32)(result)); + + if (set_flags) + { + context.APSR.N = result >> 63 != 0; + context.APSR.Z = result == 0; + } + } } void ARMv7_instrs::UQADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) @@ -3907,6 +5549,12 @@ void ARMv7_instrs::UXTB(ARMv7Context& context, const ARMv7Code code, const ARMv7 default: throw __FUNCTION__; } + if (context.debug) + { + if (context.debug & DF_DISASM) context.debug_str = fmt::format("uxtb%s %s,%s%s", fmt_cond(cond), fmt_reg(d), fmt_reg(m), fmt_shift(SRType_ROR, rot)); + if (process_debug(context)) return; + } + if (ConditionPassed(context, cond)) { context.write_gpr(d, (context.read_gpr(m) >> rot) & 0xff); diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h index 2a18646d42..e759f5e40b 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h @@ -18,12 +18,11 @@ enum ARMv7_encoding enum SRType : u32 { - SRType_None, SRType_LSL, SRType_LSR, SRType_ASR, SRType_ROR, - SRType_RRX + SRType_RRX, }; namespace ARMv7_instrs @@ -79,6 +78,10 @@ namespace ARMv7_instrs void CMP_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); void CMP_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); + void DBG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); + void DMB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); + void DSB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); + void EOR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); void EOR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); void EOR_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 9fe72a3d49..0a57e4abcf 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -18,7 +18,7 @@ void ARMv7Context::write_pc(u32 value) u32 ARMv7Context::read_pc() { - return thread.PC; + return ISET == ARM ? thread.PC + 8 : thread.PC + 4; } u32 ARMv7Context::get_stack_arg(u32 pos) @@ -118,7 +118,7 @@ void ARMv7Thread::InitRegs() context.ITSTATE.IT = 0; context.SP = m_stack_addr + m_stack_size; context.TLS = armv7_get_tls(GetId()); - context.R_ADDR = 0; + context.debug |= DF_DISASM | DF_PRINT; } void ARMv7Thread::InitStack() @@ -230,14 +230,14 @@ void ARMv7Thread::FastStop() m_status = Stopped; } -armv7_thread::armv7_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio) +armv7_thread::armv7_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio) { thread = &Emu.GetCPU().AddThread(CPU_THREAD_ARMv7); thread->SetName(name); thread->SetEntry(entry); - thread->SetStackSize(stack_size ? stack_size : Emu.GetInfo().GetProcParam().primary_stacksize); - thread->SetPrio(prio ? prio : Emu.GetInfo().GetProcParam().primary_prio); + thread->SetStackSize(stack_size); + thread->SetPrio(prio); argc = 0; } diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.h b/rpcs3/Emu/ARMv7/ARMv7Thread.h index a8a0f75311..5bbc4a564c 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.h +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.h @@ -39,7 +39,7 @@ class armv7_thread : cpu_thread u32 argc; public: - armv7_thread(u32 entry, const std::string& name = "", u32 stack_size = 0, u32 prio = 0); + armv7_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio); cpu_thread& args(std::initializer_list values) override; diff --git a/rpcs3/Emu/ARMv7/Modules/psv_cond.cpp b/rpcs3/Emu/ARMv7/Modules/psv_cond.cpp new file mode 100644 index 0000000000..c89511b19d --- /dev/null +++ b/rpcs3/Emu/ARMv7/Modules/psv_cond.cpp @@ -0,0 +1,13 @@ +#include "stdafx.h" +#include "Emu/Memory/Memory.h" +#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/PSVObjectList.h" +#include "sceLibKernel.h" +#include "psv_cond.h" + +psv_cond_t::psv_cond_t(const char* name, u32 attr, s32 mutexId) + : attr(attr) + , mutexId(mutexId) +{ + strcpy_trunc(this->name, name); +} diff --git a/rpcs3/Emu/ARMv7/Modules/psv_cond.h b/rpcs3/Emu/ARMv7/Modules/psv_cond.h new file mode 100644 index 0000000000..cd8c518615 --- /dev/null +++ b/rpcs3/Emu/ARMv7/Modules/psv_cond.h @@ -0,0 +1,24 @@ +#pragma once + +struct psv_cond_t +{ + char name[32]; + u32 attr; + s32 mutexId; + +private: + psv_cond_t() = delete; + psv_cond_t(const psv_cond_t&) = delete; + psv_cond_t(psv_cond_t&&) = delete; + + psv_cond_t& operator =(const psv_cond_t&) = delete; + psv_cond_t& operator =(psv_cond_t&&) = delete; + +public: + psv_cond_t(const char* name, u32 attr, s32 mutexId); + void on_init(s32 id) {} + void on_stop() {} + +}; + +extern psv_object_list_t g_psv_cond_list; diff --git a/rpcs3/Emu/ARMv7/Modules/psv_event_flag.h b/rpcs3/Emu/ARMv7/Modules/psv_event_flag.h index bc1cb2d4e9..44f1c8214b 100644 --- a/rpcs3/Emu/ARMv7/Modules/psv_event_flag.h +++ b/rpcs3/Emu/ARMv7/Modules/psv_event_flag.h @@ -16,6 +16,9 @@ private: public: psv_event_flag_t(const char* name, u32 attr, u32 pattern); + void on_init(s32 id) {} + void on_stop() {} + }; extern psv_object_list_t g_psv_ef_list; diff --git a/rpcs3/Emu/ARMv7/Modules/psv_mutex.cpp b/rpcs3/Emu/ARMv7/Modules/psv_mutex.cpp new file mode 100644 index 0000000000..7733ad54ea --- /dev/null +++ b/rpcs3/Emu/ARMv7/Modules/psv_mutex.cpp @@ -0,0 +1,13 @@ +#include "stdafx.h" +#include "Emu/Memory/Memory.h" +#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/PSVObjectList.h" +#include "sceLibKernel.h" +#include "psv_mutex.h" + +psv_mutex_t::psv_mutex_t(const char* name, u32 attr, s32 count) + : attr(attr) + , count(count) +{ + strcpy_trunc(this->name, name); +} diff --git a/rpcs3/Emu/ARMv7/Modules/psv_mutex.h b/rpcs3/Emu/ARMv7/Modules/psv_mutex.h new file mode 100644 index 0000000000..5da6ad4590 --- /dev/null +++ b/rpcs3/Emu/ARMv7/Modules/psv_mutex.h @@ -0,0 +1,24 @@ +#pragma once + +struct psv_mutex_t +{ + char name[32]; + u32 attr; + s32 count; + +private: + psv_mutex_t() = delete; + psv_mutex_t(const psv_mutex_t&) = delete; + psv_mutex_t(psv_mutex_t&&) = delete; + + psv_mutex_t& operator =(const psv_mutex_t&) = delete; + psv_mutex_t& operator =(psv_mutex_t&&) = delete; + +public: + psv_mutex_t(const char* name, u32 attr, s32 count); + void on_init(s32 id) {} + void on_stop() {} + +}; + +extern psv_object_list_t g_psv_mutex_list; diff --git a/rpcs3/Emu/ARMv7/Modules/psv_sema.h b/rpcs3/Emu/ARMv7/Modules/psv_sema.h index 30b3fa6c4c..95608c3c04 100644 --- a/rpcs3/Emu/ARMv7/Modules/psv_sema.h +++ b/rpcs3/Emu/ARMv7/Modules/psv_sema.h @@ -17,6 +17,8 @@ private: public: psv_sema_t(const char* name, u32 attr, s32 init_value, s32 max_value); + void on_init(s32 id) {} + void on_stop() {} }; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index d7bd58c79a..016917d6de 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -10,6 +10,8 @@ #include "sceLibKernel.h" #include "psv_sema.h" #include "psv_event_flag.h" +#include "psv_mutex.h" +#include "psv_cond.h" #define RETURN_ERROR(code) { Emu.Pause(); sceLibKernel.Error("%s() failed: %s", __FUNCTION__, #code); return code; } @@ -522,7 +524,13 @@ s32 sceKernelGetSemaInfo(s32 semaId, vm::psv::ptr pInfo) s32 sceKernelCreateMutex(vm::psv::ptr pName, u32 attr, s32 initCount, vm::psv::ptr pOptParam) { - throw __FUNCTION__; + sceLibKernel.Error("sceKernelCreateMutex(pName=0x%x, attr=0x%x, initCount=%d, pOptParam=0x%x)", pName, attr, initCount, pOptParam); + + std::shared_ptr mutex(new psv_mutex_t(pName.get_ptr(), attr, initCount)); + + const s32 id = g_psv_mutex_list.add(mutex); + + return id; } s32 sceKernelDeleteMutex(s32 mutexId) @@ -616,7 +624,13 @@ s32 sceKernelGetLwMutexInfoById(s32 lwMutexId, vm::psv::ptr pName, u32 attr, s32 mutexId, vm::psv::ptr pOptParam) { - throw __FUNCTION__; + sceLibKernel.Error("sceKernelCreateCond(pName=0x%x, attr=0x%x, mutexId=0x%x, pOptParam=0x%x)", pName, attr, mutexId, pOptParam); + + std::shared_ptr cond(new psv_cond_t(pName.get_ptr(), attr, mutexId)); + + const s32 id = g_psv_cond_list.add(cond); + + return id; } s32 sceKernelDeleteCond(s32 condId) diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index d280e3dc24..3e5b21c44e 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -2,6 +2,7 @@ #include "Utilities/Log.h" #include "Emu/System.h" #include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Thread.h" #include "Emu/ARMv7/ARMv7Callback.h" extern psv_log_base sceLibc; @@ -12,6 +13,139 @@ typedef void(atexit_func_t)(vm::psv::ptr); std::vector> g_atexit; +std::string armv7_fmt(ARMv7Context& context, vm::psv::ptr fmt, u32 g_count, u32 f_count, u32 v_count) +{ + std::string result; + + for (char c = *fmt++; c; c = *fmt++) + { + switch (c) + { + case '%': + { + const auto start = fmt - 1; + + // read flags + const bool plus_sign = *fmt == '+' ? fmt++, true : false; + const bool minus_sign = *fmt == '-' ? fmt++, true : false; + const bool space_sign = *fmt == ' ' ? fmt++, true : false; + const bool number_sign = *fmt == '#' ? fmt++, true : false; + const bool zero_padding = *fmt == '0' ? fmt++, true : false; + + // read width + const u32 width = [&]() -> u32 + { + u32 width = 0; + + if (*fmt == '*') + { + fmt++; + return context.get_next_gpr_arg(g_count, f_count, v_count); + } + + while (*fmt - '0' < 10) + { + width = width * 10 + (*fmt++ - '0'); + } + + return width; + }(); + + // read precision + const u32 prec = [&]() -> u32 + { + u32 prec = 0; + + if (*fmt != '.') + { + return 0; + } + + if (*++fmt == '*') + { + fmt++; + return context.get_next_gpr_arg(g_count, f_count, v_count); + } + + while (*fmt - '0' < 10) + { + prec = prec * 10 + (*fmt++ - '0'); + } + + return prec; + }(); + + switch (char cf = *fmt++) + { + case '%': + { + if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; + + result += '%'; + continue; + } + case 'd': + case 'i': + { + // signed decimal + const s64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + + if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; + + result += fmt::to_sdec(value); + continue; + } + case 'x': + case 'X': + { + // hexadecimal + const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + + if (plus_sign || minus_sign || space_sign || prec) break; + + if (number_sign && value) + { + result += cf == 'x' ? "0x" : "0X"; + } + + const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::toupper(fmt::to_hex(value)); + + if (hex.length() >= width) + { + result += hex; + } + else if (zero_padding) + { + result += std::string(width - hex.length(), '0') + hex; + } + else + { + result += hex + std::string(width - hex.length(), ' '); + } + continue; + } + case 's': + { + // string + auto string = vm::psv::ptr::make(context.get_next_gpr_arg(g_count, f_count, v_count)); + + if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; + + result += string.get_ptr(); + continue; + } + } + + throw fmt::format("armv7_fmt(): unknown formatting: '%s'", start.get_ptr()); + } + } + + result += c; + } + + return result; +} + namespace sce_libc_func { void __cxa_atexit(vm::psv::ptr func, vm::psv::ptr arg, vm::psv::ptr dso) @@ -59,80 +193,24 @@ namespace sce_libc_func }); } - std::string armv7_fmt(ARMv7Context& context, vm::psv::ptr fmt, u32 g_count, u32 f_count, u32 v_count) - { - std::string result; - - for (char c = *fmt++; c; c = *fmt++) - { - switch (c) - { - case '%': - { - const auto start = fmt - 1; - const bool number_sign = *fmt == '#' ? fmt++, true : false; - - switch (*fmt++) - { - case '%': - { - result += '%'; - continue; - } - case 'd': - case 'i': - { - // signed decimal - const s64 value = context.get_next_gpr_arg(g_count, f_count, v_count); - - result += fmt::to_sdec(value); - continue; - } - case 'x': - { - // hexadecimal - const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count); - - if (number_sign && value) - { - result += "0x"; - } - - result += fmt::to_hex(value); - continue; - } - default: - { - throw fmt::Format("armv7_fmt(): unknown formatting: '%s'", start.get_ptr()); - } - } - } - } - - result += c; - } - - return result; - } - void printf(ARMv7Context& context, vm::psv::ptr fmt) // va_args... { sceLibc.Warning("printf(fmt=0x%x)", fmt); + sceLibc.Log("*** *fmt = '%s'", fmt.get_ptr()); - sceLibc.Notice("*** *fmt = '%s'", fmt.get_ptr()); + const std::string& result = armv7_fmt(context, fmt, 1, 0, 0); + sceLibc.Log("*** -> '%s'", result); - LOG_NOTICE(TTY, armv7_fmt(context, fmt, 1, 0, 0)); + LOG_NOTICE(TTY, result); } void sprintf(ARMv7Context& context, vm::psv::ptr str, vm::psv::ptr fmt) // va_args... { sceLibc.Warning("sprintf(str=0x%x, fmt=0x%x)", str, fmt); - - sceLibc.Notice("*** *fmt = '%s'", fmt.get_ptr()); + sceLibc.Log("*** *fmt = '%s'", fmt.get_ptr()); const std::string& result = armv7_fmt(context, fmt, 2, 0, 0); - - sceLibc.Notice("*** res -> '%s'", result); + sceLibc.Log("*** -> '%s'", result); ::memcpy(str.get_ptr(), result.c_str(), result.size() + 1); } @@ -158,11 +236,12 @@ namespace sce_libc_func ::memset(dst.get_ptr(), value, size); } - void _Assert(vm::psv::ptr text, vm::psv::ptr func) + void _Assert(ARMv7Context& context, vm::psv::ptr text, vm::psv::ptr func) { - sceLibc.Warning("_Assert(text=0x%x, func=0x%x)", text, func); + sceLibc.Error("_Assert(text=0x%x, func=0x%x)", text, func); LOG_ERROR(TTY, "%s : %s\n", func.get_ptr(), text.get_ptr()); + LOG_NOTICE(ARMv7, context.thread.RegsToString()); Emu.Pause(); } } diff --git a/rpcs3/Emu/ARMv7/Modules/scePerf.cpp b/rpcs3/Emu/ARMv7/Modules/scePerf.cpp index e7939506bc..fabf63691a 100644 --- a/rpcs3/Emu/ARMv7/Modules/scePerf.cpp +++ b/rpcs3/Emu/ARMv7/Modules/scePerf.cpp @@ -134,6 +134,11 @@ s32 scePerfArmPmonSelectEvent(ARMv7Context& context, s32 threadId, u32 counter, case SCE_PERF_ARM_PMON_BRANCH_MISPREDICT: case SCE_PERF_ARM_PMON_DCACHE_MISS: + case SCE_PERF_ARM_PMON_DCACHE_STALL: + case SCE_PERF_ARM_PMON_ICACHE_STALL: + case SCE_PERF_ARM_PMON_DATA_EVICTION: + case SCE_PERF_ARM_PMON_WRITE_STALL: + case SCE_PERF_ARM_PMON_MAINTLB_STALL: case SCE_PERF_ARM_PMON_UNALIGNED: { value = 1; // these events will probably never be implemented diff --git a/rpcs3/Emu/ARMv7/Modules/sceSysmodule.cpp b/rpcs3/Emu/ARMv7/Modules/sceSysmodule.cpp index a845595c87..51158c0226 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSysmodule.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceSysmodule.cpp @@ -6,21 +6,21 @@ extern psv_log_base sceSysmodule; s32 sceSysmoduleLoadModule(u16 id) { - sceSysmodule.Error("sceSysmoduleLoadModule(id=0x%04x) -> SCE_OK", id); + sceSysmodule.Warning("sceSysmoduleLoadModule(id=0x%04x) -> SCE_OK", id); return SCE_OK; // loading succeeded } s32 sceSysmoduleUnloadModule(u16 id) { - sceSysmodule.Error("sceSysmoduleUnloadModule(id=0x%04x) -> SCE_OK", id); + sceSysmodule.Warning("sceSysmoduleUnloadModule(id=0x%04x) -> SCE_OK", id); return SCE_OK; // unloading succeeded } s32 sceSysmoduleIsLoaded(u16 id) { - sceSysmodule.Error("sceSysmoduleIsLoaded(id=0x%04x) -> SCE_OK", id); + sceSysmodule.Warning("sceSysmoduleIsLoaded(id=0x%04x) -> SCE_OK", id); return SCE_OK; // module is loaded } diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.cpp b/rpcs3/Emu/ARMv7/PSVFuncList.cpp index 29990a3208..21d9c6488e 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.cpp +++ b/rpcs3/Emu/ARMv7/PSVFuncList.cpp @@ -10,7 +10,7 @@ void add_psv_func(psv_func& data) g_psv_func_list.push_back(data); } -psv_func* get_psv_func_by_nid(u32 nid) +const psv_func* get_psv_func_by_nid(u32 nid) { for (auto& f : g_psv_func_list) { @@ -23,7 +23,7 @@ psv_func* get_psv_func_by_nid(u32 nid) return nullptr; } -u32 get_psv_func_index(psv_func* func) +u32 get_psv_func_index(const psv_func* func) { auto res = func - g_psv_func_list.data(); @@ -32,14 +32,21 @@ u32 get_psv_func_index(psv_func* func) return (u32)res; } -void execute_psv_func_by_index(ARMv7Context& context, u32 index) +const psv_func* get_psv_func_by_index(u32 index) { assert(index < g_psv_func_list.size()); + + return &g_psv_func_list[index]; +} + +void execute_psv_func_by_index(ARMv7Context& context, u32 index) +{ + auto func = get_psv_func_by_index(index); auto old_last_syscall = context.thread.m_last_syscall; - context.thread.m_last_syscall = g_psv_func_list[index].nid; + context.thread.m_last_syscall = func->nid; - (*g_psv_func_list[index].func)(context); + (*func->func)(context); context.thread.m_last_syscall = old_last_syscall; } @@ -174,7 +181,7 @@ void initialize_psv_modules() // setup special functions (without NIDs) psv_func unimplemented; unimplemented.nid = 0; - unimplemented.name = "Special function (unimplemented stub)"; + unimplemented.name = "UNIMPLEMENTED"; unimplemented.func.reset(new psv_func_detail::func_binder([](ARMv7Context& context) { context.thread.m_last_syscall = vm::psv::read32(context.thread.PC + 4); @@ -184,7 +191,7 @@ void initialize_psv_modules() psv_func hle_return; hle_return.nid = 1; - hle_return.name = "Special function (return from HLE)"; + hle_return.name = "HLE_RETURN"; hle_return.func.reset(new psv_func_detail::func_binder([](ARMv7Context& context) { context.thread.FastStop(); diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.h b/rpcs3/Emu/ARMv7/PSVFuncList.h index a1948dcbec..8ddb45ab75 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.h +++ b/rpcs3/Emu/ARMv7/PSVFuncList.h @@ -492,9 +492,11 @@ template void reg_psv_func(u32 nid, psv_log_base* mo add_psv_func(f); } // Find registered HLE function by its ID -psv_func* get_psv_func_by_nid(u32 nid); +const psv_func* get_psv_func_by_nid(u32 nid); // Get index of registered HLE function -u32 get_psv_func_index(psv_func* func); +u32 get_psv_func_index(const psv_func* func); +// Find registered HLE function by its index +const psv_func* get_psv_func_by_index(u32 index); // Execute registered HLE function by its index void execute_psv_func_by_index(ARMv7Context& context, u32 index); // Register all HLE functions diff --git a/rpcs3/Emu/ARMv7/PSVObjectList.cpp b/rpcs3/Emu/ARMv7/PSVObjectList.cpp index cc8e97a1c0..5e89e15c73 100644 --- a/rpcs3/Emu/ARMv7/PSVObjectList.cpp +++ b/rpcs3/Emu/ARMv7/PSVObjectList.cpp @@ -5,12 +5,18 @@ #include "Modules/sceLibKernel.h" #include "Modules/psv_sema.h" #include "Modules/psv_event_flag.h" +#include "Modules/psv_mutex.h" +#include "Modules/psv_cond.h" psv_object_list_t g_psv_sema_list; psv_object_list_t g_psv_ef_list; +psv_object_list_t g_psv_mutex_list; +psv_object_list_t g_psv_cond_list; void clear_all_psv_objects() { g_psv_sema_list.clear(); g_psv_ef_list.clear(); + g_psv_mutex_list.clear(); + g_psv_cond_list.clear(); } diff --git a/rpcs3/Emu/ARMv7/PSVObjectList.h b/rpcs3/Emu/ARMv7/PSVObjectList.h index d25c6e39ce..5be66688e0 100644 --- a/rpcs3/Emu/ARMv7/PSVObjectList.h +++ b/rpcs3/Emu/ARMv7/PSVObjectList.h @@ -25,8 +25,18 @@ template class psv_object_list_t // Class for managing object data { std::array, 0x8000> m_data; + std::atomic m_hint; // guessing next free position std::mutex m_mutex; // TODO: remove it when shared_ptr atomic ops are fully available +public: + psv_object_list_t() : m_hint(0) {} + + psv_object_list_t(const psv_object_list_t&) = delete; + psv_object_list_t(psv_object_list_t&&) = delete; + + psv_object_list_t& operator =(const psv_object_list_t&) = delete; + psv_object_list_t& operator =(psv_object_list_t&&) = delete; + public: static const u32 uid_class = type; @@ -60,18 +70,18 @@ public: { std::lock_guard lock(m_mutex); - for (auto& value : m_data) + for (u32 i = 0, j = m_hint % m_data.size(); i < m_data.size(); i++, j = (j + 1) % m_data.size()) { - // find an empty position and move the pointer - //std::shared_ptr old_ptr = nullptr; - //if (std::atomic_compare_exchange_strong(&value, &old_ptr, data)) - if (!value) + // find an empty position and copy the pointer + if (!m_data[j]) { - value = data; + m_data[j] = data; + m_hint = j + 1; // guess next position psv_uid_t id = psv_uid_t::make(1); // odd number id.type = uid_class; // set type - id.number = &value - m_data.data(); // set position - return id.uid; + id.number = j; // set position + data->on_init(id.uid); // save UID + return id.uid; // return UID } } @@ -86,12 +96,14 @@ public: return nullptr; } + const u32 pos = psv_uid_t::make(uid).number; + std::lock_guard lock(m_mutex); std::shared_ptr old_ptr = nullptr; - m_data[psv_uid_t::make(uid).number].swap(old_ptr); + m_data[pos].swap(old_ptr); + m_hint = pos; return old_ptr; - //return std::atomic_exchange>(&m_data[psv_uid_t::make(uid).number], nullptr); } // remove all objects @@ -99,10 +111,17 @@ public: { std::lock_guard lock(m_mutex); - for (auto& value : m_data) + for (auto& object : m_data) { - value = nullptr; + if (object) + { + object->on_stop(); + } + + object = nullptr; } + + m_hint = 0; } }; diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 201385e827..83a0101e6d 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -2500,39 +2500,16 @@ private: } void MFOCRF(u32 a, u32 rd, u32 crm) { - /* - if(a) - { - u32 n = 0, count = 0; - for(u32 i = 0; i < 8; ++i) - { - if(crm & (1 << i)) - { - n = i; - count++; - } - } - - if(count == 1) - { - //RD[32+4*n : 32+4*n+3] = CR[4*n : 4*n+3]; - u8 offset = n * 4; - CPU.GPR[rd] = (CPU.GPR[rd] & ~(0xf << offset)) | ((u32)CPU.GetCR(7 - n) << offset); - } - else - CPU.GPR[rd] = 0; - } - else - { - */ CPU.GPR[rd] = CPU.CR.CR; - //} } void LWARX(u32 rd, u32 ra, u32 rb) { - CPU.R_ADDR = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.R_VALUE = vm::get_ref(vm::cast(CPU.R_ADDR)); - CPU.GPR[rd] = re32((u32)CPU.R_VALUE); + const u32 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + + be_t value; + vm::reservation_acquire(&value, vm::cast(addr), sizeof(value)); + + CPU.GPR[rd] = value; } void LDX(u32 rd, u32 ra, u32 rb) { @@ -2682,9 +2659,12 @@ private: } void LDARX(u32 rd, u32 ra, u32 rb) { - CPU.R_ADDR = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.R_VALUE = vm::get_ref(vm::cast(CPU.R_ADDR)); - CPU.GPR[rd] = re64(CPU.R_VALUE); + const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + + be_t value; + vm::reservation_acquire(&value, vm::cast(addr), sizeof(value)); + + CPU.GPR[rd] = value; } void DCBF(u32 ra, u32 rb) { @@ -2800,15 +2780,8 @@ private: { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if (CPU.R_ADDR == addr) - { - CPU.SetCR_EQ(0, InterlockedCompareExchange(vm::get_ptr(vm::cast(CPU.R_ADDR)), re32((u32)CPU.GPR[rs]), (u32)CPU.R_VALUE) == (u32)CPU.R_VALUE); - } - else - { - CPU.SetCR_EQ(0, false); - } - CPU.R_ADDR = 0; + const be_t value = be_t::make((u32)CPU.GPR[rs]); + CPU.SetCR_EQ(0, vm::reservation_update(vm::cast(addr), &value, sizeof(value))); } void STWX(u32 rs, u32 ra, u32 rb) { @@ -2859,15 +2832,8 @@ private: { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if (CPU.R_ADDR == addr) - { - CPU.SetCR_EQ(0, InterlockedCompareExchange(vm::get_ptr(vm::cast(CPU.R_ADDR)), re64(CPU.GPR[rs]), CPU.R_VALUE) == CPU.R_VALUE); - } - else - { - CPU.SetCR_EQ(0, false); - } - CPU.R_ADDR = 0; + const be_t value = be_t::make(CPU.GPR[rs]); + CPU.SetCR_EQ(0, vm::reservation_update(vm::cast(addr), &value, sizeof(value))); } void STBX(u32 rs, u32 ra, u32 rb) { @@ -2945,9 +2911,7 @@ private: } void ECIWX(u32 rd, u32 ra, u32 rb) { - //HACK! - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::read32(vm::cast(addr)); + throw __FUNCTION__; } void LHZUX(u32 rd, u32 ra, u32 rb) { @@ -3020,9 +2984,7 @@ private: } void ECOWX(u32 rs, u32 ra, u32 rb) { - //HACK! - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::write32(vm::cast(addr), (u32)CPU.GPR[rs]); + throw __FUNCTION__; } void STHUX(u32 rs, u32 ra, u32 rb) { diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index 5678d5f9d9..dedaf358bf 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -2463,25 +2463,27 @@ void Compiler::MFOCRF(u32 a, u32 rd, u32 crm) { } void Compiler::LWARX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } + throw __FUNCTION__; + + //auto addr_i64 = GetGpr(rb); + //if (ra) { + // auto ra_i64 = GetGpr(ra); + // addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); + //} - auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR)); - auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(addr_i64, resv_addr_i64_ptr, 8); + //auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR)); + //auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); + //m_ir_builder->CreateAlignedStore(addr_i64, resv_addr_i64_ptr, 8); - auto resv_val_i32 = ReadMemory(addr_i64, 32, 4, false, false); - auto resv_val_i64 = m_ir_builder->CreateZExt(resv_val_i32, m_ir_builder->getInt64Ty()); - auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE)); - auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(resv_val_i64, resv_val_i64_ptr, 8); + //auto resv_val_i32 = ReadMemory(addr_i64, 32, 4, false, false); + //auto resv_val_i64 = m_ir_builder->CreateZExt(resv_val_i32, m_ir_builder->getInt64Ty()); + //auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE)); + //auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); + //m_ir_builder->CreateAlignedStore(resv_val_i64, resv_val_i64_ptr, 8); - resv_val_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt32Ty()), resv_val_i32); - resv_val_i64 = m_ir_builder->CreateZExt(resv_val_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, resv_val_i64); + //resv_val_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt32Ty()), resv_val_i32); + //resv_val_i64 = m_ir_builder->CreateZExt(resv_val_i32, m_ir_builder->getInt64Ty()); + //SetGpr(rd, resv_val_i64); } void Compiler::LDX(u32 rd, u32 ra, u32 rb) { @@ -2739,23 +2741,25 @@ void Compiler::MULHW(u32 rd, u32 ra, u32 rb, bool rc) { } void Compiler::LDARX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } + throw __FUNCTION__; - auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR)); - auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(addr_i64, resv_addr_i64_ptr, 8); + //auto addr_i64 = GetGpr(rb); + //if (ra) { + // auto ra_i64 = GetGpr(ra); + // addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); + //} - auto resv_val_i64 = ReadMemory(addr_i64, 64, 8, false); - auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE)); - auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(resv_val_i64, resv_val_i64_ptr, 8); + //auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR)); + //auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); + //m_ir_builder->CreateAlignedStore(addr_i64, resv_addr_i64_ptr, 8); - resv_val_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt64Ty()), resv_val_i64); - SetGpr(rd, resv_val_i64); + //auto resv_val_i64 = ReadMemory(addr_i64, 64, 8, false); + //auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE)); + //auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); + //m_ir_builder->CreateAlignedStore(resv_val_i64, resv_val_i64_ptr, 8); + + //resv_val_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt64Ty()), resv_val_i64); + //SetGpr(rd, resv_val_i64); } void Compiler::DCBF(u32 ra, u32 rb) { @@ -2919,45 +2923,47 @@ void Compiler::STDX(u32 rs, u32 ra, u32 rb) { } void Compiler::STWCX_(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } + throw __FUNCTION__; - auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR)); - auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8); - auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64); + //auto addr_i64 = GetGpr(rb); + //if (ra) { + // auto ra_i64 = GetGpr(ra); + // addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); + //} - auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then"); - auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else"); - auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge"); - m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb); + //auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR)); + //auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); + //auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8); + //auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64); - m_ir_builder->SetInsertPoint(then_bb); - auto rs_i32 = GetGpr(rs, 32); - rs_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i32->getType()), rs_i32); - resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr(0))); - auto resv_addr_val_i32_ptr = m_ir_builder->CreateIntToPtr(resv_addr_i64, m_ir_builder->getInt32Ty()->getPointerTo()); - auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE)); - auto resv_val_i32_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - auto resv_val_i32 = m_ir_builder->CreateAlignedLoad(resv_val_i32_ptr, 8); + //auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then"); + //auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else"); + //auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge"); + //m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb); - auto res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i32_ptr, resv_val_i32, rs_i32, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic); - auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1}); - auto cr_i32 = GetCr(); - cr_i32 = SetBit(cr_i32, 2, success_i1); - SetCr(cr_i32); - m_ir_builder->CreateAlignedStore(m_ir_builder->getInt64(0), resv_addr_i64_ptr, 8); - m_ir_builder->CreateBr(merge_bb); + //m_ir_builder->SetInsertPoint(then_bb); + //auto rs_i32 = GetGpr(rs, 32); + //rs_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i32->getType()), rs_i32); + //resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr(0))); + //auto resv_addr_val_i32_ptr = m_ir_builder->CreateIntToPtr(resv_addr_i64, m_ir_builder->getInt32Ty()->getPointerTo()); + //auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE)); + //auto resv_val_i32_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); + //auto resv_val_i32 = m_ir_builder->CreateAlignedLoad(resv_val_i32_ptr, 8); - m_ir_builder->SetInsertPoint(else_bb); - cr_i32 = GetCr(); - cr_i32 = ClrBit(cr_i32, 2); - SetCr(cr_i32); - m_ir_builder->CreateBr(merge_bb); - m_ir_builder->SetInsertPoint(merge_bb); + //auto res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i32_ptr, resv_val_i32, rs_i32, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic); + //auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1}); + //auto cr_i32 = GetCr(); + //cr_i32 = SetBit(cr_i32, 2, success_i1); + //SetCr(cr_i32); + //m_ir_builder->CreateAlignedStore(m_ir_builder->getInt64(0), resv_addr_i64_ptr, 8); + //m_ir_builder->CreateBr(merge_bb); + + //m_ir_builder->SetInsertPoint(else_bb); + //cr_i32 = GetCr(); + //cr_i32 = ClrBit(cr_i32, 2); + //SetCr(cr_i32); + //m_ir_builder->CreateBr(merge_bb); + //m_ir_builder->SetInsertPoint(merge_bb); } void Compiler::STWX(u32 rs, u32 ra, u32 rb) { @@ -3060,45 +3066,47 @@ void Compiler::SUBFZE(u32 rd, u32 ra, u32 oe, bool rc) { } void Compiler::STDCX_(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } + throw __FUNCTION__; - auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR)); - auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8); - auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64); + //auto addr_i64 = GetGpr(rb); + //if (ra) { + // auto ra_i64 = GetGpr(ra); + // addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); + //} - auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then"); - auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else"); - auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge"); - m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb); + //auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR)); + //auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); + //auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8); + //auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64); - m_ir_builder->SetInsertPoint(then_bb); - auto rs_i64 = GetGpr(rs, 64); - rs_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i64->getType()), rs_i64); - resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr(0))); - auto resv_addr_val_i64_ptr = m_ir_builder->CreateIntToPtr(resv_addr_i64, m_ir_builder->getInt64Ty()->getPointerTo()); - auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE)); - auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - auto resv_val_i64 = m_ir_builder->CreateAlignedLoad(resv_val_i64_ptr, 8); + //auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then"); + //auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else"); + //auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge"); + //m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb); - auto res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i64_ptr, resv_val_i64, rs_i64, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic); - auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1}); - auto cr_i32 = GetCr(); - cr_i32 = SetBit(cr_i32, 2, success_i1); - SetCr(cr_i32); - m_ir_builder->CreateAlignedStore(m_ir_builder->getInt64(0), resv_addr_i64_ptr, 8); - m_ir_builder->CreateBr(merge_bb); + //m_ir_builder->SetInsertPoint(then_bb); + //auto rs_i64 = GetGpr(rs, 64); + //rs_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i64->getType()), rs_i64); + //resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr(0))); + //auto resv_addr_val_i64_ptr = m_ir_builder->CreateIntToPtr(resv_addr_i64, m_ir_builder->getInt64Ty()->getPointerTo()); + //auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE)); + //auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); + //auto resv_val_i64 = m_ir_builder->CreateAlignedLoad(resv_val_i64_ptr, 8); - m_ir_builder->SetInsertPoint(else_bb); - cr_i32 = GetCr(); - cr_i32 = ClrBit(cr_i32, 2); - SetCr(cr_i32); - m_ir_builder->CreateBr(merge_bb); - m_ir_builder->SetInsertPoint(merge_bb); + //auto res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i64_ptr, resv_val_i64, rs_i64, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic); + //auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1}); + //auto cr_i32 = GetCr(); + //cr_i32 = SetBit(cr_i32, 2, success_i1); + //SetCr(cr_i32); + //m_ir_builder->CreateAlignedStore(m_ir_builder->getInt64(0), resv_addr_i64_ptr, 8); + //m_ir_builder->CreateBr(merge_bb); + + //m_ir_builder->SetInsertPoint(else_bb); + //cr_i32 = GetCr(); + //cr_i32 = ClrBit(cr_i32, 2); + //SetCr(cr_i32); + //m_ir_builder->CreateBr(merge_bb); + //m_ir_builder->SetInsertPoint(merge_bb); } void Compiler::STBX(u32 rs, u32 ra, u32 rb) { @@ -3263,15 +3271,16 @@ void Compiler::EQV(u32 ra, u32 rs, u32 rb, bool rc) { } void Compiler::ECIWX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } + throw __FUNCTION__; + //auto addr_i64 = GetGpr(rb); + //if (ra) { + // auto ra_i64 = GetGpr(ra); + // addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); + //} - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); + //auto mem_i32 = ReadMemory(addr_i64, 32); + //auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); + //SetGpr(rd, mem_i64); } void Compiler::LHZUX(u32 rd, u32 ra, u32 rb) { @@ -3422,13 +3431,14 @@ void Compiler::ORC(u32 ra, u32 rs, u32 rb, bool rc) { } void Compiler::ECOWX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } + throw __FUNCTION__; + //auto addr_i64 = GetGpr(rb); + //if (ra) { + // auto ra_i64 = GetGpr(ra); + // addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); + //} - WriteMemory(addr_i64, GetGpr(rs, 32)); + //WriteMemory(addr_i64, GetGpr(rs, 32)); } void Compiler::STHUX(u32 rs, u32 ra, u32 rb) { diff --git a/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp b/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp index f30a713c09..511125e233 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp @@ -59,10 +59,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp /// Time base register u64 TB; - /// Reservations - u64 R_ADDR; - u64 R_VALUE; - /// Memory block u32 address; u64 mem_block[64]; @@ -86,9 +82,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp CTR = ppu.CTR; TB = ppu.TB; - R_ADDR = ppu.R_ADDR; - R_VALUE = ppu.R_VALUE; - address = addr; for (int i = 0; i < (sizeof(mem_block) / 8); i++) { mem_block[i] = vm::read64(address + (i * 8)); @@ -114,9 +107,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp ppu.CTR = CTR; ppu.TB = TB; - ppu.R_ADDR = R_ADDR; - ppu.R_VALUE = R_VALUE; - for (int i = 0; i < (sizeof(mem_block) / 8); i++) { vm::write64(address + (i * 8), mem_block[i]); } @@ -151,8 +141,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp LR = rng(); CTR = rng(); TB = rng(); - R_ADDR = rng(); - R_VALUE = rng(); address = addr; for (int i = 0; i < (sizeof(mem_block) / 8); i++) { @@ -187,7 +175,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp // fmt::by_value(FPSCR.VXZDZ), fmt::by_value(FPSCR.VXIDI), fmt::by_value(FPSCR.VXISI), fmt::by_value(FPSCR.VXSNAN), // fmt::by_value(FPSCR.XX), fmt::by_value(FPSCR.ZX), fmt::by_value(FPSCR.UX), fmt::by_value(FPSCR.OX), fmt::by_value(FPSCR.VX), fmt::by_value(FPSCR.FEX), fmt::by_value(FPSCR.FX)); //ret += fmt::Format("VSCR = 0x%08x [NJ=%d | SAT=%d]\n", VSCR.VSCR, fmt::by_value(VSCR.NJ), fmt::by_value(VSCR.SAT)); // TODO: Uncomment after implementing VSCR.SAT - ret += fmt::Format("R_ADDR = 0x%016llx R_VALUE = 0x%016llx\n", R_ADDR, R_VALUE); for (int i = 0; i < (sizeof(mem_block) / 8); i += 2) { ret += fmt::Format("mem_block[%d] = 0x%016llx mem_block[%d] = 0x%016llx\n", i, mem_block[i], i + 1, mem_block[i + 1]); @@ -724,8 +711,6 @@ void Compiler::RunAllTests() { input.GPR[14] = 10; input.GPR[21] = 15; input.GPR[23] = 0x10000; - input.R_ADDR = 0x10000; - input.R_VALUE = 0x1122334455667788; input.mem_block[0] = 0x8877665544332211; VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LBZ, 0, input, 5, 0, 0x10000); @@ -739,8 +724,8 @@ void Compiler::RunAllTests() { VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZU, 0, input, 5, 14, 0x10000); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZX, 0, input, 5, 0, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZX, 1, input, 5, 14, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECIWX, 0, input, 5, 0, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECIWX, 1, input, 5, 14, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECIWX, 0, input, 5, 0, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECIWX, 1, input, 5, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZUX, 0, input, 5, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHA, 0, input, 5, 0, 0x100F0); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHA, 1, input, 5, 14, 0x100F0); @@ -780,10 +765,10 @@ void Compiler::RunAllTests() { VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LFDX, 0, input, 5, 0, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LFDX, 1, input, 5, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LFDUX, 0, input, 5, 14, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWARX, 0, input, 5, 0, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWARX, 1, input, 5, 14, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDARX, 0, input, 5, 0, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDARX, 1, input, 5, 14, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWARX, 0, input, 5, 0, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWARX, 1, input, 5, 14, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDARX, 0, input, 5, 0, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDARX, 1, input, 5, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LSWI, 0, input, 5, 23, 0); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LSWI, 1, input, 5, 23, 2); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LSWI, 2, input, 5, 23, 7); @@ -819,8 +804,8 @@ void Compiler::RunAllTests() { VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STB, 0, input, 3, 0, 0x10000); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STB, 1, input, 3, 14, 0x10000); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBU, 0, input, 3, 14, 0x10000); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDCX_, 0, input, 3, 0, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDCX_, 1, input, 3, 14, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDCX_, 0, input, 3, 0, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDCX_, 1, input, 3, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBX, 0, input, 3, 0, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBX, 1, input, 3, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBUX, 0, input, 3, 14, 23); @@ -829,8 +814,8 @@ void Compiler::RunAllTests() { VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHU, 0, input, 3, 14, 0x10000); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHX, 0, input, 3, 0, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHX, 1, input, 3, 14, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECOWX, 0, input, 3, 0, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECOWX, 1, input, 3, 14, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECOWX, 0, input, 3, 0, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECOWX, 1, input, 3, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHUX, 0, input, 3, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHBRX, 0, input, 3, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STW, 0, input, 3, 0, 0x10000); @@ -848,8 +833,8 @@ void Compiler::RunAllTests() { VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDU, 0, input, 3, 14, 0x10000); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDX, 0, input, 3, 0, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDX, 1, input, 3, 14, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWCX_, 0, input, 3, 0, 23); - VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWCX_, 1, input, 3, 14, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWCX_, 0, input, 3, 0, 23); + //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWCX_, 1, input, 3, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDUX, 0, input, 3, 14, 23); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFS, 0, input, 3, 0, 0x10000); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFS, 1, input, 3, 14, 0x10000); diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 820b244c2b..834200b1ae 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -536,11 +536,6 @@ public: //TBR : Time-Base Registers u64 TB; //TBR 0x10C - 0x10D - u64 cycle; - - u64 R_ADDR; // reservation address - u64 R_VALUE; // reservation value (BE) - u32 owned_mutexes; std::function custom_task; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index f5faf9fff1..e944fcd60d 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -99,8 +99,6 @@ void SPUThread::InitRegs() m_event_mask = 0; m_events = 0; - - R_ADDR = 0; } void SPUThread::InitStack() @@ -437,103 +435,48 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs) if (op == MFC_GETLLAR_CMD) // get reservation { - if (R_ADDR) - { - m_events |= SPU_EVENT_LR; - } + //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - R_ADDR = ea; - for (u32 i = 0; i < 16; i++) + vm::reservation_acquire(vm::get_ptr(ls_offset + lsa), ea, 128, [this]() { - R_DATA[i] = vm::get_ptr((u32)R_ADDR)[i]; - vm::get_ptr(ls_offset + lsa)[i] = R_DATA[i]; - } + //std::shared_ptr t = Emu.GetCPU().GetThread(tid); + + //if (t && (t->GetType() == CPU_THREAD_SPU || t->GetType() == CPU_THREAD_RAW_SPU)) + //{ + // SPUThread& spu = static_cast(*t); + + // spu.m_events |= SPU_EVENT_LR; // TODO: atomic op + // spu.Notify(); + //} + + m_events |= SPU_EVENT_LR; // TODO: atomic op + Notify(); + }); + MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS); } else if (op == MFC_PUTLLC_CMD) // store conditional { - MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); - - if (R_ADDR == ea) + if (vm::reservation_update(ea, vm::get_ptr(ls_offset + lsa), 128)) { - u32 changed = 0, mask = 0; - u64 buf[16]; - for (u32 i = 0; i < 16; i++) - { - buf[i] = vm::get_ptr(ls_offset + lsa)[i]; - if (buf[i] != R_DATA[i]) - { - changed++; - mask |= (0x3 << (i * 2)); - if (vm::get_ptr((u32)R_ADDR)[i] != R_DATA[i]) - { - m_events |= SPU_EVENT_LR; - MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); - R_ADDR = 0; - return; - } - } - } - - for (u32 i = 0; i < 16; i++) - { - if (buf[i] != R_DATA[i]) - { - if (InterlockedCompareExchange(&vm::get_ptr((u32)R_ADDR)[i], buf[i], R_DATA[i]) != R_DATA[i]) - { - m_events |= SPU_EVENT_LR; - MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); - - if (changed > 1) - { - LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: Memory corrupted (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)", - changed, mask, op, cmd, lsa, ea, tag, size); - Emu.Pause(); - } - - break; - } - } - } - - if (changed > 1) - { - LOG_WARNING(Log::SPU, "MFC_PUTLLC_CMD: Reservation impossibru (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)", - changed, mask, op, cmd, lsa, ea, tag, size); - - SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode); - for (s32 i = (s32)PC; i < (s32)PC + 4 * 7; i += 4) - { - dis_asm.dump_pc = i; - dis_asm.offset = vm::get_ptr(ls_offset); - const u32 opcode = vm::read32(i + ls_offset); - (*SPU_instr::rrr_list)(&dis_asm, opcode); - if (i >= 0 && i < 0x40000) - { - LOG_NOTICE(Log::SPU, "*** %s", dis_asm.last_opcode.c_str()); - } - } - } + MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); } else { MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); } - R_ADDR = 0; } - else // store unconditional + else // store unconditional (may be wrong) { - if (R_ADDR) // may be wrong + vm::reservation_op(ea, 128, [this, tag, lsa, ea]() { - m_events |= SPU_EVENT_LR; - } + ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); + }); - ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); if (op == MFC_PUTLLUC_CMD) { MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS); } - R_ADDR = 0; } break; } @@ -548,19 +491,6 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs) bool SPUThread::CheckEvents() { // checks events: - // SPU_EVENT_LR: - if (R_ADDR) - { - for (u32 i = 0; i < 16; i++) - { - if (vm::get_ptr((u32)R_ADDR)[i] != R_DATA[i]) - { - m_events |= SPU_EVENT_LR; - R_ADDR = 0; - break; - } - } - } return (m_events & m_event_mask) != 0; } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index c2e2cc2f03..bab5f1aa2d 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -277,9 +277,6 @@ public: u32 SRR0; SPU_SNRConfig_hdr cfg; // Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2) - u64 R_ADDR; // reservation address - u64 R_DATA[16]; // lock line data (BE) - std::shared_ptr SPUPs[64]; // SPU Thread Event Ports EventManager SPUQs; // SPU Queue Mapping std::shared_ptr group; // associated SPU Thread Group (null for raw spu) diff --git a/rpcs3/Emu/Memory/Memory.cpp b/rpcs3/Emu/Memory/Memory.cpp index 502694ff93..7f87615796 100644 --- a/rpcs3/Emu/Memory/Memory.cpp +++ b/rpcs3/Emu/Memory/Memory.cpp @@ -102,20 +102,17 @@ void MemoryBase::Init(MemoryType type) memset(m_pages, 0, sizeof(m_pages)); memset(RawSPUMem, 0, sizeof(RawSPUMem)); + LOG_NOTICE(MEMORY, "Initializing memory: base_addr = 0x%llx, priv_addr = 0x%llx", (u64)vm::g_base_addr, (u64)vm::g_priv_addr); + #ifdef _WIN32 - if (!vm::g_base_addr) + if (!vm::g_base_addr || !vm::g_priv_addr) #else - if ((s64)vm::g_base_addr == (s64)-1) + if ((s64)vm::g_base_addr == (s64)-1 || (s64)vm::g_priv_addr == (s64)-1) #endif { LOG_ERROR(MEMORY, "Initializing memory failed"); - assert(0); return; } - else - { - LOG_NOTICE(MEMORY, "Initializing memory: base_addr = 0x%llx", (u64)vm::g_base_addr); - } switch (type) { @@ -207,7 +204,7 @@ bool MemoryBase::Map(const u64 addr, const u32 size) } MemoryBlocks.push_back((new MemoryBlock())->SetRange(addr, size)); - + LOG_WARNING(MEMORY, "Memory mapped at 0x%llx: size=0x%x", addr, size); return true; } @@ -231,20 +228,14 @@ bool MemoryBase::Unmap(const u64 addr) MemBlockInfo::MemBlockInfo(u64 _addr, u32 _size) : MemInfo(_addr, PAGE_4K(_size)) { - void* real_addr = (void*)((u64)Memory.GetBaseAddr() + _addr); + void* real_addr = vm::get_ptr(vm::cast(_addr)); + void* priv_addr = vm::get_priv_ptr(vm::cast(_addr)); + #ifdef _WIN32 - mem = VirtualAlloc(real_addr, size, MEM_COMMIT, PAGE_READWRITE); + if (!VirtualAlloc(priv_addr, size, MEM_COMMIT, PAGE_READWRITE) || !VirtualAlloc(real_addr, size, MEM_COMMIT, PAGE_READWRITE)) #else - if (::mprotect(real_addr, size, PROT_READ | PROT_WRITE)) - { - mem = nullptr; - } - else - { - mem = real_addr; - } + if (mprotect(real_addr, size, PROT_READ | PROT_WRITE) || mprotect(priv_addr, size, PROT_READ | PROT_WRITE)) #endif - if (mem != real_addr) { LOG_ERROR(MEMORY, "Memory allocation failed (addr=0x%llx, size=0x%x)", addr, size); Emu.Pause(); @@ -252,7 +243,9 @@ MemBlockInfo::MemBlockInfo(u64 _addr, u32 _size) else { Memory.RegisterPages(_addr, PAGE_4K(_size)); - memset(mem, 0, size); + + mem = real_addr; + memset(mem, 0, size); // ??? } } @@ -262,9 +255,11 @@ void MemBlockInfo::Free() { Memory.UnregisterPages(addr, size); #ifdef _WIN32 - if (!VirtualFree(mem, size, MEM_DECOMMIT)) + DWORD old; + + if (!VirtualProtect(mem, size, PAGE_NOACCESS, &old) || !VirtualProtect(vm::get_priv_ptr(vm::cast(addr)), size, PAGE_NOACCESS, &old)) #else - if (::mprotect(mem, size, PROT_NONE)) + if (mprotect(mem, size, PROT_NONE) || mprotect(vm::get_priv_ptr(vm::cast(addr)), size, PROT_NONE)) #endif { LOG_ERROR(MEMORY, "Memory deallocation failed (addr=0x%llx, size=0x%x)", addr, size); @@ -437,7 +432,7 @@ u64 DynamicMemoryBlockBase::AllocAlign(u32 size, u32 align) LOG_ERROR(MEMORY, "DynamicMemoryBlockBase::AllocAlign(size=0x%x, align=0x%x): memory block not initialized", size, align); return 0; } - + size = PAGE_4K(size); u32 exsize; @@ -715,4 +710,4 @@ bool VirtualMemoryBlock::Unreserve(u32 size) u32 VirtualMemoryBlock::GetReservedAmount() { return m_reserve_size; -} \ No newline at end of file +} diff --git a/rpcs3/Emu/Memory/Memory.h b/rpcs3/Emu/Memory/Memory.h index 3f9a981041..a6aabf35ee 100644 --- a/rpcs3/Emu/Memory/Memory.h +++ b/rpcs3/Emu/Memory/Memory.h @@ -72,11 +72,6 @@ public: Close(); } - static void* const GetBaseAddr() - { - return vm::g_base_addr; - } - void RegisterPages(u64 addr, u32 size); void UnregisterPages(u64 addr, u32 size); diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 04d3a0f90a..1a0b9edd5c 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -1,24 +1,339 @@ #include "stdafx.h" +#include "Utilities/Log.h" #include "Memory.h" +#include "Emu/System.h" #include "Emu/CPU/CPUThread.h" #include "Emu/Cell/PPUThread.h" #include "Emu/ARMv7/ARMv7Thread.h" +#include "Emu/SysCalls/lv2/sys_time.h" + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#include + +/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */ +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif +#endif + namespace vm { - #ifdef _WIN32 - #include - void* const g_base_addr = VirtualAlloc(nullptr, 0x100000000, MEM_RESERVE, PAGE_NOACCESS); - #else - #include +#ifdef _WIN32 + HANDLE g_memory_handle; +#endif - /* OS X uses MAP_ANON instead of MAP_ANONYMOUS */ - #ifndef MAP_ANONYMOUS - #define MAP_ANONYMOUS MAP_ANON - #endif + void* g_priv_addr; - void* const g_base_addr = mmap(nullptr, 0x100000000, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - #endif + void* initialize() + { +#ifdef _WIN32 + g_memory_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_RESERVE, 0x1, 0x0, NULL); + + void* base_addr = MapViewOfFile(g_memory_handle, FILE_MAP_WRITE, 0, 0, 0x100000000); // main memory + g_priv_addr = MapViewOfFile(g_memory_handle, FILE_MAP_WRITE, 0, 0, 0x100000000); // memory mirror for privileged access + + return base_addr; + + //return VirtualAlloc(nullptr, 0x100000000, MEM_RESERVE, PAGE_NOACCESS); +#else + //shm_unlink("/rpcs3_vm"); + + int memory_handle = shm_open("/rpcs3_vm", O_RDWR | O_CREAT | O_EXCL, 0); + + if (memory_handle == -1) + { + printf("shm_open() failed\n"); + return (void*)-1; + } + + ftruncate(memory_handle, 0x100000000); + + void* base_addr = mmap(nullptr, 0x100000000, PROT_NONE, MAP_SHARED, memory_handle, 0); + g_priv_addr = mmap(nullptr, 0x100000000, PROT_NONE, MAP_SHARED, memory_handle, 0); + + shm_unlink("/rpcs3_vm"); + + return base_addr; + + //return mmap(nullptr, 0x100000000, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); +#endif + } + + void finalize() + { +#ifdef _WIN32 + UnmapViewOfFile(g_base_addr); + UnmapViewOfFile(g_priv_addr); + CloseHandle(g_memory_handle); +#else + munmap(g_base_addr, 0x100000000); + munmap(g_priv_addr, 0x100000000); +#endif + } + + void* const g_base_addr = (atexit(finalize), initialize()); + + class reservation_mutex_t + { + std::atomic m_owner; + std::condition_variable m_cv; + std::mutex m_cv_mutex; + + public: + reservation_mutex_t() + : m_owner(nullptr) + { + } + + bool do_notify; + + __noinline void lock() + { + NamedThreadBase* owner = GetCurrentNamedThread(); + NamedThreadBase* old = nullptr; + + while (!m_owner.compare_exchange_strong(old, owner)) + { + std::unique_lock cv_lock(m_cv_mutex); + + m_cv.wait_for(cv_lock, std::chrono::milliseconds(1)); + + if (old == owner) + { + throw __FUNCTION__; + } + + old = nullptr; + } + + do_notify = true; + } + + __noinline void unlock() + { + NamedThreadBase* owner = GetCurrentNamedThread(); + + if (!m_owner.compare_exchange_strong(owner, nullptr)) + { + throw __FUNCTION__; + } + + if (do_notify) + { + m_cv.notify_one(); + } + } + + }; + + std::function g_reservation_cb = nullptr; + NamedThreadBase* g_reservation_owner = nullptr; + + u32 g_reservation_addr = 0; + u32 g_reservation_size = 0; + + reservation_mutex_t g_reservation_mutex; + + void _reservation_set(u32 addr, bool no_access = false) + { + //const auto stamp0 = get_time(); + +#ifdef _WIN32 + DWORD old; + if (!VirtualProtect(vm::get_ptr(addr & ~0xfff), 4096, no_access ? PAGE_NOACCESS : PAGE_READONLY, &old)) +#else + if (mprotect(vm::get_ptr(addr & ~0xfff), 4096, no_access ? PROT_NONE : PROT_READ)) +#endif + { + throw fmt::format("vm::_reservation_set() failed (addr=0x%x)", addr); + } + + //LOG_NOTICE(MEMORY, "VirtualProtect: %f us", (get_time() - stamp0) / 80.f); + } + + bool _reservation_break(u32 addr) + { + if (g_reservation_addr >> 12 == addr >> 12) + { + //const auto stamp0 = get_time(); + +#ifdef _WIN32 + DWORD old; + if (!VirtualProtect(vm::get_ptr(addr & ~0xfff), 4096, PAGE_READWRITE, &old)) +#else + if (mprotect(vm::get_ptr(addr & ~0xfff), 4096, PROT_READ | PROT_WRITE)) +#endif + { + throw fmt::format("vm::_reservation_break() failed (addr=0x%x)", addr); + } + + //LOG_NOTICE(MEMORY, "VirtualAlloc: %f us", (get_time() - stamp0) / 80.f); + + if (g_reservation_cb) + { + g_reservation_cb(); + g_reservation_cb = nullptr; + } + + g_reservation_owner = nullptr; + g_reservation_addr = 0; + g_reservation_size = 0; + + return true; + } + + return false; + } + + bool reservation_break(u32 addr) + { + std::lock_guard lock(g_reservation_mutex); + + return _reservation_break(addr); + } + + bool reservation_acquire(void* data, u32 addr, u32 size, const std::function& callback) + { + //const auto stamp0 = get_time(); + + bool broken = false; + + assert(size == 1 || size == 2 || size == 4 || size == 8 || size == 128); + assert((addr + size - 1 & ~0xfff) == (addr & ~0xfff)); + + { + std::lock_guard lock(g_reservation_mutex); + + // silent unlocking to prevent priority boost for threads going to break reservation + //g_reservation_mutex.do_notify = false; + + // break previous reservation + if (g_reservation_owner) + { + broken = _reservation_break(g_reservation_addr); + } + + // change memory protection to read-only + _reservation_set(addr); + + // may not be necessary + _mm_mfence(); + + // set additional information + g_reservation_addr = addr; + g_reservation_size = size; + g_reservation_owner = GetCurrentNamedThread(); + g_reservation_cb = callback; + + // copy data + memcpy(data, vm::get_ptr(addr), size); + } + + return broken; + } + + bool reservation_update(u32 addr, const void* data, u32 size) + { + assert(size == 1 || size == 2 || size == 4 || size == 8 || size == 128); + assert((addr + size - 1 & ~0xfff) == (addr & ~0xfff)); + + std::lock_guard lock(g_reservation_mutex); + + if (g_reservation_owner != GetCurrentNamedThread() || g_reservation_addr != addr || g_reservation_size != size) + { + // atomic update failed + return false; + } + + // change memory protection to no access + _reservation_set(addr, true); + + // update memory using privileged access + memcpy(vm::get_priv_ptr(addr), data, size); + + // remove callback to not call it on successful update + g_reservation_cb = nullptr; + + // free the reservation and restore memory protection + _reservation_break(addr); + + // atomic update succeeded + return true; + } + + bool reservation_query(u32 addr, bool is_writing) + { + std::lock_guard lock(g_reservation_mutex); + + { + LV2_LOCK(0); + + if (!Memory.IsGoodAddr(addr)) + { + return false; + } + } + + if (is_writing) + { + // break the reservation + _reservation_break(addr); + } + + return true; + } + + void reservation_free() + { + std::lock_guard lock(g_reservation_mutex); + + if (g_reservation_owner == GetCurrentNamedThread()) + { + _reservation_break(g_reservation_addr); + } + } + + void reservation_op(u32 addr, u32 size, std::function proc) + { + assert(size == 1 || size == 2 || size == 4 || size == 8 || size == 128); + assert((addr + size - 1 & ~0xfff) == (addr & ~0xfff)); + + std::lock_guard lock(g_reservation_mutex); + + // break previous reservation + if (g_reservation_owner != GetCurrentNamedThread() || g_reservation_addr != addr || g_reservation_size != size) + { + if (g_reservation_owner) + { + _reservation_break(g_reservation_addr); + } + } + + // change memory protection to no access + _reservation_set(addr, true); + + // set additional information + g_reservation_addr = addr; + g_reservation_size = size; + g_reservation_owner = GetCurrentNamedThread(); + g_reservation_cb = nullptr; + + // may not be necessary + _mm_mfence(); + + // do the operation + proc(); + + // remove the reservation + _reservation_break(addr); + } bool check_addr(u32 addr) { @@ -62,8 +377,12 @@ namespace vm { return res; } - - assert(!real_pointer); + + if (real_pointer) + { + throw fmt::format("vm::get_addr(0x%016llx) failed: not a part of virtual memory", (u64)real_pointer); + } + return 0; } @@ -263,4 +582,4 @@ namespace vm } } } -} \ No newline at end of file +} diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 7cc958c3ba..a49c21eaab 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -21,7 +21,24 @@ namespace vm static void set_stack_size(u32 size) {} static void initialize_stack() {} +#ifdef _WIN32 + extern HANDLE g_memory_handle; +#endif + + extern void* g_priv_addr; extern void* const g_base_addr; + + // break the reservation, return true if it was successfully broken + bool reservation_break(u32 addr); + // read memory and reserve it for further atomic update, return true if the previous reservation was broken + bool reservation_acquire(void* data, u32 addr, u32 size, const std::function& callback = nullptr); + // attempt to atomically update reserved memory + bool reservation_update(u32 addr, const void* data, u32 size); + bool reservation_query(u32 addr, bool is_writing); + void reservation_free(); + // perform complete operation + void reservation_op(u32 addr, u32 size, std::function proc); + bool map(u32 addr, u32 size, u32 flags); bool unmap(u32 addr, u32 size = 0, u32 flags = 0); u32 alloc(u32 size, memory_location location = user_space); @@ -40,6 +57,18 @@ namespace vm return *get_ptr(addr); } + template + T* const get_priv_ptr(u32 addr) + { + return reinterpret_cast(static_cast(g_priv_addr) + addr); + } + + template + T& get_priv_ref(u32 addr) + { + return *get_priv_ptr(addr); + } + u32 get_addr(const void* real_pointer); __noinline void error(const u64 addr, const char* func); diff --git a/rpcs3/Emu/Memory/vm_ptr.h b/rpcs3/Emu/Memory/vm_ptr.h index 0c588cd7ee..68d940ea6b 100644 --- a/rpcs3/Emu/Memory/vm_ptr.h +++ b/rpcs3/Emu/Memory/vm_ptr.h @@ -213,6 +213,11 @@ namespace vm { return vm::get_ptr(vm::cast(m_addr)); } + + T* get_priv_ptr() const + { + return vm::get_priv_ptr(vm::cast(m_addr)); + } static const _ptr_base make(const AT& addr) { @@ -243,6 +248,11 @@ namespace vm return vm::get_ptr(vm::cast(m_addr)); } + void* get_priv_ptr() const + { + return vm::get_priv_ptr(vm::cast(m_addr)); + } + explicit operator void*() const { return get_ptr(); @@ -301,6 +311,11 @@ namespace vm return vm::get_ptr(vm::cast(m_addr)); } + const void* get_priv_ptr() const + { + return vm::get_priv_ptr(vm::cast(m_addr)); + } + explicit operator const void*() const { return get_ptr(); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysmodule.cpp b/rpcs3/Emu/SysCalls/Modules/cellSysmodule.cpp index 69445ccb17..28828c9d38 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysmodule.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSysmodule.cpp @@ -136,7 +136,7 @@ const char *getModuleName(int id) { } } - return 0; + return "UNKNOWN MODULE"; } int cellSysmoduleInitialize() @@ -159,11 +159,12 @@ int cellSysmoduleSetMemcontainer(u32 ct_id) int cellSysmoduleLoadModule(u16 id) { + cellSysmodule->Warning("cellSysmoduleLoadModule(id=0x%04x: %s)", id, getModuleName(id)); + if (id == 0xf054) { cellSysmodule->Todo("cellSysmoduleLoadModule: CELL_SYSMODULE_LIBATRAC3MULTI"); } - cellSysmodule->Warning("cellSysmoduleLoadModule(%s)", getModuleName(id)); if (Module* m = Emu.GetModuleManager().GetModuleById(id)) { @@ -180,7 +181,8 @@ int cellSysmoduleLoadModule(u16 id) int cellSysmoduleUnloadModule(u16 id) { - cellSysmodule->Warning("cellSysmoduleUnloadModule(%s)", getModuleName(id)); + cellSysmodule->Warning("cellSysmoduleUnloadModule(id=0x%04x: %s)", id, getModuleName(id)); + Module* m = Emu.GetModuleManager().GetModuleById(id); if(!m) @@ -199,7 +201,8 @@ int cellSysmoduleUnloadModule(u16 id) int cellSysmoduleIsLoaded(u16 id) { - cellSysmodule->Warning("cellSysmoduleIsLoaded(%s)", getModuleName(id)); + cellSysmodule->Warning("cellSysmoduleIsLoaded(id=0x%04x: %s)", id, getModuleName(id)); + Module* m = Emu.GetModuleManager().GetModuleById(id); if(!m) diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp b/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp index 26a1246041..f72c74a1ea 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp @@ -69,6 +69,13 @@ struct sceNpTrophyInternal sceNpTrophyInternal sceNpTrophyInstance; +static sceNpTrophyInternalContext& getContext(u32 context) { + // The invalid context is 0, so remap contexts 1... to indices 0... + if (context == 0) + throw "getContext: context == 0"; + return sceNpTrophyInstance.contexts[context - 1]; +} + // Functions int sceNpTrophyInit(u32 pool_addr, u32 poolSize, u32 containerId, u64 options) { @@ -114,6 +121,7 @@ int sceNpTrophyCreateContext(vm::ptr context, vm::ptr ctxt.trp_stream.reset(stream); ctxt.trp_name = entry->name; stream = nullptr; + *context = sceNpTrophyInstance.contexts.size(); // contexts start from 1 return CELL_OK; } } @@ -124,7 +132,7 @@ int sceNpTrophyCreateContext(vm::ptr context, vm::ptr int sceNpTrophyCreateHandle(vm::ptr handle) { - sceNpTrophy->Warning("sceNpTrophyCreateHandle(handle_addr=0x%x)", handle.addr()); + sceNpTrophy->Todo("sceNpTrophyCreateHandle(handle_addr=0x%x)", handle.addr()); if (!sceNpTrophyInstance.m_bInitialized) return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; @@ -144,11 +152,13 @@ int sceNpTrophyRegisterContext(u32 context, u32 handle, vm::ptr= sceNpTrophyInstance.contexts.size()) + if (context == 0 || context > sceNpTrophyInstance.contexts.size()) { + sceNpTrophy->Warning("sceNpTrophyRegisterContext: invalid context (%d)", context); return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; + } // TODO: There are other possible errors - sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context]; + sceNpTrophyInternalContext& ctxt = getContext(context); if (!ctxt.trp_stream) return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST; @@ -219,11 +229,13 @@ int sceNpTrophyGetRequiredDiskSpace(u32 context, u32 handle, vm::ptr reqspa if (!sceNpTrophyInstance.m_bInitialized) return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; - if (context >= sceNpTrophyInstance.contexts.size()) + if (context == 0 || context > sceNpTrophyInstance.contexts.size()) { + sceNpTrophy->Warning("sceNpTrophyGetRequiredDiskSpace: invalid context (%d)", context); return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; + } // TODO: There are other possible errors - sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context]; + const sceNpTrophyInternalContext& ctxt = getContext(context); if (!ctxt.trp_stream) return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST; @@ -260,7 +272,7 @@ int sceNpTrophyGetGameInfo(u32 context, u32 handle, vm::ptr return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; // TODO: There are other possible errors - sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context]; + sceNpTrophyInternalContext& ctxt = getContext(context); if (trophyId >= (s32)ctxt.tropusr->GetTrophiesCount()) return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID; if (ctxt.tropusr->GetTrophyUnlockState(trophyId)) @@ -351,15 +363,20 @@ int sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, vm::ptr sceNpTrophyInstance.contexts.size()) { + sceNpTrophy->Warning("sceNpTrophyGetTrophyUnlockState: invalid context (%d)", context); + return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; + } // TODO: There are other possible errors - sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context]; - *count = ctxt.tropusr->GetTrophiesCount(); - if (*count > 128) + const sceNpTrophyInternalContext& ctxt = getContext(context); + u32 count_ = ctxt.tropusr->GetTrophiesCount(); + *count = count_; + if (count_ > 128) sceNpTrophy->Warning("sceNpTrophyGetTrophyUnlockState: More than 128 trophies detected!"); // Pack up to 128 bools in u32 flag_bits[4] - for (u32 id=0; id<*count; id++) + for (u32 id = 0; id < count_; id++) { if (ctxt.tropusr->GetTrophyUnlockState(id)) flags->flag_bits[id/32] |= 1<<(id%32); @@ -387,7 +404,7 @@ int sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptr g_armv7_dump; + void Emulator::Stop() { if(IsStopped()) return; @@ -365,6 +367,14 @@ void Emulator::Stop() finalize_psv_modules(); clear_all_psv_objects(); + + for (auto& v : g_armv7_dump) + { + LOG_NOTICE(ARMv7, v.second); + } + + g_armv7_dump.clear(); + m_rsx_callback = 0; // TODO: check finalization order diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index 89112c8692..1d0ea7a16e 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -401,8 +401,8 @@ namespace loader armv7_decoder_initialize(code_start, code_end); const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread"; - const u32 stack_size = proc_param->sceUserMainThreadStackSize ? *proc_param->sceUserMainThreadStackSize : 0; - const u32 priority = proc_param->sceUserMainThreadPriority ? *proc_param->sceUserMainThreadPriority : 0; + const u32 stack_size = proc_param->sceUserMainThreadStackSize ? *proc_param->sceUserMainThreadStackSize : 256 * 1024; + const u32 priority = proc_param->sceUserMainThreadPriority ? *proc_param->sceUserMainThreadPriority : 160; armv7_thread(entry, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run(); break; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index daed4a06ea..5327e220e3 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -56,7 +56,9 @@ + + @@ -334,7 +336,9 @@ + + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 0720c265c4..ea11ba34b9 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -583,7 +583,7 @@ Emu\GPU\RSX - + Emu\GPU\RSX @@ -670,7 +670,7 @@ Emu\CPU\ARMv7 - + Emu\CPU\ARMv7 @@ -696,7 +696,7 @@ Emu\CPU\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\CPU\ARMv7\Modules Emu\CPU\ARMv7\Modules @@ -848,6 +848,12 @@ Emu\CPU\ARMv7\Modules + + Emu\CPU\ARMv7\Objects + + + Emu\CPU\ARMv7\Objects + @@ -1350,7 +1356,7 @@ Emu\GPU\RSX - + Emu\GPU\RSX @@ -1479,7 +1485,7 @@ Emu\CPU\ARMv7\Modules - + Emu\CPU\ARMv7 @@ -1490,7 +1496,7 @@ Emu\CPU\ARMv7\Objects - Emu\CPU\ARMv7\Modules + Emu\CPU\ARMv7\Modules Emu\CPU\ARMv7\Modules @@ -1510,5 +1516,11 @@ Emu\CPU\ARMv7\Modules + + Emu\CPU\ARMv7\Objects + + + Emu\CPU\ARMv7\Objects + \ No newline at end of file