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