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
};
union ARMv7Code
{
struct
{
u16 code0;
u16 code1;
};
u32 data;
};
struct ARMv7Context
{
ARMv7Thread& thread;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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
};

View File

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

View File

@ -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

View File

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

View File

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

View File

@ -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);

View File

@ -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;
};

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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())
{