ARMv7 decoder improved

This commit is contained in:
Nekotekina 2015-01-22 00:09:37 +03:00
parent 6069be7a93
commit 79d03ece66
15 changed files with 204 additions and 63 deletions

View file

@ -10,17 +10,6 @@ enum ARMv7InstructionSet
ThumbEE ThumbEE
}; };
union ARMv7Code
{
struct
{
u16 code0;
u16 code1;
};
u32 data;
};
struct ARMv7Context struct ARMv7Context
{ {
ARMv7Thread& thread; ARMv7Thread& thread;

View file

@ -1,4 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include <unordered_map>
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "ARMv7Thread.h" #include "ARMv7Thread.h"
#include "ARMv7Interpreter.h" #include "ARMv7Interpreter.h"
@ -595,31 +596,164 @@ const ARMv7_opcode_t ARMv7_opcode_table[] =
ARMv7_OP4(0x0fff, 0xffff, 0x0320, 0xf001, A1, YIELD), ARMv7_OP4(0x0fff, 0xffff, 0x0320, 0xf001, A1, YIELD),
}; };
u8 ARMv7Decoder::DecodeMemory(const u32 address) struct ARMv7_op2_table_t
{ {
ARMv7Code code; const ARMv7_opcode_t* data[0x10000];
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;
//LOG_NOTICE(GENERAL, "code0 = 0x%04x, code1 = 0x%04x, data = 0x%08x, arg = 0x%08x", code.code0, code.code1, code.data, arg); ARMv7_op2_table_t()
{
// old decoding algorithm std::vector<const ARMv7_opcode_t*> t2;
for (auto& opcode : ARMv7_opcode_table) for (auto& opcode : ARMv7_opcode_table)
{ {
if ((opcode.type < A1) == ((address & 0x1) == 0) && (arg & opcode.mask) == opcode.code) if (opcode.length == 2)
{ {
code.data = opcode.length == 2 ? code.code0 : arg; t2.push_back(&opcode);
(*opcode.func)(m_thr.context, code, opcode.type);
//LOG_NOTICE(ARMv7, "%s, %s", opcode.name, m_thr.RegsToString());
return opcode.length;
} }
} }
ARMv7_instrs::UNK(m_thr.context, code); for (u32 i = 0; i < 0x10000; i++)
return address & 0x1 ? 4 : 2; {
data[i] = nullptr;
for (auto& opcode : t2)
{
if (((i << 16) & opcode->mask) == opcode->code)
{
data[i] = opcode;
break;
}
}
}
}
} 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); //execute_main_group(&m_thr);
//// LOG_NOTICE(GENERAL, "%s, %d \n\n", m_thr.m_last_instr_name, m_thr.m_last_instr_size); //// LOG_NOTICE(GENERAL, "%s, %d \n\n", m_thr.m_last_instr_name, m_thr.m_last_instr_size);

View file

@ -1,16 +1,18 @@
#pragma once #pragma once
#include "Emu/CPU/CPUDecoder.h" #include "Emu/CPU/CPUDecoder.h"
class ARMv7Thread; struct ARMv7Context;
class ARMv7Decoder : public CPUDecoder class ARMv7Decoder : public CPUDecoder
{ {
ARMv7Thread& m_thr; ARMv7Context& m_ctx;
public: 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);

View file

@ -1,4 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#if 0
#include "ARMv7DisAsm.h" #include "ARMv7DisAsm.h"
void ARMv7DisAsm::UNK(const u32 data) void ARMv7DisAsm::UNK(const u32 data)
@ -1119,4 +1120,4 @@ void ARMv7DisAsm::UXTH(const u32 data, const ARMv7_encoding type)
{ {
Write(__FUNCTION__); Write(__FUNCTION__);
} }
#endif

View file

@ -1,5 +1,4 @@
#pragma once #pragma once
#include "Emu/ARMv7/ARMv7Opcodes.h"
#include "Emu/CPU/CPUDisAsm.h" #include "Emu/CPU/CPUDisAsm.h"
static const char* g_arm_cond_name[16] = static const char* g_arm_cond_name[16] =
@ -10,6 +9,14 @@ static const char* g_arm_cond_name[16] =
"gt", "le", "al", "al", "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 class ARMv7DisAsm
: public CPUDisAsm : public CPUDisAsm
{ {
@ -24,6 +31,7 @@ protected:
return (u32)dump_pc + imm; return (u32)dump_pc + imm;
} }
#if 0
std::string GetRegsListString(u16 regs_list) std::string GetRegsListString(u16 regs_list)
{ {
std::string regs_str; std::string regs_str;
@ -316,4 +324,5 @@ protected:
virtual void UXTB(const u32 data, const ARMv7_encoding type); virtual void UXTB(const u32 data, const ARMv7_encoding type);
virtual void UXTB16(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); virtual void UXTH(const u32 data, const ARMv7_encoding type);
#endif
}; };

View file

@ -1,5 +1,16 @@
#pragma once #pragma once
union ARMv7Code
{
struct
{
u16 code0;
u16 code1;
};
u32 data;
};
enum ARMv7_encoding enum ARMv7_encoding
{ {
T1, T2, T3, T4, A1, A2 T1, T2, T3, T4, A1, A2

View file

@ -1,16 +1,8 @@
#pragma once #pragma once
#if 0
#include "Emu/ARMv7/ARMv7Thread.h" #include "Emu/ARMv7/ARMv7Thread.h"
#include "Emu/ARMv7/ARMv7Interpreter.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; using namespace ARMv7_instrs;
struct ARMv7_Instruction struct ARMv7_Instruction

View file

@ -106,7 +106,7 @@ void ARMv7Thread::DoRun()
case 1: case 1:
case 2: case 2:
m_dec = new ARMv7Decoder(*this); m_dec = new ARMv7Decoder(context);
break; break;
} }
} }

