- }
- do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr);
- }
- if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR
- if(!c||memtarget) {
- //emit_readword_indexed((int)rdram-0x80000000,temp2,temp2);
- emit_readword_indexed_tlb((int)rdram-0x80000000,temp2,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);
- 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
- 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((int)rdram-0x80000000,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);
- 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) {
-#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_DIVIDER*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);
- emit_writeword(s,(int)&readmem_dword);
- wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32);
-#ifdef MUPEN64 /// FIXME
- 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));
-#endif
-#ifdef PCSX
- emit_movimm(source[i],0);
- emit_writeword(0,(int)&psxRegs.code);
-#endif
- if(copr==9||copr==11||copr==12||copr==13) {
- 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_DIVIDER*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) {
- emit_movimm(start+i*4+4,0);
- emit_movimm(0,1);
- emit_writeword(0,(int)&pcaddr);
- emit_writeword(1,(int)&pending_exception);
- }
- //else if(copr==12&&is_delayslot) emit_call((int)MTC0_R12);
- //else
- emit_call((int)MTC0);
- 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_DIVIDER*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_DIVIDER*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
- 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_DIVIDER*count,HOST_CCREG); // TODO: Should there be an extra cycle here?
- emit_jmp((int)jump_eret);
- }
- }
-}
-
-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 30:
- emit_movimm(0,tl);
- break;
- 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_shr(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(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(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_shl(temp,7,temp);
- emit_writeword(temp,(int)®_cop2d[9]);
- emit_andimm(sl,0x03e0,temp);
- emit_shl(temp,2,temp);
- emit_writeword(temp,(int)®_cop2d[10]);
- emit_andimm(sl,0x7c00,temp);
- emit_shr(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 7:
- case 29:
- 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)
- 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)
- 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);