- literal_pool(256);
- assem_debug("do_cop1stub %x\n",start+stubs[n][3]*4);
- set_jump_target(stubs[n][1],(int)out);
- int i=stubs[n][3];
-// int rs=stubs[n][4];
- struct regstat *i_regs=(struct regstat *)stubs[n][5];
- int ds=stubs[n][6];
- if(!ds) {
- load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i);
- //if(i_regs!=®s[i]) printf("oops: regs[i]=%x i_regs=%x",(int)®s[i],(int)i_regs);
- }
- //else {printf("fp exception in delay slot\n");}
- wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty);
- if(regs[i].regmap_entry[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG);
- emit_movimm(start+(i-ds)*4,EAX); // Get PC
- emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle...
- emit_jmp(ds?(int)fp_exception_ds:(int)fp_exception);
-}
-
-#ifndef DISABLE_TLB
-
-/* TLB */
-
-int do_tlb_r(int s,int ar,int map,int x,int a,int shift,int c,u_int addr)
-{
- if(c) {
- if((signed int)addr>=(signed int)0xC0000000) {
- // address_generation already loaded the const
- emit_readword_dualindexedx4(FP,map,map);
- }
- else
- return -1; // No mapping
- }
- else {
- assert(s!=map);
- emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,map);
- emit_addsr12(map,s,map);
- // Schedule this while we wait on the load
- //if(x) emit_xorimm(s,x,ar);
- if(shift>=0) emit_shlimm(s,3,shift);
- if(~a) emit_andimm(s,a,ar);
- emit_readword_dualindexedx4(FP,map,map);
- }
- return map;
-}
-int do_tlb_r_branch(int map, int c, u_int addr, int *jaddr)
-{
- if(!c||(signed int)addr>=(signed int)0xC0000000) {
- emit_test(map,map);
- *jaddr=(int)out;
- emit_js(0);
- }
- return map;
-}
-
-int gen_tlb_addr_r(int ar, int map) {
- if(map>=0) {
- assem_debug("add %s,%s,%s lsl #2\n",regname[ar],regname[ar],regname[map]);
- output_w32(0xe0800100|rd_rn_rm(ar,ar,map));
- }
-}
-
-int do_tlb_w(int s,int ar,int map,int x,int c,u_int addr)
-{
- if(c) {
- if(addr<0x80800000||addr>=0xC0000000) {
- // address_generation already loaded the const
- emit_readword_dualindexedx4(FP,map,map);
- }
- else
- return -1; // No mapping
- }
- else {
- assert(s!=map);
- emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,map);
- emit_addsr12(map,s,map);
- // Schedule this while we wait on the load
- //if(x) emit_xorimm(s,x,ar);
- emit_readword_dualindexedx4(FP,map,map);
- }
- return map;
-}
-int do_tlb_w_branch(int map, int c, u_int addr, int *jaddr)
-{
- if(!c||addr<0x80800000||addr>=0xC0000000) {
- emit_testimm(map,0x40000000);
- *jaddr=(int)out;
- emit_jne(0);
- }
-}
-
-int gen_tlb_addr_w(int ar, int map) {
- if(map>=0) {
- assem_debug("add %s,%s,%s lsl #2\n",regname[ar],regname[ar],regname[map]);
- output_w32(0xe0800100|rd_rn_rm(ar,ar,map));
- }
-}
-
-// Generate the address of the memory_map entry, relative to dynarec_local
-generate_map_const(u_int addr,int reg) {
- //printf("generate_map_const(%x,%s)\n",addr,regname[reg]);
- emit_movimm((addr>>12)+(((u_int)memory_map-(u_int)&dynarec_local)>>2),reg);
-}
-
-#else
-
-static int do_tlb_r() { return 0; }
-static int do_tlb_r_branch() { return 0; }
-static int gen_tlb_addr_r() { return 0; }
-static int do_tlb_w() { return 0; }
-static int do_tlb_w_branch() { return 0; }
-static int gen_tlb_addr_w() { return 0; }
-
-#endif // DISABLE_TLB
-
-/* Special assem */
-
-void shift_assemble_arm(int i,struct regstat *i_regs)
-{
- if(rt1[i]) {
- if(opcode2[i]<=0x07) // SLLV/SRLV/SRAV
- {
- signed char s,t,shift;
- t=get_reg(i_regs->regmap,rt1[i]);
- s=get_reg(i_regs->regmap,rs1[i]);
- shift=get_reg(i_regs->regmap,rs2[i]);
- if(t>=0){
- if(rs1[i]==0)
- {
- emit_zeroreg(t);
- }
- else if(rs2[i]==0)
- {
- assert(s>=0);
- if(s!=t) emit_mov(s,t);
- }
- else
- {
- emit_andimm(shift,31,HOST_TEMPREG);
- if(opcode2[i]==4) // SLLV
- {
- emit_shl(s,HOST_TEMPREG,t);
- }
- if(opcode2[i]==6) // SRLV
- {
- emit_shr(s,HOST_TEMPREG,t);
- }
- if(opcode2[i]==7) // SRAV
- {
- emit_sar(s,HOST_TEMPREG,t);
- }
- }
- }
- } else { // DSLLV/DSRLV/DSRAV
- signed char sh,sl,th,tl,shift;
- th=get_reg(i_regs->regmap,rt1[i]|64);
- tl=get_reg(i_regs->regmap,rt1[i]);
- sh=get_reg(i_regs->regmap,rs1[i]|64);
- sl=get_reg(i_regs->regmap,rs1[i]);
- shift=get_reg(i_regs->regmap,rs2[i]);
- if(tl>=0){
- if(rs1[i]==0)
- {
- emit_zeroreg(tl);
- if(th>=0) emit_zeroreg(th);
- }
- else if(rs2[i]==0)
- {
- assert(sl>=0);
- if(sl!=tl) emit_mov(sl,tl);
- if(th>=0&&sh!=th) emit_mov(sh,th);
- }
- else
- {
- // FIXME: What if shift==tl ?
- assert(shift!=tl);
- int temp=get_reg(i_regs->regmap,-1);
- int real_th=th;
- if(th<0&&opcode2[i]!=0x14) {th=temp;} // DSLLV doesn't need a temporary register
- assert(sl>=0);
- assert(sh>=0);
- emit_andimm(shift,31,HOST_TEMPREG);
- if(opcode2[i]==0x14) // DSLLV
- {
- if(th>=0) emit_shl(sh,HOST_TEMPREG,th);
- emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
- emit_orrshr(sl,HOST_TEMPREG,th);
- emit_andimm(shift,31,HOST_TEMPREG);
- emit_testimm(shift,32);
- emit_shl(sl,HOST_TEMPREG,tl);
- if(th>=0) emit_cmovne_reg(tl,th);
- emit_cmovne_imm(0,tl);
- }
- if(opcode2[i]==0x16) // DSRLV
- {
- assert(th>=0);
- emit_shr(sl,HOST_TEMPREG,tl);
- emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
- emit_orrshl(sh,HOST_TEMPREG,tl);
- emit_andimm(shift,31,HOST_TEMPREG);
- emit_testimm(shift,32);
- emit_shr(sh,HOST_TEMPREG,th);
- emit_cmovne_reg(th,tl);
- if(real_th>=0) emit_cmovne_imm(0,th);
- }
- if(opcode2[i]==0x17) // DSRAV
- {
- assert(th>=0);
- emit_shr(sl,HOST_TEMPREG,tl);
- emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
- if(real_th>=0) {
- assert(temp>=0);
- emit_sarimm(th,31,temp);
- }
- emit_orrshl(sh,HOST_TEMPREG,tl);
- emit_andimm(shift,31,HOST_TEMPREG);
- emit_testimm(shift,32);
- emit_sar(sh,HOST_TEMPREG,th);
- emit_cmovne_reg(th,tl);
- if(real_th>=0) emit_cmovne_reg(temp,th);
- }
- }
- }
- }
- }
-}
-
-#ifdef PCSX
-static void speculate_mov(int rs,int rt)
-{
- if(rt!=0) {
- smrv_strong_next|=1<<rt;
- smrv[rt]=smrv[rs];
- }
-}
-
-static void speculate_mov_weak(int rs,int rt)
-{
- if(rt!=0) {
- smrv_weak_next|=1<<rt;
- smrv[rt]=smrv[rs];
- }
-}
-
-static void speculate_register_values(int i)
-{
- if(i==0) {
- memcpy(smrv,psxRegs.GPR.r,sizeof(smrv));
- // gp,sp are likely to stay the same throughout the block
- smrv_strong_next=(1<<28)|(1<<29)|(1<<30);
- smrv_weak_next=~smrv_strong_next;
- //printf(" llr %08x\n", smrv[4]);
- }
- smrv_strong=smrv_strong_next;
- smrv_weak=smrv_weak_next;
- switch(itype[i]) {
- case ALU:
- if ((smrv_strong>>rs1[i])&1) speculate_mov(rs1[i],rt1[i]);
- else if((smrv_strong>>rs2[i])&1) speculate_mov(rs2[i],rt1[i]);
- else if((smrv_weak>>rs1[i])&1) speculate_mov_weak(rs1[i],rt1[i]);
- else if((smrv_weak>>rs2[i])&1) speculate_mov_weak(rs2[i],rt1[i]);
- else {
- smrv_strong_next&=~(1<<rt1[i]);
- smrv_weak_next&=~(1<<rt1[i]);
- }
- break;
- case SHIFTIMM:
- smrv_strong_next&=~(1<<rt1[i]);
- smrv_weak_next&=~(1<<rt1[i]);
- // fallthrough
- case IMM16:
- if(rt1[i]&&is_const(®s[i],rt1[i])) {
- int value,hr=get_reg(regs[i].regmap,rt1[i]);
- if(hr>=0) {
- if(get_final_value(hr,i,&value))
- smrv[rt1[i]]=value;
- else smrv[rt1[i]]=constmap[i][hr];
- smrv_strong_next|=1<<rt1[i];
- }
- }
- else {
- if ((smrv_strong>>rs1[i])&1) speculate_mov(rs1[i],rt1[i]);
- else if((smrv_weak>>rs1[i])&1) speculate_mov_weak(rs1[i],rt1[i]);
- }
- break;
- case LOAD:
- if(start<0x2000&&(rt1[i]==26||(smrv[rt1[i]]>>24)==0xa0)) {
- // special case for BIOS
- smrv[rt1[i]]=0xa0000000;
- smrv_strong_next|=1<<rt1[i];
- break;
- }
- // fallthrough
- case SHIFT:
- case LOADLR:
- case MOV:
- smrv_strong_next&=~(1<<rt1[i]);
- smrv_weak_next&=~(1<<rt1[i]);
- break;
- case COP0:
- case COP2:
- if(opcode2[i]==0||opcode2[i]==2) { // MFC/CFC
- smrv_strong_next&=~(1<<rt1[i]);
- smrv_weak_next&=~(1<<rt1[i]);
- }
- break;
- case C2LS:
- if (opcode[i]==0x32) { // LWC2
- smrv_strong_next&=~(1<<rt1[i]);
- smrv_weak_next&=~(1<<rt1[i]);
- }
- break;
- }
-#if 0
- int r=4;
- printf("x %08x %08x %d %d c %08x %08x\n",smrv[r],start+i*4,
- ((smrv_strong>>r)&1),(smrv_weak>>r)&1,regs[i].isconst,regs[i].wasconst);
-#endif
-}
-
-enum {
- MTYPE_8000 = 0,
- MTYPE_8020,
- MTYPE_0000,
- MTYPE_A000,
- MTYPE_1F80,
-};
-
-static int get_ptr_mem_type(u_int a)
-{
- if(a < 0x00200000) {
- if(a<0x1000&&((start>>20)==0xbfc||(start>>24)==0xa0))
- // return wrong, must use memhandler for BIOS self-test to pass
- // 007 does similar stuff from a00 mirror, weird stuff
- return MTYPE_8000;
- return MTYPE_0000;
- }
- if(0x1f800000 <= a && a < 0x1f801000)
- return MTYPE_1F80;
- if(0x80200000 <= a && a < 0x80800000)
- return MTYPE_8020;
- if(0xa0000000 <= a && a < 0xa0200000)
- return MTYPE_A000;
- return MTYPE_8000;
-}
-#endif
-
-static int emit_fastpath_cmp_jump(int i,int addr,int *addr_reg_override)
-{
- int jaddr,type=0;
-
-#ifdef PCSX
- int mr=rs1[i];
- if(((smrv_strong|smrv_weak)>>mr)&1) {
- type=get_ptr_mem_type(smrv[mr]);
- //printf("set %08x @%08x r%d %d\n", smrv[mr], start+i*4, mr, type);
- }
- else {
- // use the mirror we are running on
- type=get_ptr_mem_type(start);
- //printf("set nospec @%08x r%d %d\n", start+i*4, mr, type);
- }
-
- if(type==MTYPE_8020) { // RAM 80200000+ mirror
- emit_andimm(addr,~0x00e00000,HOST_TEMPREG);
- addr=*addr_reg_override=HOST_TEMPREG;
- type=0;
- }
- else if(type==MTYPE_0000) { // RAM 0 mirror
- emit_orimm(addr,0x80000000,HOST_TEMPREG);
- addr=*addr_reg_override=HOST_TEMPREG;
- type=0;
- }
- else if(type==MTYPE_A000) { // RAM A mirror
- emit_andimm(addr,~0x20000000,HOST_TEMPREG);
- addr=*addr_reg_override=HOST_TEMPREG;
- type=0;
- }
- else if(type==MTYPE_1F80) { // scratchpad
- emit_addimm(addr,-0x1f800000,HOST_TEMPREG);
- emit_cmpimm(HOST_TEMPREG,0x1000);
- jaddr=(int)out;
- emit_jc(0);
- }
-#endif
-
- if(type==0)
- {
- emit_cmpimm(addr,RAM_SIZE);
- jaddr=(int)out;
- #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
- // Hint to branch predictor that the branch is unlikely to be taken
- if(rs1[i]>=28)
- emit_jno_unlikely(0);
- else
- #endif
- emit_jno(0);
- }
-
- return jaddr;
-}
-
-#define shift_assemble shift_assemble_arm
-
-void loadlr_assemble_arm(int i,struct regstat *i_regs)
-{
- int s,th,tl,temp,temp2,addr,map=-1;
- int offset;
- int jaddr=0;
- int memtarget=0,c=0;
- int fastload_reg_override=0;
- u_int hr,reglist=0;
- th=get_reg(i_regs->regmap,rt1[i]|64);
- tl=get_reg(i_regs->regmap,rt1[i]);
- s=get_reg(i_regs->regmap,rs1[i]);
- temp=get_reg(i_regs->regmap,-1);
- temp2=get_reg(i_regs->regmap,FTEMP);
- addr=get_reg(i_regs->regmap,AGEN1+(i&1));
- assert(addr<0);
- offset=imm[i];
- for(hr=0;hr<HOST_REGS;hr++) {
- if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
- }
- reglist|=1<<temp;
- if(offset||s<0||c) addr=temp2;
- else addr=s;
- if(s>=0) {
- c=(i_regs->wasconst>>s)&1;
- if(c) {
- memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
- if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1;
- }
- }
- if(!using_tlb) {
- if(!c) {
- #ifdef RAM_OFFSET
- map=get_reg(i_regs->regmap,ROREG);
- if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG);
- #endif
- emit_shlimm(addr,3,temp);
- if (opcode[i]==0x22||opcode[i]==0x26) {
- emit_andimm(addr,0xFFFFFFFC,temp2); // LWL/LWR
- }else{
- emit_andimm(addr,0xFFFFFFF8,temp2); // LDL/LDR
- }
- jaddr=emit_fastpath_cmp_jump(i,temp2,&fastload_reg_override);
- }
- else {
- if (opcode[i]==0x22||opcode[i]==0x26) {
- emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
- }else{
- emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR
- }
- }
- }else{ // using tlb
- int a;
- if(c) {
- a=-1;
- }else if (opcode[i]==0x22||opcode[i]==0x26) {
- a=0xFFFFFFFC; // LWL/LWR
- }else{
- a=0xFFFFFFF8; // LDL/LDR
- }
- map=get_reg(i_regs->regmap,TLREG);
- assert(map>=0);
- reglist&=~(1<<map);
- map=do_tlb_r(addr,temp2,map,0,a,c?-1:temp,c,constmap[i][s]+offset);
- if(c) {
- if (opcode[i]==0x22||opcode[i]==0x26) {
- emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
- }else{
- emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR
- }
- }
- do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr);
- }
- if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR
- if(!c||memtarget) {
- int a=temp2;
- if(fastload_reg_override) a=fastload_reg_override;
- //emit_readword_indexed((int)rdram-0x80000000,temp2,temp2);
- emit_readword_indexed_tlb(0,a,map,temp2);
- if(jaddr) add_stub(LOADW_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
- }
- else
- inline_readstub(LOADW_STUB,i,(constmap[i][s]+offset)&0xFFFFFFFC,i_regs->regmap,FTEMP,ccadj[i],reglist);
- if(rt1[i]) {
- assert(tl>=0);
- emit_andimm(temp,24,temp);
-#ifdef BIG_ENDIAN_MIPS
- if (opcode[i]==0x26) // LWR
-#else
- if (opcode[i]==0x22) // LWL
-#endif
- emit_xorimm(temp,24,temp);
- emit_movimm(-1,HOST_TEMPREG);
- if (opcode[i]==0x26) {
- emit_shr(temp2,temp,temp2);
- emit_bic_lsr(tl,HOST_TEMPREG,temp,tl);
- }else{
- emit_shl(temp2,temp,temp2);
- emit_bic_lsl(tl,HOST_TEMPREG,temp,tl);
- }
- emit_or(temp2,tl,tl);
- }
- //emit_storereg(rt1[i],tl); // DEBUG
- }
- if (opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR
- // FIXME: little endian, fastload_reg_override
- int temp2h=get_reg(i_regs->regmap,FTEMP|64);
- if(!c||memtarget) {
- //if(th>=0) emit_readword_indexed((int)rdram-0x80000000,temp2,temp2h);
- //emit_readword_indexed((int)rdram-0x7FFFFFFC,temp2,temp2);
- emit_readdword_indexed_tlb(0,temp2,map,temp2h,temp2);
- if(jaddr) add_stub(LOADD_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
- }
- else
- inline_readstub(LOADD_STUB,i,(constmap[i][s]+offset)&0xFFFFFFF8,i_regs->regmap,FTEMP,ccadj[i],reglist);
- if(rt1[i]) {
- assert(th>=0);
- assert(tl>=0);
- emit_testimm(temp,32);
- emit_andimm(temp,24,temp);
- if (opcode[i]==0x1A) { // LDL
- emit_rsbimm(temp,32,HOST_TEMPREG);
- emit_shl(temp2h,temp,temp2h);
- emit_orrshr(temp2,HOST_TEMPREG,temp2h);
- emit_movimm(-1,HOST_TEMPREG);
- emit_shl(temp2,temp,temp2);
- emit_cmove_reg(temp2h,th);
- emit_biceq_lsl(tl,HOST_TEMPREG,temp,tl);
- emit_bicne_lsl(th,HOST_TEMPREG,temp,th);
- emit_orreq(temp2,tl,tl);
- emit_orrne(temp2,th,th);
- }
- if (opcode[i]==0x1B) { // LDR
- emit_xorimm(temp,24,temp);
- emit_rsbimm(temp,32,HOST_TEMPREG);
- emit_shr(temp2,temp,temp2);
- emit_orrshl(temp2h,HOST_TEMPREG,temp2);
- emit_movimm(-1,HOST_TEMPREG);
- emit_shr(temp2h,temp,temp2h);
- emit_cmovne_reg(temp2,tl);
- emit_bicne_lsr(th,HOST_TEMPREG,temp,th);
- emit_biceq_lsr(tl,HOST_TEMPREG,temp,tl);
- emit_orrne(temp2h,th,th);
- emit_orreq(temp2h,tl,tl);
- }
- }
- }
-}
-#define loadlr_assemble loadlr_assemble_arm
-
-void cop0_assemble(int i,struct regstat *i_regs)
-{
- if(opcode2[i]==0) // MFC0
- {
- signed char t=get_reg(i_regs->regmap,rt1[i]);
- char copr=(source[i]>>11)&0x1f;
- //assert(t>=0); // Why does this happen? OOT is weird
- if(t>=0&&rt1[i]!=0) {
-#ifdef MUPEN64
- emit_addimm(FP,(int)&fake_pc-(int)&dynarec_local,0);
- emit_movimm((source[i]>>11)&0x1f,1);
- emit_writeword(0,(int)&PC);
- emit_writebyte(1,(int)&(fake_pc.f.r.nrd));
- if(copr==9) {
- emit_readword((int)&last_count,ECX);
- emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc
- emit_add(HOST_CCREG,ECX,HOST_CCREG);
- emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
- emit_writeword(HOST_CCREG,(int)&Count);
- }
- emit_call((int)MFC0);
- emit_readword((int)&readmem_dword,t);
-#else
- emit_readword((int)®_cop0+copr*4,t);
-#endif
- }
- }
- else if(opcode2[i]==4) // MTC0
- {
- signed char s=get_reg(i_regs->regmap,rs1[i]);
- char copr=(source[i]>>11)&0x1f;
- assert(s>=0);
-#ifdef MUPEN64
- emit_writeword(s,(int)&readmem_dword);
- wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32);
- emit_addimm(FP,(int)&fake_pc-(int)&dynarec_local,0);
- emit_movimm((source[i]>>11)&0x1f,1);
- emit_writeword(0,(int)&PC);
- emit_writebyte(1,(int)&(fake_pc.f.r.nrd));
-#else
- wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32);
-#endif
- if(copr==9||copr==11||copr==12||copr==13) {
- emit_readword((int)&last_count,HOST_TEMPREG);
- emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc
- emit_add(HOST_CCREG,HOST_TEMPREG,HOST_CCREG);
- emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
- emit_writeword(HOST_CCREG,(int)&Count);
- }
- // What a mess. The status register (12) can enable interrupts,
- // so needs a special case to handle a pending interrupt.
- // The interrupt must be taken immediately, because a subsequent
- // instruction might disable interrupts again.
- if(copr==12||copr==13) {
-#ifdef PCSX
- if (is_delayslot) {
- // burn cycles to cause cc_interrupt, which will
- // reschedule next_interupt. Relies on CCREG from above.
- assem_debug("MTC0 DS %d\n", copr);
- emit_writeword(HOST_CCREG,(int)&last_count);
- emit_movimm(0,HOST_CCREG);
- emit_storereg(CCREG,HOST_CCREG);
- if(s!=1)
- emit_mov(s,1);
- emit_movimm(copr,0);
- emit_call((int)pcsx_mtc0_ds);
- return;
- }
-#endif
- emit_movimm(start+i*4+4,HOST_TEMPREG);
- emit_writeword(HOST_TEMPREG,(int)&pcaddr);
- emit_movimm(0,HOST_TEMPREG);
- emit_writeword(HOST_TEMPREG,(int)&pending_exception);
- }
- //else if(copr==12&&is_delayslot) emit_call((int)MTC0_R12);
- //else
-#ifdef PCSX
- if(s!=1)
- emit_mov(s,1);
- emit_movimm(copr,0);
- emit_call((int)pcsx_mtc0);
-#else
- emit_call((int)MTC0);
-#endif
- if(copr==9||copr==11||copr==12||copr==13) {
- emit_readword((int)&Count,HOST_CCREG);
- emit_readword((int)&next_interupt,ECX);
- emit_addimm(HOST_CCREG,-CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
- emit_sub(HOST_CCREG,ECX,HOST_CCREG);
- emit_writeword(ECX,(int)&last_count);
- emit_storereg(CCREG,HOST_CCREG);
- }
- if(copr==12||copr==13) {
- assert(!is_delayslot);
- emit_readword((int)&pending_exception,14);
- }
- emit_loadreg(rs1[i],s);
- if(get_reg(i_regs->regmap,rs1[i]|64)>=0)
- emit_loadreg(rs1[i]|64,get_reg(i_regs->regmap,rs1[i]|64));
- if(copr==12||copr==13) {
- emit_test(14,14);
- emit_jne((int)&do_interrupt);
- }
- cop1_usable=0;
- }
- else
- {
- assert(opcode2[i]==0x10);
-#ifndef DISABLE_TLB
- if((source[i]&0x3f)==0x01) // TLBR
- emit_call((int)TLBR);
- if((source[i]&0x3f)==0x02) // TLBWI
- emit_call((int)TLBWI_new);
- if((source[i]&0x3f)==0x06) { // TLBWR
- // The TLB entry written by TLBWR is dependent on the count,
- // so update the cycle count
- emit_readword((int)&last_count,ECX);
- if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG);
- emit_add(HOST_CCREG,ECX,HOST_CCREG);
- emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
- emit_writeword(HOST_CCREG,(int)&Count);
- emit_call((int)TLBWR_new);
- }
- if((source[i]&0x3f)==0x08) // TLBP
- emit_call((int)TLBP);
-#endif
-#ifdef PCSX
- if((source[i]&0x3f)==0x10) // RFE
- {
- emit_readword((int)&Status,0);
- emit_andimm(0,0x3c,1);
- emit_andimm(0,~0xf,0);
- emit_orrshr_imm(1,2,0);
- emit_writeword(0,(int)&Status);
- }
-#else
- if((source[i]&0x3f)==0x18) // ERET
- {
- int count=ccadj[i];
- if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG);
- emit_addimm(HOST_CCREG,CLOCK_ADJUST(count),HOST_CCREG); // TODO: Should there be an extra cycle here?
- emit_jmp((int)jump_eret);
- }
-#endif
- }
-}
-
-static void cop2_get_dreg(u_int copr,signed char tl,signed char temp)
-{
- switch (copr) {
- case 1:
- case 3:
- case 5:
- case 8:
- case 9:
- case 10:
- case 11:
- emit_readword((int)®_cop2d[copr],tl);
- emit_signextend16(tl,tl);
- emit_writeword(tl,(int)®_cop2d[copr]); // hmh
- break;
- case 7:
- case 16:
- case 17:
- case 18:
- case 19:
- emit_readword((int)®_cop2d[copr],tl);
- emit_andimm(tl,0xffff,tl);
- emit_writeword(tl,(int)®_cop2d[copr]);
- break;
- case 15:
- emit_readword((int)®_cop2d[14],tl); // SXY2
- emit_writeword(tl,(int)®_cop2d[copr]);
- break;
- case 28:
- case 29:
- emit_readword((int)®_cop2d[9],temp);
- emit_testimm(temp,0x8000); // do we need this?
- emit_andimm(temp,0xf80,temp);
- emit_andne_imm(temp,0,temp);
- emit_shrimm(temp,7,tl);
- emit_readword((int)®_cop2d[10],temp);
- emit_testimm(temp,0x8000);
- emit_andimm(temp,0xf80,temp);
- emit_andne_imm(temp,0,temp);
- emit_orrshr_imm(temp,2,tl);
- emit_readword((int)®_cop2d[11],temp);
- emit_testimm(temp,0x8000);
- emit_andimm(temp,0xf80,temp);
- emit_andne_imm(temp,0,temp);
- emit_orrshl_imm(temp,3,tl);
- emit_writeword(tl,(int)®_cop2d[copr]);
- break;
- default:
- emit_readword((int)®_cop2d[copr],tl);
- break;
- }
-}
-
-static void cop2_put_dreg(u_int copr,signed char sl,signed char temp)
-{
- switch (copr) {
- case 15:
- emit_readword((int)®_cop2d[13],temp); // SXY1
- emit_writeword(sl,(int)®_cop2d[copr]);
- emit_writeword(temp,(int)®_cop2d[12]); // SXY0
- emit_readword((int)®_cop2d[14],temp); // SXY2
- emit_writeword(sl,(int)®_cop2d[14]);
- emit_writeword(temp,(int)®_cop2d[13]); // SXY1
- break;
- case 28:
- emit_andimm(sl,0x001f,temp);
- emit_shlimm(temp,7,temp);
- emit_writeword(temp,(int)®_cop2d[9]);
- emit_andimm(sl,0x03e0,temp);
- emit_shlimm(temp,2,temp);
- emit_writeword(temp,(int)®_cop2d[10]);
- emit_andimm(sl,0x7c00,temp);
- emit_shrimm(temp,3,temp);
- emit_writeword(temp,(int)®_cop2d[11]);
- emit_writeword(sl,(int)®_cop2d[28]);
- break;
- case 30:
- emit_movs(sl,temp);
- emit_mvnmi(temp,temp);
- emit_clz(temp,temp);
- emit_writeword(sl,(int)®_cop2d[30]);
- emit_writeword(temp,(int)®_cop2d[31]);
- break;
- case 31:
- break;
- default:
- emit_writeword(sl,(int)®_cop2d[copr]);
- break;
- }
-}
-
-void cop2_assemble(int i,struct regstat *i_regs)
-{
- u_int copr=(source[i]>>11)&0x1f;
- signed char temp=get_reg(i_regs->regmap,-1);
- if (opcode2[i]==0) { // MFC2
- signed char tl=get_reg(i_regs->regmap,rt1[i]);
- if(tl>=0&&rt1[i]!=0)
- cop2_get_dreg(copr,tl,temp);
- }
- else if (opcode2[i]==4) { // MTC2
- signed char sl=get_reg(i_regs->regmap,rs1[i]);
- cop2_put_dreg(copr,sl,temp);
- }
- else if (opcode2[i]==2) // CFC2
- {
- signed char tl=get_reg(i_regs->regmap,rt1[i]);
- if(tl>=0&&rt1[i]!=0)
- emit_readword((int)®_cop2c[copr],tl);
- }
- else if (opcode2[i]==6) // CTC2
- {
- signed char sl=get_reg(i_regs->regmap,rs1[i]);
- switch(copr) {
- case 4:
- case 12:
- case 20:
- case 26:
- case 27:
- case 29:
- case 30:
- emit_signextend16(sl,temp);
- break;
- case 31:
- //value = value & 0x7ffff000;
- //if (value & 0x7f87e000) value |= 0x80000000;
- emit_shrimm(sl,12,temp);
- emit_shlimm(temp,12,temp);
- emit_testimm(temp,0x7f000000);
- emit_testeqimm(temp,0x00870000);
- emit_testeqimm(temp,0x0000e000);
- emit_orrne_imm(temp,0x80000000,temp);
- break;
- default:
- temp=sl;
- break;
- }
- emit_writeword(temp,(int)®_cop2c[copr]);
- assert(sl>=0);
- }
-}
-
-static void c2op_prologue(u_int op,u_int reglist)
-{
- save_regs_all(reglist);
- emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs
-}
-
-static void c2op_epilogue(u_int op,u_int reglist)
-{
- restore_regs_all(reglist);
-}
-
-static void c2op_assemble(int i,struct regstat *i_regs)
-{
- signed char temp=get_reg(i_regs->regmap,-1);
- u_int c2op=source[i]&0x3f;
- u_int hr,reglist=0;
- int need_flags,need_ir;
- for(hr=0;hr<HOST_REGS;hr++) {
- if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
- }