mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 12:32:43 +00:00
ARMv7 decoder improved
This commit is contained in:
parent
6069be7a93
commit
79d03ece66
@ -10,17 +10,6 @@ enum ARMv7InstructionSet
|
||||
ThumbEE
|
||||
};
|
||||
|
||||
union ARMv7Code
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 code0;
|
||||
u16 code1;
|
||||
};
|
||||
|
||||
u32 data;
|
||||
};
|
||||
|
||||
struct ARMv7Context
|
||||
{
|
||||
ARMv7Thread& thread;
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include <unordered_map>
|
||||
#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<const ARMv7_opcode_t*> 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<const ARMv7_opcode_t*> 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<u32, const ARMv7_opcode_t*> 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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -1,5 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
union ARMv7Code
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 code0;
|
||||
u16 code1;
|
||||
};
|
||||
|
||||
u32 data;
|
||||
};
|
||||
|
||||
enum ARMv7_encoding
|
||||
{
|
||||
T1, T2, T3, T4, A1, A2
|
||||
|
@ -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
|
||||
|
@ -106,7 +106,7 @@ void ARMv7Thread::DoRun()
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
m_dec = new ARMv7Decoder(*this);
|
||||
m_dec = new ARMv7Decoder(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
class CPUDecoder
|
||||
{
|
||||
public:
|
||||
virtual u8 DecodeMemory(const u32 address)=0;
|
||||
virtual u32 DecodeMemory(const u32 address) = 0;
|
||||
|
||||
virtual ~CPUDecoder() = default;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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<void>(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<u32>(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;
|
||||
}
|
||||
|
@ -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())
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user