mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-04 21:39:54 +00:00
- Implemented some ARMv7 instructions.
This commit is contained in:
parent
f18fff08c7
commit
099333c992
@ -13,23 +13,125 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
u32 branchTarget(u32 imm)
|
||||
{
|
||||
return imm << 1;
|
||||
}
|
||||
|
||||
virtual u8 DecodeMemory(const u64 address)
|
||||
{
|
||||
using namespace ARMv7_opcodes;
|
||||
const u16 code0 = Memory.Read16(address);
|
||||
const u16 code1 = Memory.Read16(address + 2);
|
||||
const u16 opcode = code0;
|
||||
|
||||
switch(opcode)
|
||||
switch(code0 >> 12) //15 - 12
|
||||
{
|
||||
case 0:
|
||||
m_op.NULL_OP();
|
||||
case T1_CBZ:
|
||||
switch((code0 >> 10) & 0x1)
|
||||
{
|
||||
case 0:
|
||||
switch((code0 >> 8) & 0x1)
|
||||
{
|
||||
case 1:
|
||||
m_op.CBZ((code0 >> 11) & 0x1, branchTarget((((code0 >> 9) & 0x1) << 5) | (code0 >> 3) & 0x1f), code0 & 0x7, 2);
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
m_op.UNK(opcode, code0, code1);
|
||||
case T1_B:
|
||||
m_op.B((code0 >> 8) & 0xf, branchTarget(code0 & 0xff), 2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
switch(code0 >> 11) //15 - 11
|
||||
{
|
||||
case T2_B:
|
||||
m_op.B(0xf, branchTarget(code0 & 0xfff), 2);
|
||||
return 2;
|
||||
|
||||
case T3_B:
|
||||
{
|
||||
u8 S = (code0 >> 10) & 0x1;
|
||||
u8 J1 = (code1 >> 13) & 0x1;
|
||||
u8 J2 = (code1 >> 11) & 0x1;
|
||||
u8 I1 = 1 - (J1 ^ S);
|
||||
u8 I2 = 1 - (J2 ^ S);
|
||||
u16 imm11 = code1 & 0x7ff;
|
||||
u32 imm32;
|
||||
|
||||
switch(code1 >> 14)
|
||||
{
|
||||
case 2: //B
|
||||
{
|
||||
u8 cond;
|
||||
switch((code1 >> 12) & 0x1)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
cond = (code0 >> 6) & 0xf;
|
||||
u32 imm6 = code0 & 0x3f;
|
||||
imm32 = sign<19, u32>((S << 19) | (I1 << 18) | (I2 << 17) | (imm6 << 11) | imm11);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
cond = 0xf;
|
||||
u32 imm10 = code0 & 0x7ff;
|
||||
imm32 = sign<23, u32>((S << 23) | (I1 << 22) | (I2 << 21) | (imm10 << 11) | imm11);
|
||||
break;
|
||||
}
|
||||
|
||||
m_op.B(cond, branchTarget(imm32), 4);
|
||||
}
|
||||
return 4;
|
||||
|
||||
case 3: //BL
|
||||
switch((code1 >> 12) & 0x1)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 1:
|
||||
u32 imm10 = code0 & 0x7ff;
|
||||
imm32 = sign<23, u32>((S << 23) | (I1 << 22) | (I2 << 21) | (imm10 << 11) | imm11);
|
||||
m_op.BL(branchTarget(imm32), 4);
|
||||
return 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch(code0 >> 9)
|
||||
{
|
||||
case T1_PUSH:
|
||||
m_op.PUSH((((code0 >> 8) & 0x1) << 14) | (code0 & 0xff));
|
||||
return 2;
|
||||
|
||||
case T1_POP:
|
||||
m_op.POP((((code0 >> 8) & 0x1) << 15) | (code0 & 0xff));
|
||||
return 2;
|
||||
}
|
||||
|
||||
switch(code0)
|
||||
{
|
||||
case T2_PUSH:
|
||||
m_op.PUSH(code1);
|
||||
return 4;
|
||||
|
||||
case T2_POP:
|
||||
m_op.POP(code1);
|
||||
return 4;
|
||||
|
||||
case T1_NOP:
|
||||
m_op.NOP();
|
||||
return 2;
|
||||
}
|
||||
|
||||
m_op.UNK(code0, code1);
|
||||
return 2;
|
||||
}
|
||||
};
|
||||
|
@ -4,6 +4,14 @@
|
||||
#include "Gui/DisAsmFrame.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
static const char* g_arm_cond_name[16] =
|
||||
{
|
||||
"eq", "ne", "cs", "cc",
|
||||
"mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt",
|
||||
"gt", "le", "al", "al",
|
||||
};
|
||||
|
||||
class ARMv7DisAsm
|
||||
: public CPUDisAsm
|
||||
, public ARMv7Opcodes
|
||||
@ -16,7 +24,27 @@ public:
|
||||
protected:
|
||||
virtual u32 DisAsmBranchTarget(const s32 imm)
|
||||
{
|
||||
return dump_pc + (imm << 2);
|
||||
return dump_pc + imm;
|
||||
}
|
||||
|
||||
wxString GetRegsListString(u16 regs_list)
|
||||
{
|
||||
wxString regs_str;
|
||||
|
||||
for(u16 mask=0x1, i=0; mask; mask <<= 1, i++)
|
||||
{
|
||||
if(regs_list & mask)
|
||||
{
|
||||
if(!regs_str.IsEmpty())
|
||||
{
|
||||
regs_str += ", ";
|
||||
}
|
||||
|
||||
regs_str += g_arm_reg_name[i];
|
||||
}
|
||||
}
|
||||
|
||||
return regs_str;
|
||||
}
|
||||
|
||||
void NULL_OP()
|
||||
@ -24,13 +52,45 @@ protected:
|
||||
Write("null");
|
||||
}
|
||||
|
||||
void PUSH(u16 regs_list)
|
||||
{
|
||||
Write(wxString::Format("push {%s}", GetRegsListString(regs_list)));
|
||||
}
|
||||
|
||||
void POP(u16 regs_list)
|
||||
{
|
||||
Write(wxString::Format("pop {%s}", GetRegsListString(regs_list)));
|
||||
}
|
||||
|
||||
void NOP()
|
||||
{
|
||||
Write("nop");
|
||||
}
|
||||
|
||||
void UNK(const u16 opcode, const u16 code0, const u16 code1)
|
||||
void B(u8 cond, u32 imm, u8 intstr_size)
|
||||
{
|
||||
Write(wxString::Format("Unknown/Illegal opcode! (0x%04x : 0x%04x : 0x%04x)", opcode, code0, code1));
|
||||
if((cond & 0xe) == 0xe)
|
||||
{
|
||||
Write(wxString::Format("b 0x%x", DisAsmBranchTarget(imm) + intstr_size));
|
||||
}
|
||||
else
|
||||
{
|
||||
Write(wxString::Format("b[%s] 0x%x", g_arm_cond_name[cond], DisAsmBranchTarget(imm) + intstr_size));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void CBZ(u8 op, u32 imm, u8 rn, u8 intstr_size)
|
||||
{
|
||||
Write(wxString::Format("cb%sz 0x%x,%s", (op ? "n" : ""), DisAsmBranchTarget(imm) + intstr_size, g_arm_reg_name[rn]));
|
||||
}
|
||||
|
||||
void BL(u32 imm, u8 intstr_size)
|
||||
{
|
||||
Write(wxString::Format("bl 0x%x", DisAsmBranchTarget(imm) + intstr_size));
|
||||
}
|
||||
|
||||
void UNK(const u16 code0, const u16 code1)
|
||||
{
|
||||
Write(wxString::Format("Unknown/Illegal opcode! (0x%04x : 0x%04x)", code0, code1));
|
||||
}
|
||||
};
|
@ -10,6 +10,30 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
bool ConditionPassed(u8 cond)
|
||||
{
|
||||
bool result;
|
||||
|
||||
switch(cond >> 1)
|
||||
{
|
||||
case 0: result = CPU.APSR.Z == 1; break;
|
||||
case 1: result = CPU.APSR.C == 1; break;
|
||||
case 2: result = CPU.APSR.N == 1; break;
|
||||
case 3: result = CPU.APSR.V == 1; break;
|
||||
case 4: result = CPU.APSR.C == 1 && CPU.APSR.Z == 0; break;
|
||||
case 5: result = CPU.APSR.N == CPU.APSR.V; break;
|
||||
case 6: result = CPU.APSR.N == CPU.APSR.V && CPU.APSR.Z == 0; break;
|
||||
case 7: return true;
|
||||
}
|
||||
|
||||
if(cond & 0x1)
|
||||
{
|
||||
return !result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
void NULL_OP()
|
||||
{
|
||||
@ -21,9 +45,55 @@ protected:
|
||||
{
|
||||
}
|
||||
|
||||
void UNK(const u16 opcode, const u16 code0, const u16 code1)
|
||||
void PUSH(u16 regs_list)
|
||||
{
|
||||
ConLog.Error("Unknown/Illegal opcode! (0x%04x : 0x%04x : 0x%04x)", opcode, code0, code1);
|
||||
for(u16 mask=0x1, i=0; mask; mask <<= 1, i++)
|
||||
{
|
||||
if(regs_list & mask)
|
||||
{
|
||||
Memory.Write32(CPU.SP, CPU.read_gpr(i));
|
||||
CPU.SP += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void POP(u16 regs_list)
|
||||
{
|
||||
for(u16 mask=(0x1 << 15), i=15; mask; mask >>= 1, i++)
|
||||
{
|
||||
if(regs_list & mask)
|
||||
{
|
||||
CPU.SP -= 4;
|
||||
CPU.write_gpr(i, Memory.Read32(CPU.SP));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void B(u8 cond, u32 imm, u8 intstr_size)
|
||||
{
|
||||
if(ConditionPassed(cond))
|
||||
{
|
||||
CPU.SetBranch(CPU.PC + intstr_size + imm);
|
||||
}
|
||||
}
|
||||
|
||||
void CBZ(u8 op, u32 imm, u8 rn, u8 intstr_size)
|
||||
{
|
||||
if((CPU.GPR[rn] == 0) ^ op)
|
||||
{
|
||||
CPU.SetBranch(CPU.PC + intstr_size + imm);
|
||||
}
|
||||
}
|
||||
|
||||
void BL(u32 imm, u8 intstr_size)
|
||||
{
|
||||
CPU.LR = (CPU.PC + intstr_size) | 1;
|
||||
CPU.SetBranch(CPU.PC + intstr_size + imm);
|
||||
}
|
||||
|
||||
void UNK(const u16 code0, const u16 code1)
|
||||
{
|
||||
ConLog.Error("Unknown/Illegal opcode! (0x%04x : 0x%04x)", code0, code1);
|
||||
Emu.Pause();
|
||||
}
|
||||
};
|
@ -1,10 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
static const char* g_arm_reg_name[16] =
|
||||
{
|
||||
"r0", "r1", "r2", "r3",
|
||||
"r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11",
|
||||
"r12", "sp", "lr", "pc",
|
||||
};
|
||||
|
||||
namespace ARMv7_opcodes
|
||||
{
|
||||
enum ARMv7_MainOpcodes
|
||||
enum ARMv7_T1Opcodes
|
||||
{
|
||||
T1_CBZ = 0xb,
|
||||
T1_B = 0xd,
|
||||
T1_PUSH = 0x1d,
|
||||
T1_POP = 0x5e,
|
||||
T1_NOP = 0xBF00,
|
||||
};
|
||||
|
||||
enum ARMv7_T2Opcodes
|
||||
{
|
||||
T2_B = 0x1c,
|
||||
T2_PUSH = 0xe92d,
|
||||
T2_POP = 0xe8bd,
|
||||
};
|
||||
|
||||
enum ARMv7_T3Opcodes
|
||||
{
|
||||
T3_B = 0x1e,
|
||||
};
|
||||
}
|
||||
|
||||
@ -14,5 +38,12 @@ public:
|
||||
virtual void NULL_OP() = 0;
|
||||
virtual void NOP() = 0;
|
||||
|
||||
virtual void UNK(const u16 opcode, const u16 code0, const u16 code1) = 0;
|
||||
virtual void PUSH(u16 regs_list) = 0;
|
||||
virtual void POP(u16 regs_list) = 0;
|
||||
|
||||
virtual void B(u8 cond, u32 imm, u8 intstr_size) = 0;
|
||||
virtual void CBZ(u8 op, u32 imm, u8 rn, u8 intstr_size) = 0;
|
||||
virtual void BL(u32 imm, u8 intstr_size)=0;
|
||||
|
||||
virtual void UNK(const u16 code0, const u16 code1) = 0;
|
||||
};
|
||||
|
@ -10,15 +10,26 @@ ARMv7Thread::ARMv7Thread() : CPUThread(CPU_THREAD_ARMv7)
|
||||
|
||||
void ARMv7Thread::InitRegs()
|
||||
{
|
||||
memset(GPR, 0, sizeof(GPR[0]) * 15);
|
||||
APSR.APSR = 0;
|
||||
IPSR.IPSR = 0;
|
||||
SP = m_stack_point;
|
||||
}
|
||||
|
||||
void ARMv7Thread::InitStack()
|
||||
{
|
||||
if(!m_stack_addr)
|
||||
{
|
||||
m_stack_size = 0x10000;
|
||||
m_stack_addr = Memory.Alloc(0x10000, 1);
|
||||
}
|
||||
|
||||
m_stack_point = m_stack_addr;
|
||||
}
|
||||
|
||||
u64 ARMv7Thread::GetFreeStackSize() const
|
||||
{
|
||||
return GetStackSize() - (m_stack_point - GetStackAddr());
|
||||
return GetStackSize() - (SP - GetStackAddr());
|
||||
}
|
||||
|
||||
void ARMv7Thread::SetArg(const uint pos, const u64 arg)
|
||||
@ -28,7 +39,15 @@ void ARMv7Thread::SetArg(const uint pos, const u64 arg)
|
||||
|
||||
wxString ARMv7Thread::RegsToString()
|
||||
{
|
||||
return wxEmptyString;
|
||||
wxString result;
|
||||
for(int i=0; i<15; ++i)
|
||||
{
|
||||
result += wxString::Format("%s\t= 0x%08x\n", g_arm_reg_name[i], GPR[i]);
|
||||
}
|
||||
|
||||
result += wxString::Format("APSR\t= 0x%08x [N: %d, Z: %d, C: %d, V: %d, Q: %d]\n", APSR.APSR, APSR.N, APSR.Z, APSR.C, APSR.V, APSR.Q);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wxString ARMv7Thread::ReadRegString(wxString reg)
|
||||
|
@ -1,11 +1,82 @@
|
||||
#pragma once
|
||||
#include "Emu\CPU\CPUThread.h"
|
||||
#include "Emu/CPU/CPUThread.h"
|
||||
|
||||
class ARMv7Thread : public CPUThread
|
||||
{
|
||||
public:
|
||||
ARMv7Thread();
|
||||
|
||||
union
|
||||
{
|
||||
u32 GPR[15];
|
||||
|
||||
struct
|
||||
{
|
||||
u32 pad[13];
|
||||
|
||||
union
|
||||
{
|
||||
u32 SP;
|
||||
|
||||
struct { u16 SP_main, SP_process; };
|
||||
};
|
||||
|
||||
u32 LR;
|
||||
};
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 N : 1; //Negative condition code flag
|
||||
u32 Z : 1; //Zero condition code flag
|
||||
u32 C : 1; //Carry condition code flag
|
||||
u32 V : 1; //Overflow condition code flag
|
||||
u32 Q : 1; //Set to 1 if an SSAT or USAT instruction changes (saturates) the input value for the signed or unsigned range of the result
|
||||
u32 : 27;
|
||||
};
|
||||
|
||||
u32 APSR;
|
||||
} APSR;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 : 24;
|
||||
u32 exception : 8;
|
||||
};
|
||||
|
||||
u32 IPSR;
|
||||
} IPSR;
|
||||
|
||||
void write_gpr(u8 n, u32 value)
|
||||
{
|
||||
assert(n < 16);
|
||||
|
||||
if(n < 15)
|
||||
{
|
||||
GPR[n] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetBranch(value);
|
||||
}
|
||||
}
|
||||
|
||||
u32 read_gpr(u8 n)
|
||||
{
|
||||
assert(n < 16);
|
||||
|
||||
if(n < 15)
|
||||
{
|
||||
return GPR[n];
|
||||
}
|
||||
|
||||
return PC;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void InitRegs();
|
||||
virtual void InitStack();
|
||||
|
@ -45,8 +45,8 @@ AboutDialog::AboutDialog(wxWindow *parent)
|
||||
|
||||
//Credits
|
||||
wxBoxSizer* s_panel_credits(new wxBoxSizer(wxHORIZONTAL));
|
||||
wxStaticText* t_section1 = new wxStaticText(this, wxID_ANY, "\nDevelopers:\n\n - To be written...\n", wxDefaultPosition, wxSize(156,160));
|
||||
wxStaticText* t_section2 = new wxStaticText(this, wxID_ANY, "\nThanks:\n\n - To be written...\n", wxDefaultPosition, wxSize(156,160));
|
||||
wxStaticText* t_section1 = new wxStaticText(this, wxID_ANY, "\nDevelopers:\n\nDH\nAlexAltea", wxDefaultPosition, wxSize(156,160));
|
||||
wxStaticText* t_section2 = new wxStaticText(this, wxID_ANY, "\nThanks:\n\nBlackDaemon", wxDefaultPosition, wxSize(156,160));
|
||||
wxStaticText* t_section3 = new wxStaticText(this, wxID_ANY, "\nExternal code:\n\n - SELF Decrypter based on scetool (C) 2011-2013 by naehrwert", wxDefaultPosition, wxSize(156,160));
|
||||
s_panel_credits->AddSpacer(12);
|
||||
s_panel_credits->Add(t_section1);
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
u64 InterpreterDisAsmFrame::CentrePc(const u64 pc) const
|
||||
{
|
||||
return pc - ((m_item_count / 2) * 4);
|
||||
return pc/* - ((m_item_count / 2) * 4)*/;
|
||||
}
|
||||
|
||||
InterpreterDisAsmFrame::InterpreterDisAsmFrame(wxWindow* parent)
|
||||
@ -233,16 +233,17 @@ void InterpreterDisAsmFrame::ShowAddr(const u64 addr)
|
||||
else
|
||||
{
|
||||
disasm->offset = CPU->GetOffset();
|
||||
for(uint i=0; i<m_item_count; ++i, PC += 4)
|
||||
for(uint i=0, count = 4; i<m_item_count; ++i, PC += count)
|
||||
{
|
||||
if(!Memory.IsGoodAddr(CPU->GetOffset() + PC, 4))
|
||||
{
|
||||
m_list->SetItem(i, 0, wxString::Format("[%08llx] illegal address", PC));
|
||||
count = 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
disasm->dump_pc = PC;
|
||||
decoder->DecodeMemory(CPU->GetOffset() + PC);
|
||||
count = decoder->DecodeMemory(CPU->GetOffset() + PC);
|
||||
|
||||
if(IsBreakPoint(PC))
|
||||
{
|
||||
@ -255,13 +256,13 @@ void InterpreterDisAsmFrame::ShowAddr(const u64 addr)
|
||||
|
||||
wxColour colour;
|
||||
|
||||
if((!CPU->IsRunning() || !Emu.IsRunning()) && PC == CPU->PC)
|
||||
{
|
||||
colour = wxColour("Green");
|
||||
}
|
||||
else
|
||||
{
|
||||
colour = wxColour("White");
|
||||
if((!CPU->IsRunning() || !Emu.IsRunning()) && PC == CPU->PC)
|
||||
{
|
||||
colour = wxColour("Green");
|
||||
}
|
||||
else
|
||||
{
|
||||
colour = wxColour("White");
|
||||
|
||||
for(u32 i=0; i<Emu.GetMarkedPoints().GetCount(); ++i)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user