diff --git a/rpcs3/Emu/ARMv7/ARMv7Context.h b/rpcs3/Emu/ARMv7/ARMv7Context.h index c474dc6e6d..bdfa8107e2 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Context.h +++ b/rpcs3/Emu/ARMv7/ARMv7Context.h @@ -10,17 +10,6 @@ enum ARMv7InstructionSet ThumbEE }; -union ARMv7Code -{ - struct - { - u16 code0; - u16 code1; - }; - - u32 data; -}; - struct ARMv7Context { ARMv7Thread& thread; diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp b/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp index c28a880722..179e461aed 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include #include "Utilities/Log.h" #include "ARMv7Thread.h" #include "ARMv7Interpreter.h" @@ -595,31 +596,164 @@ const ARMv7_opcode_t ARMv7_opcode_table[] = ARMv7_OP4(0x0fff, 0xffff, 0x0320, 0xf001, A1, YIELD), }; -u8 ARMv7Decoder::DecodeMemory(const u32 address) +struct ARMv7_op2_table_t { - ARMv7Code code; - code.code0 = vm::psv::read16(address & ~1); - code.code1 = vm::psv::read16(address + 2 & ~1); - u32 arg = address & 0x1 ? code.data : (u32)code.code0 << 16 | code.code1; + const ARMv7_opcode_t* data[0x10000]; - //LOG_NOTICE(GENERAL, "code0 = 0x%04x, code1 = 0x%04x, data = 0x%08x, arg = 0x%08x", code.code0, code.code1, code.data, arg); - - // old decoding algorithm - - for (auto& opcode : ARMv7_opcode_table) + ARMv7_op2_table_t() { - if ((opcode.type < A1) == ((address & 0x1) == 0) && (arg & opcode.mask) == opcode.code) + std::vector t2; + + for (auto& opcode : ARMv7_opcode_table) { - code.data = opcode.length == 2 ? code.code0 : arg; - (*opcode.func)(m_thr.context, code, opcode.type); - //LOG_NOTICE(ARMv7, "%s, %s", opcode.name, m_thr.RegsToString()); - return opcode.length; + if (opcode.length == 2) + { + t2.push_back(&opcode); + } + } + + for (u32 i = 0; i < 0x10000; i++) + { + data[i] = nullptr; + + for (auto& opcode : t2) + { + if (((i << 16) & opcode->mask) == opcode->code) + { + data[i] = opcode; + break; + } + } } } - ARMv7_instrs::UNK(m_thr.context, code); - return address & 0x1 ? 4 : 2; +} g_op2t; +struct ARMv7_op4t_table_t +{ + std::vector table; + + ARMv7_op4t_table_t() + { + for (auto& opcode : ARMv7_opcode_table) + { + if (opcode.length == 4 && opcode.type < A1) + { + table.push_back(&opcode); + } + } + } + +} g_op4t; + +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 + // 2. If some instruction is not recognized, print the error + // 3. Possibly print disasm + g_opct.clear(); + + while (addr < end_addr) + { + ARMv7Code code = {}; + code.code0 = vm::psv::read16(addr); + + auto found = g_op2t.data[code.code0]; + + if (!found) + { + code.code1 = code.code0; + code.code0 = vm::psv::read16(addr + 2); + + auto op = g_opct.find(code.data); + if (op != g_opct.end()) + { + found = op->second; + } + } + + if (!found) + { + for (auto opcode : g_op4t.table) + { + if ((code.data & opcode->mask) == opcode->code) + { + g_opct[code.data] = (found = opcode); + break; + } + } + } + + if (!found) + { + LOG_ERROR(ARMv7, "Unknown instruction found at address 0x%08x: %04x %04x", addr, code.code1, code.code0); + addr += 4; + } + else + { + if (dump) if (found->length == 2) + { + LOG_NOTICE(ARMv7, "0x%08x: %04x %s", addr, code.code0, found->name); + } + else + { + LOG_NOTICE(ARMv7, "0x%08x: %04x %04x %s", addr, code.code1, code.code0, found->name); + } + + addr += found->length; + } + } + + while (vm::psv::read16(addr) == 0xf870) + { + g_opct[0xf8700000 | vm::psv::read16(addr + 2)] = g_op4t.table[0]; + addr += 16; + } + + LOG_NOTICE(ARMv7, "armv7_decoder_initialize() finished, g_opct.size() = %lld", g_opct.size()); +} + +u32 ARMv7Decoder::DecodeMemory(const u32 address) +{ + if (address & 0x1) + { + throw "ARMv7Decoder::DecodeMemory() failed (something is wrong with instruction set)"; + } + + ARMv7Code code = {}; + code.code0 = vm::psv::read16(address); + + if (auto opcode = g_op2t.data[code.code0]) + { + (*opcode->func)(m_ctx, code, opcode->type); + return 2; + } + + code.code1 = code.code0; + code.code0 = vm::psv::read16(address + 2); + + auto op = g_opct.find(code.data); + if (op != g_opct.end()) + { + (*op->second->func)(m_ctx, code, op->second->type); + return 4; + } + + //for (auto opcode : g_op4t.table) + //{ + // if ((code.data & opcode->mask) == opcode->code) + // { + // (*opcode->func)(m_ctx, code, opcode->type); + // return 4; + // } + //} + + ARMv7_instrs::UNK(m_ctx, code); + return 2; + + // "group" decoding algorithm (temporarily disabled) //execute_main_group(&m_thr); //// LOG_NOTICE(GENERAL, "%s, %d \n\n", m_thr.m_last_instr_name, m_thr.m_last_instr_size); diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.h b/rpcs3/Emu/ARMv7/ARMv7Decoder.h index 341ed6a276..229f74014b 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.h +++ b/rpcs3/Emu/ARMv7/ARMv7Decoder.h @@ -1,16 +1,18 @@ #pragma once #include "Emu/CPU/CPUDecoder.h" -class ARMv7Thread; +struct ARMv7Context; class ARMv7Decoder : public CPUDecoder { - ARMv7Thread& m_thr; + ARMv7Context& m_ctx; public: - ARMv7Decoder(ARMv7Thread& thr) : m_thr(thr) + ARMv7Decoder(ARMv7Context& context) : m_ctx(context) { } - virtual u8 DecodeMemory(const u32 address); + virtual u32 DecodeMemory(const u32 address); }; + +void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump = false); diff --git a/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp b/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp index ccb2582cad..6a3626522b 100644 --- a/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#if 0 #include "ARMv7DisAsm.h" void ARMv7DisAsm::UNK(const u32 data) @@ -1119,4 +1120,4 @@ void ARMv7DisAsm::UXTH(const u32 data, const ARMv7_encoding type) { Write(__FUNCTION__); } - +#endif diff --git a/rpcs3/Emu/ARMv7/ARMv7DisAsm.h b/rpcs3/Emu/ARMv7/ARMv7DisAsm.h index 05375dc167..848baaf7cb 100644 --- a/rpcs3/Emu/ARMv7/ARMv7DisAsm.h +++ b/rpcs3/Emu/ARMv7/ARMv7DisAsm.h @@ -1,5 +1,4 @@ #pragma once -#include "Emu/ARMv7/ARMv7Opcodes.h" #include "Emu/CPU/CPUDisAsm.h" static const char* g_arm_cond_name[16] = @@ -10,6 +9,14 @@ static const char* g_arm_cond_name[16] = "gt", "le", "al", "al", }; +static const char* g_arm_reg_name[16] = +{ + "r0", "r1", "r2", "r3", + "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", + "r12", "sp", "lr", "pc", +}; + class ARMv7DisAsm : public CPUDisAsm { @@ -24,6 +31,7 @@ protected: return (u32)dump_pc + imm; } +#if 0 std::string GetRegsListString(u16 regs_list) { std::string regs_str; @@ -316,4 +324,5 @@ protected: virtual void UXTB(const u32 data, const ARMv7_encoding type); virtual void UXTB16(const u32 data, const ARMv7_encoding type); virtual void UXTH(const u32 data, const ARMv7_encoding type); +#endif }; diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h index b73b46b2f9..4f187e379b 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h @@ -1,5 +1,16 @@ #pragma once +union ARMv7Code +{ + struct + { + u16 code0; + u16 code1; + }; + + u32 data; +}; + enum ARMv7_encoding { T1, T2, T3, T4, A1, A2 diff --git a/rpcs3/Emu/ARMv7/ARMv7Opcodes.h b/rpcs3/Emu/ARMv7/ARMv7Opcodes.h index 7a7f0e7e53..ed415bf2a2 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Opcodes.h +++ b/rpcs3/Emu/ARMv7/ARMv7Opcodes.h @@ -1,16 +1,8 @@ #pragma once - +#if 0 #include "Emu/ARMv7/ARMv7Thread.h" #include "Emu/ARMv7/ARMv7Interpreter.h" -static const char* g_arm_reg_name[16] = -{ - "r0", "r1", "r2", "r3", - "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", - "r12", "sp", "lr", "pc", -}; -#if 0 using namespace ARMv7_instrs; struct ARMv7_Instruction diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index abd6b2791f..e4b1d65291 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -106,7 +106,7 @@ void ARMv7Thread::DoRun() case 1: case 2: - m_dec = new ARMv7Decoder(*this); + m_dec = new ARMv7Decoder(context); break; } } diff --git a/rpcs3/Emu/CPU/CPUDecoder.h b/rpcs3/Emu/CPU/CPUDecoder.h index beb0027055..0a0aea1e0c 100644 --- a/rpcs3/Emu/CPU/CPUDecoder.h +++ b/rpcs3/Emu/CPU/CPUDecoder.h @@ -5,7 +5,7 @@ class CPUDecoder { public: - virtual u8 DecodeMemory(const u32 address)=0; + virtual u32 DecodeMemory(const u32 address) = 0; virtual ~CPUDecoder() = default; }; diff --git a/rpcs3/Emu/Cell/PPCDecoder.cpp b/rpcs3/Emu/Cell/PPCDecoder.cpp index de2b55fdf9..6425cf7c7a 100644 --- a/rpcs3/Emu/Cell/PPCDecoder.cpp +++ b/rpcs3/Emu/Cell/PPCDecoder.cpp @@ -2,7 +2,7 @@ #include "Emu/Memory/Memory.h" #include "PPCDecoder.h" -u8 PPCDecoder::DecodeMemory(const u32 address) +u32 PPCDecoder::DecodeMemory(const u32 address) { u32 instr = vm::read32(address); Decode(instr); diff --git a/rpcs3/Emu/Cell/PPCDecoder.h b/rpcs3/Emu/Cell/PPCDecoder.h index b13ab08efd..a653f06e81 100644 --- a/rpcs3/Emu/Cell/PPCDecoder.h +++ b/rpcs3/Emu/Cell/PPCDecoder.h @@ -5,9 +5,9 @@ class PPCDecoder : public CPUDecoder { public: - virtual void Decode(const u32 code)=0; + virtual void Decode(const u32 code) = 0; - virtual u8 DecodeMemory(const u32 address); + virtual u32 DecodeMemory(const u32 address); virtual ~PPCDecoder() = default; }; diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index 1b977a6e52..1b85a16d21 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -45,7 +45,7 @@ public: virtual void Decode(const u32 code); - virtual u8 DecodeMemory(const u32 address); + virtual u32 DecodeMemory(const u32 address); }; #define c (*compiler) diff --git a/rpcs3/Emu/Cell/SPURecompilerCore.cpp b/rpcs3/Emu/Cell/SPURecompilerCore.cpp index 197f42987e..a829019603 100644 --- a/rpcs3/Emu/Cell/SPURecompilerCore.cpp +++ b/rpcs3/Emu/Cell/SPURecompilerCore.cpp @@ -180,7 +180,7 @@ void SPURecompilerCore::Compile(u16 pos) first = false; } -u8 SPURecompilerCore::DecodeMemory(const u32 address) +u32 SPURecompilerCore::DecodeMemory(const u32 address) { assert(CPU.ls_offset == address - CPU.PC); const u32 m_offset = CPU.ls_offset; diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index 988d1d779c..80906f88ca 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -6,6 +6,7 @@ #include "ELF32.h" #include "Emu/Cell/SPUThread.h" #include "Emu/ARMv7/ARMv7Thread.h" +#include "Emu/ARMv7/ARMv7Decoder.h" #include "Emu/ARMv7/PSVFuncList.h" #include "Emu/System.h" @@ -98,17 +99,8 @@ namespace loader u32 entry = 0; // actual entry point (ELFs entry point is ignored) u32 fnid_addr = 0; - - // load section names - //assert(m_ehdr.data_le.e_shstrndx < m_shdrs.size()); - //const u32 sname_off = m_shdrs[m_ehdr.data_le.e_shstrndx].data_le.sh_offset; - //const u32 sname_size = m_shdrs[m_ehdr.data_le.e_shstrndx].data_le.sh_size; - //const u32 sname_base = sname_size ? Memory.PSV.RAM.AllocAlign(sname_size) : 0; - //if (sname_base) - //{ - // m_stream->Seek(handler::get_stream_offset() + sname_off); - // m_stream->Read(vm::get_ptr(sname_base), sname_size); - //} + u32 code_start = 0; + u32 code_end = 0; for (auto& shdr : m_shdrs) { @@ -125,7 +117,14 @@ namespace loader name.push_back(c); } - if (!strcmp(name.c_str(), ".sceModuleInfo.rodata")) + if (!strcmp(name.c_str(), ".text")) + { + LOG_NOTICE(LOADER, ".text analysis..."); + + code_start = shdr.data_le.sh_addr; + code_end = shdr.data_le.sh_size + code_start; + } + else if (!strcmp(name.c_str(), ".sceModuleInfo.rodata")) { LOG_NOTICE(LOADER, ".sceModuleInfo.rodata analysis..."); @@ -190,6 +189,8 @@ namespace loader vm::psv::write16(addr + 2, 0); // index 0 (unimplemented stub) vm::psv::write32(addr + 4, nid); // nid } + + code_end = std::min(addr, code_end); } } else if (!strcmp(name.c_str(), ".sceRefs.rodata")) @@ -238,6 +239,8 @@ namespace loader } } + armv7_decoder_initialize(code_start, code_end); + arm7_thread(entry & ~1 /* TODO: Thumb/ARM encoding selection */, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); break; } diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index 706aee8000..c943495597 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -516,7 +516,7 @@ namespace loader if (module && !module->Load(nid)) { - LOG_WARNING(LOADER, "Unimplemented function '%s' in '%s' module (HLE)", SysCalls::GetHLEFuncName(nid).c_str(), module_name.c_str()); + LOG_ERROR(LOADER, "Unimplemented function '%s' in '%s' module (HLE)", SysCalls::GetHLEFuncName(nid).c_str(), module_name.c_str()); } else //if (Ini.HLELogging.GetValue()) {