www.pudn.com > potemkin_sourceforPSP.rar > ARMDataProcessing.cpp
#include "stdafx.h"
#include "../../Globals.h"
#include "ARM.h"
#include "ARMCompiler.h"
#include "ARMAnalyst.h"
#include "../IR/IR.h"
//////////////////////////////////////////////////////////////////////////
// ARM
//////////////////////////////////////////////////////////////////////////
namespace ARMInstructions
{
//decompose a data processing instruction into IR. Quite a bit of logic!
void Comp_bitwise1(u32 op, IROpID irop, bool secondIn, int fm, bool wantsC = false)
{
IR_StartBranch(op>>28);
InstructionInfo info = CurrentAnalysis();
InstructionInfo opInfo = ARMGetInfo(op);
int rd = (op>>12) & 0xF;
int rn = (op>>16) & 0xF;
int rs = (op>>8 ) & 0xF;
int rm = (op ) & 0xF;
int Sflag = (op>>20) & 1;
if (rd == ARM_REG_PC && Sflag)
info.flagsOut = 0;
if ((op&(1<<25))) //imm shift
{
u32 cnst = op & 0xFF;
u32 shift = ((op >> 8) & 0xF) << 1;
u32 shifterOperand = _rotr(cnst,shift);
u32 shifter_carry_out = shifterOperand>>31;
if (shift!=0 && (info.flagsOut & FL_C) && !(fm&FL_C) && !wantsC)
IR_Add(IR_SETFLAG,FL_C,0,IRImm(shifter_carry_out));
if (secondIn)
IR_Add(irop, info.flagsOut&fm, rd, IRReg(rn), IRImm(shifterOperand));
else
IR_Add(irop, info.flagsOut&fm, rd, IRImm(shifterOperand));
}
else
{
int shiftType = (op>>5)&3;
if ((op&0x10)) //reg shift
{
IROpID shiftOp;
switch((op>>5) & 0x3)
{
case 0: shiftOp = IR_LSL; break;
case 1: shiftOp = IR_LSR; break;
case 2: shiftOp = IR_ASR; break;
case 3: shiftOp = IR_ROR; break;
}
IR_Add(shiftOp,wantsC?0:(info.flagsOut&FL_C),IRTEMP0,rm,rs);
if (secondIn)
IR_Add(irop, info.flagsOut&fm, rd, IRReg(rn), IRTEMP0);
else
IR_Add(irop, info.flagsOut&fm, rd, IRTEMP0);
Compiler_AddCycles(1);
}
else //immediate shift
{
u32 shiftAmt = (op>>7) & 0x1F;
IROpID shiftOp;
bool zero = false;
bool copyTop = false;
switch((op>>5) & 0x3)
{
case 0: shiftOp = IR_LSL; break;
case 1: shiftOp = IR_LSR; if (shiftAmt==0) {shiftAmt=32;} break;
case 2: shiftOp = IR_ASR; if (shiftAmt==0) {shiftAmt=32;} break;
case 3: shiftOp = (shiftAmt==0)?IR_RRX:IR_ROR; break;
}
/* causes problems with glass
if (shiftOp == IR_LSL && irop == IR_MOV)
{
IR_Add(shiftOp,wantsC?0:(info.flagsOut&FL_C),rd,rm,IRImm(shiftAmt));
}
else*/
{
int tempReg;
if (shiftOp == IR_LSL && shiftAmt == 0)
tempReg = rm;
else
{
if (shiftAmt == 32) //hack for big shifts that x86 don't support
{ //possibly this is better done in x86 backend
IR_Add(shiftOp,0,IRTEMP0,IRReg(rm),IRImm((u32)31));
IR_Add(shiftOp,info.flagsOut&FL_C,IRTEMP0,IRTEMP0,IRImm((u32)1));
}
else
IR_Add(shiftOp,wantsC?0:(info.flagsOut&FL_C),IRTEMP0,IRReg(rm),IRImm(shiftAmt));
tempReg = IRTEMP0;
}
if (secondIn)
IR_Add(irop, info.flagsOut&fm, rd, IRReg(rn), IRReg(tempReg));
else
IR_Add(irop, info.flagsOut&fm, rd, IRReg(tempReg));
}
}
}
if (rd == ARM_REG_PC)
{
//if sflag set RTE so we update cpsr
IR_Add(IR_LEAVE,0,0,ARM_REG_PC,Sflag ? IRL_RTE : IRL_BRARM);
if (Sflag && irop != IR_MOV && irop != IR_SUB)
{
_dbg_assert_msg_(CPU, 0, "Instruction other than MOV and SUB used to return from interrupt");
}
if (!IR_IsInBranch())
Compiler_ExitCompile();
Compiler_AddCycles(1); //2 for logical, but hey
}
IR_EndBranch();
}
void Comp_AND(u32 op) {Comp_bitwise1(op,IR_AND,true,~FL_C);}
void Comp_EOR(u32 op) {Comp_bitwise1(op,IR_XOR,true,~FL_C);}
void Comp_ORR(u32 op) {Comp_bitwise1(op,IR_OR,true,~FL_C);}
void Comp_BIC(u32 op) {Comp_bitwise1(op,IR_BIC,true,~FL_C);}
void Comp_SUB(u32 op) {Comp_bitwise1(op,IR_SUB,true,0xF);}
void Comp_RSB(u32 op) {Comp_bitwise1(op,IR_RSB,true,0xF);}
void Comp_ADD(u32 op) {Comp_bitwise1(op,IR_ADD,true,0xF);}
void Comp_ADC(u32 op) {Comp_bitwise1(op,IR_ADC,true,0xF,true);}
void Comp_SBC(u32 op) {Comp_bitwise1(op,IR_SBC,true,0xF,true);}
void Comp_RSC(u32 op) {Comp_bitwise1(op,IR_RSC,true,0xF);}
void Comp_TST(u32 op) {Comp_bitwise1(op,IR_TST,true,~FL_C);}
void Comp_TEQ(u32 op) {Comp_bitwise1(op,IR_TEQ,true,~FL_C);}
void Comp_CMP(u32 op) {Comp_bitwise1(op,IR_CMP,true,0xF);}
void Comp_CMN(u32 op) {Comp_bitwise1(op,IR_CMN,true,0xF);}
void Comp_MOV(u32 op) {Comp_bitwise1(op,IR_MOV,false,~FL_C);}
void Comp_MVN(u32 op) {Comp_bitwise1(op,IR_NOT,false,~FL_C);}
void Comp_CLZ(u32 op)
{
IR_StartBranch(op>>28);
InstructionInfo &info = CurrentAnalysis();
int rd = (op>>12)&0xF;
int rm = (op)&0xF;
IR_Add(IR_CLZ,info.flagsOut,rd,IRReg(rm));
IR_EndBranch();
}
//Multiply
void Comp_MUL(u32 op)
{
IR_StartBranch(op>>28);
InstructionInfo &info = CurrentAnalysis();
int rd = (op>>16)&0xF;
int rs = (op>>8)&0xF;
int rm = (op)&0xF;
IR_Add(IR_MUL,info.flagsOut,rd,IRReg(rm),IRReg(rs));
IR_EndBranch();
Compiler_AddCycles(info.flagsOut?3:1);
}
void Comp_MLA(u32 op)
{
IR_StartBranch(op>>28);
InstructionInfo &info = CurrentAnalysis();
int rd = (op>>16)&0xF;
int rn = (op>>12)&0xF;
int rs = (op>>8)&0xF;
int rm = (op)&0xF;
IR_Add(IR_MUL,0,IRTEMP0,rm,rs);
IR_Add(IR_ADD,info.flagsOut,rd,IRReg(rn),IRReg(IRTEMP0));
IR_EndBranch();
Compiler_AddCycles(info.flagsOut?3:1);
}
void Comp_UMULL(u32 op)
{
InstructionInfo &info = CurrentAnalysis();
int rm = op&0xf;
int rs = (op>>8)&0xf;
int rdhi = (op>>16)&0xf;
int rdlo = (op>>12)&0xf;
IR_Add(IR_UMUL64,info.flagsOut,rdlo,rm,rs,0,rdhi);
Compiler_AddCycles(2);
}
void Comp_UMLAL(u32 op)
{
InstructionInfo &info = CurrentAnalysis();
int rm = op&0xf;
int rs = (op>>8)&0xf;
int rdhi = (op>>16)&0xf;
int rdlo = (op>>12)&0xf;
IR_Add(IR_UMAD64,info.flagsOut,rdlo,rm,rs,0,rdhi);
Compiler_AddCycles(2);
}
void Comp_SMULL(u32 op)
{
InstructionInfo &info = CurrentAnalysis();
int rm = op&0xf;
int rs = (op>>8)&0xf;
int rdhi = (op>>16)&0xf;
int rdlo = (op>>12)&0xf;
IR_Add(IR_MUL64,info.flagsOut,rdlo,rm,rs,0,rdhi);
Compiler_AddCycles(2);
}
void Comp_SMLAL(u32 op)
{
InstructionInfo &info = CurrentAnalysis();
int rm = op&0xf;
int rs = (op>>8)&0xf;
int rdhi = (op>>16)&0xf;
int rdlo = (op>>12)&0xf;
IR_Add(IR_MAD64,info.flagsOut,rdlo,rm,rs,0,rdhi);
Compiler_AddCycles(2);
}
}