View file

@ -5,7 +5,7 @@
class CPUDecoder class CPUDecoder
{ {
public: public:
virtual u8 DecodeMemory(const u32 address)=0; virtual u32 DecodeMemory(const u32 address) = 0;
virtual ~CPUDecoder() = default; virtual ~CPUDecoder() = default;
}; };

View file

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "PPCDecoder.h" #include "PPCDecoder.h"
u8 PPCDecoder::DecodeMemory(const u32 address) u32 PPCDecoder::DecodeMemory(const u32 address)
{ {
u32 instr = vm::read32(address); u32 instr = vm::read32(address);
Decode(instr); Decode(instr);

View file

@ -7,7 +7,7 @@ class PPCDecoder : public CPUDecoder
public: 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; virtual ~PPCDecoder() = default;
}; };

View file

@ -45,7 +45,7 @@ public:
virtual void Decode(const u32 code); virtual void Decode(const u32 code);
virtual u8 DecodeMemory(const u32 address); virtual u32 DecodeMemory(const u32 address);
}; };
#define c (*compiler) #define c (*compiler)

View file

@ -180,7 +180,7 @@ void SPURecompilerCore::Compile(u16 pos)
first = false; first = false;
} }
u8 SPURecompilerCore::DecodeMemory(const u32 address) u32 SPURecompilerCore::DecodeMemory(const u32 address)
{ {
assert(CPU.ls_offset == address - CPU.PC); assert(CPU.ls_offset == address - CPU.PC);
const u32 m_offset = CPU.ls_offset; const u32 m_offset = CPU.ls_offset;

View file

@ -6,6 +6,7 @@
#include "ELF32.h" #include "ELF32.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h" #include "Emu/ARMv7/ARMv7Thread.h"
#include "Emu/ARMv7/ARMv7Decoder.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/System.h" #include "Emu/System.h"
@ -98,17 +99,8 @@ namespace loader
u32 entry = 0; // actual entry point (ELFs entry point is ignored) u32 entry = 0; // actual entry point (ELFs entry point is ignored)
u32 fnid_addr = 0; u32 fnid_addr = 0;
u32 code_start = 0;
// load section names u32 code_end = 0;
//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);
//}
for (auto& shdr : m_shdrs) for (auto& shdr : m_shdrs)
{ {
@ -125,7 +117,14 @@ namespace loader
name.push_back(c); 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..."); LOG_NOTICE(LOADER, ".sceModuleInfo.rodata analysis...");
@ -190,6 +189,8 @@ namespace loader
vm::psv::write16(addr + 2, 0); // index 0 (unimplemented stub) vm::psv::write16(addr + 2, 0); // index 0 (unimplemented stub)
vm::psv::write32(addr + 4, nid); // nid vm::psv::write32(addr + 4, nid); // nid
} }
code_end = std::min<u32>(addr, code_end);
} }
} }
else if (!strcmp(name.c_str(), ".sceRefs.rodata")) 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(); arm7_thread(entry & ~1 /* TODO: Thumb/ARM encoding selection */, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run();
break; break;
} }

View file

@ -516,7 +516,7 @@ namespace loader
if (module && !module->Load(nid)) 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()) else //if (Ini.HLELogging.GetValue())
{ {