diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.h b/rpcs3/Emu/ARMv7/ARMv7Decoder.h index 019925c934..71f37e3b38 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.h +++ b/rpcs3/Emu/ARMv7/ARMv7Decoder.h @@ -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; } }; diff --git a/rpcs3/Emu/ARMv7/ARMv7DisAsm.h b/rpcs3/Emu/ARMv7/ARMv7DisAsm.h index e314836014..3217907018 100644 --- a/rpcs3/Emu/ARMv7/ARMv7DisAsm.h +++ b/rpcs3/Emu/ARMv7/ARMv7DisAsm.h @@ -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)); } }; \ No newline at end of file diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h index dd9229027e..8d32701813 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h @@ -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(); } }; \ No newline at end of file diff --git a/rpcs3/Emu/ARMv7/ARMv7Opcodes.h b/rpcs3/Emu/ARMv7/ARMv7Opcodes.h index 7f37dc0d4b..35d3684c8e 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Opcodes.h +++ b/rpcs3/Emu/ARMv7/ARMv7Opcodes.h @@ -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; }; diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 7fbe342903..15fc560c76 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -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) diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.h b/rpcs3/Emu/ARMv7/ARMv7Thread.h index 33ea8478a1..7f5ad7dd52 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.h +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.h @@ -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(); diff --git a/rpcs3/Gui/AboutDialog.cpp b/rpcs3/Gui/AboutDialog.cpp index d9cd394894..38ce2abcc7 100644 --- a/rpcs3/Gui/AboutDialog.cpp +++ b/rpcs3/Gui/AboutDialog.cpp @@ -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); diff --git a/rpcs3/Gui/InterpreterDisAsm.cpp b/rpcs3/Gui/InterpreterDisAsm.cpp index e78bf3a47e..0742d6ee41 100644 --- a/rpcs3/Gui/InterpreterDisAsm.cpp +++ b/rpcs3/Gui/InterpreterDisAsm.cpp @@ -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; iGetOffset() + 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