#include "types.h" #include "emitter.h" #include extern "C"{ #include } int ppc_condition_flags[][3] = { // bo,bi,logical {PPC_CC_T, PPC_CC_OVR,0}, // 0 {PPC_CC_F, PPC_CC_OVR,0}, // 1 {PPC_CC_T, PPC_CC_NEG,1}, // 2 {PPC_CC_F, PPC_CC_NEG,1}, // 3 {PPC_CC_T, PPC_CC_ZER,0}, // 4 {PPC_CC_F, PPC_CC_ZER,0}, // 5 {PPC_CC_F, PPC_CC_POS,1}, // 6 {PPC_CC_T, PPC_CC_POS,1}, // 7 {PPC_CC_A, PPC_CC_NEG,0}, // 8 fake {PPC_CC_A, PPC_CC_NEG,0}, // 9 fake {PPC_CC_A, PPC_CC_NEG,0}, // A fake {PPC_CC_A, PPC_CC_NEG,0}, // B fake {PPC_CC_T, PPC_CC_NEG,0}, // C {PPC_CC_F, PPC_CC_NEG,0}, // D {PPC_CC_F, PPC_CC_POS,0}, // E {PPC_CC_T, PPC_CC_POS,0}, // F }; bool IsS8(u32 value) { if (((value&0xFFFFFF80)==0xFFFFFF80) || (value&0xFFFFFF80)==0 ) return true; else return false; } ppc_ptr ppc_ptr::create(unat ptr) { ppc_ptr rv(0); rv.ptr_int=ptr; return rv; } ppc_ptr_imm ppc_ptr_imm::create(unat ptr) { ppc_ptr_imm rv(0); rv.ptr_int=ptr; return rv; } void* ppc_Label::GetPtr() { return owner->ppc_buff + this->target_opcode; } void ppc_block::Init(dyna_reallocFP* ral,dyna_finalizeFP* alf) { ralloc=ral; allocfin=alf; ppc_buff=0; ppc_indx=0; ppc_size=0; do_realloc=true; bc_tab_next_idx=0; } //Generates code.if user_data is non zero , user_data_size bytes are allocated after the executable code //and user_data is set to the first byte of em.Allways 16 byte alligned void* ppc_block::Generate() { if (do_realloc) { u8* final_buffer=0; final_buffer=(u8*)allocfin(ppc_buff,ppc_size,ppc_indx); if (final_buffer==0) return 0; ppc_buff=final_buffer; } ApplyPatches(ppc_buff); memicbi(ppc_buff,ppc_indx); bool force=false; // force=true; // force=(u32)ppc_buff>=0x8054f510; if(do_disasm || force) printf("Gen %p %04x %04x\n",ppc_buff,ppc_size,ppc_indx); if (do_disasm || force) for(u32 i=0;i externs; void Apply(u8* base) { for (u32 i=0;iApply((u8*)lolwhut); } bool ppc_block_externs::Modify(u32 offs,u8* dst) { return ((ppc_block_externs_i*)this)->Modify(offs,dst); } void ppc_block_externs::Free() { ((ppc_block_externs_i*)this)->Free(); } ppc_block_externs* ppc_block::GetExterns() { ppc_block_externs_i* rv=new ppc_block_externs_i(); u8* base=ppc_buff; for (u32 i=0;iowner==this) dest = base + patches[i].lbl->target_opcode; else dest = patches[i].lbl->owner->ppc_buff + patches[i].lbl->target_opcode; } u32 start_diff=(u32)(dest-base); if (start_diff>=ppc_indx) { rv->Add(dest,patches[i].offset,patches[i].type&0xF); } } return rv; } /*void ppc_block::CopyTo(void* to) { memcpy(to,ppc_buff,ppc_indx); free(ppc_buff); ppc_buff=(u8*)to; ApplyPatches(ppc_buff); } */ //wut ? void ppc_block::ApplyPatches(u8* base) { for (u32 i=0;iowner==this) dest = base + patches[i].lbl->target_opcode; else dest = patches[i].lbl->owner->ppc_buff + patches[i].lbl->target_opcode; } s32 diff=(s32)(dest-diff_offset); if ((patches[i].type&0xF)==1) { verify(IsS8(diff)); *code_offset=(u8)diff; } else if ((patches[i].type&0xF)==2) { *(u16*)code_offset=(u16)diff; } else if ((patches[i].type&0xF)==4) { *(u32*)code_offset=(u32)diff; } else if ((patches[i].type&0xF)==5) // 5 is for BC { verify(!(diff&3)); verify(diff<0x10000); *(u32*)code_offset|=(u32)diff&0xffff; } else if ((patches[i].type&0xF)==6) // 6 is for B { verify(!(diff&3)); verify(diff<0x04000000); *(u32*)code_offset|=(u32)diff&0x03ffffff; } } /* process branches */ u32 i; PowerPC_instr op,newop; u32 opaddr,jmpaddr; for(i=0;i>2,0,0); *(PowerPC_instr*)opaddr=newop; } else if((op&0xfc000000) == 1<<26) // bl { //printf("bl %08x %08x %08x\n",opaddr,op,jmpaddr); GEN_B(newop,jmpaddr>>2,0,1); *(PowerPC_instr*)opaddr=newop; } else if((op&0xfc000000) == 5<<26) // bc { u32 absaddr=bc_tab[(op>>2)&0x3fff]; jmpaddr=absaddr-opaddr; if((s32)jmpaddr>=-32768 && (s32)jmpaddr<=32767) { //printf("bc %08x %08x %08x\n",opaddr,op,jmpaddr); } else { // invert branch int bo,bo_n=0; bo=(op>>PPC_RD_SHIFT)&PPC_REG_MASK; switch(bo&~3){ case PPC_CC_F: bo_n=PPC_CC_T;break; case PPC_CC_T: bo_n=PPC_CC_F;break; default: verify(false); } bo_n|=bo&3; op&=~(PPC_REG_MASK<=-(1<<25) && (s32)jmpaddr<=(1<<25)); GEN_B(b,jmpaddr>>2,0,lk); verify(*((PowerPC_instr*)opaddr+1)==PPC_NOP); *((PowerPC_instr*)opaddr+1)=b; jmpaddr=8; //printf("ind bc %08x %08x %08x\n",opaddr,op,jmpaddr); } newop=op&~0xfc00fffc; PPC_SET_OPCODE(newop,PPC_OPCODE_BC); PPC_SET_BD(newop,jmpaddr>>2); *(PowerPC_instr*)opaddr=newop; } } } ppc_block::ppc_block() { labels.reserve(64); do_disasm=false; do_disasm_imm=false; } ppc_block::~ppc_block() { //ensure everything is free'd :) Free(); } //Will free any used resources exept generated code void ppc_block::Free() { for (u32 i =0;ippc_size<(size+ppc_indx)) { verify(do_realloc!=false); u32 old_size=ppc_size; ppc_size+=128; ppc_size*=2; ppc_buff=(u8*)ralloc(ppc_buff,old_size,ppc_size); } } void ppc_block::write8(u32 value) { ppc_buffer_ensure(15); //printf("ppc_block::write8 %02X\n",value); ppc_buff[ppc_indx]=value; ppc_indx+=1; } void ppc_block::write16(u32 value) { ppc_buffer_ensure(15); //printf("ppc_block::write16 %04X\n",value); *(u16*)&ppc_buff[ppc_indx]=value; ppc_indx+=2; } void ppc_block::write32(u32 value) { ppc_buffer_ensure(15); //printf("ppc_block::write32 %08X\n",value); // if(do_disasm_imm) printf("do_disasm_imm\n"); if (do_disasm_imm) disassemble(ppc_indx,value); *(u32*)&ppc_buff[ppc_indx]=value; ppc_indx+=4; } //Label related code //NOTE : Label position in mem must not chainge void ppc_block::CreateLabel(ppc_Label* lbl,bool mark,u32 sz) { memset(lbl,0xFFFFFFFF,sizeof(ppc_Label)); lbl->owner=this; lbl->marked=false; lbl->patch_sz=sz; if (mark) MarkLabel(lbl); } //Allocate a label and create it :).Will be delete'd when calling free and/or dtor ppc_Label* ppc_block::CreateLabel(bool mark,u32 sz) { ppc_Label* lbl = new ppc_Label(); CreateLabel(lbl,mark,sz); labels.push_back(lbl); return lbl; } //Mark a label so that it points to next emitted opcode void ppc_block::MarkLabel(ppc_Label* lbl) { verify(lbl->marked==false); lbl->marked=true; lbl->target_opcode=ppc_indx; //lbl->target_opcode=(u32)opcodes.size(); } ppc_gpr_reg ppc_block::getHighReg(u16 value) { verify((((u32)(&sh4r))&0xffff)==0); if(value==HA((u32)&sh4r)) { return (ppc_reg)RSH4R; } EMIT_LIS(this,RTMP,value); return (ppc_reg)RTMP; } void ppc_block::emitBranch(void * addr, int lk) { u32 faa=(u32)addr&0x7fffffff; u32 aa=faa&0x03ffffff; if(aa==faa) // 26 bits max for rel { write32(aa|((lk?1:0)<<26)); // primary opcode 0=b; 1=bl } else { emitLongBranch(addr,lk); } } void ppc_block::emitLongBranch(void * addr, int lk) { EMIT_LIS(this,RTMP,((u32)addr)>>16); EMIT_ORI(this,RTMP,RTMP,(u32)addr); EMIT_MTLR(this,RTMP); EMIT_BLR(this,lk); } void ppc_block::emitBranchConditional(void * addr, int bo, int bi, int lk, int force_short) { PowerPC_instr ppc=NEW_PPC_INSTR(); PPC_SET_OPCODE(ppc,5); // primary opcode 5=bc verify(bc_tab_next_idx<0x4000); bc_tab[bc_tab_next_idx]=(u32)addr; PPC_SET_BD(ppc,bc_tab_next_idx++); PPC_SET_BO(ppc,bo); PPC_SET_BI(ppc,bi); PPC_SET_LK(ppc,lk); write32(ppc); if (!force_short) write32(PPC_NOP); } void ppc_block::emitLoadDouble(ppc_fpr_reg reg, void * addr) { ppc_reg hr=getHighReg(HA((u32)addr)); EMIT_LFD(this,reg,(u32)addr,hr); } void ppc_block::emitLoadFloat(ppc_fpr_reg reg, void * addr) { ppc_reg hr=getHighReg(HA((u32)addr)); EMIT_LFS(this,reg,(u32)addr,hr); } void ppc_block::emitLoad32(ppc_gpr_reg reg, void * addr) { ppc_reg hr=getHighReg(HA((u32)addr)); EMIT_LWZ(this,reg,(u32)addr,hr); } void ppc_block::emitLoad16(ppc_gpr_reg reg, void * addr) { ppc_reg hr=getHighReg(HA((u32)addr)); EMIT_LHZ(this,reg,(u32)addr,hr); } void ppc_block::emitLoad8(ppc_gpr_reg reg, void * addr) { ppc_reg hr=getHighReg(HA((u32)addr)); EMIT_LBZ(this,reg,(u32)addr,hr); } void ppc_block::emitStoreDouble(void * addr, ppc_fpr_reg reg) { ppc_reg hr=getHighReg(HA((u32)addr)); EMIT_STFD(this,reg,(u32)addr,hr); } void ppc_block::emitStoreFloat(void * addr, ppc_fpr_reg reg) { ppc_reg hr=getHighReg(HA((u32)addr)); EMIT_STFS(this,reg,(u32)addr,hr); } void ppc_block::emitStore32(void * addr, ppc_gpr_reg reg) { ppc_reg hr=getHighReg(HA((u32)addr)); EMIT_STW(this,reg,(u32)addr,hr); } void ppc_block::emitStore16(void * addr, ppc_gpr_reg reg) { ppc_reg hr=getHighReg(HA((u32)addr)); EMIT_STH(this,reg,(u32)addr,hr); } void ppc_block::emitStore8(void * addr, ppc_gpr_reg reg) { ppc_reg hr=getHighReg(HA((u32)addr)); EMIT_STB(this,reg,(u32)addr,hr); } void ppc_block::emitMoveRegister(ppc_gpr_reg to,ppc_gpr_reg from) { EMIT_OR(this,to,from,from); } void ppc_block::emitLoadImmediate32(ppc_gpr_reg reg, u32 val) { if((s32)val>=-32768 && (s32)val<=32767) { EMIT_LI(this,reg,val); } else { EMIT_LIS(this,reg,val>>16); if (val&0xffff) EMIT_ORI(this,reg,reg,val); } } void ppc_block::emitBranchConditionalToLabel(ppc_Label * lab,int lk,int bo,int bi) { verify(lab); verify((u32)lab>=0x80000000); code_patch cp; cp.type=5|16; cp.lbl=lab; cp.offset=ppc_indx; // next op patches.push_back(cp); EMIT_BC(this,0,0,lk,bo,bi); } void ppc_block::emitBranchToLabel(ppc_Label * lab,int lk) { verify(lab); verify((u32)lab>=0x80000000); code_patch cp; cp.type=6|16; cp.lbl=lab; cp.offset=ppc_indx; // next op patches.push_back(cp); EMIT_B(this,0,0,lk); } extern "C" { void debugValue(u32 value){ printf("dv %d(%x)\n",value,value); } } static u32 r[32]; void ppc_block::emitDebugValue(u32 value) { emitStore32(&r[3],R3); emitStore32(&r[4],R4); emitStore32(&r[5],R5); emitLoadImmediate32(R3,value); emitBranch((void*)debugValue,1); emitLoad32(R3,&r[3]); emitLoad32(R4,&r[4]); emitLoad32(R5,&r[5]); } void ppc_block::emitDebugReg(ppc_gpr_reg reg) { emitStore32(&r[3],R3); emitStore32(&r[4],R4); emitStore32(&r[5],R5); if (reg!=R3) emitMoveRegister(R3,reg); emitBranch((void*)debugValue,1); emitLoad32(R3,&r[3]); emitLoad32(R4,&r[4]); emitLoad32(R5,&r[5]); } void ppc_block::vectorWriteBack(u32 reg) { if (reg>=xf_0 && reg<=xf_15) { u32 vr=(reg-xf_0)/4; // printf("VectorWriteBack %d %d\n",reg,vr); switch (vr) { case 0: EMIT_LI(this,RTMP,offsetof(Sh4RegContext,xf[0])); EMIT_STVX(this,RXF0,RTMP,RSH4R); break; case 1: EMIT_LI(this,RTMP,offsetof(Sh4RegContext,xf[4])); EMIT_STVX(this,RXF4,RTMP,RSH4R); break; case 2: EMIT_LI(this,RTMP,offsetof(Sh4RegContext,xf[8])); EMIT_STVX(this,RXF8,RTMP,RSH4R); break; case 3: EMIT_LI(this,RTMP,offsetof(Sh4RegContext,xf[12])); EMIT_STVX(this,RXF12,RTMP,RSH4R); break; } } } void ppc_block::vectorReload(u32 reg) { if (reg>=xf_0 && reg<=xf_15) { u32 vr=(reg-xf_0)/4; // printf("VectorReload %d %d\n",reg,vr); switch (vr) { case 0: EMIT_LI(this,RTMP,offsetof(Sh4RegContext,xf[0])); EMIT_LVX(this,RXF0,RTMP,RSH4R); break; case 1: EMIT_LI(this,RTMP,offsetof(Sh4RegContext,xf[4])); EMIT_LVX(this,RXF4,RTMP,RSH4R); break; case 2: EMIT_LI(this,RTMP,offsetof(Sh4RegContext,xf[8])); EMIT_LVX(this,RXF8,RTMP,RSH4R); break; case 3: EMIT_LI(this,RTMP,offsetof(Sh4RegContext,xf[12])); EMIT_LVX(this,RXF12,RTMP,RSH4R); break; } } }