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=84370089f7625e2d699a912c6fd0f9962843f0ce;hp=b2b5d2895262fd529aa7e969d3940325427c47c1;hb=c7b746f050d33e3bb5b06707dcc52f8699858e40;hpb=68b3faeed93986cef07197ee2471a9e561803dbc diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c index b2b5d289..84370089 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" @@ -36,9 +41,21 @@ #include "assem_arm.h" #endif +#ifdef __BLACKBERRY_QNX__ +#undef __clear_cache +#define __clear_cache(start,end) msync(start, (size_t)((void*)end - (void*)start), MS_SYNC | MS_CACHE_ONLY | MS_INVALIDATE_ICACHE); +#elif defined(__MACH__) +#include +#define __clear_cache mach_clear_cache +static void __clear_cache(void *start, void *end) { + size_t len = (char *)end - (char *)start; + sys_dcache_flush(start, len); + sys_icache_invalidate(start, len); +} +#endif + #define MAXBLOCK 4096 #define MAX_OUTPUT_BLOCK_SIZE 262144 -#define CLOCK_DIVIDER 2 struct regstat { @@ -52,7 +69,8 @@ struct regstat uint64_t uu; u_int wasconst; u_int isconst; - uint64_t constmap[HOST_REGS]; + u_int loadedconst; // host regs that have constants loaded + u_int waswritten; // MIPS regs that were used as store base before }; struct ll_entry @@ -80,10 +98,19 @@ 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 u_int smrv[32]; // speculated MIPS register values + static u_int smrv_strong; // mask or regs that are likely to have correct values + static u_int smrv_weak; // same, but somewhat less likely + static u_int smrv_strong_next; // same, but after current insn executes + static u_int smrv_weak_next; int imm[MAXBLOCK]; 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]; @@ -91,13 +118,11 @@ struct ll_entry uint64_t p32[MAXBLOCK]; uint64_t pr32[MAXBLOCK]; signed char regmap_pre[MAXBLOCK][HOST_REGS]; - 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]; + static uint64_t current_constmap[HOST_REGS]; + static uint64_t constmap[MAXBLOCK][HOST_REGS]; + static struct regstat regs[MAXBLOCK]; + static 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]; @@ -121,8 +146,19 @@ struct ll_entry char shadow[1048576] __attribute__((aligned(16))); void *copy; int expirep; +#ifndef PCSX u_int using_tlb; +#else + static const u_int using_tlb=0; +#endif + int new_dynarec_did_compile; + int new_dynarec_hacks; u_int stop_after_jal; +#ifndef RAM_FIXED + static u_int ram_offset; +#else + static const u_int ram_offset=0; +#endif extern u_char restore_candidate[512]; extern int cycle_count; @@ -134,19 +170,21 @@ struct ll_entry #define CSREG 35 // Coprocessor status #define CCREG 36 // Cycle count #define INVCP 37 // Pointer to invalid_code -#define TEMPREG 38 -#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 -#define RHTBL 42 // Return address hash table address -#define RTEMP 43 // JR/JALR address register -#define MAXREG 43 -#define AGEN1 44 // Address generation temporary register -#define AGEN2 45 // Address generation temporary register -#define MGEN1 46 // Maptable address generation temporary register -#define MGEN2 47 // Maptable address generation temporary register -#define BTREG 48 // Branch target temporary register +#define MMREG 38 // Pointer to memory_map +#define ROREG 39 // ram offset (if rdram!=0x80000000) +#define TEMPREG 40 +#define FTEMP 40 // FPU temporary register +#define PTEMP 41 // Prefetch temporary register +#define TLREG 42 // TLB mapping offset +#define RHASH 43 // Return address hash +#define RHTBL 44 // Return address hash table address +#define RTEMP 45 // JR/JALR address register +#define MAXREG 45 +#define AGEN1 46 // Address generation temporary register +#define AGEN2 47 // Address generation temporary register +#define MGEN1 48 // Maptable address generation temporary register +#define MGEN2 49 // Maptable address generation temporary register +#define BTREG 50 // Branch target temporary register /* instruction types */ #define NOP 0 // No operation @@ -254,11 +292,15 @@ 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 +#define NO_CYCLE_PENALTY_THR 12 + +int cycle_multiplier; // 100 for 1.0 + +static int CLOCK_ADJUST(int x) +{ + int s=(x>>31)|1; + return (x * cycle_multiplier + s * 50) / 100; +} static void tlb_hacks() { @@ -309,7 +351,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 @@ -317,6 +366,7 @@ static u_int get_page(u_int vaddr) return page; } +#ifndef PCSX static u_int get_vpage(u_int vaddr) { u_int vpage=(vaddr^0x80000000)>>12; @@ -326,6 +376,13 @@ static u_int get_vpage(u_int vaddr) if(vpage>2048) vpage=2048+(vpage&2047); return vpage; } +#else +// no virtual mem in PCSX +static u_int get_vpage(u_int vaddr) +{ + return get_page(vaddr); +} +#endif // Get address from virtual address // This is called from the recompiled JR/JALR instructions @@ -357,7 +414,10 @@ 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; +#ifndef DISABLE_TLB memory_map[vaddr>>12]|=0x40000000; +#endif if(vpage<2048) { #ifndef DISABLE_TLB if(tlb_LUT_r[vaddr>>12]) { @@ -449,6 +509,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 @@ -562,11 +623,11 @@ void set_const(struct regstat *cur,signed char reg,uint64_t value) for (hr=0;hrregmap[hr]==reg) { cur->isconst|=1<constmap[hr]=value; + current_constmap[hr]=value; } else if((cur->regmap[hr]^64)==reg) { cur->isconst|=1<constmap[hr]=value>>32; + current_constmap[hr]=value>>32; } } } @@ -585,6 +646,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) { @@ -599,10 +661,10 @@ uint64_t get_const(struct regstat *cur,signed char reg) if(!reg) return 0; for (hr=0;hrregmap[hr]==reg) { - return cur->constmap[hr]; + return current_constmap[hr]; } } - printf("Unknown constant in r%d\n",reg); + SysPrintf("Unknown constant in r%d\n",reg); exit(1); } @@ -705,12 +767,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)) { @@ -763,11 +819,7 @@ int needed_again(int r, int i) } } }*/ - for(hr=0;hraddr); inv_debug("EXP: Lookup pointer to %x at %x (%x)\n",(int)ptr,(int)head->addr,head->vaddr); @@ -1088,20 +1140,12 @@ void ll_kill_pointers(struct ll_entry *head,int addr,int shift) { inv_debug("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr); u_int host_addr=(u_int)kill_pointer(head->addr); - - if((host_addr>>12)!=(old_host_addr>>12)) { - #ifdef __arm__ - __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff)); - #endif - old_host_addr=host_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; } - #ifdef __arm__ - if (old_host_addr) - __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff)); - #endif } // This is called when we write to a compiled block (see do_invstub) @@ -1109,7 +1153,6 @@ void invalidate_page(u_int page) { struct ll_entry *head; struct ll_entry *next; - u_int old_host_addr=0; head=jump_in[page]; jump_in[page]=0; while(head!=NULL) { @@ -1124,22 +1167,54 @@ void invalidate_page(u_int page) while(head!=NULL) { inv_debug("INVALIDATE: kill pointer to %x (%x)\n",head->vaddr,(int)head->addr); u_int host_addr=(u_int)kill_pointer(head->addr); - - if((host_addr>>12)!=(old_host_addr>>12)) { - #ifdef __arm__ - __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff)); - #endif - old_host_addr=host_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; } +} + +static void invalidate_block_range(u_int block, u_int first, u_int last) +{ + u_int page=get_page(block<<12); + //printf("first=%d last=%d\n",first,last); + invalidate_page(page); + assert(first+5>page); // NB: this assumes MAXBLOCK<=4096 (4 pages) + assert(last>2; + u_int real_block=tlb_LUT_w[block]>>12; + invalid_code[real_block]=1; + if(real_block>=0x80000&&real_block<0x80800) memory_map[real_block]=((u_int)rdram-0x80000000)>>2; + } + else if(block>=0x80000&&block<0x80800) memory_map[block]=((u_int)rdram-0x80000000)>>2; +#endif + + #ifdef USE_MINI_HT + memset(mini_ht,-1,sizeof(mini_ht)); #endif } + void invalidate_block(u_int block) { u_int page=get_page(block<<12); @@ -1156,7 +1231,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<0x80000000+RAM_SIZE) { + if(page<2048&&start>=(u_int)rdram&&end<(u_int)rdram+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; @@ -1173,42 +1248,71 @@ void invalidate_block(u_int block) } 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) - assert(last>2; - u_int real_block=tlb_LUT_w[block]>>12; - invalid_code[real_block]=1; - if(real_block>=0x80000&&real_block<0x80800) memory_map[real_block]=((u_int)rdram-0x80000000)>>2; - } - else if(block>=0x80000&&block<0x80800) memory_map[block]=((u_int)rdram-0x80000000)>>2; -#endif - - #ifdef USE_MINI_HT - memset(mini_ht,-1,sizeof(mini_ht)); - #endif + 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_vpage(addr); + if(page<2048) { // RAM + struct ll_entry *head; + u_int addr_min=~0, addr_max=0; + u_int mask=RAM_SIZE-1; + u_int addr_main=0x80000000|(addr&mask); + int pg1; + inv_code_start=addr_main&~0xfff; + inv_code_end=addr_main|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(ram_offset) { + start-=ram_offset; + end-=ram_offset; + } + if(start<=addr_main&&addr_mainaddr_max) addr_max=end; + } + else if(addr_maininv_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_code_start=(addr&~mask)|(inv_code_start&mask); + inv_code_end=(addr&~mask)|(inv_code_end&mask); + inv_debug("INV ADDR: %08x miss, inv %08x-%08x, sk %d\n", addr, inv_code_start, inv_code_end, 0); + 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() { u_int page,n; @@ -1245,6 +1349,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); @@ -1274,11 +1380,13 @@ void clean_blocks(u_int page) inv|=invalid_code[i]; } } +#ifndef DISABLE_TLB if((signed int)head->vaddr>=(signed int)0xC0000000) { u_int addr = (head->vaddr+(memory_map[head->vaddr>>12]<<2)); //printf("addr=%x start=%x end=%x\n",addr,start,end); if(addr=end) inv=1; } +#endif else if((signed int)head->vaddr>=(signed int)0x80000000+RAM_SIZE) { inv=1; } @@ -1331,8 +1439,6 @@ void mov_alloc(struct regstat *current,int i) void shiftimm_alloc(struct regstat *current,int i) { - clear_const(current,rs1[i]); - clear_const(current,rt1[i]); if(opcode2[i]<=0x3) // SLL/SRL/SRA { if(rt1[i]) { @@ -1341,8 +1447,21 @@ void shiftimm_alloc(struct regstat *current,int i) alloc_reg(current,i,rt1[i]); current->is32|=1LL<>imm[i]); + if(opcode2[i]==0x03) set_const(current,rt1[i],v>>imm[i]); + } + else clear_const(current,rt1[i]); } } + else + { + clear_const(current,rs1[i]); + clear_const(current,rt1[i]); + } + if(opcode2[i]>=0x38&&opcode2[i]<=0x3b) // DSLL/DSRL/DSRA { if(rt1[i]) { @@ -1394,7 +1513,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<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]); + assert(get_reg(current->regmap,rt1[i])>=0); if(opcode[i]==0x27||opcode[i]==0x37) // LWU/LD { current->is32&=~(1LL<is32|=1LL<is32&=~(1LL<isconst=0; } @@ -1855,7 +2005,7 @@ void delayslot_alloc(struct regstat *current,int i) case HLECALL: case SPAN: assem_debug("jump in the delay slot. this shouldn't happen.\n");//exit(1); - printf("Disabled speculative precompilation\n"); + SysPrintf("Disabled speculative precompilation\n"); stop_after_jal=1; break; case IMM16: @@ -1918,6 +2068,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); @@ -2596,7 +2747,7 @@ void shiftimm_assemble(int i,struct regstat *i_regs) t=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); //assert(t>=0); - if(t>=0){ + if(t>=0&&!((i_regs->isconst>>t)&1)){ if(rs1[i]==0) { emit_zeroreg(t); @@ -2739,6 +2890,7 @@ void load_assemble(int i,struct regstat *i_regs) int offset; int jaddr=0; int memtarget=0,c=0; + int fastload_reg_override=0; u_int hr,reglist=0; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); @@ -2750,8 +2902,10 @@ 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)0x80000000+RAM_SIZE; - if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + if (c) { + memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE; + if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + } } //printf("load_assemble: c=%d\n",c); //if(c) printf("load_assemble: const=%x\n",(int)constmap[i][s]+offset); @@ -2768,41 +2922,46 @@ void load_assemble(int i,struct regstat *i_regs) #endif if(offset||s<0||c) addr=tl; else addr=s; - if(tl>=0) { - //assert(tl>=0); - //assert(rt1[i]); - reglist&=~(1<=0) reglist&=~(1<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); + assert(tl>=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>=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_jno(0); - } + #ifdef R29_HACK + // Strmnnrmn's speed hack + if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE) + #endif + { + jaddr=emit_fastpath_cmp_jump(i,addr,&fastload_reg_override); } - }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 if(ram_offset&&memtarget) { + emit_addimm(addr,ram_offset,HOST_TEMPREG); + fastload_reg_override=HOST_TEMPREG; + } + }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); + reglist&=~(1<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); @@ -2812,70 +2971,84 @@ 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); + if(fastload_reg_override) a=fastload_reg_override; + + 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 + if(fastload_reg_override) a=fastload_reg_override; //#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{ + #if 1 //def 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) { + 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); - if(jaddr) - add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + emit_readword_indexed_tlb(0,a,map,tl); } - 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); @@ -2885,73 +3058,89 @@ 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); + if(fastload_reg_override) a=fastload_reg_override; + + 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 + if(fastload_reg_override) a=fastload_reg_override; //#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{ + #if 1 //def 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) { + 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); - 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_readword_indexed_tlb(0,a,map,tl); } - emit_zeroreg(th); + if(jaddr) + add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } - if (opcode[i]==0x37) { // LD - if(!c||memtarget) { + else { + inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist); + } + emit_zeroreg(th); + } + 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); @@ -2960,15 +3149,16 @@ 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); - if(jaddr) - add_stub(LOADD_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); + emit_readdword_indexed_tlb(0,a,map,th,tl); } - 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) @@ -3015,6 +3205,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]); @@ -3024,8 +3215,10 @@ 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)0x80000000+RAM_SIZE; - if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + if(c) { + memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE; + if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + } } assert(tl>=0); assert(temp>=0); @@ -3037,9 +3230,9 @@ void store_assemble(int i,struct regstat *i_regs) else addr=s; if(!using_tlb) { if(!c) { + #ifndef PCSX #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); @@ -3047,6 +3240,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 { @@ -3059,6 +3253,13 @@ void store_assemble(int i,struct regstat *i_regs) #endif emit_jno(0); } + #else + jaddr=emit_fastpath_cmp_jump(i,addr,&faststore_reg_override); + #endif + } + else if(ram_offset&&memtarget) { + emit_addimm(addr,ram_offset,HOST_TEMPREG); + faststore_reg_override=HOST_TEMPREG; } }else{ // using tlb int x=0; @@ -3066,78 +3267,85 @@ 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) { - gen_tlb_addr_w(temp,map); - emit_writehword_indexed(tl,x,temp); + gen_tlb_addr_w(a,map); + emit_writehword_indexed(tl,x,a); }else - emit_writehword_indexed(tl,(int)rdram-0x80000000+x,temp); + //emit_writehword_indexed(tl,(int)rdram-0x80000000+x,a); + emit_writehword_indexed(tl,x,a); } type=STOREH_STUB; } if (opcode[i]==0x2B) { // SW - if(!c||memtarget) + if(!c||memtarget) { + int a=addr; + if(faststore_reg_override) a=faststore_reg_override; //emit_writeword_indexed(tl,(int)rdram-0x80000000,addr); - emit_writeword_indexed_tlb(tl,0,addr,map,temp); + emit_writeword_indexed_tlb(tl,0,a,map,temp); + } type=STOREW_STUB; } if (opcode[i]==0x3F) { // SD if(!c||memtarget) { + int a=addr; + if(faststore_reg_override) a=faststore_reg_override; if(rs2[i]) { assert(th>=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; } - if(!using_tlb&&(!c||memtarget)) - // addr could be a temp, make sure it survives STORE*_STUB - reglist|=1<regmap,rs2[i],ccadj[i],reglist); + jaddr=0; } - if(!using_tlb) { +#endif + if(!using_tlb&&!(i_regs->waswritten&(1<regmap,rs2[i],ccadj[i],reglist); + } + // basic current block modification detection.. + // not looking back as that should be in mips cache already + if(c&&start+i*4regmap==regs[i].regmap); // not delay slot + if(i_regs->regmap==regs[i].regmap) { + load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i); + wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty); + emit_movimm(start+i*4+4,0); + emit_writeword(0,(int)&pcaddr); + emit_jmp((int)do_interrupt); } } //if(opcode[i]==0x2B || opcode[i]==0x3F) @@ -3162,8 +3393,12 @@ void store_assemble(int i,struct regstat *i_regs) //if(opcode[i]==0x2B) /*if(opcode[i]==0x2B || opcode[i]==0x28 || opcode[i]==0x29 || opcode[i]==0x3F) { - //emit_pusha(); + #ifdef __i386__ + emit_pusha(); + #endif + #ifdef __arm__ save_regs(0x100f); + #endif emit_readword((int)&last_count,ECX); #ifdef __i386__ if(get_reg(i_regs->regmap,CCREG)<0) @@ -3182,8 +3417,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 }/**/ } @@ -3196,7 +3435,7 @@ void storelr_assemble(int i,struct regstat *i_regs) int jaddr=0,jaddr2; int case1,case2,case3; int done0,done1,done2; - 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); @@ -3207,188 +3446,201 @@ void storelr_assemble(int i,struct regstat *i_regs) offset=imm[i]; if(s>=0) { c=(i_regs->isconst>>s)&1; - memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE; - if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + if(c) { + memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE; + if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; + } } 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,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); - } - } - 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); + reglist&=~(1<=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,i,(int)i_regs,temp,ccadj[i],reglist); } - if(!using_tlb) { + 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&&!(i_regs->waswritten&(1<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); @@ -3396,9 +3648,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<regmap,TLREG); assert(map>=0); + reglist&=~(1<waswritten&(1<>16)&0x1f; s=get_reg(i_regs->regmap,rs1[i]); @@ -3646,27 +3908,34 @@ void c2ls_assemble(int i,struct regstat *i_regs) } else { if(!c) { - emit_cmpimm(offset||c||s<0?ar:s,RAM_SIZE); - jaddr2=(int)out; - emit_jno(0); + jaddr2=emit_fastpath_cmp_jump(i,ar,&fastio_reg_override); + } + else if(ram_offset&&memtarget) { + emit_addimm(ar,ram_offset,HOST_TEMPREG); + fastio_reg_override=HOST_TEMPREG; } 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); + int a=ar; + if(fastio_reg_override) a=fastio_reg_override; + emit_readword_indexed(0,a,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); + int a=ar; + if(fastio_reg_override) a=fastio_reg_override; + emit_writeword_indexed(tl,0,a); } } if(jaddr2) add_stub(type,jaddr2,(int)out,i,ar,(int)i_regs,ccadj[i],reglist); - if (opcode[i]==0x3a) { // SWC2 + if(opcode[i]==0x3a) // SWC2 + if(!(i_regs->waswritten&(1<regmap,INVCP); assert(ir>=0); @@ -3674,9 +3943,13 @@ void c2ls_assemble(int i,struct regstat *i_regs) #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); @@ -3736,7 +4008,7 @@ void syscall_assemble(int i,struct regstat *i_regs) assert(ccreg==HOST_CCREG); 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_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle... emit_jmp((int)jump_syscall_hle); // XXX } @@ -3747,7 +4019,7 @@ void hlecall_assemble(int i,struct regstat *i_regs) 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_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); // XXX emit_jmp((int)jump_hlecall); } @@ -3757,12 +4029,13 @@ void intcall_assemble(int i,struct regstat *i_regs) 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_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); emit_jmp((int)jump_intcall); } void ds_assemble(int i,struct regstat *i_regs) { + speculate_register_values(i); is_delayslot=1; switch(itype[i]) { case ALU: @@ -3812,7 +4085,7 @@ void ds_assemble(int i,struct regstat *i_regs) case CJUMP: case SJUMP: case FJUMP: - printf("Jump in the delay slot. This is probably a bug.\n"); + SysPrintf("Jump in the delay slot. This is probably a bug.\n"); } is_delayslot=0; } @@ -3833,8 +4106,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; } @@ -3967,12 +4243,13 @@ 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) { 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); @@ -4018,6 +4295,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) // printf("poor load scheduling!\n"); } else if(c) { +#ifndef DISABLE_TLB if(rm>=0) { if(!entry||entry[rm]!=mgr) { if(itype[i]==STORE||itype[i]==STORELR||(opcode[i]&0x3b)==0x39||(opcode[i]&0x3b)==0x3a) { @@ -4032,6 +4310,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) } } } +#endif if(rs1[i]!=rt1[i]||itype[i]!=LOAD) { if(!entry||entry[ra]!=agr) { if (opcode[i]==0x22||opcode[i]==0x26) { @@ -4044,6 +4323,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) (using_tlb&&((signed int)constmap[i][rs]+offset)>=(signed int)0xC0000000)) #endif emit_movimm(constmap[i][rs]+offset,ra); + regs[i].loadedconst|=1<regmap,agr); @@ -4104,6 +4384,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) (using_tlb&&((signed int)constmap[i+1][rs]+offset)>=(signed int)0xC0000000)) #endif emit_movimm(constmap[i+1][rs]+offset,ra); + regs[i+1].loadedconst|=1<=0&&((regs[i-1].isconst>>hr)&1)&&pre[hr]==regmap[hr] + &®map[hr]==regs[i-1].regmap[hr]&&((regs[i-1].loadedconst>>hr)&1)) + { + regs[i].loadedconst|=1<=0) { //if(entry[hr]!=regmap[hr]) { - if(i==0||!((regs[i-1].isconst>>hr)&1)||pre[hr]!=regmap[hr]||bt[i]) { + if(!((regs[i].loadedconst>>hr)&1)) { if(((regs[i].isconst>>hr)&1)&®map[hr]<64&®map[hr]>0) { - int value; + int value,similar=0; if(get_final_value(hr,i,&value)) { - if(value==0) { + // see if some other register has similar value + for(hr2=0;hr2>hr2)&1)) { + if(is_similar_value(value,constmap[i][hr2])) { + similar=1; + break; + } + } + } + if(similar) { + int value2; + if(get_final_value(hr2,i,&value2)) // is this needed? + emit_movimm_from(value2,hr2,value,hr); + else + emit_movimm(value,hr); + } + else if(value==0) { emit_zeroreg(hr); } else { emit_movimm(value,hr); } } + regs[i].loadedconst|=1<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); @@ -4473,7 +4783,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 @@ -4491,7 +4801,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) { @@ -4532,19 +4842,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; @@ -4574,7 +4884,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 @@ -4666,7 +4978,7 @@ void ds_assemble_entry(int i) case CJUMP: case SJUMP: case FJUMP: - printf("Jump in the delay slot. This is probably a bug.\n"); + SysPrintf("Jump in the delay slot. This is probably a bug.\n"); } store_regs_bt(regs[t].regmap,regs[t].is32,regs[t].dirty,ba[i]+4); load_regs_bt(regs[t].regmap,regs[t].is32,regs[t].dirty,ba[i]+4); @@ -4684,6 +4996,7 @@ void do_cc(int i,signed char i_regmap[],int *adj,int addr,int taken,int invert) int count; int jaddr; int idle=0; + int t=0; if(itype[i]==RJUMP) { *adj=0; @@ -4691,7 +5004,7 @@ void do_cc(int i,signed char i_regmap[],int *adj,int addr,int taken,int invert) //if(ba[i]>=start && ba[i]<(start+slen*4)) if(internal_branch(branch_regs[i].is32,ba[i])) { - int t=(ba[i]-start)>>2; + t=(ba[i]-start)>>2; if(is_ds[t]) *adj=-1; // Branch into delay slot adds an extra cycle else *adj=ccadj[t]; } @@ -4710,13 +5023,20 @@ void do_cc(int i,signed char i_regmap[],int *adj,int addr,int taken,int invert) emit_jmp(0); } else if(*adj==0||invert) { - emit_addimm_and_set_flags(CLOCK_DIVIDER*(count+2),HOST_CCREG); + int cycles=CLOCK_ADJUST(count+2); + // faster loop HACK + if (t&&*adj) { + int rel=t-i; + if(-NO_CYCLE_PENALTY_THR>2].regmap_entry); @@ -5001,9 +5321,45 @@ add_to_linker(int addr,int target,int ext) linkcount++; } +static void ujump_assemble_write_ra(int i) +{ + int rt; + unsigned int return_address; + 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)&&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 @@ -5015,6 +5371,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; @@ -5023,46 +5383,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); @@ -5071,7 +5393,7 @@ void ujump_assemble(int i,struct regstat *i_regs) if(rt1[i]==31&&temp>=0) emit_prefetchreg(temp); #endif do_cc(i,branch_regs[i].regmap,&adj,ba[i],TAKEN,0); - if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(adj) emit_addimm(cc,CLOCK_ADJUST(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(internal_branch(branch_regs[i].is32,ba[i])) assem_debug("branch: internal\n"); @@ -5086,11 +5408,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]) { @@ -5117,6 +5461,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; @@ -5126,25 +5474,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 @@ -5175,8 +5506,14 @@ void rjump_assemble(int i,struct regstat *i_regs) //do_cc(i,branch_regs[i].regmap,&adj,-1,TAKEN); //if(adj) emit_addimm(cc,2*(ccadj[i]+2-adj),cc); // ??? - Shouldn't happen //assert(adj==0); - emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),HOST_CCREG); add_stub(CC_STUB,(int)out,jump_vaddr_reg[rs],0,i,-1,TAKEN,0); +#ifdef PCSX + if(itype[i+1]==COP0&&(source[i+1]&0x3f)==0x10) + // special case for RFE + emit_jmp(0); + else +#endif emit_jns(0); //load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,-1); #ifdef USE_MINI_HT @@ -5237,26 +5574,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]); @@ -5292,7 +5618,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); @@ -5317,7 +5643,7 @@ void cjump_assemble(int i,struct regstat *i_regs) if(unconditional) { do_cc(i,branch_regs[i].regmap,&adj,ba[i],TAKEN,0); if(i!=(ba[i]-start)>>2 || source[i+1]!=0) { - if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(adj) emit_addimm(cc,CLOCK_ADJUST(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(internal) assem_debug("branch: internal\n"); @@ -5336,7 +5662,7 @@ void cjump_assemble(int i,struct regstat *i_regs) } } else if(nop) { - emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); + emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc); int jaddr=(int)out; emit_jns(0); add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,NOTTAKEN,0); @@ -5344,7 +5670,7 @@ void cjump_assemble(int i,struct regstat *i_regs) else { int taken=0,nottaken=0,nottaken1=0; do_cc(i,branch_regs[i].regmap,&adj,-1,0,invert); - if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(adj&&!invert) emit_addimm(cc,CLOCK_ADJUST(ccadj[i]+2-adj),cc); if(!only32) { assert(s1h>=0); @@ -5436,7 +5762,7 @@ void cjump_assemble(int i,struct regstat *i_regs) #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(match&&(!internal||!is_ds[(ba[i]-start)>>2])) { if(adj) { - emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); + emit_addimm(cc,-CLOCK_ADJUST(adj),cc); add_to_linker((int)out,ba[i],internal); }else{ emit_addnop(13); @@ -5446,7 +5772,7 @@ void cjump_assemble(int i,struct regstat *i_regs) }else #endif { - if(adj) emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); + if(adj) emit_addimm(cc,-CLOCK_ADJUST(adj),cc); store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(internal) @@ -5466,7 +5792,7 @@ void cjump_assemble(int i,struct regstat *i_regs) if(nottaken1) set_jump_target(nottaken1,(int)out); if(adj) { - if(!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); + if(!invert) emit_addimm(cc,CLOCK_ADJUST(adj),cc); } } // (!unconditional) } // if(ooo) @@ -5570,7 +5896,7 @@ void cjump_assemble(int i,struct regstat *i_regs) store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); do_cc(i,i_regmap,&adj,ba[i],TAKEN,0); assem_debug("cycle count (adj)\n"); - if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(adj) emit_addimm(cc,CLOCK_ADJUST(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(internal) assem_debug("branch: internal\n"); @@ -5602,7 +5928,7 @@ void cjump_assemble(int i,struct regstat *i_regs) if(cc==-1&&!likely[i]) { // Cycle count isn't in a register, temporarily load it then write it out emit_loadreg(CCREG,HOST_CCREG); - emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),HOST_CCREG); int jaddr=(int)out; emit_jns(0); add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,NOTTAKEN,0); @@ -5611,7 +5937,7 @@ void cjump_assemble(int i,struct regstat *i_regs) else{ cc=get_reg(i_regmap,CCREG); assert(cc==HOST_CCREG); - emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); + emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc); int jaddr=(int)out; emit_jns(0); add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0); @@ -5631,11 +5957,9 @@ 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; @@ -5644,19 +5968,7 @@ void sjump_assemble(int i,struct regstat *i_regs) //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; - } - if(rt1[i]==31&&(rs1[i+1]==31||rs2[i+1]==31||rt1[i+1]==31||rt2[i+1]==31)) - // BxxZAL $ra is available to delay insn, so do it in order - 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); } @@ -5678,7 +5990,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); @@ -5716,7 +6028,7 @@ void sjump_assemble(int i,struct regstat *i_regs) if(unconditional) { do_cc(i,branch_regs[i].regmap,&adj,ba[i],TAKEN,0); if(i!=(ba[i]-start)>>2 || source[i+1]!=0) { - if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(adj) emit_addimm(cc,CLOCK_ADJUST(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(internal) assem_debug("branch: internal\n"); @@ -5735,7 +6047,7 @@ void sjump_assemble(int i,struct regstat *i_regs) } } else if(nevertaken) { - emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); + emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc); int jaddr=(int)out; emit_jns(0); add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,NOTTAKEN,0); @@ -5743,7 +6055,7 @@ void sjump_assemble(int i,struct regstat *i_regs) else { int nottaken=0; do_cc(i,branch_regs[i].regmap,&adj,-1,0,invert); - if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(adj&&!invert) emit_addimm(cc,CLOCK_ADJUST(ccadj[i]+2-adj),cc); if(!only32) { assert(s1h>=0); @@ -5801,7 +6113,7 @@ void sjump_assemble(int i,struct regstat *i_regs) #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(match&&(!internal||!is_ds[(ba[i]-start)>>2])) { if(adj) { - emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); + emit_addimm(cc,-CLOCK_ADJUST(adj),cc); add_to_linker((int)out,ba[i],internal); }else{ emit_addnop(13); @@ -5811,7 +6123,7 @@ void sjump_assemble(int i,struct regstat *i_regs) }else #endif { - if(adj) emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); + if(adj) emit_addimm(cc,-CLOCK_ADJUST(adj),cc); store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(internal) @@ -5830,7 +6142,7 @@ void sjump_assemble(int i,struct regstat *i_regs) } if(adj) { - if(!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); + if(!invert) emit_addimm(cc,CLOCK_ADJUST(adj),cc); } } // (!unconditional) } // if(ooo) @@ -5913,7 +6225,7 @@ void sjump_assemble(int i,struct regstat *i_regs) store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); do_cc(i,i_regmap,&adj,ba[i],TAKEN,0); assem_debug("cycle count (adj)\n"); - if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(adj) emit_addimm(cc,CLOCK_ADJUST(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(internal) assem_debug("branch: internal\n"); @@ -5944,7 +6256,7 @@ void sjump_assemble(int i,struct regstat *i_regs) if(cc==-1&&!likely[i]) { // Cycle count isn't in a register, temporarily load it then write it out emit_loadreg(CCREG,HOST_CCREG); - emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),HOST_CCREG); int jaddr=(int)out; emit_jns(0); add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,NOTTAKEN,0); @@ -5953,7 +6265,7 @@ void sjump_assemble(int i,struct regstat *i_regs) else{ cc=get_reg(i_regmap,CCREG); assert(cc==HOST_CCREG); - emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); + emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc); int jaddr=(int)out; emit_jns(0); add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0); @@ -5971,25 +6283,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? } @@ -6008,7 +6310,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); @@ -6029,7 +6331,7 @@ void fjump_assemble(int i,struct regstat *i_regs) assem_debug("cycle count (adj)\n"); if(1) { int nottaken=0; - if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(adj&&!invert) emit_addimm(cc,CLOCK_ADJUST(ccadj[i]+2-adj),cc); if(1) { assert(fs>=0); emit_testimm(fs,0x800000); @@ -6056,7 +6358,7 @@ void fjump_assemble(int i,struct regstat *i_regs) } // if(!only32) if(invert) { - if(adj) emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); + if(adj) emit_addimm(cc,-CLOCK_ADJUST(adj),cc); #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK else if(match) emit_addnop(13); #endif @@ -6077,7 +6379,7 @@ void fjump_assemble(int i,struct regstat *i_regs) } if(adj) { - if(!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); + if(!invert) emit_addimm(cc,CLOCK_ADJUST(adj),cc); } } // (!unconditional) } // if(ooo) @@ -6129,7 +6431,7 @@ void fjump_assemble(int i,struct regstat *i_regs) store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); do_cc(i,i_regmap,&adj,ba[i],TAKEN,0); assem_debug("cycle count (adj)\n"); - if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); + if(adj) emit_addimm(cc,CLOCK_ADJUST(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(internal) assem_debug("branch: internal\n"); @@ -6159,7 +6461,7 @@ void fjump_assemble(int i,struct regstat *i_regs) if(cc==-1&&!likely[i]) { // Cycle count isn't in a register, temporarily load it then write it out emit_loadreg(CCREG,HOST_CCREG); - emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); + emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),HOST_CCREG); int jaddr=(int)out; emit_jns(0); add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,NOTTAKEN,0); @@ -6168,7 +6470,7 @@ void fjump_assemble(int i,struct regstat *i_regs) else{ cc=get_reg(i_regmap,CCREG); assert(cc==HOST_CCREG); - emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); + emit_addimm_and_set_flags(CLOCK_ADJUST(ccadj[i]+2),cc); int jaddr=(int)out; emit_jns(0); add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0); @@ -6241,7 +6543,7 @@ static void pagespan_assemble(int i,struct regstat *i_regs) if((opcode[i]&0x2e)==4||opcode[i]==0x11) { // BEQ/BNE/BEQL/BNEL/BC1 load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,CCREG,CCREG); } - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]+2),HOST_CCREG); if(opcode[i]==2) // J { unconditional=1; @@ -6511,7 +6813,7 @@ static void pagespan_ds() case CJUMP: case SJUMP: case FJUMP: - printf("Jump in the delay slot. This is probably a bug.\n"); + SysPrintf("Jump in the delay slot. This is probably a bug.\n"); } int btaddr=get_reg(regs[0].regmap,BTREG); if(btaddr<0) { @@ -6539,16 +6841,22 @@ 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=0; uint64_t tdep; + uint64_t gte_u_unknown=0; + if(new_dynarec_hacks&NDHACK_GTE_UNNEEDED) + gte_u_unknown=~0ll; if(iend==slen-1) { u=1;uu=1; + gte_u=gte_u_unknown; }else{ u=unneeded_reg[iend+1]; uu=unneeded_reg_upper[iend+1]; u=1;uu=1; + gte_u=gte_unneeded[iend+1]; } + for (i=iend;i>=istart;i--) { //printf("unneeded registers i=%d (%d,%d) r=%d\n",i,istart,iend,r); @@ -6562,6 +6870,7 @@ void unneeded_registers(int istart,int iend,int r) // Branch out of this block, flush all regs u=1; uu=1; + gte_u=gte_u_unknown; /* Hexagon hack if(itype[i]==UJUMP&&rt1[i]==31) { @@ -6593,17 +6902,21 @@ void unneeded_registers(int istart,int iend,int r) uu&=~((1LL<>rt1[i+1])&1; @@ -6630,17 +6945,21 @@ void unneeded_registers(int istart,int iend,int r) temp_uu&=~((1LL<>rt1[i])&1; @@ -6650,8 +6969,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]=gte_u_unknown; } } /*else*/ if(1) { if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000) @@ -6666,6 +6989,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; @@ -6680,10 +7004,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; @@ -6698,20 +7025,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]) { @@ -7424,7 +7766,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<>2; + for(n=526336;n<1048576;n++) // 0x80800000 .. 0xFFFFFFFF + memory_map[n]=-1; +#endif + for(n=0;n<4096;n++) ll_clear(jump_in+n); + for(n=0;n<4096;n++) ll_clear(jump_out+n); + for(n=0;n<4096;n++) ll_clear(jump_dirty+n); +} void new_dynarec_init() { printf("Init new dynarec\n"); out=(u_char *)BASE_ADDR; +#if BASE_ADDR_FIXED if (mmap (out, 1<>2; - for(n=526336;n<1048576;n++) // 0x80800000 .. 0xFFFFFFFF - memory_map[n]=-1; #ifdef MUPEN64 for(n=0;n<0x8000;n++) { // 0 .. 0x7FFFFFFF writemem[n] = write_nomem_new; @@ -7737,17 +8104,24 @@ void new_dynarec_init() #endif tlb_hacks(); arch_init(); +#ifndef RAM_FIXED + ram_offset=(u_int)rdram-0x80000000; +#endif + if (ram_offset!=0) + SysPrintf("warning: RAM is not directly mapped, performance will suffer\n"); } void new_dynarec_cleanup() { int n; - if (munmap ((void *)BASE_ADDR, 1<>26; switch(op) { @@ -7889,17 +8266,10 @@ int new_recompile_block(int addr) case 0x11: strcpy(insn[i],"MTHI"); type=MOV; break; case 0x12: strcpy(insn[i],"MFLO"); type=MOV; break; case 0x13: strcpy(insn[i],"MTLO"); type=MOV; break; - case 0x14: strcpy(insn[i],"DSLLV"); type=SHIFT; break; - case 0x16: strcpy(insn[i],"DSRLV"); type=SHIFT; break; - case 0x17: strcpy(insn[i],"DSRAV"); type=SHIFT; break; case 0x18: strcpy(insn[i],"MULT"); type=MULTDIV; break; case 0x19: strcpy(insn[i],"MULTU"); type=MULTDIV; break; case 0x1A: strcpy(insn[i],"DIV"); type=MULTDIV; break; case 0x1B: strcpy(insn[i],"DIVU"); type=MULTDIV; break; - case 0x1C: strcpy(insn[i],"DMULT"); type=MULTDIV; break; - case 0x1D: strcpy(insn[i],"DMULTU"); type=MULTDIV; break; - case 0x1E: strcpy(insn[i],"DDIV"); type=MULTDIV; break; - case 0x1F: strcpy(insn[i],"DDIVU"); type=MULTDIV; break; case 0x20: strcpy(insn[i],"ADD"); type=ALU; break; case 0x21: strcpy(insn[i],"ADDU"); type=ALU; break; case 0x22: strcpy(insn[i],"SUB"); type=ALU; break; @@ -7910,22 +8280,31 @@ int new_recompile_block(int addr) case 0x27: strcpy(insn[i],"NOR"); type=ALU; break; case 0x2A: strcpy(insn[i],"SLT"); type=ALU; break; case 0x2B: strcpy(insn[i],"SLTU"); type=ALU; break; - case 0x2C: strcpy(insn[i],"DADD"); type=ALU; break; - case 0x2D: strcpy(insn[i],"DADDU"); type=ALU; break; - case 0x2E: strcpy(insn[i],"DSUB"); type=ALU; break; - case 0x2F: strcpy(insn[i],"DSUBU"); type=ALU; break; case 0x30: strcpy(insn[i],"TGE"); type=NI; break; case 0x31: strcpy(insn[i],"TGEU"); type=NI; break; case 0x32: strcpy(insn[i],"TLT"); type=NI; break; case 0x33: strcpy(insn[i],"TLTU"); type=NI; break; case 0x34: strcpy(insn[i],"TEQ"); type=NI; break; case 0x36: strcpy(insn[i],"TNE"); type=NI; break; +#ifndef FORCE32 + case 0x14: strcpy(insn[i],"DSLLV"); type=SHIFT; break; + case 0x16: strcpy(insn[i],"DSRLV"); type=SHIFT; break; + case 0x17: strcpy(insn[i],"DSRAV"); type=SHIFT; break; + case 0x1C: strcpy(insn[i],"DMULT"); type=MULTDIV; break; + case 0x1D: strcpy(insn[i],"DMULTU"); type=MULTDIV; break; + case 0x1E: strcpy(insn[i],"DDIV"); type=MULTDIV; break; + case 0x1F: strcpy(insn[i],"DDIVU"); type=MULTDIV; break; + case 0x2C: strcpy(insn[i],"DADD"); type=ALU; break; + case 0x2D: strcpy(insn[i],"DADDU"); type=ALU; break; + case 0x2E: strcpy(insn[i],"DSUB"); type=ALU; break; + case 0x2F: strcpy(insn[i],"DSUBU"); type=ALU; break; case 0x38: strcpy(insn[i],"DSLL"); type=SHIFTIMM; break; case 0x3A: strcpy(insn[i],"DSRL"); type=SHIFTIMM; break; case 0x3B: strcpy(insn[i],"DSRA"); type=SHIFTIMM; break; case 0x3C: strcpy(insn[i],"DSLL32"); type=SHIFTIMM; break; case 0x3E: strcpy(insn[i],"DSRL32"); type=SHIFTIMM; break; case 0x3F: strcpy(insn[i],"DSRA32"); type=SHIFTIMM; break; +#endif } break; case 0x01: strcpy(insn[i],"regimm"); type=NI; @@ -8115,7 +8494,9 @@ int new_recompile_block(int addr) case 0x24: strcpy(insn[i],"LBU"); type=LOAD; break; case 0x25: strcpy(insn[i],"LHU"); type=LOAD; break; case 0x26: strcpy(insn[i],"LWR"); type=LOADLR; break; +#ifndef FORCE32 case 0x27: strcpy(insn[i],"LWU"); type=LOAD; break; +#endif case 0x28: strcpy(insn[i],"SB"); type=STORE; break; case 0x29: strcpy(insn[i],"SH"); type=STORE; break; case 0x2A: strcpy(insn[i],"SWL"); type=STORELR; break; @@ -8142,11 +8523,14 @@ int new_recompile_block(int addr) #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 (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; } } @@ -8163,21 +8547,9 @@ int new_recompile_block(int addr) case 0x3B: strcpy(insn[i],"HLECALL"); type=HLECALL; break; #endif default: strcpy(insn[i],"???"); type=NI; - printf("NI %08x @%08x (%08x)\n", source[i], addr + i*4, addr); + SysPrintf("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>21)&0x1f; @@ -8349,7 +8722,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; @@ -8359,6 +8731,23 @@ 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; @@ -8372,6 +8761,23 @@ 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_rs[i]=gte_reg_reads[source[i]&0x3f]; + gte_rt[i]=gte_reg_writes[source[i]&0x3f]; + gte_rt[i]|=1ll<<63; // every op changes flags + if((source[i]&0x3f)==GTE_MVMVA) { + int v = (source[i] >> 15) & 3; + gte_rs[i]&=~0xe3fll; + if(v==3) gte_rs[i]|=0xe00ll; + else gte_rs[i]|=3ll<<(v*2); + } break; case FLOAT: case FCONV: @@ -8410,6 +8816,41 @@ int new_recompile_block(int addr) else if(type==CJUMP||type==SJUMP||type==FJUMP) ba[i]=start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14); else ba[i]=-1; +#ifdef PCSX + if(i>0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP)) { + int do_in_intrp=0; + // branch in delay slot? + if(type==RJUMP||type==UJUMP||type==CJUMP||type==SJUMP||type==FJUMP) { + // don't handle first branch and call interpreter if it's hit + SysPrintf("branch in delay slot @%08x (%08x)\n", addr + i*4, addr); + do_in_intrp=1; + } + // basic load delay detection + else if((type==LOAD||type==LOADLR||type==COP0||type==COP2||type==C2LS)&&rt1[i]!=0) { + int t=(ba[i-1]-start)/4; + if(0 <= t && t < i &&(rt1[i]==rs1[t]||rt1[i]==rs2[t])&&itype[t]!=CJUMP&&itype[t]!=SJUMP) { + // jump target wants DS result - potential load delay effect + SysPrintf("load delay @%08x (%08x)\n", addr + i*4, addr); + do_in_intrp=1; + bt[t+1]=1; // expected return from interpreter + } + else if(i>=2&&rt1[i-2]==2&&rt1[i]==2&&rs1[i]!=2&&rs2[i]!=2&&rs1[i-1]!=2&&rs2[i-1]!=2&& + !(i>=3&&(itype[i-3]==RJUMP||itype[i-3]==UJUMP||itype[i-3]==CJUMP||itype[i-3]==SJUMP))) { + // v0 overwrite like this is a sign of trouble, bail out + SysPrintf("v0 overwrite @%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; + ba[i-1]=-1; + itype[i-1]=INTCALL; + done=2; + i--; // don't compile the DS + } + } +#endif /* 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]==0) { // Continue past subroutine call (JAL) @@ -8431,6 +8872,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; } @@ -8442,7 +8884,7 @@ int new_recompile_block(int addr) // Stop if we're compiling junk if(itype[i]==NI&&opcode[i]==0x11) { done=stop_after_jal=1; - printf("Disabled speculative precompilation\n"); + SysPrintf("Disabled speculative precompilation\n"); } } slen=i; @@ -8469,12 +8911,14 @@ int new_recompile_block(int addr) dirty_reg(¤t,CCREG); current.isconst=0; current.wasconst=0; + current.waswritten=0; int ds=0; int cc=0; - int hr; - + int hr=-1; + +#ifndef FORCE32 provisional_32bit(); - +#endif if((u_int)addr&1) { // First instruction is delay slot cc=-1; @@ -8496,6 +8940,7 @@ int new_recompile_block(int addr) if(current.regmap[hr]==0) current.regmap[hr]=-1; } current.isconst=0; + current.waswritten=0; } if(i>1) { @@ -8516,6 +8961,7 @@ int new_recompile_block(int addr) } } } +#ifndef FORCE32 // If something jumps here with 64-bit values // then promote those registers to 64 bits if(bt[i]) @@ -8534,7 +8980,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;hr0&&(itype[i-1]==STORE||itype[i-1]==STORELR||(itype[i-1]==C2LS&&opcode[i-1]==0x3a))&&(u_int)imm[i-1]<0x800) + current.waswritten|=1<=0x800) + current.waswritten&=~(1<0) { @@ -9138,7 +9596,7 @@ int new_recompile_block(int addr) branch_regs[i-1].is32|=1LL<<31; } memcpy(&branch_regs[i-1].regmap_entry,&branch_regs[i-1].regmap,sizeof(current.regmap)); - memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); + memcpy(constmap[i],constmap[i-1],sizeof(current_constmap)); break; case RJUMP: memcpy(&branch_regs[i-1],¤t,sizeof(current)); @@ -9163,7 +9621,7 @@ int new_recompile_block(int addr) } #endif memcpy(&branch_regs[i-1].regmap_entry,&branch_regs[i-1].regmap,sizeof(current.regmap)); - memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); + memcpy(constmap[i],constmap[i-1],sizeof(current_constmap)); break; case CJUMP: if((opcode[i-1]&0x3E)==4) // BEQ/BNE @@ -9199,7 +9657,7 @@ int new_recompile_block(int addr) branch_regs[i-1].isconst=0; branch_regs[i-1].wasconst=0; memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap)); - memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); + memcpy(constmap[i],constmap[i-1],sizeof(current_constmap)); } else if((opcode[i-1]&0x3E)==6) // BLEZ/BGTZ @@ -9232,7 +9690,7 @@ int new_recompile_block(int addr) branch_regs[i-1].isconst=0; branch_regs[i-1].wasconst=0; memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap)); - memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); + memcpy(constmap[i],constmap[i-1],sizeof(current_constmap)); } else // Alloc the delay slot in case the branch is taken @@ -9298,7 +9756,7 @@ int new_recompile_block(int addr) branch_regs[i-1].isconst=0; branch_regs[i-1].wasconst=0; memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap)); - memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); + memcpy(constmap[i],constmap[i-1],sizeof(current_constmap)); } else // Alloc the delay slot in case the branch is taken @@ -9412,6 +9870,21 @@ int new_recompile_block(int addr) { cc=0; } +#if defined(PCSX) && !defined(DRC_DBG) + else if(itype[i]==C2OP&>e_cycletab[source[i]&0x3f]>2) + { + // GTE runs in parallel until accessed, divide by 2 for a rough guess + cc+=gte_cycletab[source[i]&0x3f]/2; + } + else if(/*itype[i]==LOAD||itype[i]==STORE||*/itype[i]==C1LS) // load,store causes weird timing issues + { + cc+=2; // 2 cycle penalty (after CLOCK_DIVIDER) + } + else if(itype[i]==C2LS) + { + cc+=4; + } +#endif else { cc++; @@ -9422,7 +9895,7 @@ int new_recompile_block(int addr) regs[i].is32=current.is32; regs[i].dirty=current.dirty; regs[i].isconst=current.isconst; - memcpy(constmap[i],current.constmap,sizeof(current.constmap)); + memcpy(constmap[i],current_constmap,sizeof(current_constmap)); } for(hr=0;hr=0) { @@ -9432,6 +9905,7 @@ int new_recompile_block(int addr) } } if(current.regmap[HOST_BTREG]==BTREG) current.regmap[HOST_BTREG]=-1; + regs[i].waswritten=current.waswritten; } /* Pass 4 - Cull unused host registers */ @@ -9474,8 +9948,8 @@ int new_recompile_block(int addr) } } // Don't need stuff which is overwritten - if(regs[i].regmap[hr]!=regmap_pre[i][hr]) nr&=~(1<>(regs[i].regmap[hr]&63))&1)) { - printf("fail: %x (%d %d!=%d)\n",start+i*4,hr,regmap_pre[i+1][hr],regs[i].regmap[hr]); + SysPrintf("fail: %x (%d %d!=%d)\n",start+i*4,hr,regmap_pre[i+1][hr],regs[i].regmap[hr]); assert(regmap_pre[i+1][hr]==regs[i].regmap[hr]); } regmap_pre[i+1][hr]=-1; if(regs[i+1].regmap_entry[hr]==CCREG) regs[i+1].regmap_entry[hr]=-1; + regs[i+1].wasconst&=~(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 - 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) { @@ -9763,22 +10242,26 @@ int new_recompile_block(int addr) 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 - ||itype[i+1]==COP2||itype[i+1]==C2LS||itype[i+1]==C2OP) - { - // 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) + if(ooo[i]) { + if(count_free_regs(regs[i].regmap)<=minimum_free_regs[i+1]) + f_regmap[hr]=branch_regs[i].regmap[hr]; + }else{ + if(count_free_regs(branch_regs[i].regmap)<=minimum_free_regs[i+1]) f_regmap[hr]=branch_regs[i].regmap[hr]; } // Avoid dirty->clean 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[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++) { @@ -9790,6 +10273,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 - ||itype[k-1]==COP2||itype[k-1]==C2LS||itype[k-1]==C2OP) { - 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; @@ -9823,7 +10300,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) { @@ -9890,13 +10367,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; @@ -9940,7 +10448,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) { @@ -10102,6 +10775,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) { @@ -10118,6 +10792,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); @@ -10157,6 +10832,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) { @@ -10242,7 +10918,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; @@ -10356,13 +11032,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)) { @@ -10620,8 +11316,13 @@ int new_recompile_block(int addr) wb_valid(regmap_pre[i],regs[i].regmap_entry,dirty_pre,regs[i].wasdirty,is32_pre, unneeded_reg[i],unneeded_reg_upper[i]); } - is32_pre=regs[i].is32; - dirty_pre=regs[i].dirty; + if((itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP)&&!likely[i]) { + is32_pre=branch_regs[i].is32; + dirty_pre=branch_regs[i].dirty; + }else{ + is32_pre=regs[i].is32; + dirty_pre=regs[i].dirty; + } #endif // write back if(i<2||(itype[i-2]!=UJUMP&&itype[i-2]!=RJUMP&&(source[i-2]>>16)!=0x1000)) @@ -10642,9 +11343,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); @@ -10741,7 +11442,7 @@ int new_recompile_block(int addr) store_regs_bt(regs[i-1].regmap,regs[i-1].is32,regs[i-1].dirty,start+i*4); if(regs[i-1].regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i-1]+1),HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i-1]+1),HOST_CCREG); } else if(!likely[i-2]) { @@ -10764,7 +11465,7 @@ int new_recompile_block(int addr) store_regs_bt(regs[i-1].regmap,regs[i-1].is32,regs[i-1].dirty,start+i*4); if(regs[i-1].regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i-1]+1),HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i-1]+1),HOST_CCREG); add_to_linker((int)out,start+i*4,0); emit_jmp(0); } @@ -10843,7 +11544,11 @@ int new_recompile_block(int addr) u_int vpage=get_vpage(vaddr); literal_pool(256); //if(!(is32[i]&(~unneeded_reg_upper[i])&~(1LL<BASE_ADDR+(1<(u_int)BASE_ADDR+(1<>12;i<=(start+slen*4)>>12;i++) { @@ -10915,14 +11620,23 @@ int new_recompile_block(int addr) } #endif } + inv_code_start=inv_code_end=~0; +#ifdef PCSX + // 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)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 */ - int end=((((int)out-BASE_ADDR)>>(TARGET_SIZE_2-16))+16384)&65535; + int end=((((int)out-(int)BASE_ADDR)>>(TARGET_SIZE_2-16))+16384)&65535; while(expirep!=end) { int shift=TARGET_SIZE_2-3; // Divide into 8 blocks - int base=BASE_ADDR+((expirep>>13)<>13)<>11)&3) { @@ -10958,6 +11672,10 @@ int new_recompile_block(int addr) break; case 3: // Clear jump_out + #ifdef __arm__ + if((expirep&2047)==0) + do_clear_cache(); + #endif ll_remove_matching_addrs(jump_out+(expirep&2047),base,shift); ll_remove_matching_addrs(jump_out+2048+(expirep&2047),base,shift); break;