www.pudn.com > potemkin_sourceforPSP.rar > ARMDis.cpp
#include "stdafx.h"
#include "../../Globals.h"
#include "../MemMap.h"
#include "ARM.h"
#include "ARMDis.h"
#include "ARMTables.h"
u32 disPC;
//TODO: Condition codes!
#define RDi(x) ((x>>12)&0xF)
#define RNi(x) ((x>>16)&0xF)
#define RMi(x) (x&0xf)
#define RSi(x) ((x>>8)&0xF)
#define RD(x) GetReg(RDi(x))
#define RN(x) GetReg(RNi(x))
#define RM(x) GetReg((x)&0xF)
#define RS(x) GetReg((x>>8)&0xF)
namespace ARMDis
{
const TCHAR *GetCondIdx(int index)
{
return conditionNames[index];
}
const TCHAR *GetCond(u32 op)
{
return GetCondIdx(op>>28);
}
const TCHAR *GetReg(u32 reg)
{
static const TCHAR *regs[16] =
{
"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","sp","lr","pc"
};
return regs[reg];
}
const TCHAR *GetS(u32 op)
{
return S_FLAG(op)? "." : "" ;
}
void Dis_Unknown(u32 op, char *out)
{
strcpy(out,"???\t-- unknown --");
}
void Dis_Unimpl(u32 op, char *out)
{
strcpy(out,"???\t-- unimplemented --");
}
// data processing addressing mode
void Dis_DPAddr(u32 op, char *out)
{
if ((op&(1<<25))) //imm shift
{
u32 cnst = op&0xFF;
u32 shift = ((op>>8)&0xF) << 1;
sprintf(out,"$%0x",_rotr(cnst,shift));
}
else
{
if ((op&0x10)) //reg shift
{
TCHAR shifttype[4];
switch((op>>5) & 0x3)
{
case 0: _tcscpy(shifttype,"lsl"); break;
case 1: _tcscpy(shifttype,"lsr"); break;
case 2: _tcscpy(shifttype,"asr"); break;
case 3: _tcscpy(shifttype,"ror"); break;
}
sprintf(out,"%s %s %s", RM(op), shifttype, RS(op));
}
else //immediate
{
int shiftAmt = (op>>7) & 0x1F;
TCHAR shifttype[4];
switch((op>>5) & 0x3)
{
case 0: _tcscpy(shifttype,"lsl"); break;
case 1: _tcscpy(shifttype,"lsr"); break;
case 2: _tcscpy(shifttype,"asr"); break;
case 3: _tcscpy(shifttype,shiftAmt?"ror":"rrx"); if (!shiftAmt) shiftAmt=1; break;//ROR / RRX
}
if (strcmp(shifttype,"lsl") == 0 && shiftAmt == 0)
sprintf(out,"%s",RM(op));
else
sprintf(out,"%s %s %d", RM(op), shifttype, shiftAmt);
}
}
}
//type 1 - 3 op
void Dis_DP1(u32 op, char *out, char *name)
{
char addr[16];
Dis_DPAddr(op, addr);
sprintf(out, "%s%s%s\t%s, %s, %s",name,GetCond(op),GetS(op),RD(op),RN(op),addr);
}
//type 2 - 2 op (tests with no output except the flags)
void Dis_DP2(u32 op, char *out, char *name)
{
char addr[16];
Dis_DPAddr(op, addr);
sprintf(out, "%s%s.\t%s, %s",name,GetCond(op),RN(op),addr);
}
//type 3 - 1 op (mov, mvn)
void Dis_DP3(u32 op, char *out, char *name)
{
char addr[16];
Dis_DPAddr(op, addr);
sprintf(out, "%s%s%s\t%s, %s",name,GetCond(op),GetS(op),RD(op),addr);
}
void Dis_AND(u32 op, char *out) {Dis_DP1(op,out,"and");}
void Dis_EOR(u32 op, char *out) {Dis_DP1(op,out,"eor");}
void Dis_SUB(u32 op, char *out) {Dis_DP1(op,out,"sub");}
void Dis_RSB(u32 op, char *out) {Dis_DP1(op,out,"rsb");}
void Dis_ADD(u32 op, char *out) {Dis_DP1(op,out,"add");}
void Dis_ADC(u32 op, char *out) {Dis_DP1(op,out,"adc");}
void Dis_SBC(u32 op, char *out) {Dis_DP1(op,out,"sbc");}
void Dis_RSC(u32 op, char *out) {Dis_DP1(op,out,"rsc");}
void Dis_TST(u32 op, char *out) {Dis_DP2(op,out,"tst");}
void Dis_TEQ(u32 op, char *out) {Dis_DP2(op,out,"teq");}
void Dis_CMP(u32 op, char *out) {Dis_DP2(op,out,"cmp");}
void Dis_CMN(u32 op, char *out) {Dis_DP2(op,out,"cmn");}
void Dis_ORR(u32 op, char *out) {Dis_DP1(op,out,"orr");}
void Dis_MOV(u32 op, char *out) {Dis_DP3(op,out,"mov");}
void Dis_BIC(u32 op, char *out) {Dis_DP1(op,out,"bic");}
void Dis_MVN(u32 op, char *out) {Dis_DP3(op,out,"mvn");}
void Dis_CLZ(u32 op, char *out)
{
sprintf(out, "clz%s\t%s, %s",GetCond(op),RD(op),RM(op));
}
void Dis_MRS(u32 op, char *out)
{
sprintf(out, "mrs%s\t%s, %s_%c%c%c",GetCond(op),RD(op),(op&(1<<22)) ? "SPSR" : "CPSR",
((op&0x00010000)?'c':'_'), ((op&0x00020000)?'x':'_'),
((op&0x00040000)?'s':'_'), ((op&0x00080000)?'f':'_'));
}
void Dis_MSRreg(u32 op, char *out)
{
sprintf(out, "msr\t%s_%c%c%c%c, %s",(op&(1<<22)) ? "SPSR" : "CPSR",
((op&0x00010000)?'c':'_'), ((op&0x00020000)?'x':'_'),
((op&0x00040000)?'s':'_'), ((op&0x00080000)?'f':'_'),RM(op));
}
void Dis_MSRimm(u32 op, char *out)
{
int rot = (op>>8)&0xf;
int val = _rotr(op&0xff,rot);
sprintf(out, "msr\t%s_%c%c%c%c, %08x",(op&(1<<22)) ? "SPSR" : "CPSR",
((op&0x00010000)?'c':'_'), ((op&0x00020000)?'x':'_'),
((op&0x00040000)?'s':'_'), ((op&0x00080000)?'f':'_'),val);
}
void Dis_ldst(u32 op, char *out, char *name)
{
TCHAR part2[256];
sprintf(out, "%s%s\t%s, ",name,GetCond(op),RD(op));
char sign = (op & (1<<23)) ? '+' : '-';
if (op & (1<<25))
{
//reg offset
int shiftAmt = (op>>7) & 0x1F;
TCHAR shifttype[4];
switch((op>>5) & 0x3)
{
case 0: _tcscpy(shifttype,"lsl"); break;
case 1: _tcscpy(shifttype,"lsr"); break;
case 2: _tcscpy(shifttype,"asr"); break;
case 3: _tcscpy(shifttype,shiftAmt?"ror":"rrx"); if (!shiftAmt) shiftAmt=1; break;//ROR / RRX
}
if (!(op & (1<<24)))
{
//postindex
if (strcmp(shifttype,"lsl") == 0 && shiftAmt == 0)
sprintf(part2,"[%s], %c%s",RN(op),sign,RM(op));
else
sprintf(part2,"[%s], %c%s %s %d",RN(op),sign,RM(op), shifttype, shiftAmt);
}
else
{
//preindex or normal
TCHAR *preindex = (op & (1<<21)) ? "!" : "";
if (strcmp(shifttype,"lsl") == 0 && shiftAmt == 0)
sprintf(part2,"[%s %c %s]%s",RN(op),sign,RM(op),preindex);
else
sprintf(part2,"[%s %c %s %s %d]%s",RN(op),sign,RM(op), shifttype, shiftAmt,preindex);
}
}
else
{
//imm offset
int imm = op&0xFFF;
if (!(op & (1<<24)))
{
//postindex
sprintf(part2, "[%s], %c%03x",RN(op),sign,imm);
}
else
{
//preindex or normal
TCHAR *preindex = (op & (1<<21)) ? "!" : "";
//immediate offset
if (RNi(op) == 15)
{
int addr = disPC+8;
sign=='+' ? addr+=imm : addr-=imm;
sprintf(part2, "[$%08x]%s (%08x)",addr,preindex,ReadMem32Unchecked(addr));
}
else
{
if (imm!=0)
sprintf(part2, "[%s %c $%03x]%s",RN(op),sign,imm,preindex);
else
sprintf(part2, "[%s]%s",RN(op),preindex);
}
}
}
strcat(out,part2);
}
void Dis_LDR(u32 op, char *out) {Dis_ldst(op,out,"ldr");}
void Dis_STR(u32 op, char *out) {Dis_ldst(op,out,"str");}
void Dis_LDRB(u32 op, char *out){Dis_ldst(op,out,"ldrb");}
void Dis_STRB(u32 op, char *out){Dis_ldst(op,out,"strb");}
void Dis_ldst2(u32 op, char *out, char *name)
{
TCHAR part2[256];
sprintf(out, "%s%s\t%s, ",name,GetCond(op),RD(op));
char sign = (op & (1<<23)) ? '+' : '-';
if (op&(1<<22))
{
//immediate offset
u8 imm = (op&0xF) | ((op>>4)&0xF0);
if (!(op & (1<<24)))
{
//postindexed
sprintf(part2,"[%s], %c$%02x",RN(op),sign,imm);
}
else
{
//preindexed or normal
TCHAR *preindex = (op&(1<<21)) ? "!" : "";
sprintf(part2,"[%s %c $%02x]%s",RN(op),sign,imm,preindex);
}
}
else
{
//register offset
if (!(op & (1<<24)))
{
//postindexed
sprintf(part2,"[%s], %c%s",RN(op),sign,RM(op));
}
else
{
//preindexed or normal
TCHAR *preindex = (op&(1<<21)) ? "!" : "";
sprintf(part2,"[%s %c %s]%s",RN(op),sign,RM(op),preindex);
}
}
strcat(out,part2);
}
void Dis_LDRH(u32 op, char *out) {Dis_ldst2(op,out,"ldrh");}
void Dis_STRH(u32 op, char *out) {Dis_ldst2(op,out,"strh");}
void Dis_LDRSH(u32 op, char *out) {Dis_ldst2(op,out,"ldrsh");}
void Dis_STRSH(u32 op, char *out) {Dis_ldst2(op,out,"strsh");}
void Dis_LDRSB(u32 op, char *out) {Dis_ldst2(op,out,"ldrsb");}
void Dis_STRSB(u32 op, char *out) {Dis_ldst2(op,out,"strsb");}
void Dis_stldm(u32 op, char *out, char *name)
{
TCHAR *pre = (op&(1<<24)) ? "b" : "a"; //before after
TCHAR *up = (op&(1<<23)) ? "i" : "d";
TCHAR *PSRuser = (op&(1<<22)) ? "^" : "";
TCHAR *writeback = (op&(1<<21)) ? "!" : "";
TCHAR reglist[512] = "{";
int count=0;
for (int i=0; i<16; i++)
{
if (op&(1<>8)&0xf;
int rdhi = (op>>16)&0xf;
int rdlo = (op>>12)&0xf;
sprintf(out,"umull\t%s:%s, %s, %s",GetReg(rdhi),GetReg(rdlo),GetReg(rm),GetReg(rs));
}
void Dis_UMLAL(u32 op, char *out)
{
int rm = op&0xf;
int rs = (op>>8)&0xf;
int rdhi = (op>>16)&0xf;
int rdlo = (op>>12)&0xf;
sprintf(out,"umlal\t%s:%s, %s, %s",GetReg(rdhi),GetReg(rdlo),GetReg(rm),GetReg(rs));
}
void Dis_SMULL(u32 op, char *out)
{
int rm = op&0xf;
int rs = (op>>8)&0xf;
int rdhi = (op>>16)&0xf;
int rdlo = (op>>12)&0xf;
sprintf(out,"smull\t%s:%s, %s, %s",GetReg(rdhi),GetReg(rdlo),GetReg(rm),GetReg(rs));
}
void Dis_SMLAL(u32 op, char *out)
{
int rm = op&0xf;
int rs = (op>>8)&0xf;
int rdhi = (op>>16)&0xf;
int rdlo = (op>>12)&0xf;
sprintf(out,"smlal\t%s:%s, %s, %s",GetReg(rdhi),GetReg(rdlo),GetReg(rm),GetReg(rs));
}
//Software i
void Dis_SWI(u32 op, char *out)
{
sprintf(out,"swi%s\t%08x",GetCond(op),op&0xFFFFFF);
}
//Branch and
void Dis_B(u32 op, char *out)
{
u32 addr = disPC+8+4*SEX24(op&0xFFFFFF);
sprintf(out,"b%s\t->$%08x", GetCond(op), addr);
}
void Dis_BL(u32 op, char *out)
{
u32 addr = disPC+8+4*SEX24(op&0xFFFFFF);
sprintf(out,"bl%s\t->$%08x", GetCond(op), addr);
}
void Dis_BLXr(u32 op, char *out)
{
sprintf(out,"blx%s\t->%s", GetCond(op), RM(op));
}
void Dis_BXr(u32 op, char *out)
{
sprintf(out,"bx%s\t->%s", GetCond(op), RM(op));
}
//////////////////////////////////////////////////////////////////////////
//THUMB
//////////////////////////////////////////////////////////////////////////
#define TR0(op) GetReg(op&7)
#define TR1(op) GetReg((op>>3)&7)
#define TR2(op) GetReg((op>>6)&7)
void Dis_T_Unimpl(u16 op, char *out)
{
strcpy(out,"???\t-- unimplemented --");
}
void Dis_T_Unknown(u16 op, char *out)
{
strcpy(out,"???\t-- unknown --");
}
void Dis_T_2op(u16 op, char *out, char *name)
{
sprintf(out,"%s\t%s, %s",name,TR0(op),TR1(op));
}
//Data process
void Dis_T_AND(u16 op, char *out){Dis_T_2op(op,out,"and.");}
void Dis_T_EOR(u16 op, char *out){Dis_T_2op(op,out,"eor.");}
void Dis_T_ORR(u16 op, char *out){Dis_T_2op(op,out,"orr.");}
void Dis_T_BIC(u16 op, char *out){Dis_T_2op(op,out,"bic.");}
void Dis_T_LSL(u16 op, char *out){Dis_T_2op(op,out,"lsl.");}
void Dis_T_LSR(u16 op, char *out){Dis_T_2op(op,out,"lsr.");}
void Dis_T_ASR(u16 op, char *out){Dis_T_2op(op,out,"asr.");}
void Dis_T_ROR(u16 op, char *out){Dis_T_2op(op,out,"ror.");}
void Dis_T_ADC(u16 op, char *out){Dis_T_2op(op,out,"adc.");}
void Dis_T_SBC(u16 op, char *out){Dis_T_2op(op,out,"sbc.");}
void Dis_T_CMP(u16 op, char *out){Dis_T_2op(op,out,"cmp.");}
void Dis_T_CMN(u16 op, char *out){Dis_T_2op(op,out,"cmn.");}
void Dis_T_TST(u16 op, char *out){Dis_T_2op(op,out,"tst.");}
void Dis_T_NEG(u16 op, char *out){Dis_T_2op(op,out,"neg.");}
void Dis_T_MVN(u16 op, char *out){Dis_T_2op(op,out,"mvn.");}
void Dis_T_MUL(u16 op, char *out){Dis_T_2op(op,out,"mul.");}
void Dis_T_hiop(u16 op, char *out,char *name)
{
int rd = ((op>>4)&8)|(op&7);
int rm = (op>>3)&0xf;
sprintf(out,"%s\t%s, %s",name,GetReg(rd),GetReg(rm));
}
void Dis_T_ADDhi(u16 op, char *out){Dis_T_hiop(op,out,"add ");}
void Dis_T_CMPhi(u16 op, char *out){Dis_T_hiop(op,out,"cmp.");}
void Dis_T_MOVhi(u16 op, char *out){Dis_T_hiop(op,out,"mov ");}
void Dis_T_3op(u16 op, char *out, char *name)
{
sprintf(out,"%s\t%s, %s, %s",name,TR0(op),TR1(op),TR2(op));
}
void Dis_T_ADD(u16 op, char *out){Dis_T_3op(op,out,"add.");}
void Dis_T_SUB(u16 op, char *out){Dis_T_3op(op,out,"sub.");}
void Dis_T_2opimm(u16 op, char *out, char *name)
{
sprintf(out,"%s\t%s, %s, %d",name,TR0(op),TR1(op),(op>>6)&7);
}
void Dis_T_ADDimm(u16 op, char *out){Dis_T_2opimm(op,out,"add.");}
void Dis_T_SUBimm(u16 op, char *out){Dis_T_2opimm(op,out,"sub.");}
void Dis_T_Shift(u16 op, char *out,char *name)
{
int shift = (op >> 6) & 31;
sprintf(out,"%s\t%s, %s, %d",name,TR0(op),TR1(op),shift);
}
void Dis_T_LSLimm(u16 op, char *out){Dis_T_Shift(op,out,"lsl.");}
void Dis_T_LSRimm(u16 op, char *out){Dis_T_Shift(op,out,"lsr.");}
void Dis_T_ASRimm(u16 op, char *out){Dis_T_Shift(op,out,"asr.");}
void Dis_T_Imm8(u16 op, char *out,char *name)
{
int value = op & 0xff;
sprintf(out,"%s\t%s, $%02x",name,TR0(op>>8),value);
}
void Dis_T_CMPimm(u16 op, char *out){Dis_T_Imm8(op,out,"cmp.");}
void Dis_T_MOVimm(u16 op, char *out){Dis_T_Imm8(op,out,"mov.");}
void Dis_T_ADDlim(u16 op, char *out){Dis_T_Imm8(op,out,"add.");}
void Dis_T_SUBlim(u16 op, char *out){Dis_T_Imm8(op,out,"sub.");}
void Dis_T_ADDpc(u16 op, char *out)
{
sprintf(out,"add\t%s, pc, $%03x",TR0(op>>8),(op&0xff) << 2);
}
void Dis_T_ADDsp(u16 op, char *out)
{
sprintf(out,"add\t%s, sp, $%03x",TR0(op>>8),(op&0xff) << 2);
}
void Dis_T_multiple(u16 op, char *out, char *name)
{
TCHAR temp[256]={0};
for (int i=0; i<7; i++)
{
if (op&(1<>8),temp);
}
void Dis_T_STMIA(u16 op, char *out) {Dis_T_multiple(op,out,"stmia");}
void Dis_T_LDMIA(u16 op, char *out) {Dis_T_multiple(op,out,"ldmia");}
void Dis_T_ADDspi(u16 op, char *out)
{
sprintf(out,"add\tsp, $%03x",(op&0x7F)*4);
}
void Dis_T_SUBspi(u16 op, char *out)
{
sprintf(out,"sub\tsp, $%03x",(op&0x7F)*4);
}
//stack
void Dis_T_POP(u16 op, char *out)
{
sprintf(out,"pop\t...");
}
void Dis_T_PUSH(u16 op, char *out)
{
sprintf(out,"push\t...");
}
//loadstore
void Dis_T_LDRimm(u16 op, char *out)
{
u32 addr=(disPC&~3)+(op&0xff)*4+4;
sprintf(out,"ldr\t%s, [%08x] (%08x)",TR0(op>>8),addr,ReadMem32Unchecked(addr));
}
void Dis_T_LDRisp(u16 op, char *out)
{
sprintf(out,"ldr\t%s, [sp, $%03x]",TR0(op>>8),(op&0xFF)*4);
}
void Dis_T_ld2opimm(u16 op, char *out, char *name, int mul)
{
sprintf(out,"%s\t%s, [%s + %d]",name,TR0(op),TR1(op),((op>>6)&0x1F) * mul);
}
void Dis_T_LDR(u16 op, char *out) {Dis_T_ld2opimm(op,out,"ldr",4);}
void Dis_T_LDRH(u16 op, char *out) {Dis_T_ld2opimm(op,out,"ldrh",2);}
void Dis_T_LDRB(u16 op, char *out) {Dis_T_ld2opimm(op,out,"ldrb",1);}
void Dis_T_STR(u16 op, char *out) {Dis_T_ld2opimm(op,out,"str",4);}
void Dis_T_STRB(u16 op, char *out) {Dis_T_ld2opimm(op,out,"strb",1);}
void Dis_T_STRH(u16 op, char *out) {Dis_T_ld2opimm(op,out,"strh",2);}
void Dis_T_ld3reg(u16 op, char *out, char *name)
{
sprintf(out,"%s\t%s, [%s + %s]",name,TR0(op),TR1(op),TR2(op));
}
void Dis_T_LDRrof(u16 op, char *out) {Dis_T_ld3reg(op,out,"ldr");}
void Dis_T_LDRBro(u16 op, char *out) {Dis_T_ld3reg(op,out,"ldrb");}
void Dis_T_LDRHro(u16 op, char *out) {Dis_T_ld3reg(op,out,"ldrh");}
void Dis_T_LDRSB(u16 op, char *out) {Dis_T_ld3reg(op,out,"ldrsb");}
void Dis_T_LDRSH(u16 op, char *out) {Dis_T_ld3reg(op,out,"ldrsh");}
void Dis_T_STRrof(u16 op, char *out) {Dis_T_ld3reg(op,out,"str");}
void Dis_T_STRHro(u16 op, char *out) {Dis_T_ld3reg(op,out,"strh");}
void Dis_T_STRBro(u16 op, char *out) {Dis_T_ld3reg(op,out,"strb");}
void Dis_T_STRisp(u16 op, char *out)
{
sprintf(out,"str\t%s, [sp, $%03x]",TR0(op>>8),(op&0xFF)*4);
}
//Software int
void Dis_T_SWI(u16 op, char *out)
{
sprintf(out,"swi\t$%04x",op&0xFF);
}
//branch
void Dis_T_Bcond(u16 op, char *out)
{
sprintf(out,"b%s\t->$%08x",GetCondIdx((op>>8)&0xf),disPC+((s32)(s8)op)*2+4);
}
void Dis_T_B(u16 op, char *out)
{
sprintf(out,"b\t->$%08x",disPC+((s32)SEX11(op))*2+4);
}
void Dis_T_BX(u16 op, char *out)
{
sprintf(out,"bx\t->%s",GetReg((op>>3)&0xF));
}
void Dis_T_BLX(u16 op, char *out)
{
sprintf(out,"blx\t->%s",GetReg((op>>3)&0xF));
}
void Dis_T_BLend(u16 op, char *out)
{
sprintf(out,"-\t-");
}
void Dis_T_BLbig(u16 op, char *out)
{
u16 op2 = ReadMem16Unchecked(disPC+2);
bool bx = (op & (1<<11)) ? true : false;
u32 offset = disPC+4+(SEX11(op)<<12);
offset += (op2 & 0x7ff)*2;
if (bx==0)
offset &=~3;
sprintf(out,"bl%s\t->$%08x",bx?"":"x",offset);
}
}