- Implemented some ARMv7 instructions.

This commit is contained in:
DH 2013-11-06 03:01:15 +02:00
parent f18fff08c7
commit 099333c992
8 changed files with 382 additions and 28 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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