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=0128758237383cb34bd6f1ad8acf2de2aebd792c;hp=39204ceda1b21eba8ba5bd12c62389b77781028e;hb=4600ba0381ea86bdfdcba8f4f762c89f5c51af5b;hpb=3e5353548dd510c805424878a1f0de1da7a44a0c diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c index 39204ced..01287582 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.c +++ b/libpcsxcore/new_dynarec/new_dynarec.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - new_dynarec.c * - * Copyright (C) 2009-2010 Ari64 * + * Copyright (C) 2009-2011 Ari64 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -21,10 +21,15 @@ #include #include //include for uint64_t #include +#include #include "emu_if.h" //emulator interface -#include +//#define DISASM +//#define assem_debug printf +//#define inv_debug printf +#define assem_debug(...) +#define inv_debug(...) #ifdef __i386__ #include "assem_x86.h" @@ -80,6 +85,10 @@ struct ll_entry u_char dep1[MAXBLOCK]; u_char dep2[MAXBLOCK]; u_char lt1[MAXBLOCK]; + static uint64_t gte_rs[MAXBLOCK]; // gte: 32 data and 32 ctl regs + static uint64_t gte_rt[MAXBLOCK]; + static uint64_t gte_unneeded[MAXBLOCK]; + static int gte_reads_flags; // gte flag read encountered int imm[MAXBLOCK]; u_int ba[MAXBLOCK]; char likely[MAXBLOCK]; @@ -126,6 +135,7 @@ struct ll_entry #else static const u_int using_tlb=0; #endif + static u_int sp_in_mirror; u_int stop_after_jal; extern u_char restore_candidate[512]; extern int cycle_count; @@ -260,12 +270,6 @@ int tracedebug=0; //#define DEBUG_CYCLE_COUNT 1 -void nullf() {} -//#define assem_debug printf -//#define inv_debug printf -#define assem_debug nullf -#define inv_debug nullf - static void tlb_hacks() { #ifndef DISABLE_TLB @@ -370,6 +374,7 @@ void *get_addr(u_int vaddr) if(verify_dirty(head->addr)) { //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,invalid_code[vaddr>>12]); invalid_code[vaddr>>12]=0; + inv_code_start=inv_code_end=~0; memory_map[vaddr>>12]|=0x40000000; if(vpage<2048) { #ifndef DISABLE_TLB @@ -462,6 +467,7 @@ void *get_addr_32(u_int vaddr,u_int flags) if(verify_dirty(head->addr)) { //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,invalid_code[vaddr>>12]); invalid_code[vaddr>>12]=0; + inv_code_start=inv_code_end=~0; memory_map[vaddr>>12]|=0x40000000; if(vpage<2048) { #ifndef DISABLE_TLB @@ -598,6 +604,7 @@ void clear_const(struct regstat *cur,signed char reg) int is_const(struct regstat *cur,signed char reg) { int hr; + if(reg<0) return 0; if(!reg) return 1; for (hr=0;hrregmap[hr]&63)==reg) { @@ -718,12 +725,6 @@ int needed_again(int r, int i) int j; int b=-1; int rn=10; - int hr; - u_char hsn[MAXREG+1]; - int preferred_reg; - - memset(hsn,10,sizeof(hsn)); - lsn(hsn,i,&preferred_reg); if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) { @@ -776,11 +777,7 @@ int needed_again(int r, int i) } } }*/ - for(hr=0;hr2047||(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<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; - } - } -#ifndef DISABLE_TLB - if(page<2048&&(signed int)start>=(signed int)0xC0000000&&(signed int)end>=(signed int)0xC0000000) { - if(((start+memory_map[start>>12]-(u_int)rdram)>>12)<=page&&((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)>=page) { - if((((start+memory_map[start>>12]-(u_int)rdram)>>12)&2047)>12]-(u_int)rdram)>>12)&2047; - if((((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)&2047)>last) last=((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)&2047; - } - } -#endif - } - head=head->next; - } //printf("first=%d last=%d\n",first,last); invalidate_page(page); assert(first+5>page); // NB: this assumes MAXBLOCK<=4096 (4 pages) @@ -1186,9 +1155,6 @@ void invalidate_block(u_int block) // Don't trap writes invalid_code[block]=1; -#ifdef PCSX - invalid_code[((u_int)0x80000000>>12)|page]=1; -#endif #ifndef DISABLE_TLB // If there is a valid TLB entry for this page, remove write protect if(tlb_LUT_w[block]) { @@ -1206,10 +1172,98 @@ void invalidate_block(u_int block) memset(mini_ht,-1,sizeof(mini_ht)); #endif } + +void invalidate_block(u_int block) +{ + u_int page=get_page(block<<12); + u_int vpage=get_vpage(block<<12); + inv_debug("INVALIDATE: %x (%d)\n",block<<12,page); + //inv_debug("invalid_code[block]=%d\n",invalid_code[block]); + u_int first,last; + first=last=page; + struct ll_entry *head; + head=jump_dirty[vpage]; + //printf("page=%d vpage=%d\n",page,vpage); + while(head!=NULL) { + u_int start,end; + 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<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; + } + } +#ifndef DISABLE_TLB + if(page<2048&&(signed int)start>=(signed int)0xC0000000&&(signed int)end>=(signed int)0xC0000000) { + if(((start+memory_map[start>>12]-(u_int)rdram)>>12)<=page&&((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)>=page) { + if((((start+memory_map[start>>12]-(u_int)rdram)>>12)&2047)>12]-(u_int)rdram)>>12)&2047; + if((((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)&2047)>last) last=((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)&2047; + } + } +#endif + } + head=head->next; + } + invalidate_block_range(block,first,last); +} + void invalidate_addr(u_int addr) { +#ifdef PCSX + //static int rhits; + // this check is done by the caller + //if (inv_code_start<=addr&&addr<=inv_code_end) { rhits++; return; } + u_int page=get_page(addr); + if(page<2048) { // RAM + struct ll_entry *head; + u_int addr_min=~0, addr_max=0; + int mask=RAM_SIZE-1; + int pg1; + inv_code_start=addr&~0xfff; + inv_code_end=addr|0xfff; + pg1=page; + if (pg1>0) { + // must check previous page too because of spans.. + pg1--; + inv_code_start-=0x1000; + } + for(;pg1<=page;pg1++) { + for(head=jump_dirty[pg1];head!=NULL;head=head->next) { + u_int start,end; + get_bounds((int)head->addr,&start,&end); + if((start&mask)<=(addr&mask)&&(addr&mask)<(end&mask)) { + if(startaddr_max) addr_max=end; + } + else if(addrinv_code_start) + inv_code_start=end; + } + } + } + if (addr_min!=~0) { + inv_debug("INV ADDR: %08x hit %08x-%08x\n", addr, addr_min, addr_max); + inv_code_start=inv_code_end=~0; + invalidate_block_range(addr>>12,(addr_min&mask)>>12,(addr_max&mask)>>12); + return; + } + else { + inv_debug("INV ADDR: %08x miss, inv %08x-%08x, sk %d\n", addr, inv_code_start, inv_code_end, 0);//rhits); + } + //rhits=0; + if(page!=0) // FIXME: don't know what's up with page 0 (Klonoa) + return; + } +#endif invalidate_block(addr>>12); } + // This is called when loading a save state. // Anything could have changed, so invalidate everything. void invalidate_all_pages() @@ -1248,6 +1302,8 @@ void add_link(u_int vaddr,void *src) { u_int page=get_page(vaddr); inv_debug("add_link: %x -> %x (%d)\n",(int)src,vaddr,page); + int *ptr=(int *)(src+4); + assert((*ptr&0x0fff0000)==0x059f0000); ll_add(jump_out+page,vaddr,src); //int ptr=get_pointer(src); //inv_debug("add_link: Pointer is to %x\n",(int)ptr); @@ -1601,13 +1657,9 @@ void load_alloc(struct regstat *current,int i) //if(rs1[i]!=rt1[i]&&needed_again(rs1[i],i)) clear_const(current,rs1[i]); // Does this help or hurt? if(!rs1[i]) current->u&=~1LL; // Allow allocating r0 if it's the source register if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); - if(rt1[i]) { + if(rt1[i]&&!((current->u>>rt1[i])&1)) { alloc_reg(current,i,rt1[i]); - if(get_reg(current->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; - } + assert(get_reg(current->regmap,rt1[i])>=0); if(opcode[i]==0x27||opcode[i]==0x37) // LWU/LD { current->is32&=~(1LL<regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); @@ -2826,6 +2881,14 @@ void load_assemble(int i,struct regstat *i_regs) if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE) #endif { + #ifdef PCSX + if(sp_in_mirror&&rs1[i]==29) { + emit_andimm(addr,~0x00e00000,HOST_TEMPREG); + emit_cmpimm(HOST_TEMPREG,RAM_SIZE); + fastload_reg_override=HOST_TEMPREG; + } + else + #endif emit_cmpimm(addr,RAM_SIZE); jaddr=(int)out; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK @@ -2843,6 +2906,7 @@ void load_assemble(int i,struct regstat *i_regs) if (opcode[i]==0x21||opcode[i]==0x25) x=2; // LH/LHU map=get_reg(i_regs->regmap,TLREG); assert(map>=0); + reglist&=~(1<=0); if(!c||memtarget) { if(!dummy) { + int a=addr; + if(fastload_reg_override) a=fastload_reg_override; //emit_readword_indexed((int)rdram-0x80000000,addr,tl); #ifdef HOST_IMM_ADDR32 if(c) emit_readword_tlb(constmap[i][s]+offset,map,tl); else #endif - emit_readword_indexed_tlb(0,addr,map,tl); + emit_readword_indexed_tlb(0,a,map,tl); } if(jaddr) add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); @@ -3017,6 +3091,8 @@ void load_assemble(int i,struct regstat *i_regs) if (opcode[i]==0x37) { // LD if(!c||memtarget) { if(!dummy) { + int a=addr; + if(fastload_reg_override) a=fastload_reg_override; //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); @@ -3025,7 +3101,7 @@ void load_assemble(int i,struct regstat *i_regs) emit_readdword_tlb(constmap[i][s]+offset,map,th,tl); else #endif - emit_readdword_indexed_tlb(0,addr,map,th,tl); + emit_readdword_indexed_tlb(0,a,map,th,tl); } if(jaddr) add_stub(LOADD_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); @@ -3081,6 +3157,7 @@ void store_assemble(int i,struct regstat *i_regs) int jaddr=0,jaddr2,type; int memtarget=0,c=0; int agr=AGEN1+(i&1); + int faststore_reg_override=0; u_int hr,reglist=0; th=get_reg(i_regs->regmap,rs2[i]|64); tl=get_reg(i_regs->regmap,rs2[i]); @@ -3105,9 +3182,16 @@ void store_assemble(int i,struct regstat *i_regs) else addr=s; if(!using_tlb) { if(!c) { + #ifdef PCSX + if(sp_in_mirror&&rs1[i]==29) { + emit_andimm(addr,~0x00e00000,HOST_TEMPREG); + emit_cmpimm(HOST_TEMPREG,RAM_SIZE); + faststore_reg_override=HOST_TEMPREG; + } + else + #endif #ifdef R29_HACK // Strmnnrmn's speed hack - memtarget=1; if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE) #endif emit_cmpimm(addr,RAM_SIZE); @@ -3115,6 +3199,7 @@ void store_assemble(int i,struct regstat *i_regs) if(s==addr) emit_mov(s,temp); #endif #ifdef R29_HACK + memtarget=1; if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE) #endif { @@ -3134,6 +3219,7 @@ void store_assemble(int i,struct regstat *i_regs) if (opcode[i]==0x29) x=2; // SH map=get_reg(i_regs->regmap,TLREG); assert(map>=0); + reglist&=~(1<=0); //emit_writeword_indexed(th,(int)rdram-0x80000000,addr); //emit_writeword_indexed(tl,(int)rdram-0x7FFFFFFC,addr); - emit_writedword_indexed_tlb(th,tl,0,addr,map,temp); + emit_writedword_indexed_tlb(th,tl,0,a,map,temp); }else{ // Store zero //emit_writeword_indexed(tl,(int)rdram-0x80000000,temp); //emit_writeword_indexed(tl,(int)rdram-0x7FFFFFFC,temp); - emit_writedword_indexed_tlb(tl,tl,0,addr,map,temp); + emit_writedword_indexed_tlb(tl,tl,0,a,map,temp); } } type=STORED_STUB; } +#ifdef PCSX + if(jaddr) { + // PCSX store handlers don't check invcode again + reglist|=1<regmap,CCREG)<0) @@ -3249,8 +3354,12 @@ void store_assemble(int i,struct regstat *i_regs) emit_writeword(0,(int)&Count); #endif emit_call((int)memdebug); - //emit_popa(); + #ifdef __i386__ + emit_popa(); + #endif + #ifdef __arm__ restore_regs(0x100f); + #endif }/**/ } @@ -3309,6 +3418,7 @@ void storelr_assemble(int i,struct regstat *i_regs) }else{ // using tlb int map=get_reg(i_regs->regmap,TLREG); assert(map>=0); + reglist&=~(1<=0) emit_mov(s,temp); do_tlb_w_branch(map,c,constmap[i][s]+offset,&jaddr); @@ -3559,6 +3669,7 @@ void c1ls_assemble(int i,struct regstat *i_regs) { map=get_reg(i_regs->regmap,TLREG); assert(map>=0); + reglist&=~(1<>16)&0x1f; @@ -4060,7 +4171,7 @@ static void loop_preload(signed char pre[],signed char entry[]) 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||itype[i]==C2LS) { - int ra; + int ra=-1; int agr=AGEN1+(i&1); int mgr=MGEN1+(i&1); if(itype[i]==LOAD) { @@ -4436,7 +4547,7 @@ void load_all_regs(signed char i_regmap[]) emit_zeroreg(hr); } else - if(i_regmap[hr]>0 && i_regmap[hr]!=CCREG) + if(i_regmap[hr]>0 && (i_regmap[hr]&63)0 && i_regmap[hr]!=CCREG) + if(i_regmap[hr]>0 && (i_regmap[hr]&63)=0&®s[t].regmap_entry[hr]<64) { + if(regs[t].regmap_entry[hr]>=0&®s[t].regmap_entry[hr]=64) { + if(regs[t].regmap_entry[hr]>=64&®s[t].regmap_entry[hr]>(regs[t].regmap_entry[hr]&63))&1) { int lr=get_reg(regs[t].regmap_entry,regs[t].regmap_entry[hr]-64); @@ -4567,7 +4678,7 @@ void load_regs_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int ad } // Load 32-bit regs for(hr=0;hr=0&®s[t].regmap_entry[hr]<64) { + if(hr!=EXCLUDE_REG&®s[t].regmap_entry[hr]>=0&®s[t].regmap_entry[hr]>hr)&1) && ((i_dirty>>hr)&1) && (((i_is32&~unneeded_reg_upper[t])>>i_regmap[hr])&1) ) || (((i_is32&~regs[t].was32&~unneeded_reg_upper[t])>>(i_regmap[hr]&63))&1)) { #else @@ -4585,7 +4696,7 @@ void load_regs_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int ad } //Load 64-bit regs for(hr=0;hr=64) { + if(hr!=EXCLUDE_REG&®s[t].regmap_entry[hr]>=64&®s[t].regmap_entry[hr]>(regs[t].regmap_entry[hr]&63))&1) { @@ -4626,19 +4737,19 @@ int match_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr) { if(i_regmap[hr]!=regs[t].regmap_entry[hr]) { - if(regs[t].regmap_entry[hr]!=-1) + if(regs[t].regmap_entry[hr]>=0&&(regs[t].regmap_entry[hr]|64)>hr)&1) { - if(i_regmap[hr]<64) + if(i_regmap[hr]>i_regmap[hr])&1)) return 0; } - else + else if(i_regmap[hr]>=64&&i_regmap[hr]>(i_regmap[hr]&63))&1)) return 0; @@ -4812,7 +4923,7 @@ void do_cc(int i,signed char i_regmap[],int *adj,int addr,int taken,int invert) } else { - emit_cmpimm(HOST_CCREG,-2*(count+2)); + emit_cmpimm(HOST_CCREG,-CLOCK_DIVIDER*(count+2)); jaddr=(int)out; emit_jns(0); } @@ -4878,7 +4989,7 @@ void do_ccstub(int n) emit_loadreg(rs2[i],s2l); #endif int hr=0; - int addr,alt,ntaddr; + int addr=-1,alt=-1,ntaddr=-1; while(hr=0); + return_address=start+i*4+8; + if(rt>=0) { + #ifdef USE_MINI_HT + if(internal_branch(branch_regs[i].is32,return_address)&&rt1[i+1]!=31) { + int temp=-1; // note: must be ds-safe + #ifdef HOST_TEMPREG + temp=HOST_TEMPREG; + #endif + if(temp>=0) do_miniht_insert(return_address,rt,temp); + else emit_movimm(return_address,rt); + } + else + #endif + { + #ifdef REG_PREFETCH + if(temp>=0) + { + if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); + } + #endif + emit_movimm(return_address,rt); // PC into link register + #ifdef IMM_PREFETCH + emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); + #endif + } + } +} + void ujump_assemble(int i,struct regstat *i_regs) { signed char *i_regmap=i_regs->regmap; + int ra_done=0; if(i==(ba[i]-start)>>2) assem_debug("idle loop\n"); address_generation(i+1,i_regs,regs[i].regmap_entry); #ifdef REG_PREFETCH @@ -5111,6 +5258,10 @@ void ujump_assemble(int i,struct regstat *i_regs) if(i_regmap[temp]==PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } #endif + if(rt1[i]==31&&(rt1[i]==rs1[i+1]||rt1[i]==rs2[i+1])) { + ujump_assemble_write_ra(i); // writeback ra for DS + ra_done=1; + } ds_assemble(i+1,i_regs); uint64_t bc_unneeded=branch_regs[i].u; uint64_t bc_unneeded_upper=branch_regs[i].uu; @@ -5119,46 +5270,8 @@ void ujump_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,CCREG,CCREG); - if(rt1[i]==31) { - int rt; - unsigned int 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]); - //assert(rt>=0); - return_address=start+i*4+8; - if(rt>=0) { - #ifdef USE_MINI_HT - if(internal_branch(branch_regs[i].is32,return_address)) { - int temp=rt+1; - if(temp==EXCLUDE_REG||temp>=HOST_REGS|| - branch_regs[i].regmap[temp]>=0) - { - temp=get_reg(branch_regs[i].regmap,-1); - } - #ifdef HOST_TEMPREG - if(temp<0) temp=HOST_TEMPREG; - #endif - if(temp>=0) do_miniht_insert(return_address,rt,temp); - else emit_movimm(return_address,rt); - } - else - #endif - { - #ifdef REG_PREFETCH - if(temp>=0) - { - if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); - } - #endif - emit_movimm(return_address,rt); // PC into link register - #ifdef IMM_PREFETCH - emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); - #endif - } - } - } + if(!ra_done&&rt1[i]==31) + ujump_assemble_write_ra(i); int cc,adj; cc=get_reg(branch_regs[i].regmap,CCREG); assert(cc==HOST_CCREG); @@ -5182,11 +5295,33 @@ void ujump_assemble(int i,struct regstat *i_regs) } } +static void rjump_assemble_write_ra(int i) +{ + int rt,return_address; + 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; + #ifdef REG_PREFETCH + if(temp>=0) + { + if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); + } + #endif + emit_movimm(return_address,rt); // PC into link register + #ifdef IMM_PREFETCH + emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); + #endif +} + void rjump_assemble(int i,struct regstat *i_regs) { signed char *i_regmap=i_regs->regmap; int temp; int rs,cc,adj; + int ra_done=0; rs=get_reg(branch_regs[i].regmap,rs1[i]); assert(rs>=0); if(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]) { @@ -5213,6 +5348,10 @@ void rjump_assemble(int i,struct regstat *i_regs) if(rh>=0) do_preload_rhash(rh); } #endif + if(rt1[i]!=0&&(rt1[i]==rs1[i+1]||rt1[i]==rs2[i+1])) { + rjump_assemble_write_ra(i); + ra_done=1; + } ds_assemble(i+1,i_regs); uint64_t bc_unneeded=branch_regs[i].u; uint64_t bc_unneeded_upper=branch_regs[i].uu; @@ -5222,25 +5361,8 @@ 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]!=0) { - int rt,return_address; - 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; - #ifdef REG_PREFETCH - if(temp>=0) - { - if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); - } - #endif - emit_movimm(return_address,rt); // PC into link register - #ifdef IMM_PREFETCH - emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); - #endif - } + if(!ra_done&&rt1[i]!=0) + rjump_assemble_write_ra(i); cc=get_reg(branch_regs[i].regmap,CCREG); assert(cc==HOST_CCREG); #ifdef USE_MINI_HT @@ -6600,8 +6722,8 @@ static void pagespan_ds() void unneeded_registers(int istart,int iend,int r) { int i; - uint64_t u,uu,b,bu; - uint64_t temp_u,temp_uu; + uint64_t u,uu,gte_u,b,bu,gte_bu; + uint64_t temp_u,temp_uu,temp_gte_u; uint64_t tdep; if(iend==slen-1) { u=1;uu=1; @@ -6610,6 +6732,8 @@ void unneeded_registers(int istart,int iend,int r) uu=unneeded_reg_upper[iend+1]; u=1;uu=1; } + gte_u=temp_gte_u=0; + for (i=iend;i>=istart;i--) { //printf("unneeded registers i=%d (%d,%d) r=%d\n",i,istart,iend,r); @@ -6623,6 +6747,7 @@ void unneeded_registers(int istart,int iend,int r) // Branch out of this block, flush all regs u=1; uu=1; + gte_u=0; /* Hexagon hack if(itype[i]==UJUMP&&rt1[i]==31) { @@ -6654,17 +6779,21 @@ void unneeded_registers(int istart,int iend,int r) uu&=~((1LL<>rt1[i+1])&1; @@ -6691,17 +6822,21 @@ void unneeded_registers(int istart,int iend,int r) temp_uu&=~((1LL<>rt1[i])&1; @@ -6711,8 +6846,11 @@ void unneeded_registers(int istart,int iend,int r) temp_uu&=~((1LL<>2]=1; unneeded_reg_upper[(ba[i]-start)>>2]=1; + gte_unneeded[(ba[i]-start)>>2]=0; } } /*else*/ if(1) { if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000) @@ -6727,6 +6866,7 @@ void unneeded_registers(int istart,int iend,int r) // Unconditional branch u=unneeded_reg[(ba[i]-start)>>2]; uu=unneeded_reg_upper[(ba[i]-start)>>2]; + gte_u=gte_unneeded[(ba[i]-start)>>2]; branch_unneeded_reg[i]=u; branch_unneeded_reg_upper[i]=uu; //u=1; @@ -6741,10 +6881,13 @@ void unneeded_registers(int istart,int iend,int r) uu&=~((1LL<>2]; bu=unneeded_reg_upper[(ba[i]-start)>>2]; + gte_bu=gte_unneeded[(ba[i]-start)>>2]; branch_unneeded_reg[i]=b; branch_unneeded_reg_upper[i]=bu; //b=1; @@ -6759,20 +6902,25 @@ void unneeded_registers(int istart,int iend,int r) bu&=~((1LL<>2]&(1<>2]&(1<=0) { + will_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>(branch_regs[i].regmap[r]&63))&1)<>2]>>(branch_regs[i].regmap[r]&63))&1)<start+i*4) { // Disable recursion (for debugging) for(r=0;r>2].regmap_entry[r]) { + signed char target_reg=branch_regs[i].regmap[r]; + if(target_reg==regs[(ba[i]-start)>>2].regmap_entry[r]) { will_dirty_i&=will_dirty[(ba[i]-start)>>2]&(1<>2]&(1<=0) { + will_dirty_i&=((unneeded_reg[(ba[i]-start)>>2]>>(target_reg&63))&1)<>2]>>(target_reg&63))&1)<>2].regmap_entry[r]) { @@ -7485,7 +7641,7 @@ void clean_registers(int istart,int iend,int wr) } } } - // Merge in delay slot + // Merge in delay slot (won't dirty) for(r=0;r=0) { + else if(regmap_pre[i][r]>=0&&(nr=get_reg(regs[i].regmap,regmap_pre[i][r]))>=0) { // Register moved to a different register will_dirty_i&=~(1<0x80200000&& + 0x10000<=psxRegs.GPR.n.sp&&(psxRegs.GPR.n.sp&~0xe0e00000)>21)&0x1f; - if (source[i]&0x3f) { + //if (op2 & 0x10) { + if (source[i]&0x3f) { // use this hack to support old savestates with patched gte insns if (gte_handlers[source[i]&0x3f]!=NULL) { - snprintf(insn[i], sizeof(insn[i]), "COP2 %x", source[i]&0x3f); + if (gte_regnames[source[i]&0x3f]!=NULL) + strcpy(insn[i],gte_regnames[source[i]&0x3f]); + else + snprintf(insn[i], sizeof(insn[i]), "COP2 %x", source[i]&0x3f); type=C2OP; } } @@ -8250,6 +8425,7 @@ int new_recompile_block(int addr) us2[i]=0; dep1[i]=0; dep2[i]=0; + gte_rs[i]=gte_rt[i]=0; switch(type) { case LOAD: rs1[i]=(source[i]>>21)&0x1f; @@ -8413,7 +8589,6 @@ 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; @@ -8423,6 +8598,28 @@ int new_recompile_block(int addr) if(op2==5) us1[i]=rs1[i]; // DMTC1 rs2[i]=CSREG; break; + case COP2: + rs1[i]=0; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + if(op2<3) rt1[i]=(source[i]>>16)&0x1F; // MFC2/CFC2 + if(op2>3) rs1[i]=(source[i]>>16)&0x1F; // MTC2/CTC2 + rs2[i]=CSREG; + int gr=(source[i]>>11)&0x1F; + switch(op2) + { + case 0x00: gte_rs[i]=1ll<>21)&0x1F; rs2[i]=CSREG; @@ -8436,6 +8633,16 @@ int new_recompile_block(int addr) rt1[i]=0; rt2[i]=0; imm[i]=(short)source[i]; + if(op==0x32) gte_rt[i]=1ll<<((source[i]>>16)&0x1F); // LWC2 + else gte_rs[i]=1ll<<((source[i]>>16)&0x1F); // SWC2 + break; + case C2OP: + rs1[i]=0; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + gte_rt[i]=1ll<<63; // every op changes flags + // TODO: other regs? break; case FLOAT: case FCONV: @@ -8499,13 +8706,6 @@ int new_recompile_block(int addr) do_in_intrp=1; } } - // check for link register access in delay slot - // TODO: teach the recompiler to handle this - 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); - do_in_intrp=1; - } if(do_in_intrp) { rs1[i-1]=CCREG; rs2[i-1]=rt1[i-1]=rt2[i-1]=0; @@ -8537,6 +8737,7 @@ int new_recompile_block(int addr) // Does the block continue due to a branch? for(j=i-1;j>=0;j--) { + if(ba[j]==start+i*4) done=j=0; // Branch into delay slot if(ba[j]==start+i*4+4) done=j=0; if(ba[j]==start+i*4+8) done=j=0; } @@ -8577,7 +8778,7 @@ int new_recompile_block(int addr) current.wasconst=0; int ds=0; int cc=0; - int hr; + int hr=-1; #ifndef FORCE32 provisional_32bit(); @@ -8642,7 +8843,9 @@ int new_recompile_block(int addr) } if(temp_is32!=current.is32) { //printf("dumping 32-bit regs (%x)\n",start+i*4); - #ifdef DESTRUCTIVE_WRITEBACK + #ifndef DESTRUCTIVE_WRITEBACK + if(ds) + #endif for(hr=0;hr>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 - if(t<2||(itype[t-2]!=UJUMP)) // call/ret assumes no registers allocated + if(t<2||(itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||rt1[t-2]!=31) // call/ret assumes no registers allocated for(hr=0;hr64) { @@ -9902,7 +10109,7 @@ int new_recompile_block(int addr) // 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&&get_reg(regmap_pre[t],f_regmap[hr])<0) { + if(regs[t].regmap[hr]==f_regmap[hr]||(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++) { @@ -9941,7 +10148,7 @@ int new_recompile_block(int addr) break; } // call/ret fast path assumes no registers allocated - if(k>2&&(itype[k-3]==UJUMP||itype[k-3]==RJUMP)) { + if(k>2&&(itype[k-3]==UJUMP||itype[k-3]==RJUMP)&&rt1[k-3]==31) { break; } if(r>63) { @@ -10089,7 +10296,7 @@ int new_recompile_block(int addr) } } }else{ - int count=0; + // Non branch or undetermined branch target for(hr=0;hr=0) { + score[hr]=0;earliest_available[hr]=i+1; + loop_start[hr]=MAXBLOCK; + } + if(itype[i]==UJUMP||itype[i]==RJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { + if(branch_regs[i].regmap[hr]>=0) { + score[hr]=0;earliest_available[hr]=i+2; + loop_start[hr]=MAXBLOCK; + } + } + } + // No register allocations after unconditional jumps + if(itype[i]==UJUMP||itype[i]==RJUMP||(source[i]>>16)==0x1000) + { + for(hr=0;hr=0) break; + if(itype[j]==UJUMP||itype[j]==RJUMP||itype[j]==CJUMP||itype[j]==SJUMP||itype[j]==FJUMP) { + if(branch_regs[j].regmap[hr]>=0) break; + 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; + } + } + else if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j]) break; + if(itype[j]==UJUMP||itype[j]==RJUMP||itype[j]==CJUMP||itype[j]==SJUMP||itype[j]==FJUMP) { + int t=(ba[j]-start)>>2; + if(t=earliest_available[hr]) { + if(t==1||(t>1&&itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||(t>1&&rt1[t-2]!=31)) { // call/ret assumes no registers allocated + // Score a point for hoisting loop invariant + if(t>16)==0x1000) + { + // Stop on unconditional branch + break; + } + else + if(itype[j]==LOAD||itype[j]==LOADLR|| + itype[j]==STORE||itype[j]==STORELR||itype[j]==C1LS) { + score[hr]++; + end[hr]=j; + } + } + } + } + // Find highest score and allocate that register + int maxscore=0; + for(hr=0;hrscore[maxscore]) { + maxscore=hr; + //printf("highest score: %d %d (%x->%x)\n",score[hr],hr,start+i*4,start+end[hr]*4); + } + } + } + if(score[maxscore]>1) + { + if(i=0) {printf("oops: %x %x was %d=%d\n",loop_start[maxscore]*4+start,j*4+start,maxscore,regs[j].regmap[maxscore]);} + assert(regs[j].regmap[maxscore]<0); + if(j>loop_start[maxscore]) regs[j].regmap_entry[maxscore]=reg; + regs[j].regmap[maxscore]=reg; + regs[j].dirty&=~(1<>16)!=0x1000) { + regmap_pre[j+2][maxscore]=reg; + regs[j+2].wasdirty&=~(1<>2; + if(t==loop_start[maxscore]) { + if(t==1||(t>1&&itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||(t>1&&rt1[t-2]!=31)) // call/ret assumes no registers allocated + regs[t].regmap_entry[maxscore]=reg; + } + } + else + { + if(j<1||(itype[j-1]!=RJUMP&&itype[j-1]!=UJUMP&&itype[j-1]!=CJUMP&&itype[j-1]!=SJUMP&&itype[j-1]!=FJUMP)) { + regmap_pre[j+1][maxscore]=reg; + regs[j+1].wasdirty&=~(1<=0) { @@ -10236,6 +10623,7 @@ int new_recompile_block(int addr) } } } + // Load source into target register if(lt1[i+1]&&get_reg(regs[i+1].regmap,rs1[i+1])<0) { if((hr=get_reg(regs[i+1].regmap,rt1[i+1]))>=0) { @@ -10252,6 +10640,7 @@ int new_recompile_block(int addr) } } } + // Preload map address #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||itype[i+1]==C2LS) { hr=get_reg(regs[i+1].regmap,TLREG); @@ -10291,6 +10680,7 @@ int new_recompile_block(int addr) } } #endif + // Address for store instruction (non-constant) 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) { @@ -10490,14 +10880,27 @@ int new_recompile_block(int addr) } //requires_32bit[i]=is32[i]&~unneeded_reg_upper[i]; // DEBUG } +#else + for (i=slen-1;i>=0;i--) + { + if(itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) + { + // Conditional branch + if((source[i]>>16)!=0x1000&&i>16)!=0x1000)) @@ -10777,9 +11190,9 @@ int new_recompile_block(int addr) if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { // Load the delay slot registers if necessary - if(rs1[i+1]!=rs1[i]&&rs1[i+1]!=rs2[i]) + if(rs1[i+1]!=rs1[i]&&rs1[i+1]!=rs2[i]&&(rs1[i+1]!=rt1[i]||rt1[i]==0)) load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs1[i+1],rs1[i+1]); - if(rs2[i+1]!=rs1[i+1]&&rs2[i+1]!=rs1[i]&&rs2[i+1]!=rs2[i]) + if(rs2[i+1]!=rs1[i+1]&&rs2[i+1]!=rs1[i]&&rs2[i+1]!=rs2[i]&&(rs2[i+1]!=rt1[i]||rt1[i]==0)) load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs2[i+1],rs2[i+1]); if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,INVCP,INVCP); @@ -11054,11 +11467,14 @@ int new_recompile_block(int addr) } #endif } + inv_code_start=inv_code_end=~0; #ifdef PCSX - // PCSX maps all RAM mirror invalid_code tests to 0x80000000..0x80000000+RAM_SIZE + // for PCSX we need to mark all mirrors too if(get_page(start)<(RAM_SIZE>>12)) for(i=start>>12;i<=(start+slen*4)>>12;i++) - invalid_code[((u_int)0x80000000>>12)|i]=0; + invalid_code[((u_int)0x00000000>>12)|(i&0x1ff)]= + invalid_code[((u_int)0x80000000>>12)|(i&0x1ff)]= + invalid_code[((u_int)0xa0000000>>12)|(i&0x1ff)]=0; #endif /* Pass 10 - Free memory by expiring oldest blocks */