X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=libpcsxcore%2Fnew_dynarec%2Fnew_dynarec.c;h=9bc0f60a4776b1f0c50b846022ddf8bd600548b8;hp=6f7c5673785dd63e1638f30794b4a0b26deb752e;hb=0bbd14543fec5fd4f5664b676771812663235252;hpb=2002a1dbd97bc1b94b12ec3e90702a770b040858 diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c index 6f7c5673..9bc0f60a 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.c +++ b/libpcsxcore/new_dynarec/new_dynarec.c @@ -84,6 +84,7 @@ struct ll_entry u_int ba[MAXBLOCK]; char likely[MAXBLOCK]; char is_ds[MAXBLOCK]; + char ooo[MAXBLOCK]; uint64_t unneeded_reg[MAXBLOCK]; uint64_t unneeded_reg_upper[MAXBLOCK]; uint64_t branch_unneeded_reg[MAXBLOCK]; @@ -94,10 +95,9 @@ struct ll_entry signed char regmap[MAXBLOCK][HOST_REGS]; signed char regmap_entry[MAXBLOCK][HOST_REGS]; uint64_t constmap[MAXBLOCK][HOST_REGS]; - uint64_t known_value[HOST_REGS]; - u_int known_reg; struct regstat regs[MAXBLOCK]; struct regstat branch_regs[MAXBLOCK]; + signed char minimum_free_regs[MAXBLOCK]; u_int needed_reg[MAXBLOCK]; uint64_t requires_32bit[MAXBLOCK]; u_int wont_dirty[MAXBLOCK]; @@ -135,7 +135,7 @@ struct ll_entry #define CCREG 36 // Cycle count #define INVCP 37 // Pointer to invalid_code #define TEMPREG 38 -#define FTEMP 38 // FPU temporary register +#define FTEMP 38 // FPU/LDL/LDR temporary register #define PTEMP 39 // Prefetch temporary register #define TLREG 40 // TLB mapping offset #define RHASH 41 // Return address hash @@ -175,6 +175,11 @@ struct ll_entry #define OTHER 23 // Other #define SPAN 24 // Branch/delay slot spans 2 pages #define NI 25 // Not implemented +#define HLECALL 26// PCSX fake opcodes for HLE +#define COP2 27 // Coprocessor 2 move +#define C2LS 28 // Coprocessor 2 load/store +#define C2OP 29 // Coprocessor 2 operation +#define INTCALL 30// Call interpreter to handle rare corner cases /* stubs */ #define CC_STUB 1 @@ -213,7 +218,11 @@ void cc_interrupt(); void fp_exception(); void fp_exception_ds(); void jump_syscall(); +void jump_syscall_hle(); void jump_eret(); +void jump_hlecall(); +void jump_intcall(); +void new_dyna_leave(); // TLB void TLBWI_new(); @@ -300,7 +309,14 @@ static void tlb_hacks() static u_int get_page(u_int vaddr) { +#ifndef PCSX u_int page=(vaddr^0x80000000)>>12; +#else + u_int page=vaddr&~0xe0000000; + if (page < 0x1000000) + page &= ~0x0e00000; // RAM mirrors + page>>=12; +#endif #ifndef DISABLE_TLB if(page>262143&&tlb_LUT_r[vaddr>>12]) page=(tlb_LUT_r[vaddr>>12]^0x80000000)>>12; #endif @@ -399,6 +415,9 @@ void *get_addr_ht(u_int vaddr) void *get_addr_32(u_int vaddr,u_int flags) { +#ifdef FORCE32 + return get_addr(vaddr); +#else //printf("TRACE: count=%d next=%d (get_addr_32 %x,flags %x)\n",Count,next_interupt,vaddr,flags); int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; if(ht_bin[0]==vaddr) return (void *)ht_bin[1]; @@ -478,6 +497,7 @@ void *get_addr_32(u_int vaddr,u_int flags) Context=(Context&0xFF80000F)|((BadVAddr>>9)&0x007FFFF0); EntryHi=BadVAddr&0xFFFFE000; return get_addr_ht(0x80000000); +#endif } void clear_all_regs(signed char regmap[]) @@ -626,7 +646,7 @@ void lsn(u_char hsn[], int i, int *preferred_reg) } // On some architectures stores need invc_ptr #if defined(HOST_IMM8) - if(itype[i+j]==STORE || itype[i+j]==STORELR || (opcode[i+j]&0x3b)==0x39) { + if(itype[i+j]==STORE || itype[i+j]==STORELR || (opcode[i+j]&0x3b)==0x39 || (opcode[i+j]&0x3b)==0x3a) { hsn[INVCP]=j; } #endif @@ -663,19 +683,19 @@ void lsn(u_char hsn[], int i, int *preferred_reg) hsn[RHTBL]=1; } // Coprocessor load/store needs FTEMP, even if not declared - if(itype[i]==C1LS) { + if(itype[i]==C1LS||itype[i]==C2LS) { hsn[FTEMP]=0; } // Load L/R also uses FTEMP as a temporary register if(itype[i]==LOADLR) { hsn[FTEMP]=0; } - // Also 64-bit SDL/SDR - if(opcode[i]==0x2c||opcode[i]==0x2d) { + // Also SWL/SWR/SDL/SDR + if(opcode[i]==0x2a||opcode[i]==0x2e||opcode[i]==0x2c||opcode[i]==0x2d) { hsn[FTEMP]=0; } // Don't remove the TLB registers either - if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS ) { + if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS || itype[i]==C2LS) { hsn[TLREG]=0; } // Don't remove the miniht registers @@ -716,7 +736,7 @@ int needed_again(int r, int i) j++; break; } - if(itype[i+j]==SYSCALL||((source[i+j]&0xfc00003f)==0x0d)) + if(itype[i+j]==SYSCALL||itype[i+j]==HLECALL||itype[i+j]==INTCALL||((source[i+j]&0xfc00003f)==0x0d)) { break; } @@ -962,14 +982,10 @@ void ll_add(struct ll_entry **head,int vaddr,void *addr) // Add virtual address mapping for 32-bit compiled block void ll_add_32(struct ll_entry **head,int vaddr,u_int reg32,void *addr) { - struct ll_entry *new_entry; - new_entry=malloc(sizeof(struct ll_entry)); - assert(new_entry!=NULL); - new_entry->vaddr=vaddr; - new_entry->reg32=reg32; - new_entry->addr=addr; - new_entry->next=*head; - *head=new_entry; + ll_add(head,vaddr,addr); +#ifndef FORCE32 + (*head)->reg32=reg32; +#endif } // Check if an address is already compiled @@ -1077,16 +1093,18 @@ void ll_kill_pointers(struct ll_entry *head,int addr,int shift) (((ptr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==(addr>>shift))) { inv_debug("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr); - kill_pointer(head->addr); + u_int host_addr=(u_int)kill_pointer(head->addr); + #ifdef __arm__ + needs_clear_cache[(host_addr-(u_int)BASE_ADDR)>>17]|=1<<(((host_addr-(u_int)BASE_ADDR)>>12)&31); + #endif } head=head->next; } } // This is called when we write to a compiled block (see do_invstub) -int invalidate_page(u_int page) +void invalidate_page(u_int page) { - int modified=0; struct ll_entry *head; struct ll_entry *next; head=jump_in[page]; @@ -1102,17 +1120,17 @@ int invalidate_page(u_int page) jump_out[page]=0; while(head!=NULL) { inv_debug("INVALIDATE: kill pointer to %x (%x)\n",head->vaddr,(int)head->addr); - kill_pointer(head->addr); - modified=1; + u_int host_addr=(u_int)kill_pointer(head->addr); + #ifdef __arm__ + needs_clear_cache[(host_addr-(u_int)BASE_ADDR)>>17]|=1<<(((host_addr-(u_int)BASE_ADDR)>>12)&31); + #endif next=head->next; free(head); head=next; } - return modified; } void invalidate_block(u_int block) { - int modified; u_int page=get_page(block<<12); u_int vpage=get_vpage(block<<12); inv_debug("INVALIDATE: %x (%d)\n",block<<12,page); @@ -1127,7 +1145,7 @@ void invalidate_block(u_int block) if(vpage>2047||(head->vaddr>>12)==block) { // Ignore vaddr hash collision get_bounds((int)head->addr,&start,&end); //printf("start: %x end: %x\n",start,end); - if(page<2048&&start>=0x80000000&&end<0x80800000) { + if(page<2048&&start>=0x80000000&&end<0x80000000+RAM_SIZE) { if(((start-(u_int)rdram)>>12)<=page&&((end-1-(u_int)rdram)>>12)>=page) { if((((start-(u_int)rdram)>>12)&2047)>12)&2047; if((((end-1-(u_int)rdram)>>12)&2047)>last) last=((end-1-(u_int)rdram)>>12)&2047; @@ -1145,7 +1163,7 @@ void invalidate_block(u_int block) head=head->next; } //printf("first=%d last=%d\n",first,last); - modified=invalidate_page(page); + invalidate_page(page); assert(first+5>page); // NB: this assumes MAXBLOCK<=4096 (4 pages) assert(last=0x80000&&block<0x80800) memory_map[block]=((u_int)rdram-0x80000000)>>2; #endif - #ifdef __arm__ - if(modified) - __clear_cache((void *)BASE_ADDR,(void *)BASE_ADDR+(1<>12); } +// This is called when loading a save state. +// Anything could have changed, so invalidate everything. void invalidate_all_pages() { u_int page,n; @@ -1243,7 +1263,7 @@ void clean_blocks(u_int page) u_int i; u_int inv=0; get_bounds((int)head->addr,&start,&end); - if(start-(u_int)rdram<0x800000) { + if(start-(u_int)rdram>12;i<=(end-1-(u_int)rdram+0x80000000)>>12;i++) { inv|=invalid_code[i]; } @@ -1253,7 +1273,7 @@ void clean_blocks(u_int page) //printf("addr=%x start=%x end=%x\n",addr,start,end); if(addr=end) inv=1; } - else if((signed int)head->vaddr>=(signed int)0x80800000) { + else if((signed int)head->vaddr>=(signed int)0x80000000+RAM_SIZE) { inv=1; } if(!inv) { @@ -1368,7 +1388,10 @@ void shift_alloc(struct regstat *current,int i) if(rs1[i]) alloc_reg(current,i,rs1[i]); if(rs2[i]) alloc_reg(current,i,rs2[i]); alloc_reg(current,i,rt1[i]); - if(rt1[i]==rs2[i]) alloc_reg_temp(current,i,-1); + if(rt1[i]==rs2[i]) { + alloc_reg_temp(current,i,-1); + minimum_free_regs[i]=1; + } current->is32|=1LL<is32&=~(1LL<regmap,rt1[i])<0) { + // dummy load, but we still need a register to calculate the address + alloc_reg_temp(current,i,-1); + minimum_free_regs[i]=1; + } if(opcode[i]==0x27||opcode[i]==0x37) // LWU/LD { current->is32&=~(1LL<is32|=1LL<is32&=~(1LL<is32&=~(1LL<is32|=1LL<is32&=~(1LL<is32|=1LL<3) // MTC1/DMTC1/CTC1 @@ -1769,16 +1834,23 @@ void cop1_alloc(struct regstat *current,int i) alloc_reg_temp(current,i,-1); } } + minimum_free_regs[i]=1; } void fconv_alloc(struct regstat *current,int i) { alloc_reg(current,i,CSREG); // Load status alloc_reg_temp(current,i,-1); + minimum_free_regs[i]=1; } void float_alloc(struct regstat *current,int i) { alloc_reg(current,i,CSREG); // Load status alloc_reg_temp(current,i,-1); + minimum_free_regs[i]=1; +} +void c2op_alloc(struct regstat *current,int i) +{ + alloc_reg_temp(current,i,-1); } void fcomp_alloc(struct regstat *current,int i) { @@ -1786,6 +1858,7 @@ void fcomp_alloc(struct regstat *current,int i) alloc_reg(current,i,FSREG); // Load flags dirty_reg(current,FSREG); // Flag will be modified alloc_reg_temp(current,i,-1); + minimum_free_regs[i]=1; } void syscall_alloc(struct regstat *current,int i) @@ -1793,6 +1866,7 @@ void syscall_alloc(struct regstat *current,int i) alloc_cc(current,i); dirty_reg(current,CCREG); alloc_all(current,i); + minimum_free_regs[i]=HOST_REGS; current->isconst=0; } @@ -1805,6 +1879,7 @@ void delayslot_alloc(struct regstat *current,int i) case RJUMP: case FJUMP: case SYSCALL: + case HLECALL: case SPAN: assem_debug("jump in the delay slot. this shouldn't happen.\n");//exit(1); printf("Disabled speculative precompilation\n"); @@ -1840,11 +1915,15 @@ void delayslot_alloc(struct regstat *current,int i) cop0_alloc(current,i); break; case COP1: + case COP2: cop1_alloc(current,i); break; case C1LS: c1ls_alloc(current,i); break; + case C2LS: + c2ls_alloc(current,i); + break; case FCONV: fconv_alloc(current,i); break; @@ -1854,6 +1933,9 @@ void delayslot_alloc(struct regstat *current,int i) case FCOMP: fcomp_alloc(current,i); break; + case C2OP: + c2op_alloc(current,i); + break; } } @@ -1863,6 +1945,7 @@ static void pagespan_alloc(struct regstat *current,int i) current->isconst=0; current->wasconst=0; regs[i].wasconst=0; + minimum_free_regs[i]=HOST_REGS; alloc_all(current,i); alloc_cc(current,i); dirty_reg(current,CCREG); @@ -1874,9 +1957,9 @@ static void pagespan_alloc(struct regstat *current,int i) if(opcode[i]==0&&(opcode2[i]&0x3E)==8) // JR/JALR { alloc_reg(current,i,rs1[i]); - if (rt1[i]==31) { - alloc_reg(current,i,31); - dirty_reg(current,31); + if (rt1[i]!=0) { + alloc_reg(current,i,rt1[i]); + dirty_reg(current,rt1[i]); } } if((opcode[i]&0x2E)==4) // BEQ/BNE/BEQL/BNEL @@ -2683,7 +2766,7 @@ void load_assemble(int i,struct regstat *i_regs) int s,th,tl,addr,map=-1; int offset; int jaddr=0; - int memtarget,c=0; + int memtarget=0,c=0; u_int hr,reglist=0; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); @@ -2695,49 +2778,67 @@ void load_assemble(int i,struct regstat *i_regs) if(i_regs->regmap[HOST_CCREG]==CCREG) reglist&=~(1<=0) { c=(i_regs->wasconst>>s)&1; - memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; + 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; } + //printf("load_assemble: c=%d\n",c); + //if(c) printf("load_assemble: const=%x\n",(int)constmap[i][s]+offset); + // FIXME: Even if the load is a NOP, we should check for pagefaults... +#ifdef PCSX + if(tl<0&&(!c||(((u_int)constmap[i][s]+offset)>>16)==0x1f80) + ||rt1[i]==0) { + // could be FIFO, must perform the read + // ||dummy read + assem_debug("(forced read)\n"); + tl=get_reg(i_regs->regmap,-1); + assert(tl>=0); + } +#endif if(offset||s<0||c) addr=tl; else addr=s; + //if(tl<0) tl=get_reg(i_regs->regmap,-1); + if(tl>=0) { //printf("load_assemble: c=%d\n",c); //if(c) printf("load_assemble: const=%x\n",(int)constmap[i][s]+offset); - // FIXME: Even if the load is a NOP, we should check for pagefaults... - if(tl>=0) { - //assert(tl>=0); - //assert(rt1[i]); - reglist&=~(1<=0) reglist&=~(1<=0); // Even if the load is a NOP, we must check for pagefaults and I/O + reglist&=~(1<=0) reglist&=~(1<regmap,ROREG); + if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); + #endif //#define R29_HACK 1 - #ifdef R29_HACK - // Strmnnrmn's speed hack - if(rs1[i]!=29||start<0x80001000||start>=0x80800000) + #ifdef R29_HACK + // Strmnnrmn's speed hack + if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE) + #endif + { + 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_cmpimm(addr,0x800000); - 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); - } + emit_jno(0); } - }else{ // using tlb - int x=0; - if (opcode[i]==0x20||opcode[i]==0x24) x=3; // LB/LBU - if (opcode[i]==0x21||opcode[i]==0x25) x=2; // LH/LHU - map=get_reg(i_regs->regmap,TLREG); - assert(map>=0); - map=do_tlb_r(addr,tl,map,x,-1,-1,c,constmap[i][s]+offset); - do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr); - } - if (opcode[i]==0x20) { // LB - if(!c||memtarget) { + } + }else{ // using tlb + int x=0; + if (opcode[i]==0x20||opcode[i]==0x24) x=3; // LB/LBU + if (opcode[i]==0x21||opcode[i]==0x25) x=2; // LH/LHU + map=get_reg(i_regs->regmap,TLREG); + assert(map>=0); + map=do_tlb_r(addr,tl,map,x,-1,-1,c,constmap[i][s]+offset); + do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr); + } + int dummy=(rt1[i]==0)||(tl!=get_reg(i_regs->regmap,rt1[i])); // ignore loads to r0 and unneeded reg + if (opcode[i]==0x20) { // LB + if(!c||memtarget) { + if(!dummy) { #ifdef HOST_IMM_ADDR32 if(c) emit_movsbl_tlb((constmap[i][s]+offset)^3,map,tl); @@ -2747,55 +2848,62 @@ void load_assemble(int i,struct regstat *i_regs) //emit_xorimm(addr,3,tl); //gen_tlb_addr_r(tl,map); //emit_movsbl_indexed((int)rdram-0x80000000,tl,tl); - int x=0; + int x=0,a=tl; #ifdef BIG_ENDIAN_MIPS if(!c) emit_xorimm(addr,3,tl); else x=((constmap[i][s]+offset)^3)-(constmap[i][s]+offset); #else - if(c) x=(constmap[i][s]+offset)-(constmap[i][s]+offset); - else if (tl!=addr) emit_mov(addr,tl); + if(!c) a=addr; #endif - emit_movsbl_indexed_tlb(x,tl,map,tl); + emit_movsbl_indexed_tlb(x,a,map,tl); } - if(jaddr) - add_stub(LOADB_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - else - inline_readstub(LOADB_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + if(jaddr) + add_stub(LOADB_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - if (opcode[i]==0x21) { // LH - if(!c||memtarget) { + else + inline_readstub(LOADB_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + if (opcode[i]==0x21) { // LH + if(!c||memtarget) { + if(!dummy) { #ifdef HOST_IMM_ADDR32 if(c) emit_movswl_tlb((constmap[i][s]+offset)^2,map,tl); else #endif { - int x=0; + int x=0,a=tl; #ifdef BIG_ENDIAN_MIPS if(!c) emit_xorimm(addr,2,tl); else x=((constmap[i][s]+offset)^2)-(constmap[i][s]+offset); #else - if(c) x=(constmap[i][s]+offset)-(constmap[i][s]+offset); - else if (tl!=addr) emit_mov(addr,tl); + if(!c) a=addr; #endif //#ifdef //emit_movswl_indexed_tlb(x,tl,map,tl); //else if(map>=0) { - gen_tlb_addr_r(tl,map); - emit_movswl_indexed(x,tl,tl); - }else - emit_movswl_indexed((int)rdram-0x80000000+x,tl,tl); + gen_tlb_addr_r(a,map); + emit_movswl_indexed(x,a,tl); + }else{ + #ifdef RAM_OFFSET + emit_movswl_indexed(x,a,tl); + #else + emit_movswl_indexed((int)rdram-0x80000000+x,a,tl); + #endif + } } - if(jaddr) - add_stub(LOADH_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - else - inline_readstub(LOADH_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + if(jaddr) + add_stub(LOADH_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - if (opcode[i]==0x23) { // LW - if(!c||memtarget) { + else + inline_readstub(LOADH_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + if (opcode[i]==0x23) { // LW + if(!c||memtarget) { + if(!dummy) { //emit_readword_indexed((int)rdram-0x80000000,addr,tl); #ifdef HOST_IMM_ADDR32 if(c) @@ -2803,14 +2911,16 @@ void load_assemble(int i,struct regstat *i_regs) else #endif emit_readword_indexed_tlb(0,addr,map,tl); - if(jaddr) - add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - else - inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + if(jaddr) + add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - if (opcode[i]==0x24) { // LBU - if(!c||memtarget) { + else + inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + if (opcode[i]==0x24) { // LBU + if(!c||memtarget) { + if(!dummy) { #ifdef HOST_IMM_ADDR32 if(c) emit_movzbl_tlb((constmap[i][s]+offset)^3,map,tl); @@ -2820,56 +2930,63 @@ void load_assemble(int i,struct regstat *i_regs) //emit_xorimm(addr,3,tl); //gen_tlb_addr_r(tl,map); //emit_movzbl_indexed((int)rdram-0x80000000,tl,tl); - int x=0; + int x=0,a=tl; #ifdef BIG_ENDIAN_MIPS if(!c) emit_xorimm(addr,3,tl); else x=((constmap[i][s]+offset)^3)-(constmap[i][s]+offset); #else - if(c) x=(constmap[i][s]+offset)-(constmap[i][s]+offset); - else if (tl!=addr) emit_mov(addr,tl); + if(!c) a=addr; #endif - emit_movzbl_indexed_tlb(x,tl,map,tl); + emit_movzbl_indexed_tlb(x,a,map,tl); } - if(jaddr) - add_stub(LOADBU_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - else - inline_readstub(LOADBU_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + if(jaddr) + add_stub(LOADBU_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - if (opcode[i]==0x25) { // LHU - if(!c||memtarget) { + else + inline_readstub(LOADBU_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + if (opcode[i]==0x25) { // LHU + if(!c||memtarget) { + if(!dummy) { #ifdef HOST_IMM_ADDR32 if(c) emit_movzwl_tlb((constmap[i][s]+offset)^2,map,tl); else #endif { - int x=0; + int x=0,a=tl; #ifdef BIG_ENDIAN_MIPS if(!c) emit_xorimm(addr,2,tl); else x=((constmap[i][s]+offset)^2)-(constmap[i][s]+offset); #else - if(c) x=(constmap[i][s]+offset)-(constmap[i][s]+offset); - else if (tl!=addr) emit_mov(addr,tl); + if(!c) a=addr; #endif //#ifdef //emit_movzwl_indexed_tlb(x,tl,map,tl); //#else if(map>=0) { - gen_tlb_addr_r(tl,map); - emit_movzwl_indexed(x,tl,tl); - }else - emit_movzwl_indexed((int)rdram-0x80000000+x,tl,tl); - if(jaddr) - add_stub(LOADHU_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + gen_tlb_addr_r(a,map); + emit_movzwl_indexed(x,a,tl); + }else{ + #ifdef RAM_OFFSET + emit_movzwl_indexed(x,a,tl); + #else + emit_movzwl_indexed((int)rdram-0x80000000+x,a,tl); + #endif + } } } - else - inline_readstub(LOADHU_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + if(jaddr) + add_stub(LOADHU_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - if (opcode[i]==0x27) { // LWU - assert(th>=0); - if(!c||memtarget) { + else + inline_readstub(LOADHU_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + if (opcode[i]==0x27) { // LWU + assert(th>=0); + if(!c||memtarget) { + if(!dummy) { //emit_readword_indexed((int)rdram-0x80000000,addr,tl); #ifdef HOST_IMM_ADDR32 if(c) @@ -2877,16 +2994,18 @@ void load_assemble(int i,struct regstat *i_regs) else #endif emit_readword_indexed_tlb(0,addr,map,tl); - if(jaddr) - add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); - } - else { - inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); } - emit_zeroreg(th); + if(jaddr) + add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + } + else { + inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); } - if (opcode[i]==0x37) { // LD - if(!c||memtarget) { + emit_zeroreg(th); + } + if (opcode[i]==0x37) { // LD + if(!c||memtarget) { + if(!dummy) { //gen_tlb_addr_r(tl,map); //if(th>=0) emit_readword_indexed((int)rdram-0x80000000,addr,th); //emit_readword_indexed((int)rdram-0x7FFFFFFC,addr,tl); @@ -2896,14 +3015,15 @@ void load_assemble(int i,struct regstat *i_regs) else #endif emit_readdword_indexed_tlb(0,addr,map,th,tl); - if(jaddr) - add_stub(LOADD_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - else - inline_readstub(LOADD_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + if(jaddr) + add_stub(LOADD_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - //emit_storereg(rt1[i],tl); // DEBUG + else + inline_readstub(LOADD_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); } + } + //emit_storereg(rt1[i],tl); // DEBUG //if(opcode[i]==0x23) //if(opcode[i]==0x24) //if(opcode[i]==0x23||opcode[i]==0x24) @@ -2948,7 +3068,7 @@ void store_assemble(int i,struct regstat *i_regs) int addr,temp; int offset; int jaddr=0,jaddr2,type; - int memtarget,c=0; + int memtarget=0,c=0; int agr=AGEN1+(i&1); u_int hr,reglist=0; th=get_reg(i_regs->regmap,rs2[i]|64); @@ -2959,7 +3079,7 @@ void store_assemble(int i,struct regstat *i_regs) offset=imm[i]; if(s>=0) { c=(i_regs->wasconst>>s)&1; - memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; + 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; } assert(tl>=0); @@ -2975,14 +3095,14 @@ void store_assemble(int i,struct regstat *i_regs) #ifdef R29_HACK // Strmnnrmn's speed hack memtarget=1; - if(rs1[i]!=29||start<0x80001000||start>=0x80800000) + if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE) #endif - emit_cmpimm(addr,0x800000); + emit_cmpimm(addr,RAM_SIZE); #ifdef DESTRUCTIVE_SHIFT if(s==addr) emit_mov(s,temp); #endif #ifdef R29_HACK - if(rs1[i]!=29||start<0x80001000||start>=0x80800000) + if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE) #endif { jaddr=(int)out; @@ -3064,11 +3184,6 @@ void store_assemble(int i,struct regstat *i_regs) } type=STORED_STUB; } - if(jaddr) { - add_stub(type,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); - } else if(!memtarget) { - inline_writestub(type,i,constmap[i][s]+offset,i_regs->regmap,rs2[i],ccadj[i],reglist); - } if(!using_tlb) { if(!c||memtarget) { #ifdef DESTRUCTIVE_SHIFT @@ -3083,11 +3198,20 @@ void store_assemble(int i,struct regstat *i_regs) #else emit_cmpmem_indexedsr12_imm((int)invalid_code,addr,1); #endif + #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT) + emit_callne(invalidate_addr_reg[addr]); + #else jaddr2=(int)out; emit_jne(0); add_stub(INVCODE_STUB,jaddr2,(int)out,reglist|(1<regmap,rs2[i],ccadj[i],reglist); + } //if(opcode[i]==0x2B || opcode[i]==0x3F) //if(opcode[i]==0x2B || opcode[i]==0x28) //if(opcode[i]==0x2B || opcode[i]==0x29) @@ -3129,196 +3253,208 @@ void storelr_assemble(int i,struct regstat *i_regs) int case1,case2,case3; int done0,done1,done2; int memtarget,c=0; + int agr=AGEN1+(i&1); u_int hr,reglist=0; th=get_reg(i_regs->regmap,rs2[i]|64); tl=get_reg(i_regs->regmap,rs2[i]); s=get_reg(i_regs->regmap,rs1[i]); - temp=get_reg(i_regs->regmap,-1); + temp=get_reg(i_regs->regmap,agr); + if(temp<0) temp=get_reg(i_regs->regmap,-1); offset=imm[i]; if(s>=0) { c=(i_regs->isconst>>s)&1; - memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; + 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; } assert(tl>=0); for(hr=0;hrregmap[hr]>=0) reglist|=1<=0) { - assert(temp>=0); - if(!using_tlb) { - if(!c) { - emit_cmpimm(s<0||offset?temp:s,0x800000); - if(!offset&&s!=temp) emit_mov(s,temp); - jaddr=(int)out; - emit_jno(0); - } - else - { - if(!memtarget||!rs1[i]) { - jaddr=(int)out; - emit_jmp(0); - } - } - if((u_int)rdram!=0x80000000) - emit_addimm_no_flags((u_int)rdram-(u_int)0x80000000,temp); - }else{ // using tlb - int map=get_reg(i_regs->regmap,TLREG); - assert(map>=0); - map=do_tlb_w(c||s<0||offset?temp:s,temp,map,0,c,constmap[i][s]+offset); - if(!c&&!offset&&s>=0) emit_mov(s,temp); - do_tlb_w_branch(map,c,constmap[i][s]+offset,&jaddr); - if(!jaddr&&!memtarget) { + assert(temp>=0); + if(!using_tlb) { + if(!c) { + emit_cmpimm(s<0||offset?temp:s,RAM_SIZE); + if(!offset&&s!=temp) emit_mov(s,temp); + jaddr=(int)out; + emit_jno(0); + } + else + { + if(!memtarget||!rs1[i]) { jaddr=(int)out; emit_jmp(0); } - gen_tlb_addr_w(temp,map); } - - if (opcode[i]==0x2C||opcode[i]==0x2D) { // SDL/SDR - temp2=get_reg(i_regs->regmap,FTEMP); - if(!rs2[i]) temp2=th=tl; + #ifdef RAM_OFFSET + int map=get_reg(i_regs->regmap,ROREG); + if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); + gen_tlb_addr_w(temp,map); + #else + if((u_int)rdram!=0x80000000) + emit_addimm_no_flags((u_int)rdram-(u_int)0x80000000,temp); + #endif + }else{ // using tlb + int map=get_reg(i_regs->regmap,TLREG); + assert(map>=0); + map=do_tlb_w(c||s<0||offset?temp:s,temp,map,0,c,constmap[i][s]+offset); + if(!c&&!offset&&s>=0) emit_mov(s,temp); + do_tlb_w_branch(map,c,constmap[i][s]+offset,&jaddr); + if(!jaddr&&!memtarget) { + jaddr=(int)out; + emit_jmp(0); } + gen_tlb_addr_w(temp,map); + } + + if (opcode[i]==0x2C||opcode[i]==0x2D) { // SDL/SDR + temp2=get_reg(i_regs->regmap,FTEMP); + if(!rs2[i]) temp2=th=tl; + } #ifndef BIG_ENDIAN_MIPS emit_xorimm(temp,3,temp); #endif - emit_testimm(temp,2); - case2=(int)out; - emit_jne(0); - emit_testimm(temp,1); - case1=(int)out; - emit_jne(0); - // 0 - if (opcode[i]==0x2A) { // SWL - emit_writeword_indexed(tl,0,temp); - } - if (opcode[i]==0x2E) { // SWR - emit_writebyte_indexed(tl,3,temp); - } - if (opcode[i]==0x2C) { // SDL - emit_writeword_indexed(th,0,temp); - if(rs2[i]) emit_mov(tl,temp2); - } - if (opcode[i]==0x2D) { // SDR - emit_writebyte_indexed(tl,3,temp); - if(rs2[i]) emit_shldimm(th,tl,24,temp2); - } + emit_testimm(temp,2); + case2=(int)out; + emit_jne(0); + emit_testimm(temp,1); + case1=(int)out; + emit_jne(0); + // 0 + if (opcode[i]==0x2A) { // SWL + emit_writeword_indexed(tl,0,temp); + } + if (opcode[i]==0x2E) { // SWR + emit_writebyte_indexed(tl,3,temp); + } + if (opcode[i]==0x2C) { // SDL + emit_writeword_indexed(th,0,temp); + if(rs2[i]) emit_mov(tl,temp2); + } + if (opcode[i]==0x2D) { // SDR + emit_writebyte_indexed(tl,3,temp); + if(rs2[i]) emit_shldimm(th,tl,24,temp2); + } + done0=(int)out; + emit_jmp(0); + // 1 + set_jump_target(case1,(int)out); + if (opcode[i]==0x2A) { // SWL + // Write 3 msb into three least significant bytes + if(rs2[i]) emit_rorimm(tl,8,tl); + emit_writehword_indexed(tl,-1,temp); + if(rs2[i]) emit_rorimm(tl,16,tl); + emit_writebyte_indexed(tl,1,temp); + if(rs2[i]) emit_rorimm(tl,8,tl); + } + if (opcode[i]==0x2E) { // SWR + // Write two lsb into two most significant bytes + emit_writehword_indexed(tl,1,temp); + } + if (opcode[i]==0x2C) { // SDL + if(rs2[i]) emit_shrdimm(tl,th,8,temp2); + // Write 3 msb into three least significant bytes + if(rs2[i]) emit_rorimm(th,8,th); + emit_writehword_indexed(th,-1,temp); + if(rs2[i]) emit_rorimm(th,16,th); + emit_writebyte_indexed(th,1,temp); + if(rs2[i]) emit_rorimm(th,8,th); + } + if (opcode[i]==0x2D) { // SDR + if(rs2[i]) emit_shldimm(th,tl,16,temp2); + // Write two lsb into two most significant bytes + emit_writehword_indexed(tl,1,temp); + } + done1=(int)out; + emit_jmp(0); + // 2 + set_jump_target(case2,(int)out); + emit_testimm(temp,1); + case3=(int)out; + emit_jne(0); + if (opcode[i]==0x2A) { // SWL + // Write two msb into two least significant bytes + if(rs2[i]) emit_rorimm(tl,16,tl); + emit_writehword_indexed(tl,-2,temp); + if(rs2[i]) emit_rorimm(tl,16,tl); + } + if (opcode[i]==0x2E) { // SWR + // Write 3 lsb into three most significant bytes + emit_writebyte_indexed(tl,-1,temp); + if(rs2[i]) emit_rorimm(tl,8,tl); + emit_writehword_indexed(tl,0,temp); + if(rs2[i]) emit_rorimm(tl,24,tl); + } + if (opcode[i]==0x2C) { // SDL + if(rs2[i]) emit_shrdimm(tl,th,16,temp2); + // Write two msb into two least significant bytes + if(rs2[i]) emit_rorimm(th,16,th); + emit_writehword_indexed(th,-2,temp); + if(rs2[i]) emit_rorimm(th,16,th); + } + if (opcode[i]==0x2D) { // SDR + if(rs2[i]) emit_shldimm(th,tl,8,temp2); + // Write 3 lsb into three most significant bytes + emit_writebyte_indexed(tl,-1,temp); + if(rs2[i]) emit_rorimm(tl,8,tl); + emit_writehword_indexed(tl,0,temp); + if(rs2[i]) emit_rorimm(tl,24,tl); + } + done2=(int)out; + emit_jmp(0); + // 3 + set_jump_target(case3,(int)out); + if (opcode[i]==0x2A) { // SWL + // Write msb into least significant byte + if(rs2[i]) emit_rorimm(tl,24,tl); + emit_writebyte_indexed(tl,-3,temp); + if(rs2[i]) emit_rorimm(tl,8,tl); + } + if (opcode[i]==0x2E) { // SWR + // Write entire word + emit_writeword_indexed(tl,-3,temp); + } + if (opcode[i]==0x2C) { // SDL + if(rs2[i]) emit_shrdimm(tl,th,24,temp2); + // Write msb into least significant byte + if(rs2[i]) emit_rorimm(th,24,th); + emit_writebyte_indexed(th,-3,temp); + if(rs2[i]) emit_rorimm(th,8,th); + } + if (opcode[i]==0x2D) { // SDR + if(rs2[i]) emit_mov(th,temp2); + // Write entire word + emit_writeword_indexed(tl,-3,temp); + } + set_jump_target(done0,(int)out); + set_jump_target(done1,(int)out); + set_jump_target(done2,(int)out); + if (opcode[i]==0x2C) { // SDL + emit_testimm(temp,4); done0=(int)out; - emit_jmp(0); - // 1 - set_jump_target(case1,(int)out); - if (opcode[i]==0x2A) { // SWL - // Write 3 msb into three least significant bytes - if(rs2[i]) emit_rorimm(tl,8,tl); - emit_writehword_indexed(tl,-1,temp); - if(rs2[i]) emit_rorimm(tl,16,tl); - emit_writebyte_indexed(tl,1,temp); - if(rs2[i]) emit_rorimm(tl,8,tl); - } - if (opcode[i]==0x2E) { // SWR - // Write two lsb into two most significant bytes - emit_writehword_indexed(tl,1,temp); - } - if (opcode[i]==0x2C) { // SDL - if(rs2[i]) emit_shrdimm(tl,th,8,temp2); - // Write 3 msb into three least significant bytes - if(rs2[i]) emit_rorimm(th,8,th); - emit_writehword_indexed(th,-1,temp); - if(rs2[i]) emit_rorimm(th,16,th); - emit_writebyte_indexed(th,1,temp); - if(rs2[i]) emit_rorimm(th,8,th); - } - if (opcode[i]==0x2D) { // SDR - if(rs2[i]) emit_shldimm(th,tl,16,temp2); - // Write two lsb into two most significant bytes - emit_writehword_indexed(tl,1,temp); - } - done1=(int)out; - emit_jmp(0); - // 2 - set_jump_target(case2,(int)out); - emit_testimm(temp,1); - case3=(int)out; emit_jne(0); - if (opcode[i]==0x2A) { // SWL - // Write two msb into two least significant bytes - if(rs2[i]) emit_rorimm(tl,16,tl); - emit_writehword_indexed(tl,-2,temp); - if(rs2[i]) emit_rorimm(tl,16,tl); - } - if (opcode[i]==0x2E) { // SWR - // Write 3 lsb into three most significant bytes - emit_writebyte_indexed(tl,-1,temp); - if(rs2[i]) emit_rorimm(tl,8,tl); - emit_writehword_indexed(tl,0,temp); - if(rs2[i]) emit_rorimm(tl,24,tl); - } - if (opcode[i]==0x2C) { // SDL - if(rs2[i]) emit_shrdimm(tl,th,16,temp2); - // Write two msb into two least significant bytes - if(rs2[i]) emit_rorimm(th,16,th); - emit_writehword_indexed(th,-2,temp); - if(rs2[i]) emit_rorimm(th,16,th); - } - if (opcode[i]==0x2D) { // SDR - if(rs2[i]) emit_shldimm(th,tl,8,temp2); - // Write 3 lsb into three most significant bytes - emit_writebyte_indexed(tl,-1,temp); - if(rs2[i]) emit_rorimm(tl,8,tl); - emit_writehword_indexed(tl,0,temp); - if(rs2[i]) emit_rorimm(tl,24,tl); - } - done2=(int)out; - emit_jmp(0); - // 3 - set_jump_target(case3,(int)out); - if (opcode[i]==0x2A) { // SWL - // Write msb into least significant byte - if(rs2[i]) emit_rorimm(tl,24,tl); - emit_writebyte_indexed(tl,-3,temp); - if(rs2[i]) emit_rorimm(tl,8,tl); - } - if (opcode[i]==0x2E) { // SWR - // Write entire word - emit_writeword_indexed(tl,-3,temp); - } - if (opcode[i]==0x2C) { // SDL - if(rs2[i]) emit_shrdimm(tl,th,24,temp2); - // Write msb into least significant byte - if(rs2[i]) emit_rorimm(th,24,th); - emit_writebyte_indexed(th,-3,temp); - if(rs2[i]) emit_rorimm(th,8,th); - } - if (opcode[i]==0x2D) { // SDR - if(rs2[i]) emit_mov(th,temp2); - // Write entire word - emit_writeword_indexed(tl,-3,temp); - } + emit_andimm(temp,~3,temp); + emit_writeword_indexed(temp2,4,temp); set_jump_target(done0,(int)out); - set_jump_target(done1,(int)out); - set_jump_target(done2,(int)out); - if (opcode[i]==0x2C) { // SDL - emit_testimm(temp,4); - done0=(int)out; - emit_jne(0); - emit_andimm(temp,~3,temp); - emit_writeword_indexed(temp2,4,temp); - set_jump_target(done0,(int)out); - } - if (opcode[i]==0x2D) { // SDR - emit_testimm(temp,4); - done0=(int)out; - emit_jeq(0); - emit_andimm(temp,~3,temp); - emit_writeword_indexed(temp2,-4,temp); - set_jump_target(done0,(int)out); - } - if(!c||!memtarget) - add_stub(STORELR_STUB,jaddr,(int)out,0,(int)i_regs,rs2[i],ccadj[i],reglist); } + if (opcode[i]==0x2D) { // SDR + emit_testimm(temp,4); + done0=(int)out; + emit_jeq(0); + emit_andimm(temp,~3,temp); + emit_writeword_indexed(temp2,-4,temp); + set_jump_target(done0,(int)out); + } + if(!c||!memtarget) + add_stub(STORELR_STUB,jaddr,(int)out,i,(int)i_regs,temp,ccadj[i],reglist); if(!using_tlb) { + #ifdef RAM_OFFSET + int map=get_reg(i_regs->regmap,ROREG); + if(map<0) map=HOST_TEMPREG; + gen_orig_addr_w(temp,map); + #else emit_addimm_no_flags((u_int)0x80000000-(u_int)rdram,temp); + #endif #if defined(HOST_IMM8) int ir=get_reg(i_regs->regmap,INVCP); assert(ir>=0); @@ -3326,9 +3462,13 @@ void storelr_assemble(int i,struct regstat *i_regs) #else emit_cmpmem_indexedsr12_imm((int)invalid_code,temp,1); #endif + #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT) + emit_callne(invalidate_addr_reg[temp]); + #else jaddr2=(int)out; emit_jne(0); add_stub(INVCODE_STUB,jaddr2,(int)out,reglist|(1<=(signed int)0x80800000) { + else if(((signed int)(constmap[i][s]+offset))>=(signed int)0x80000000+RAM_SIZE) { jaddr2=(int)out; emit_jmp(0); // inline_readstub/inline_writestub? Very rare case } @@ -3496,9 +3636,13 @@ void c1ls_assemble(int i,struct regstat *i_regs) #else emit_cmpmem_indexedsr12_imm((int)invalid_code,temp,1); #endif + #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT) + emit_callne(invalidate_addr_reg[temp]); + #else jaddr3=(int)out; emit_jne(0); add_stub(INVCODE_STUB,jaddr3,(int)out,reglist|(1<>16)&0x1f; + s=get_reg(i_regs->regmap,rs1[i]); + tl=get_reg(i_regs->regmap,FTEMP); + offset=imm[i]; + assert(rs1[i]>0); + assert(tl>=0); + assert(!using_tlb); + + for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) + reglist&=~(1<regmap,agr); + if(ar<0) ar=get_reg(i_regs->regmap,-1); + reglist|=1<=0) c=(i_regs->wasconst>>s)&1; + memtarget=c&&(((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE); + if (!offset&&!c&&s>=0) ar=s; + assert(ar>=0); + + if (opcode[i]==0x3a) { // SWC2 + cop2_get_dreg(copr,tl,HOST_TEMPREG); + type=STOREW_STUB; + } + else + type=LOADW_STUB; + + if(c&&!memtarget) { + jaddr2=(int)out; + emit_jmp(0); // inline_readstub/inline_writestub? + } + else { + if(!c) { + emit_cmpimm(offset||c||s<0?ar:s,RAM_SIZE); + jaddr2=(int)out; + emit_jno(0); + } + if (opcode[i]==0x32) { // LWC2 + #ifdef HOST_IMM_ADDR32 + if(c) emit_readword_tlb(constmap[i][s]+offset,-1,tl); + else + #endif + emit_readword_indexed(0,ar,tl); + } + if (opcode[i]==0x3a) { // SWC2 + #ifdef DESTRUCTIVE_SHIFT + if(!offset&&!c&&s>=0) emit_mov(s,ar); + #endif + emit_writeword_indexed(tl,0,ar); + } + } + if(jaddr2) + add_stub(type,jaddr2,(int)out,i,ar,(int)i_regs,ccadj[i],reglist); + if (opcode[i]==0x3a) { // SWC2 +#if defined(HOST_IMM8) + int ir=get_reg(i_regs->regmap,INVCP); + assert(ir>=0); + emit_cmpmem_indexedsr12_reg(ir,ar,1); +#else + emit_cmpmem_indexedsr12_imm((int)invalid_code,ar,1); +#endif + #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT) + emit_callne(invalidate_addr_reg[ar]); + #else + jaddr3=(int)out; + emit_jne(0); + add_stub(INVCODE_STUB,jaddr3,(int)out,reglist|(1<0); if(rt1[i]) { signed char sh,sl,th,tl; th=get_reg(i_regs->regmap,rt1[i]|64); @@ -3581,7 +3814,28 @@ void syscall_assemble(int i,struct regstat *i_regs) assert(!is_delayslot); emit_movimm(start+i*4,EAX); // Get PC emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle... - emit_jmp((int)jump_syscall); + emit_jmp((int)jump_syscall_hle); // XXX +} + +void hlecall_assemble(int i,struct regstat *i_regs) +{ + signed char ccreg=get_reg(i_regs->regmap,CCREG); + assert(ccreg==HOST_CCREG); + assert(!is_delayslot); + emit_movimm(start+i*4+4,0); // Get PC + emit_movimm((int)psxHLEt[source[i]&7],1); + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // XXX + emit_jmp((int)jump_hlecall); +} + +void intcall_assemble(int i,struct regstat *i_regs) +{ + signed char ccreg=get_reg(i_regs->regmap,CCREG); + assert(ccreg==HOST_CCREG); + assert(!is_delayslot); + emit_movimm(start+i*4,0); // Get PC + emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_jmp((int)jump_intcall); } void ds_assemble(int i,struct regstat *i_regs) @@ -3610,6 +3864,12 @@ void ds_assemble(int i,struct regstat *i_regs) cop1_assemble(i,i_regs);break; case C1LS: c1ls_assemble(i,i_regs);break; + case COP2: + cop2_assemble(i,i_regs);break; + case C2LS: + c2ls_assemble(i,i_regs);break; + case C2OP: + c2op_assemble(i,i_regs);break; case FCONV: fconv_assemble(i,i_regs);break; case FLOAT: @@ -3621,6 +3881,8 @@ void ds_assemble(int i,struct regstat *i_regs) case MOV: mov_assemble(i,i_regs);break; case SYSCALL: + case HLECALL: + case INTCALL: case SPAN: case UJUMP: case RJUMP: @@ -3648,8 +3910,11 @@ int internal_branch(uint64_t i_is32,int addr) else printf("optimizable: yes\n"); }*/ //if(is32[t]&~unneeded_reg_upper[t]&~i_is32) return 0; +#ifndef FORCE32 if(requires_32bit[t]&~i_is32) return 0; - else return 1; + else +#endif + return 1; } return 0; } @@ -3778,15 +4043,17 @@ static void loop_preload(signed char pre[],signed char entry[]) } // Generate address for load/store instruction +// goes to AGEN for writes, FTEMP for LOADLR and cop1/2 loads void address_generation(int i,struct regstat *i_regs,signed char entry[]) { - if(itype[i]==LOAD||itype[i]==LOADLR||itype[i]==STORE||itype[i]==STORELR||itype[i]==C1LS) { + if(itype[i]==LOAD||itype[i]==LOADLR||itype[i]==STORE||itype[i]==STORELR||itype[i]==C1LS||itype[i]==C2LS) { int ra; int agr=AGEN1+(i&1); int mgr=MGEN1+(i&1); if(itype[i]==LOAD) { ra=get_reg(i_regs->regmap,rt1[i]); - //if(rt1[i]) assert(ra>=0); + if(ra<0) ra=get_reg(i_regs->regmap,-1); + assert(ra>=0); } if(itype[i]==LOADLR) { ra=get_reg(i_regs->regmap,FTEMP); @@ -3795,10 +4062,10 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) ra=get_reg(i_regs->regmap,agr); if(ra<0) ra=get_reg(i_regs->regmap,-1); } - if(itype[i]==C1LS) { - if (opcode[i]==0x31||opcode[i]==0x35) // LWC1/LDC1 + if(itype[i]==C1LS||itype[i]==C2LS) { + if ((opcode[i]&0x3b)==0x31||(opcode[i]&0x3b)==0x32) // LWC1/LDC1/LWC2/LDC2 ra=get_reg(i_regs->regmap,FTEMP); - else { // SWC1/SDC1 + else { // SWC1/SDC1/SWC2/SDC2 ra=get_reg(i_regs->regmap,agr); if(ra<0) ra=get_reg(i_regs->regmap,-1); } @@ -3834,11 +4101,11 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) else if(c) { if(rm>=0) { if(!entry||entry[rm]!=mgr) { - if(itype[i]==STORE||itype[i]==STORELR||opcode[i]==0x39||opcode[i]==0x3D) { + if(itype[i]==STORE||itype[i]==STORELR||(opcode[i]&0x3b)==0x39||(opcode[i]&0x3b)==0x3a) { // Stores to memory go thru the mapper to detect self-modifying // code, loads don't. if((unsigned int)(constmap[i][rs]+offset)>=0xC0000000 || - (unsigned int)(constmap[i][rs]+offset)<0x80800000 ) + (unsigned int)(constmap[i][rs]+offset)<0x80000000+RAM_SIZE ) generate_map_const(constmap[i][rs]+offset,rm); }else{ if((signed int)(constmap[i][rs]+offset)>=(signed int)0xC0000000) @@ -3854,7 +4121,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) emit_movimm((constmap[i][rs]+offset)&0xFFFFFFF8,ra); // LDL/LDR }else{ #ifdef HOST_IMM_ADDR32 - if((itype[i]!=LOAD&&opcode[i]!=0x31&&opcode[i]!=0x35) || + if((itype[i]!=LOAD&&(opcode[i]&0x3b)!=0x31&&(opcode[i]&0x3b)!=0x32) || // LWC1/LDC1/LWC2/LDC2 (using_tlb&&((signed int)constmap[i][rs]+offset)>=(signed int)0xC0000000)) #endif emit_movimm(constmap[i][rs]+offset,ra); @@ -3872,7 +4139,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) } } // Preload constants for next instruction - if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) { + if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS||itype[i+1]==C2LS) { int agr,ra; #ifndef HOST_IMM_ADDR32 // Mapper entry @@ -3883,11 +4150,12 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) int offset=imm[i+1]; int c=(regs[i+1].wasconst>>rs)&1; if(c) { - if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { + if(itype[i+1]==STORE||itype[i+1]==STORELR + ||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SWC1/SDC1, SWC2/SDC2 // Stores to memory go thru the mapper to detect self-modifying // code, loads don't. if((unsigned int)(constmap[i+1][rs]+offset)>=0xC0000000 || - (unsigned int)(constmap[i+1][rs]+offset)<0x80800000 ) + (unsigned int)(constmap[i+1][rs]+offset)<0x80000000+RAM_SIZE ) generate_map_const(constmap[i+1][rs]+offset,ra); }else{ if((signed int)(constmap[i+1][rs]+offset)>=(signed int)0xC0000000) @@ -3913,7 +4181,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) emit_movimm((constmap[i+1][rs]+offset)&0xFFFFFFF8,ra); // LDL/LDR }else{ #ifdef HOST_IMM_ADDR32 - if((itype[i+1]!=LOAD&&opcode[i+1]!=0x31&&opcode[i+1]!=0x35) || + if((itype[i+1]!=LOAD&&(opcode[i+1]&0x3b)!=0x31&&(opcode[i+1]&0x3b)!=0x32) || // LWC1/LDC1/LWC2/LDC2 (using_tlb&&((signed int)constmap[i+1][rs]+offset)>=(signed int)0xC0000000)) #endif emit_movimm(constmap[i+1][rs]+offset,ra); @@ -4387,7 +4655,9 @@ int match_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr) } } //if(is32[t]&~unneeded_reg_upper[t]&~i_is32) return 0; +#ifndef FORCE32 if(requires_32bit[t]&~i_is32) return 0; +#endif // Delay slots are not valid branch targets //if(t>0&&(itype[t-1]==RJUMP||itype[t-1]==UJUMP||itype[t-1]==CJUMP||itype[t-1]==SJUMP||itype[t-1]==FJUMP)) return 0; // Delay slots require additional processing, so do not match @@ -4427,7 +4697,7 @@ void ds_assemble_entry(int i) wb_register(CCREG,regs[t].regmap_entry,regs[t].wasdirty,regs[t].was32); load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,rs1[t],rs2[t]); address_generation(t,®s[t],regs[t].regmap_entry); - if(itype[t]==STORE||itype[t]==STORELR||(opcode[t]&0x3b)==0x39) + if(itype[t]==STORE||itype[t]==STORELR||(opcode[t]&0x3b)==0x39||(opcode[t]&0x3b)==0x3a) load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,INVCP,INVCP); cop1_usable=0; is_delayslot=0; @@ -4454,6 +4724,12 @@ void ds_assemble_entry(int i) cop1_assemble(t,®s[t]);break; case C1LS: c1ls_assemble(t,®s[t]);break; + case COP2: + cop2_assemble(t,®s[t]);break; + case C2LS: + c2ls_assemble(t,®s[t]);break; + case C2OP: + c2op_assemble(t,®s[t]);break; case FCONV: fconv_assemble(t,®s[t]);break; case FLOAT: @@ -4465,6 +4741,8 @@ void ds_assemble_entry(int i) case MOV: mov_assemble(t,®s[t]);break; case SYSCALL: + case HLECALL: + case INTCALL: case SPAN: case UJUMP: case RJUMP: @@ -4931,11 +5209,11 @@ void rjump_assemble(int i,struct regstat *i_regs) wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32, bc_unneeded,bc_unneeded_upper); load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,rs1[i],CCREG); - if(rt1[i]==31) { + if(rt1[i]!=0) { int rt,return_address; - assert(rt1[i+1]!=31); - assert(rt2[i+1]!=31); - rt=get_reg(branch_regs[i].regmap,31); + assert(rt1[i+1]!=rt1[i]); + assert(rt2[i+1]!=rt1[i]); + rt=get_reg(branch_regs[i].regmap,rt1[i]); assem_debug("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); assert(rt>=0); return_address=start+i*4+8; @@ -5042,26 +5320,15 @@ void cjump_assemble(int i,struct regstat *i_regs) int prev_cop1_usable=cop1_usable; int unconditional=0,nop=0; int only32=0; - int ooo=1; int invert=0; int internal=internal_branch(branch_regs[i].is32,ba[i]); if(i==(ba[i]-start)>>2) assem_debug("idle loop\n"); - if(likely[i]) ooo=0; if(!match) invert=1; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(i>(ba[i]-start)>>2) invert=1; #endif - - if(ooo) - if((rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]))|| - (rs2[i]&&(rs2[i]==rt1[i+1]||rs2[i]==rt2[i+1]))) - { - // Write-after-read dependency prevents out of order execution - // First test branch condition, then execute delay slot, then branch - ooo=0; - } - - if(ooo) { + + if(ooo[i]) { s1l=get_reg(branch_regs[i].regmap,rs1[i]); s1h=get_reg(branch_regs[i].regmap,rs1[i]|64); s2l=get_reg(branch_regs[i].regmap,rs2[i]); @@ -5097,7 +5364,7 @@ void cjump_assemble(int i,struct regstat *i_regs) only32=(regs[i].was32>>rs1[i])&(regs[i].was32>>rs2[i])&1; } - if(ooo) { + if(ooo[i]) { // Out of order execution (delay slot first) //printf("OOOE\n"); address_generation(i+1,i_regs,regs[i].regmap_entry); @@ -5436,30 +5703,18 @@ void sjump_assemble(int i,struct regstat *i_regs) int prev_cop1_usable=cop1_usable; int unconditional=0,nevertaken=0; int only32=0; - int ooo=1; int invert=0; int internal=internal_branch(branch_regs[i].is32,ba[i]); if(i==(ba[i]-start)>>2) assem_debug("idle loop\n"); - if(likely[i]) ooo=0; if(!match) invert=1; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(i>(ba[i]-start)>>2) invert=1; #endif //if(opcode2[i]>=0x10) return; // FIXME (BxxZAL) - assert(opcode2[i]<0x10||rs1[i]==0); // FIXME (BxxZAL) - - if(ooo) - if(rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1])) - { - // Write-after-read dependency prevents out of order execution - // First test branch condition, then execute delay slot, then branch - ooo=0; - } - // TODO: Conditional branches w/link must execute in-order so that - // condition test and write to r31 occur before cycle count test + //assert(opcode2[i]<0x10||rs1[i]==0); // FIXME (BxxZAL) - if(ooo) { + if(ooo[i]) { s1l=get_reg(branch_regs[i].regmap,rs1[i]); s1h=get_reg(branch_regs[i].regmap,rs1[i]|64); } @@ -5481,7 +5736,7 @@ void sjump_assemble(int i,struct regstat *i_regs) only32=(regs[i].was32>>rs1[i])&1; } - if(ooo) { + if(ooo[i]) { // Out of order execution (delay slot first) //printf("OOOE\n"); address_generation(i+1,i_regs,regs[i].regmap_entry); @@ -5499,8 +5754,6 @@ void sjump_assemble(int i,struct regstat *i_regs) load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG); if(rt1[i]==31) { int rt,return_address; - assert(rt1[i+1]!=31); - assert(rt2[i+1]!=31); rt=get_reg(branch_regs[i].regmap,31); assem_debug("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); if(rt>=0) { @@ -5552,7 +5805,7 @@ void sjump_assemble(int i,struct regstat *i_regs) if(!only32) { assert(s1h>=0); - if(opcode2[i]==0) // BLTZ + if((opcode2[i]&0xf)==0) // BLTZ/BLTZAL { emit_test(s1h,s1h); if(invert){ @@ -5563,7 +5816,7 @@ void sjump_assemble(int i,struct regstat *i_regs) emit_js(0); } } - if(opcode2[i]==1) // BGEZ + if((opcode2[i]&0xf)==1) // BGEZ/BLTZAL { emit_test(s1h,s1h); if(invert){ @@ -5578,7 +5831,7 @@ void sjump_assemble(int i,struct regstat *i_regs) else { assert(s1l>=0); - if(opcode2[i]==0) // BLTZ + if((opcode2[i]&0xf)==0) // BLTZ/BLTZAL { emit_test(s1l,s1l); if(invert){ @@ -5589,7 +5842,7 @@ void sjump_assemble(int i,struct regstat *i_regs) emit_js(0); } } - if(opcode2[i]==1) // BGEZ + if((opcode2[i]&0xf)==1) // BGEZ/BLTZAL { emit_test(s1l,s1l); if(invert){ @@ -5644,18 +5897,30 @@ void sjump_assemble(int i,struct regstat *i_regs) // In-order execution (branch first) //printf("IOE\n"); int nottaken=0; + if(rt1[i]==31) { + int rt,return_address; + rt=get_reg(branch_regs[i].regmap,31); + if(rt>=0) { + // Save the PC even if the branch is not taken + return_address=start+i*4+8; + emit_movimm(return_address,rt); // PC into link register + #ifdef IMM_PREFETCH + emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); + #endif + } + } if(!unconditional) { //printf("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); if(!only32) { assert(s1h>=0); - if((opcode2[i]&0x1d)==0) // BLTZ/BLTZL + if((opcode2[i]&0x0d)==0) // BLTZ/BLTZL/BLTZAL/BLTZALL { emit_test(s1h,s1h); nottaken=(int)out; emit_jns(1); } - if((opcode2[i]&0x1d)==1) // BGEZ/BGEZL + if((opcode2[i]&0x0d)==1) // BGEZ/BGEZL/BGEZAL/BGEZALL { emit_test(s1h,s1h); nottaken=(int)out; @@ -5665,13 +5930,13 @@ void sjump_assemble(int i,struct regstat *i_regs) else { assert(s1l>=0); - if((opcode2[i]&0x1d)==0) // BLTZ/BLTZL + if((opcode2[i]&0x0d)==0) // BLTZ/BLTZL/BLTZAL/BLTZALL { emit_test(s1l,s1l); nottaken=(int)out; emit_jns(1); } - if((opcode2[i]&0x1d)==1) // BGEZ/BGEZL + if((opcode2[i]&0x0d)==1) // BGEZ/BGEZL/BGEZAL/BGEZALL { emit_test(s1l,s1l); nottaken=(int)out; @@ -5764,25 +6029,15 @@ void fjump_assemble(int i,struct regstat *i_regs) assem_debug("fmatch=%d\n",match); int fs,cs; int eaddr; - int ooo=1; int invert=0; int internal=internal_branch(branch_regs[i].is32,ba[i]); if(i==(ba[i]-start)>>2) assem_debug("idle loop\n"); - if(likely[i]) ooo=0; if(!match) invert=1; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(i>(ba[i]-start)>>2) invert=1; #endif - if(ooo) - if(itype[i+1]==FCOMP) - { - // Write-after-read dependency prevents out of order execution - // First test branch condition, then execute delay slot, then branch - ooo=0; - } - - if(ooo) { + if(ooo[i]) { fs=get_reg(branch_regs[i].regmap,FSREG); address_generation(i+1,i_regs,regs[i].regmap_entry); // Is this okay? } @@ -5801,7 +6056,7 @@ void fjump_assemble(int i,struct regstat *i_regs) cop1_usable=1; } - if(ooo) { + if(ooo[i]) { // Out of order execution (delay slot first) //printf("OOOE\n"); ds_assemble(i+1,i_regs); @@ -6051,7 +6306,7 @@ static void pagespan_assemble(int i,struct regstat *i_regs) emit_mov(s1l,addr); if(opcode2[i]==9) // JALR { - int rt=get_reg(i_regs->regmap,31); + int rt=get_reg(i_regs->regmap,rt1[i]); emit_movimm(start+i*4+8,rt); } } @@ -6252,7 +6507,7 @@ static void pagespan_ds() emit_writeword(HOST_BTREG,(int)&branch_target); load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,rs1[0],rs2[0]); address_generation(0,®s[0],regs[0].regmap_entry); - if(itype[0]==STORE||itype[0]==STORELR||(opcode[0]&0x3b)==0x39) + if(itype[0]==STORE||itype[0]==STORELR||(opcode[0]&0x3b)==0x39||(opcode[0]&0x3b)==0x3a) load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,INVCP,INVCP); cop1_usable=0; is_delayslot=0; @@ -6279,6 +6534,12 @@ static void pagespan_ds() cop1_assemble(0,®s[0]);break; case C1LS: c1ls_assemble(0,®s[0]);break; + case COP2: + cop2_assemble(0,®s[0]);break; + case C2LS: + c2ls_assemble(0,®s[0]);break; + case C2OP: + c2op_assemble(0,®s[0]);break; case FCONV: fconv_assemble(0,®s[0]);break; case FLOAT: @@ -6290,6 +6551,8 @@ static void pagespan_ds() case MOV: mov_assemble(0,®s[0]);break; case SYSCALL: + case HLECALL: + case INTCALL: case SPAN: case UJUMP: case RJUMP: @@ -6356,7 +6619,7 @@ void unneeded_registers(int istart,int iend,int r) { uu=u=0x300C0F3; // Discard at, a0-a3, t6-t9 } - if(start>0x80000400&&start<0x80800000) { + if(start>0x80000400&&start<0x80000000+RAM_SIZE) { if(itype[i]==UJUMP&&rt1[i]==31) { //uu=u=0x30300FF0FLL; // Discard at, v0-v1, t0-t9, lo, hi @@ -6513,7 +6776,7 @@ void unneeded_registers(int istart,int iend,int r) } } } - else if(itype[i]==SYSCALL) + else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL) { // SYSCALL instruction (software interrupt) u=1; @@ -6545,9 +6808,6 @@ void unneeded_registers(int istart,int iend,int r) // Save it unneeded_reg[i]=u; unneeded_reg_upper[i]=uu; -#ifdef FORCE32 - unneeded_reg_upper[i]=-1LL; -#endif /* printf("ur (%d,%d) %x: ",istart,iend,start+i*4); printf("U:"); @@ -6569,6 +6829,12 @@ void unneeded_registers(int istart,int iend,int r) } printf("\n");*/ } +#ifdef FORCE32 + for (i=iend;i>=istart;i--) + { + unneeded_reg_upper[i]=branch_unneeded_reg_upper[i]=-1LL; + } +#endif } // Identify registers which are likely to contain 32-bit values @@ -6759,18 +7025,22 @@ static void provisional_32bit() if(op2==0) is32|=1LL<>dep2[i+1])&1) r32|=1LL<>11)&0x1f); // MTC1 else printf (" %x: %s\n",start+i*4,insn[i]); break; + case COP2: + if(opcode2[i]<3) + printf (" %x: %s r%d,cpr2[%d]\n",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC2 + else if(opcode2[i]>3) + printf (" %x: %s r%d,cpr2[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC2 + else printf (" %x: %s\n",start+i*4,insn[i]); + break; case C1LS: printf (" %x: %s cpr1[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]); break; + case C2LS: + printf (" %x: %s cpr2[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]); + break; + case INTCALL: + printf (" %x: %s (INTCALL)\n",start+i*4,insn[i]); + break; default: //printf (" %s %8x\n",insn[i],source[i]); printf (" %x: %s\n",start+i*4,insn[i]); @@ -7535,6 +7822,37 @@ int new_recompile_block(int addr) //rlist(); start = (u_int)addr&~3; //assert(((u_int)addr&1)==0); +#ifdef PCSX + if (Config.HLE && start == 0x80001000) // hlecall + { + // XXX: is this enough? Maybe check hleSoftCall? + u_int beginning=(u_int)out; + u_int page=get_page(start); + invalid_code[start>>12]=0; + emit_movimm(start,0); + emit_writeword(0,(int)&pcaddr); + emit_jmp((int)new_dyna_leave); +#ifdef __arm__ + __clear_cache((void *)beginning,out); +#endif + ll_add(jump_in+page,start,(void *)beginning); + return 0; + } + else if ((u_int)addr < 0x00200000 || + (0xa0000000 <= addr && addr < 0xa0200000)) { + // used for BIOS calls mostly? + source = (u_int *)((u_int)rdram+(start&0x1fffff)); + pagelimit = (addr&0xa0000000)|0x00200000; + } + else if (!Config.HLE && ( +/* (0x9fc00000 <= addr && addr < 0x9fc80000) ||*/ + (0xbfc00000 <= addr && addr < 0xbfc80000))) { + // BIOS + source = (u_int *)((u_int)psxR+(start&0x7ffff)); + pagelimit = (addr&0xfff00000)|0x80000; + } + else +#endif #ifdef MUPEN64 if ((int)addr >= 0xa4000000 && (int)addr < 0xa4001000) { source = (u_int *)((u_int)SP_DMEM+start-0xa4000000); @@ -7542,9 +7860,9 @@ int new_recompile_block(int addr) } else #endif - if ((int)addr >= 0x80000000 && (int)addr < 0x80800000) { + if ((int)addr >= 0x80000000 && (int)addr < 0x80000000+RAM_SIZE) { source = (u_int *)((u_int)rdram+start-0x80000000); - pagelimit = 0x80800000; + pagelimit = 0x80000000+RAM_SIZE; } #ifndef DISABLE_TLB else if ((signed int)addr >= (signed int)0xC0000000) { @@ -7566,7 +7884,7 @@ int new_recompile_block(int addr) else { assem_debug("Compile at unmapped memory address: %x \n", (int)addr); //assem_debug("start: %x next: %x\n",memory_map[start>>12],memory_map[(start+4096)>>12]); - return 1; // Caller will invoke exception handler + return -1; // Caller will invoke exception handler } //printf("source= %x\n",(int)source); } @@ -7596,7 +7914,8 @@ int new_recompile_block(int addr) /* Pass 1 disassembly */ for(i=0;!done;i++) { - bt[i]=0;likely[i]=0;op2=0; + bt[i]=0;likely[i]=0;ooo[i]=0;op2=0; + minimum_free_regs[i]=0; opcode[i]=op=source[i]>>26; switch(op) { @@ -7705,7 +8024,11 @@ int new_recompile_block(int addr) case 0x02: strcpy(insn[i],"TLBWI"); type=COP0; break; case 0x06: strcpy(insn[i],"TLBWR"); type=COP0; break; case 0x08: strcpy(insn[i],"TLBP"); type=COP0; break; +#ifdef PCSX + case 0x10: strcpy(insn[i],"RFE"); type=COP0; break; +#else case 0x18: strcpy(insn[i],"ERET"); type=COP0; break; +#endif } } break; @@ -7824,6 +8147,7 @@ int new_recompile_block(int addr) break; } break; +#ifndef FORCE32 case 0x14: strcpy(insn[i],"BEQL"); type=CJUMP; break; case 0x15: strcpy(insn[i],"BNEL"); type=CJUMP; break; case 0x16: strcpy(insn[i],"BLEZL"); type=CJUMP; break; @@ -7832,6 +8156,7 @@ int new_recompile_block(int addr) case 0x19: strcpy(insn[i],"DADDIU"); type=IMM16; break; case 0x1A: strcpy(insn[i],"LDL"); type=LOADLR; break; case 0x1B: strcpy(insn[i],"LDR"); type=LOADLR; break; +#endif case 0x20: strcpy(insn[i],"LB"); type=LOAD; break; case 0x21: strcpy(insn[i],"LH"); type=LOAD; break; case 0x22: strcpy(insn[i],"LWL"); type=LOADLR; break; @@ -7844,24 +8169,64 @@ int new_recompile_block(int addr) case 0x29: strcpy(insn[i],"SH"); type=STORE; break; case 0x2A: strcpy(insn[i],"SWL"); type=STORELR; break; case 0x2B: strcpy(insn[i],"SW"); type=STORE; break; +#ifndef FORCE32 case 0x2C: strcpy(insn[i],"SDL"); type=STORELR; break; case 0x2D: strcpy(insn[i],"SDR"); type=STORELR; break; +#endif case 0x2E: strcpy(insn[i],"SWR"); type=STORELR; break; case 0x2F: strcpy(insn[i],"CACHE"); type=NOP; break; case 0x30: strcpy(insn[i],"LL"); type=NI; break; case 0x31: strcpy(insn[i],"LWC1"); type=C1LS; break; +#ifndef FORCE32 case 0x34: strcpy(insn[i],"LLD"); type=NI; break; case 0x35: strcpy(insn[i],"LDC1"); type=C1LS; break; case 0x37: strcpy(insn[i],"LD"); type=LOAD; break; +#endif case 0x38: strcpy(insn[i],"SC"); type=NI; break; case 0x39: strcpy(insn[i],"SWC1"); type=C1LS; break; +#ifndef FORCE32 case 0x3C: strcpy(insn[i],"SCD"); type=NI; break; case 0x3D: strcpy(insn[i],"SDC1"); type=C1LS; break; case 0x3F: strcpy(insn[i],"SD"); type=STORE; break; +#endif +#ifdef PCSX + case 0x12: strcpy(insn[i],"COP2"); type=NI; + // note: COP MIPS-1 encoding differs from MIPS32 + op2=(source[i]>>21)&0x1f; + if (source[i]&0x3f) { + if (gte_handlers[source[i]&0x3f]!=NULL) { + snprintf(insn[i], sizeof(insn[i]), "COP2 %x", source[i]&0x3f); + type=C2OP; + } + } + else switch(op2) + { + case 0x00: strcpy(insn[i],"MFC2"); type=COP2; break; + case 0x02: strcpy(insn[i],"CFC2"); type=COP2; break; + case 0x04: strcpy(insn[i],"MTC2"); type=COP2; break; + case 0x06: strcpy(insn[i],"CTC2"); type=COP2; break; + } + break; + case 0x32: strcpy(insn[i],"LWC2"); type=C2LS; break; + case 0x3A: strcpy(insn[i],"SWC2"); type=C2LS; break; + case 0x3B: strcpy(insn[i],"HLECALL"); type=HLECALL; break; +#endif default: strcpy(insn[i],"???"); type=NI; - assem_debug("NI %08x @%08x\n", source[i], addr + i*4); + printf("NI %08x @%08x (%08x)\n", source[i], addr + i*4, addr); break; } +#ifdef PCSX + /* detect branch in delay slot early */ + if(type==RJUMP||type==UJUMP||type==CJUMP||type==SJUMP||type==FJUMP) { + opcode[i+1]=source[i+1]>>26; + opcode2[i+1]=source[i+1]&0x3f; + if((0>11)&0x1f; } rs2[i]=CCREG; break; @@ -8033,6 +8398,7 @@ int new_recompile_block(int addr) if(op2==16) if((source[i]&0x3f)==0x18) rs2[i]=CCREG; // ERET break; case COP1: + case COP2: rs1[i]=0; rs2[i]=0; rt1[i]=0; @@ -8049,6 +8415,13 @@ int new_recompile_block(int addr) rt2[i]=0; imm[i]=(short)source[i]; break; + case C2LS: + rs1[i]=(source[i]>>21)&0x1F; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + imm[i]=(short)source[i]; + break; case FLOAT: case FCONV: rs1[i]=0; @@ -8063,6 +8436,8 @@ int new_recompile_block(int addr) rt2[i]=0; break; case SYSCALL: + case HLECALL: + case INTCALL: rs1[i]=CCREG; rs2[i]=0; rt1[i]=0; @@ -8086,14 +8461,19 @@ int new_recompile_block(int addr) else ba[i]=-1; /* Is this the end of the block? */ if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) { - if(rt1[i-1]!=31) { // Continue past subroutine call (JAL) - done=1; - // Does the block continue due to a branch? - for(j=i-1;j>=0;j--) - { - if(ba[j]==start+i*4+4) done=j=0; - if(ba[j]==start+i*4+8) done=j=0; - } +#ifdef PCSX + // check for link register access in delay slot + int rt1_=rt1[i-1]; + if(rt1_!=0&&(rs1[i]==rt1_||rs2[i]==rt1_||rt1[i]==rt1_||rt2[i]==rt1_)) { + printf("link access in delay slot @%08x (%08x)\n", addr + i*4, addr); + ba[i-1]=-1; + itype[i-1]=INTCALL; + done=2; + } + else +#endif + if(rt1[i-1]==0) { // Continue past subroutine call (JAL) + done=2; } else { if(stop_after_jal) done=1; @@ -8105,8 +8485,17 @@ int new_recompile_block(int addr) // Don't get too close to the limit if(i>MAXBLOCK/2) done=1; } - if(i>0&&itype[i-1]==SYSCALL&&stop_after_jal) done=1; - assert(i=0;j--) + { + if(ba[j]==start+i*4+4) done=j=0; + if(ba[j]==start+i*4+8) done=j=0; + } + } + //assert(i0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP||itype[i]==SYSCALL)) + if(i>0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP||itype[i]==SYSCALL||itype[i]==HLECALL)) { cc=0; } @@ -9162,13 +9565,13 @@ int new_recompile_block(int addr) if(dep1[i+1]==(regs[i].regmap_entry[hr]&63)) nr|=1<>2; if(t>0&&(itype[t-1]!=UJUMP&&itype[t-1]!=RJUMP&&itype[t-1]!=CJUMP&&itype[t-1]!=SJUMP&&itype[t-1]!=FJUMP)) // loop_preload can't handle jumps into delay slots @@ -9392,28 +9798,55 @@ int new_recompile_block(int addr) f_regmap[hr]=regs[i].regmap[hr]; else f_regmap[hr]=-1; } - else if(regs[i].regmap[hr]>=0) f_regmap[hr]=regs[i].regmap[hr]; + else if(regs[i].regmap[hr]>=0) { + if(f_regmap[hr]!=regs[i].regmap[hr]) { + // dealloc old register + int n; + for(n=0;n64) { if(!((branch_regs[i].dirty>>hr)&1)) f_regmap[hr]=branch_regs[i].regmap[hr]; else f_regmap[hr]=-1; } - else if(branch_regs[i].regmap[hr]>=0) f_regmap[hr]=branch_regs[i].regmap[hr]; - if(itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS - ||itype[i+1]==SHIFT||itype[i+1]==COP1||itype[i+1]==FLOAT - ||itype[i+1]==FCOMP||itype[i+1]==FCONV) - { - // Test both in case the delay slot is ooo, - // could be done better... - if(count_free_regs(branch_regs[i].regmap)<2 - ||count_free_regs(regs[i].regmap)<2) + else if(branch_regs[i].regmap[hr]>=0) { + if(f_regmap[hr]!=branch_regs[i].regmap[hr]) { + // dealloc old register + int n; + for(n=0;nclean transition - // #ifdef DESTRUCTIVE_WRITEBACK here? + #ifdef DESTRUCTIVE_WRITEBACK if(t>0) if(get_reg(regmap_pre[t],f_regmap[hr])>=0) if((regs[t].wasdirty>>get_reg(regmap_pre[t],f_regmap[hr]))&1) f_regmap[hr]=-1; + #endif + // This check is only strictly required in the DESTRUCTIVE_WRITEBACK + // case above, however it's always a good idea. We can't hoist the + // load if the register was already allocated, so there's no point + // wasting time analyzing most of these cases. It only "succeeds" + // when the mapping was different and the load can be replaced with + // a mov, which is of negligible benefit. So such cases are + // skipped below. if(f_regmap[hr]>0) { - if(regs[t].regmap_entry[hr]<0) { + if(regs[t].regmap_entry[hr]<0&&get_reg(regmap_pre[t],f_regmap[hr])<0) { int r=f_regmap[hr]; for(j=t;j<=i;j++) { @@ -9425,6 +9858,7 @@ int new_recompile_block(int addr) // register is lower numbered than the lower-half // register. Not sure if it's worth fixing... if(get_reg(regs[j].regmap,r&63)<0) break; + if(get_reg(regs[j].regmap_entry,r&63)<0) break; if(regs[j].is32&(1LL<<(r&63))) break; } if(regs[j].regmap[hr]==f_regmap[hr]&&(f_regmap[hr]&63)1&®s[k-1].regmap[hr]==-1) { - if(itype[k-1]==STORE||itype[k-1]==STORELR - ||itype[k-1]==C1LS||itype[k-1]==SHIFT||itype[k-1]==COP1 - ||itype[k-1]==FLOAT||itype[k-1]==FCONV - ||itype[k-1]==FCOMP) { - if(count_free_regs(regs[k-1].regmap)<2) { - //printf("no free regs for store %x\n",start+(k-1)*4); - break; - } + if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) { + //printf("no free regs for store %x\n",start+(k-1)*4); + break; } - else - if(itype[k-1]!=NOP&&itype[k-1]!=MOV&&itype[k-1]!=ALU&&itype[k-1]!=SHIFTIMM&&itype[k-1]!=IMM16&&itype[k-1]!=LOAD) break; if(get_reg(regs[k-1].regmap,f_regmap[hr])>=0) { //printf("no-match due to different register\n"); break; @@ -9525,13 +9952,31 @@ int new_recompile_block(int addr) } } for(k=t;k>16)!=0x1000) { + regmap_pre[k+2][hr]=f_regmap[hr]; + regs[k+2].wasdirty&=~(1<>16)==0x1000) + { + // Stop on unconditional branch + break; + } + if(itype[j]==CJUMP||itype[j]==SJUMP||itype[j]==FJUMP) + { + if(ooo[j]) { + if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j+1]) + break; + }else{ + if(count_free_regs(branch_regs[j].regmap)<=minimum_free_regs[j+1]) + break; + } + if(get_reg(branch_regs[j].regmap,f_regmap[hr])>=0) { + //printf("no-match due to different register (branch)\n"); break; } } - else if(itype[j]!=NOP&&itype[j]!=MOV&&itype[j]!=ALU&&itype[j]!=SHIFTIMM&&itype[j]!=IMM16&&itype[j]!=LOAD) break; + if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j]) { + //printf("No free regs for store %x\n",start+j*4); + break; + } if(f_regmap[hr]>=64) { if(regs[j].is32&(1LL<<(f_regmap[hr]&63))) { break; @@ -9582,7 +10041,18 @@ int new_recompile_block(int addr) if(!((regs[i].dirty>>hr)&1)) f_regmap[hr]=regs[i].regmap[hr]; } - else if(regs[i].regmap[hr]>=0) f_regmap[hr]=regs[i].regmap[hr]; + else if(regs[i].regmap[hr]>=0) { + if(f_regmap[hr]!=regs[i].regmap[hr]) { + // dealloc old register + int n; + for(n=0;n=0) @@ -9738,7 +10197,7 @@ int new_recompile_block(int addr) } } #ifndef HOST_IMM_ADDR32 - if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) { + if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS||itype[i+1]==C2LS) { hr=get_reg(regs[i+1].regmap,TLREG); if(hr>=0) { int sr=get_reg(regs[i+1].regmap,rs1[i+1]); @@ -9776,7 +10235,8 @@ int new_recompile_block(int addr) } } #endif - if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { // SB/SH/SW/SD/SWC1/SDC1 + if(itype[i+1]==STORE||itype[i+1]==STORELR + ||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SB/SH/SW/SD/SWC1/SDC1/SWC2/SDC2 if(get_reg(regs[i+1].regmap,rs1[i+1])<0) { hr=get_reg2(regs[i].regmap,regs[i+1].regmap,-1); if(hr<0) hr=get_reg(regs[i+1].regmap,-1); @@ -9795,7 +10255,7 @@ int new_recompile_block(int addr) } } } - if(itype[i+1]==LOADLR||opcode[i+1]==0x31||opcode[i+1]==0x35) { // LWC1/LDC1 + if(itype[i+1]==LOADLR||(opcode[i+1]&0x3b)==0x31||(opcode[i+1]&0x3b)==0x32) { // LWC1/LDC1, LWC2/LDC2 if(get_reg(regs[i+1].regmap,rs1[i+1])<0) { int nr; hr=get_reg(regs[i+1].regmap,FTEMP); @@ -9830,12 +10290,12 @@ int new_recompile_block(int addr) } } } - if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR/*||itype[i+1]==C1LS*/) { + if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR/*||itype[i+1]==C1LS||||itype[i+1]==C2LS*/) { if(itype[i+1]==LOAD) hr=get_reg(regs[i+1].regmap,rt1[i+1]); - if(itype[i+1]==LOADLR||opcode[i+1]==0x31||opcode[i+1]==0x35) // LWC1/LDC1 + if(itype[i+1]==LOADLR||(opcode[i+1]&0x3b)==0x31||(opcode[i+1]&0x3b)==0x32) // LWC1/LDC1, LWC2/LDC2 hr=get_reg(regs[i+1].regmap,FTEMP); - if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { // SWC1/SDC1 + if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SWC1/SDC1/SWC2/SDC2 hr=get_reg(regs[i+1].regmap,AGEN1+((i+1)&1)); if(hr<0) hr=get_reg(regs[i+1].regmap,-1); } @@ -9860,7 +10320,7 @@ int new_recompile_block(int addr) clean_registers(0,slen-1,1); /* Pass 7 - Identify 32-bit registers */ - +#ifndef FORCE32 provisional_r32(); u_int r32=0; @@ -9930,7 +10390,7 @@ int new_recompile_block(int addr) if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<