www.pudn.com > potemkin_sourceforPSP.rar > ARMLoadStore.cpp
#include "stdafx.h"
#include "../../Globals.h"
#include "ARM.h"
#include "ARMCompiler.h"
#include "ARMTables.h"
#include "ARMAnalyst.h"
#include "../IR/IR.h"
#include "../MemMap.h"
//////////////////////////////////////////////////////////////////////////
// ARM
//////////////////////////////////////////////////////////////////////////
namespace ARMInstructions
{
#define RDi(x) ((x>>12)&0xF)
#define RNi(x) ((x>>16)&0xF)
#define RMi(x) (x&0xf)
#define RSi(x) ((x>>8)&0xF)
void Comp_ldst(u32 op, IROpID opid, int size)
{
IR_StartBranch(op>>28);
IROpID signop = (op & (1<<23)) ? IR_ADD : IR_SUB;
int rd = RDi(op);
int rn = RNi(op);
int rm = RMi(op);
if (op & (1<<25))
{
//reg offset
u32 shiftAmt = (op>>7) & 0x1F;
IROpID shiftOp;
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?IR_ROR:IR_RRX; if (!shiftAmt) shiftAmt=1; break;//ROR / RRX
}
Compiler_AddCycles(1);
if (!(op & (1<<24)))
{
_dbg_assert_msg_(CPU,0,"Unimplemented postindex form of a load/store instruction");
//postindex
//IR_Add(opid,0,RNi(op),
//IR_Add(shiftOp,0,IRTEMP0,RMi(op),IRImm(shiftAmt));
if (shiftOp == IR_LSL && 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
{
//_dbg_assert_msg_(CPU,0,"Unimplemented preindex / normal form of a load/store instruction");
//preindex or normal
bool preindex = (op & (1<<21)) ? true : false;
if (shiftOp == IR_LSL && shiftAmt == 0)
{
int tempReg = IRTEMP0;
if (preindex)
tempReg = rn;
else
IR_Add(IR_MOV,0,tempReg,rn);
IR_Add(signop,0,tempReg,tempReg,rm);
IR_Add(opid,0,rd,tempReg,rd,IRLS_UNKNOWN);
}//sprintf(part2,"[%s %c %s]%s",RN(op),sign,RM(op),preindex);
else
{
int tempReg = IRTEMP0;
if (preindex)
tempReg = rn;
else
IR_Add(IR_MOV,0,tempReg,rn);
IR_Add(shiftOp,0,IRTEMP1,rm,IRImm(shiftAmt));
IR_Add(signop,0,tempReg,rn,IRTEMP1);
IR_Add(opid,0,rd,tempReg,rd,IRLS_UNKNOWN);
}//sprintf(part2,"[%s %c %s %s %d]%s",RN(op),sign,RM(op), shifttype, shiftAmt,preindex);
}
}
else
{
//imm offset
u32 imm = op&0xFFF;
if (!(op & (1<<24)))
{
//postindex
IR_Add(opid,0,rd,rn,rd,IRLS_UNKNOWN);
if (imm)
IR_Add(signop,0,rn,rn,IRImm(imm));
}
else
{
//preindex or normal
bool preindex = (op & (1<<21)) ? true : false;
//immediate offset
if (RNi(op) == 15)
{
u32 addr = compiler_pc+8;
signop==IR_ADD ? addr+=imm : addr-=imm;
if (1)
IR_Add(opid,0,rd,IRImm(addr),rd,IRLS_UNKNOWN);
else //aggressive optimization
{
switch(opid) {
case IR_LOADBYTE:
IR_Add(IR_MOV,0,rd,IRImm((u32)ReadMem8(addr)));
break;
case IR_LOADHALF:
IR_Add(IR_MOV,0,rd,IRImm((u32)ReadMem16(addr)));
break;
case IR_LOADWORD:
IR_Add(IR_MOV,0,rd,IRImm((u32)ReadMem32(addr)));
break;
default:
IR_Add(opid,0,rd,IRImm(addr),rd,(addr&3)?IRLS_UNALIGNED:IRLS_ALIGNED);
break;
}
}
}
else
{
if (imm!=0)
{
int addrReg = IRTEMP0;
if (preindex)
addrReg = rn;
IR_Add(signop,0,addrReg,rn,IRImm(imm));
IR_Add(opid,0,rd,addrReg,rd,IRLS_UNKNOWN);
}
else
{
IR_Add(opid,0,rd,rn,rd,IRLS_UNKNOWN);
}
}
}
}
if (rd == ARM_REG_PC && opid == IR_LOADWORD)
{
IR_Add(IR_LEAVE,0,0,ARM_REG_PC,IRImm((u32)IRL_BRARM));
if (!IR_IsInBranch())
Compiler_ExitCompile();
Compiler_AddCycles(3);
}
IR_EndBranch();
Compiler_AddCycles(1);
}
void Comp_ldst2(u32 op, IROpID opid, int signExtend)
{
IR_StartBranch(op>>28);
IROpID signop = (op & (1<<23)) ? IR_ADD : IR_SUB;
int rd = RDi(op);
int rn = RNi(op);
int rm = RMi(op);
if (op&(1<<22))
{
//immediate offset
u32 imm = (op&0xF) | ((op>>4)&0xF0);
if (!(op & (1<<24)))
{
//postindexed
IR_Add(opid,0,rd,rn,rd,IRLS_UNKNOWN);
if (imm!=0)
IR_Add(signop,0,rn,rn,IRImm(imm));
}
else
{
//preindexed or normal
bool preindex = (op&(1<<21)) ? true : false;
int tempReg;
if (preindex || imm == 0)
tempReg = rn;
else
tempReg = IRTEMP0;
if (imm!=0)
IR_Add(signop,0,tempReg,rn,IRImm(imm));
IR_Add(opid,0,rd,tempReg,rd,IRLS_UNKNOWN);
}
}
else
{
//register offset
if (!(op & (1<<24)))
{
//postindexed
IR_Add(opid,0,rd,rn,rd,IRLS_UNKNOWN);
IR_Add(signop,0,rn,rn,rm);
}
else
{
//preindexed or normal
bool preindex = (op&(1<<21)) ? true : false;
int tempReg;
if (preindex)
tempReg = rn;
else
tempReg = IRTEMP0;
IR_Add(signop,0,tempReg,rn,rm);
IR_Add(opid,0,rd,tempReg,rd,IRLS_UNKNOWN);
}
}
if (signExtend)
{
IR_Add(signExtend==8 ? IR_SEX8 : IR_SEX16,0,rd,rd);
}
IR_EndBranch();
Compiler_AddCycles(1);
}
void Comp_LDRB(u32 op) {Comp_ldst(op,IR_LOADBYTE,1); Compiler_AddCycles(1);}
void Comp_STRB(u32 op) {Comp_ldst(op,IR_STOREBYTE,1);}
void Comp_LDR(u32 op) {Comp_ldst(op,IR_LOADWORD,4); Compiler_AddCycles(1);}
void Comp_STR(u32 op) {Comp_ldst(op,IR_STOREWORD,4);}
void Comp_LDRH(u32 op) {Comp_ldst2(op,IR_LOADHALF,0);Compiler_AddCycles(1);}
void Comp_STRH(u32 op) {Comp_ldst2(op,IR_STOREHALF,0);}
void Comp_LDRSB(u32 op){Comp_ldst2(op,IR_LOADBYTE,8);Compiler_AddCycles(1);}
void Comp_LDRSH(u32 op){Comp_ldst2(op,IR_LOADHALF,16);Compiler_AddCycles(1);}
void Comp_STM(u32 op)
{
IR_StartBranch(op>>28);
bool pre = (op&(1<<24)) ? true : false; //before after
IROpID direction = (op&(1<<23)) ? IR_ADD : IR_SUB;
bool PSRuser = (op&(1<<22)) ? true : false; // ^
bool writeback = (op&(1<<21)) ? true : false;
int rn = (op>>16) & 0xF;
int pointerReg = rn;
_dbg_assert_msg_(CPU,rn!=15,"LDM using r15 as base register!");
if (!writeback)
{
IR_Add(IR_MOV,0,IRTEMP0,rn);
pointerReg = IRTEMP0;
}
int count = 0;
for (int i=0; i<16; i++)
{
int n = (direction == IR_SUB)?(15-i):i;
if (op & (1<>28);
bool pre = (op&(1<<24)) ? true : false; //before after
IROpID direction = (op&(1<<23)) ? IR_ADD : IR_SUB;
bool PSRuser = (op&(1<<22)) ? true : false; // ^
bool writeback = (op&(1<<21)) ? true : false;
int rn = (op>>16) & 0xF;
int pointerReg = rn;
_dbg_assert_msg_(CPU,rn!=15,"LDM using r15 as base register!");
bool loadingPC = (op&(1<<15)) ? true : false;
if (loadingPC)
{
if (PSRuser)
{
_dbg_assert_msg_(CPU,0,"PSRuser loading PC :(");
//cpsr = spsr
}
}
else
{
if (PSRuser)
{
_dbg_assert_msg_(CPU,0,"PSRuser :(");
//in privil; user bank transfered instead
//EEEEEEEEEEEEEEVIL!!!!!!!!!!!!!!!!!!! >:(
}
}
if (!writeback)
{
IR_Add(IR_MOV,0,IRTEMP0,rn);
pointerReg = IRTEMP0;
}
int count = 0;
for (int i=0; i<16; i++)
{
int n = (direction == IR_SUB)?(15-i):i;
if (op & (1<>28);
IR_Add(IR_INTERPRET,0,0,IRImm(op));
IR_EndBranch();
}
void Comp_MSRreg(u32 op)
{
IR_StartBranch(op>>28);
if ((op&(1<<16))&&((op>>22)&1)) // if write to mode bits
IR_Add(IR_FLUSHREGS,0,0,0); //regs will change, make recompiler aware
IR_Add(IR_INTERPRET,0,0,IRImm(op));
IR_EndBranch();
}
void Comp_MSRimm(u32 op)
{
IR_StartBranch(op>>28);
if ((op&(1<<16))&&((op>>22)&1)) // if write to mode bits
IR_Add(IR_FLUSHREGS,0,0,0); //regs will change, make recompiler aware
IR_Add(IR_INTERPRET,0,0,IRImm(op));
IR_EndBranch();
}
void Comp_MCR(u32 op)
{
IR_StartBranch(op>>28);
IR_Add(IR_INTERPRET,0,0,IRImm(op));
IR_EndBranch();
}
void Comp_MRC(u32 op)
{
IR_StartBranch(op>>28);
IR_Add(IR_INTERPRET,0,0,IRImm(op));
IR_EndBranch();
}
void Comp_STC(u32 op)
{
IR_StartBranch(op>>28);
IR_Add(IR_INTERPRET,0,0,IRImm(op));
IR_EndBranch();
}
void Comp_LDC(u32 op)
{
IR_StartBranch(op>>28);
IR_Add(IR_INTERPRET,0,0,IRImm(op));
IR_EndBranch();
}
void Comp_SWP(u32 op)
{
int rd = (op>>12) & 0xF;
int rn = (op>>16) & 0xF;
int rm = (op ) & 0xF;
_dbg_assert_msg_(CPU,rd != 15 && rn != 15 && rm != 15, "r15 used as operand in SWP");
IR_StartBranch(op>>28);
IR_Add(IR_LOADWORD,0,IRTEMP0,rn,0,IRLS_UNKNOWN);
IR_Add(IR_STOREWORD,0,0,rn,rm,IRLS_UNKNOWN);
IR_Add(IR_MOV,0,rd,IRTEMP0);
IR_EndBranch();
}
void Comp_SWPB(u32 op)
{
int rd = (op>>12) & 0xF;
int rn = (op>>16) & 0xF;
int rm = (op ) & 0xF;
_dbg_assert_msg_(CPU,rd != 15 && rn != 15 && rm != 15, "r15 used as operand in SWPB");
IR_StartBranch(op>>28);
IR_Add(IR_LOADBYTE,0,IRTEMP0,rn,IRLS_ALIGNED);
IR_Add(IR_STOREBYTE,0,0,rn,rm,IRLS_ALIGNED);
IR_Add(IR_MOV,0,rd,IRTEMP0);
IR_EndBranch();
}
}