X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=libpcsxcore%2Fnew_dynarec%2Fassem_arm.c;h=c0e41162cbf7cd1c159f84b83be78f1be19c06c9;hp=0c668d3688297ab9ed6815161b45400a52328e81;hb=b1be1eeee94d3547c20719acfa6b0082404897f1;hpb=44a80f6a19c52fc9680c852c62ad27081d44c674 diff --git a/libpcsxcore/new_dynarec/assem_arm.c b/libpcsxcore/new_dynarec/assem_arm.c index 0c668d36..c0e41162 100644 --- a/libpcsxcore/new_dynarec/assem_arm.c +++ b/libpcsxcore/new_dynarec/assem_arm.c @@ -1,6 +1,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Mupen64plus - assem_arm.c * + * Mupen64plus/PCSX - assem_arm.c * * Copyright (C) 2009-2011 Ari64 * + * Copyright (C) 2010-2011 Gražvydas "notaz" Ignotas * * * * 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 * @@ -170,6 +171,7 @@ void set_jump_target_fillslot(int addr,u_int target,int copy) /* Literal pool */ add_literal(int addr,int val) { + assert(literalcount>6)+8; // get target of bl if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) { unsigned int page=source>>12; @@ -249,6 +256,7 @@ int verify_dirty(int addr) } source = source+(map_value<<2); } +#endif //printf("verify_dirty: %x %x %x\n",source,copy,len); return !memcmp((void *)source,(void *)copy,len); } @@ -275,7 +283,7 @@ void get_bounds(int addr,u_int *start,u_int *end) u_int *ptr=(u_int *)addr; #ifdef ARMv5_ONLY // get from literal pool - assert((*ptr&0xFFF00000)==0xe5900000); + assert((*ptr&0xFFFF0000)==0xe59f0000); u_int offset=*ptr&0xfff; u_int *l_ptr=(void *)ptr+offset+8; u_int source=l_ptr[0]; @@ -292,11 +300,13 @@ void get_bounds(int addr,u_int *start,u_int *end) #endif if((*ptr&0xFF000000)!=0xeb000000) ptr++; assert((*ptr&0xFF000000)==0xeb000000); // bl instruction +#ifndef DISABLE_TLB u_int verifier=(int)ptr+((signed int)(*ptr<<8)>>6)+8; // get target of bl if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) { if(memory_map[source>>12]>=0x80000000) source = 0; else source = source+(memory_map[source>>12]<<2); } +#endif *start=source; *end=source+len; } @@ -1128,7 +1138,6 @@ void emit_addimm(u_int rs,int imm,u_int rt) assert(rs<16); assert(rt<16); if(imm!=0) { - assert(imm>-65536&&imm<65536); u_int armval; if(genimm(imm,&armval)) { assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm); @@ -1137,11 +1146,13 @@ void emit_addimm(u_int rs,int imm,u_int rt) assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval); }else if(imm<0) { + assert(imm>-65536); assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],(-imm)&0xFF00); assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF); output_w32(0xe2400000|rd_rn_imm_shift(rt,rs,(-imm)>>8,8)); output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0)); }else{ + assert(imm<65536); assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF); output_w32(0xe2800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); @@ -1319,6 +1330,14 @@ void emit_shlimm(int rs,u_int imm,int rt) output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7)); } +void emit_lsls_imm(int rs,int imm,int rt) +{ + assert(imm>0); + assert(imm<32); + assem_debug("lsls %s,%s,#%d\n",regname[rt],regname[rs],imm); + output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|(imm<<7)); +} + void emit_shrimm(int rs,u_int imm,int rt) { assert(imm>0); @@ -1378,6 +1397,17 @@ void emit_signextend16(int rs,int rt) #endif } +void emit_signextend8(int rs,int rt) +{ + #ifdef ARMv5_ONLY + emit_shlimm(rs,24,rt); + emit_sarimm(rt,24,rt); + #else + assem_debug("sxtb %s,%s\n",regname[rt],regname[rs]); + output_w32(0xe6af0070|rd_rn_rm(rt,0,rs)); + #endif +} + void emit_shl(u_int rs,u_int shift,u_int rt) { assert(rs<16); @@ -1751,8 +1781,9 @@ void emit_popreg(u_int r) } void emit_callreg(u_int r) { - assem_debug("call *%%%s\n",regname[r]); - assert(0); + assert(r<15); + assem_debug("blx %s\n",regname[r]); + output_w32(0xe12fff30|r); } void emit_jmpreg(u_int r) { @@ -1775,6 +1806,31 @@ void emit_readword_dualindexedx4(int rs1, int rs2, int rt) assem_debug("ldr %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe7900000|rd_rn_rm(rt,rs1,rs2)|0x100); } +void emit_ldrcc_dualindexed(int rs1, int rs2, int rt) +{ + assem_debug("ldrcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x37900000|rd_rn_rm(rt,rs1,rs2)); +} +void emit_ldrccb_dualindexed(int rs1, int rs2, int rt) +{ + assem_debug("ldrccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x37d00000|rd_rn_rm(rt,rs1,rs2)); +} +void emit_ldrccsb_dualindexed(int rs1, int rs2, int rt) +{ + assem_debug("ldrccsb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x319000d0|rd_rn_rm(rt,rs1,rs2)); +} +void emit_ldrcch_dualindexed(int rs1, int rs2, int rt) +{ + assem_debug("ldrcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x319000b0|rd_rn_rm(rt,rs1,rs2)); +} +void emit_ldrccsh_dualindexed(int rs1, int rs2, int rt) +{ + assem_debug("ldrccsh %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x319000f0|rd_rn_rm(rt,rs1,rs2)); +} void emit_readword_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_readword_indexed(addr, rs, rt); @@ -1990,6 +2046,21 @@ void emit_writebyte_indexed_tlb(int rt, int addr, int rs, int map, int temp) } } } +void emit_strcc_dualindexed(int rs1, int rs2, int rt) +{ + assem_debug("strcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x37800000|rd_rn_rm(rt,rs1,rs2)); +} +void emit_strccb_dualindexed(int rs1, int rs2, int rt) +{ + assem_debug("strccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x37c00000|rd_rn_rm(rt,rs1,rs2)); +} +void emit_strcch_dualindexed(int rs1, int rs2, int rt) +{ + assem_debug("strcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); + output_w32(0x318000b0|rd_rn_rm(rt,rs1,rs2)); +} void emit_writeword(int rt, int addr) { u_int offset = addr-(u_int)&dynarec_local; @@ -2087,6 +2158,14 @@ void emit_shrcc_imm(int rs,u_int imm,int rt) output_w32(0x31a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); } +void emit_shrne_imm(int rs,u_int imm,int rt) +{ + assert(imm>0); + assert(imm<32); + assem_debug("lsrne %s,%s,#%d\n",regname[rt],regname[rs],imm); + output_w32(0x11a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); +} + void emit_negmi(int rs, int rt) { assem_debug("rsbmi %s,%s,#0\n",regname[rt],regname[rs]); @@ -2610,7 +2689,50 @@ emit_extjump_ds(int addr, int target) emit_extjump2(addr, target, (int)dyna_linker_ds); } +// put rt_val into rt, potentially making use of rs with value rs_val +static void emit_movimm_from(u_int rs_val,int rs,u_int rt_val,int rt) +{ + u_int xor=rs_val^rt_val; + u_int xs; + for(xs=xor;xs!=0&&(xs&3)==0;xs>>=2) + ; + if(xs<0x100) + emit_xorimm(rs,xor,rt); + else + emit_movimm(rt_val,rt); +} + +// trashes r2 +static void pass_args(int a0, int a1) +{ + if(a0==1&&a1==0) { + // must swap + emit_mov(a0,2); emit_mov(a1,1); emit_mov(2,0); + } + else if(a0!=0&&a1==0) { + emit_mov(a1,1); + if (a0>=0) emit_mov(a0,0); + } + else { + if(a0>=0&&a0!=0) emit_mov(a0,0); + if(a1>=0&&a1!=1) emit_mov(a1,1); + } +} + +static void mov_loadtype_adj(int type,int rs,int rt) +{ + switch(type) { + case LOADB_STUB: emit_signextend8(rs,rt); break; + case LOADBU_STUB: emit_andimm(rs,0xff,rt); break; + case LOADH_STUB: emit_signextend16(rs,rt); break; + case LOADHU_STUB: emit_andimm(rs,0xffff,rt); break; + case LOADW_STUB: if(rs!=rt) emit_mov(rs,rt); break; + default: assert(0); + } +} + #ifdef PCSX +#include "pcsxmem.h" #include "pcsxmem_inline.c" #endif @@ -2636,6 +2758,67 @@ do_readstub(int n) rt=get_reg(i_regmap,rt1[i]); } assert(rs>=0); +#ifdef PCSX + int r,temp=-1,temp2=HOST_TEMPREG,regs_saved=0,restore_jump=0; + reglist|=(1<=0) + reglist&=~(1<=0&&rt1[i]!=0)) { + switch(type) { + case LOADB_STUB: emit_ldrccsb_dualindexed(temp2,rs,rt); break; + case LOADBU_STUB: emit_ldrccb_dualindexed(temp2,rs,rt); break; + case LOADH_STUB: emit_ldrccsh_dualindexed(temp2,rs,rt); break; + case LOADHU_STUB: emit_ldrcch_dualindexed(temp2,rs,rt); break; + case LOADW_STUB: emit_ldrcc_dualindexed(temp2,rs,rt); break; + } + } + if(regs_saved) { + restore_jump=(int)out; + emit_jcc(0); // jump to reg restore + } + else + emit_jcc(stubs[n][2]); // return address + + if(!regs_saved) + save_regs(reglist); + int handler=0; + if(type==LOADB_STUB||type==LOADBU_STUB) + handler=(int)jump_handler_read8; + if(type==LOADH_STUB||type==LOADHU_STUB) + handler=(int)jump_handler_read16; + if(type==LOADW_STUB) + handler=(int)jump_handler_read32; + assert(handler!=0); + pass_args(rs,temp2); + int cc=get_reg(i_regmap,CCREG); + if(cc<0) + emit_loadreg(CCREG,2); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n][6]+1),2); + emit_call(handler); + if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) { + mov_loadtype_adj(type,0,rt); + } + if(restore_jump) + set_jump_target(restore_jump,(int)out); + restore_regs(reglist); + emit_jmp(stubs[n][2]); // return address +#else // !PCSX if(addr<0) addr=rt; if(addr<0&&itype[i]!=C1LS&&itype[i]!=C2LS&&itype[i]!=LOADLR) addr=get_reg(i_regmap,-1); assert(addr>=0); @@ -2714,8 +2897,38 @@ do_readstub(int n) } } emit_jmp(stubs[n][2]); // return address +#endif // !PCSX } +#ifdef PCSX +// return memhandler, or get directly accessable address and return 0 +u_int get_direct_memhandler(void *table,u_int addr,int type,u_int *addr_host) +{ + u_int l1,l2=0; + l1=((u_int *)table)[addr>>12]; + if((l1&(1<<31))==0) { + u_int v=l1<<1; + *addr_host=v+addr; + return 0; + } + else { + l1<<=1; + if(type==LOADB_STUB||type==LOADBU_STUB||type==STOREB_STUB) + l2=((u_int *)l1)[0x1000/4 + 0x1000/2 + (addr&0xfff)]; + else if(type==LOADH_STUB||type==LOADHU_STUB||type==STOREH_STUB) + l2=((u_int *)l1)[0x1000/4 + (addr&0xfff)/2]; + else + l2=((u_int *)l1)[(addr&0xfff)/4]; + if((l2&(1<<31))==0) { + u_int v=l2<<1; + *addr_host=v+(addr&0xfff); + return 0; + } + return l2<<1; + } +} +#endif + inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist) { int rs=get_reg(regmap,target); @@ -2723,6 +2936,81 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i int rt=get_reg(regmap,target); if(rs<0) rs=get_reg(regmap,-1); assert(rs>=0); +#ifdef PCSX + u_int handler,host_addr=0,is_dynamic,far_call=0; + int cc=get_reg(regmap,CCREG); + if(pcsx_direct_read(type,addr,CLOCK_ADJUST(adj+1),cc,target?rs:-1,rt)) + return; + handler=get_direct_memhandler(mem_rtab,addr,type,&host_addr); + if (handler==0) { + if(rt<0) + return; + if(addr!=host_addr) + emit_movimm_from(addr,rs,host_addr,rs); + switch(type) { + case LOADB_STUB: emit_movsbl_indexed(0,rs,rt); break; + case LOADBU_STUB: emit_movzbl_indexed(0,rs,rt); break; + case LOADH_STUB: emit_movswl_indexed(0,rs,rt); break; + case LOADHU_STUB: emit_movzwl_indexed(0,rs,rt); break; + case LOADW_STUB: emit_readword_indexed(0,rs,rt); break; + default: assert(0); + } + return; + } + is_dynamic=pcsxmem_is_handler_dynamic(addr); + if(is_dynamic) { + if(type==LOADB_STUB||type==LOADBU_STUB) + handler=(int)jump_handler_read8; + if(type==LOADH_STUB||type==LOADHU_STUB) + handler=(int)jump_handler_read16; + if(type==LOADW_STUB) + handler=(int)jump_handler_read32; + } + + // call a memhandler + if(rt>=0) + reglist&=~(1<=33554432) { + // unreachable memhandler, a plugin func perhaps + emit_movimm(handler,12); + far_call=1; + } + if(cc<0) + emit_loadreg(CCREG,2); + if(is_dynamic) { + emit_movimm(((u_int *)mem_rtab)[addr>>12]<<1,1); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2); + } + else { + emit_readword((int)&last_count,3); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2); + emit_add(2,3,2); + emit_writeword(2,(int)&Count); + } + + if(far_call) + emit_callreg(12); + else + emit_call(handler); + + if(rt>=0) { + switch(type) { + case LOADB_STUB: emit_signextend8(0,rt); break; + case LOADBU_STUB: emit_andimm(0,0xff,rt); break; + case LOADH_STUB: emit_signextend16(0,rt); break; + case LOADHU_STUB: emit_andimm(0,0xffff,rt); break; + case LOADW_STUB: if(rt!=0) emit_mov(0,rt); break; + default: assert(0); + } + } + restore_regs(reglist); +#else // if !PCSX int ftable=0; if(type==LOADB_STUB||type==LOADBU_STUB) ftable=(int)readmemb; @@ -2735,10 +3023,6 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i ftable=(int)readmemd; #endif assert(ftable!=0); -#ifdef PCSX - if(pcsx_direct_read(type,addr,target?rs:-1,rt)) - return; -#endif if(target==0) emit_movimm(addr,rs); emit_writeword(rs,(int)&address); @@ -2764,7 +3048,7 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i //emit_movimm(ftable,0); emit_movimm(((u_int *)ftable)[addr>>16],0); //emit_readword((int)&last_count,12); - emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2); #ifndef PCSX if((signed int)addr>=(signed int)0xC0000000) { // Pagefault address @@ -2781,7 +3065,7 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i // but not doing so causes random crashes... emit_readword((int)&Count,HOST_TEMPREG); emit_readword((int)&next_interupt,2); - emit_addimm(HOST_TEMPREG,-CLOCK_DIVIDER*(adj+1),HOST_TEMPREG); + emit_addimm(HOST_TEMPREG,-CLOCK_ADJUST(adj+1),HOST_TEMPREG); emit_writeword(2,(int)&last_count); emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc); if(cc<0) { @@ -2806,6 +3090,7 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth); } } +#endif // !PCSX } do_writestub(int n) @@ -2831,6 +3116,68 @@ do_writestub(int n) } assert(rs>=0); assert(rt>=0); +#ifdef PCSX + int rtmp,temp=-1,temp2=HOST_TEMPREG,regs_saved=0,restore_jump=0,ra; + int reglist2=reglist|(1<=0); int ftable=0; @@ -2902,6 +3249,7 @@ do_writestub(int n) // emit_loadreg(CCREG,cc); //} emit_jmp(stubs[n][2]); // return address +#endif // !PCSX } inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist) @@ -2912,9 +3260,35 @@ inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, assert(rs>=0); assert(rt>=0); #ifdef PCSX - if(pcsx_direct_write(type,addr,rs,rt,regmap)) + u_int handler,host_addr=0; + handler=get_direct_memhandler(mem_wtab,addr,type,&host_addr); + if (handler==0) { + if(addr!=host_addr) + emit_movimm_from(addr,rs,host_addr,rs); + switch(type) { + case STOREB_STUB: emit_writebyte_indexed(rt,0,rs); break; + case STOREH_STUB: emit_writehword_indexed(rt,0,rs); break; + case STOREW_STUB: emit_writeword_indexed(rt,0,rs); break; + default: assert(0); + } return; -#endif + } + + // call a memhandler + save_regs(reglist); + pass_args(rs,rt); + int cc=get_reg(regmap,CCREG); + if(cc<0) + emit_loadreg(CCREG,2); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2); + emit_movimm(handler,3); + // returns new cycle_count + emit_call((int)jump_handler_write_h); + emit_addimm(0,-CLOCK_ADJUST(adj+1),cc<0?2:cc); + if(cc<0) + emit_storereg(CCREG,2); + restore_regs(reglist); +#else // if !pcsx int ftable=0; if(type==STOREB_STUB) ftable=(int)writememb; @@ -2967,7 +3341,7 @@ inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, //emit_movimm(ftable,0); emit_movimm(((u_int *)ftable)[addr>>16],0); //emit_readword((int)&last_count,12); - emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2); #ifndef PCSX if((signed int)addr>=(signed int)0xC0000000) { // Pagefault address @@ -2981,7 +3355,7 @@ inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, emit_call((int)&indirect_jump); emit_readword((int)&Count,HOST_TEMPREG); emit_readword((int)&next_interupt,2); - emit_addimm(HOST_TEMPREG,-CLOCK_DIVIDER*(adj+1),HOST_TEMPREG); + emit_addimm(HOST_TEMPREG,-CLOCK_ADJUST(adj+1),HOST_TEMPREG); emit_writeword(2,(int)&last_count); emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc); if(cc<0) { @@ -2989,6 +3363,7 @@ inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, } //emit_popa(); restore_regs(reglist); +#endif } do_unalignedwritestub(int n) @@ -3012,6 +3387,21 @@ do_unalignedwritestub(int n) reglist|=(1<regmap_entry,i_regs->was32,i_regs->wasdirty); if(regs[i].regmap_entry[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); emit_movimm(start+(i-ds)*4,EAX); // Get PC - emit_addimm(HOST_CCREG,CLOCK_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(ds?(int)fp_exception_ds:(int)fp_exception); } +#ifndef DISABLE_TLB + /* TLB */ int do_tlb_r(int s,int ar,int map,int x,int a,int shift,int c,u_int addr) @@ -3243,6 +3636,17 @@ generate_map_const(u_int addr,int reg) { emit_movimm((addr>>12)+(((u_int)memory_map-(u_int)&dynarec_local)>>2),reg); } +#else + +static int do_tlb_r() { return 0; } +static int do_tlb_r_branch() { return 0; } +static int gen_tlb_addr_r() { return 0; } +static int do_tlb_w() { return 0; } +static int do_tlb_w_branch() { return 0; } +static int gen_tlb_addr_w() { return 0; } + +#endif // DISABLE_TLB + /* Special assem */ void shift_assemble_arm(int i,struct regstat *i_regs) @@ -3354,6 +3758,182 @@ void shift_assemble_arm(int i,struct regstat *i_regs) } } } + +#ifdef PCSX +static void speculate_mov(int rs,int rt) +{ + if(rt!=0) { + smrv_strong_next|=1<>rs1[i])&1) speculate_mov(rs1[i],rt1[i]); + else if((smrv_strong>>rs2[i])&1) speculate_mov(rs2[i],rt1[i]); + else if((smrv_weak>>rs1[i])&1) speculate_mov_weak(rs1[i],rt1[i]); + else if((smrv_weak>>rs2[i])&1) speculate_mov_weak(rs2[i],rt1[i]); + else { + smrv_strong_next&=~(1<=0) { + if(get_final_value(hr,i,&value)) + smrv[rt1[i]]=value; + else smrv[rt1[i]]=constmap[i][hr]; + smrv_strong_next|=1<>rs1[i])&1) speculate_mov(rs1[i],rt1[i]); + else if((smrv_weak>>rs1[i])&1) speculate_mov_weak(rs1[i],rt1[i]); + } + break; + case LOAD: + if(start<0x2000&&(rt1[i]==26||(smrv[rt1[i]]>>24)==0xa0)) { + // special case for BIOS + smrv[rt1[i]]=0xa0000000; + smrv_strong_next|=1<>r)&1),(smrv_weak>>r)&1,regs[i].isconst,regs[i].wasconst); +#endif +} + +enum { + MTYPE_8000 = 0, + MTYPE_8020, + MTYPE_0000, + MTYPE_A000, + MTYPE_1F80, +}; + +static int get_ptr_mem_type(u_int a) +{ + if(a < 0x00200000) { + if(a<0x1000&&((start>>20)==0xbfc||(start>>24)==0xa0)) + // return wrong, must use memhandler for BIOS self-test to pass + // 007 does similar stuff from a00 mirror, weird stuff + return MTYPE_8000; + return MTYPE_0000; + } + if(0x1f800000 <= a && a < 0x1f801000) + return MTYPE_1F80; + if(0x80200000 <= a && a < 0x80800000) + return MTYPE_8020; + if(0xa0000000 <= a && a < 0xa0200000) + return MTYPE_A000; + return MTYPE_8000; +} +#endif + +static int emit_fastpath_cmp_jump(int i,int addr,int *addr_reg_override) +{ + int jaddr,type=0; + +#ifdef PCSX + int mr=rs1[i]; + if(((smrv_strong|smrv_weak)>>mr)&1) { + type=get_ptr_mem_type(smrv[mr]); + //printf("set %08x @%08x r%d %d\n", smrv[mr], start+i*4, mr, type); + } + else { + // use the mirror we are running on + type=get_ptr_mem_type(start); + //printf("set nospec @%08x r%d %d\n", start+i*4, mr, type); + } + + if(type==MTYPE_8020) { // RAM 80200000+ mirror + emit_andimm(addr,~0x00e00000,HOST_TEMPREG); + addr=*addr_reg_override=HOST_TEMPREG; + type=0; + } + else if(type==MTYPE_0000) { // RAM 0 mirror + emit_orimm(addr,0x80000000,HOST_TEMPREG); + addr=*addr_reg_override=HOST_TEMPREG; + type=0; + } + else if(type==MTYPE_A000) { // RAM A mirror + emit_andimm(addr,~0x20000000,HOST_TEMPREG); + addr=*addr_reg_override=HOST_TEMPREG; + type=0; + } + else if(type==MTYPE_1F80) { // scratchpad + emit_addimm(addr,-0x1f800000,HOST_TEMPREG); + emit_cmpimm(HOST_TEMPREG,0x1000); + jaddr=(int)out; + emit_jc(0); + } +#endif + + if(type==0) + { + emit_cmpimm(addr,RAM_SIZE); + jaddr=(int)out; + #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK + // Hint to branch predictor that the branch is unlikely to be taken + if(rs1[i]>=28) + emit_jno_unlikely(0); + else + #endif + emit_jno(0); + } + + return jaddr; +} + #define shift_assemble shift_assemble_arm void loadlr_assemble_arm(int i,struct regstat *i_regs) @@ -3362,6 +3942,7 @@ void loadlr_assemble_arm(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]); @@ -3396,9 +3977,7 @@ void loadlr_assemble_arm(int i,struct regstat *i_regs) }else{ emit_andimm(addr,0xFFFFFFF8,temp2); // LDL/LDR } - emit_cmpimm(addr,RAM_SIZE); - jaddr=(int)out; - emit_jno(0); + jaddr=emit_fastpath_cmp_jump(i,temp2,&fastload_reg_override); } else { if (opcode[i]==0x22||opcode[i]==0x26) { @@ -3431,8 +4010,10 @@ void loadlr_assemble_arm(int i,struct regstat *i_regs) } if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR if(!c||memtarget) { + int a=temp2; + if(fastload_reg_override) a=fastload_reg_override; //emit_readword_indexed((int)rdram-0x80000000,temp2,temp2); - emit_readword_indexed_tlb(0,temp2,map,temp2); + emit_readword_indexed_tlb(0,a,map,temp2); if(jaddr) add_stub(LOADW_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist); } else @@ -3459,7 +4040,7 @@ void loadlr_assemble_arm(int i,struct regstat *i_regs) //emit_storereg(rt1[i],tl); // DEBUG } if (opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR - // FIXME: little endian + // FIXME: little endian, fastload_reg_override int temp2h=get_reg(i_regs->regmap,FTEMP|64); if(!c||memtarget) { //if(th>=0) emit_readword_indexed((int)rdram-0x80000000,temp2,temp2h); @@ -3521,7 +4102,7 @@ void cop0_assemble(int i,struct regstat *i_regs) emit_readword((int)&last_count,ECX); emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc emit_add(HOST_CCREG,ECX,HOST_CCREG); - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); emit_writeword(HOST_CCREG,(int)&Count); } emit_call((int)MFC0); @@ -3536,19 +4117,21 @@ void cop0_assemble(int i,struct regstat *i_regs) signed char s=get_reg(i_regs->regmap,rs1[i]); char copr=(source[i]>>11)&0x1f; assert(s>=0); +#ifdef MUPEN64 emit_writeword(s,(int)&readmem_dword); wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32); -#ifdef MUPEN64 emit_addimm(FP,(int)&fake_pc-(int)&dynarec_local,0); emit_movimm((source[i]>>11)&0x1f,1); emit_writeword(0,(int)&PC); emit_writebyte(1,(int)&(fake_pc.f.r.nrd)); +#else + wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32); #endif if(copr==9||copr==11||copr==12||copr==13) { - emit_readword((int)&last_count,ECX); + emit_readword((int)&last_count,HOST_TEMPREG); emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc - emit_add(HOST_CCREG,ECX,HOST_CCREG); - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_add(HOST_CCREG,HOST_TEMPREG,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); emit_writeword(HOST_CCREG,(int)&Count); } // What a mess. The status register (12) can enable interrupts, @@ -3564,19 +4147,23 @@ void cop0_assemble(int i,struct regstat *i_regs) emit_writeword(HOST_CCREG,(int)&last_count); emit_movimm(0,HOST_CCREG); emit_storereg(CCREG,HOST_CCREG); + if(s!=1) + emit_mov(s,1); emit_movimm(copr,0); emit_call((int)pcsx_mtc0_ds); return; } #endif - emit_movimm(start+i*4+4,0); - emit_movimm(0,1); - emit_writeword(0,(int)&pcaddr); - emit_writeword(1,(int)&pending_exception); + emit_movimm(start+i*4+4,HOST_TEMPREG); + emit_writeword(HOST_TEMPREG,(int)&pcaddr); + emit_movimm(0,HOST_TEMPREG); + emit_writeword(HOST_TEMPREG,(int)&pending_exception); } //else if(copr==12&&is_delayslot) emit_call((int)MTC0_R12); //else #ifdef PCSX + if(s!=1) + emit_mov(s,1); emit_movimm(copr,0); emit_call((int)pcsx_mtc0); #else @@ -3585,7 +4172,7 @@ void cop0_assemble(int i,struct regstat *i_regs) if(copr==9||copr==11||copr==12||copr==13) { emit_readword((int)&Count,HOST_CCREG); emit_readword((int)&next_interupt,ECX); - emit_addimm(HOST_CCREG,-CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_addimm(HOST_CCREG,-CLOCK_ADJUST(ccadj[i]),HOST_CCREG); emit_sub(HOST_CCREG,ECX,HOST_CCREG); emit_writeword(ECX,(int)&last_count); emit_storereg(CCREG,HOST_CCREG); @@ -3617,7 +4204,7 @@ void cop0_assemble(int i,struct regstat *i_regs) emit_readword((int)&last_count,ECX); if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); emit_add(HOST_CCREG,ECX,HOST_CCREG); - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); emit_writeword(HOST_CCREG,(int)&Count); emit_call((int)TLBWR_new); } @@ -3638,7 +4225,7 @@ void cop0_assemble(int i,struct regstat *i_regs) { int count=ccadj[i]; if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*count,HOST_CCREG); // TODO: Should there be an extra cycle here? + emit_addimm(HOST_CCREG,CLOCK_ADJUST(count),HOST_CCREG); // TODO: Should there be an extra cycle here? emit_jmp((int)jump_eret); } #endif @@ -3791,6 +4378,7 @@ void c2op_assemble(int i,struct regstat *i_regs) signed char temp=get_reg(i_regs->regmap,-1); u_int c2op=source[i]&0x3f; u_int hr,reglist=0; + int need_flags; for(hr=0;hrregmap[hr]>=0) reglist|=1<>63); // +1 because of how liveness detection works + assem_debug("gte unneeded %016llx, need_flags %d\n",gte_unneeded[i+1],need_flags); +#ifdef ARMv5_ONLY + // let's take more risk here + need_flags=need_flags&>e_reads_flags; +#endif + emit_call((int)(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op])); } if(i>=slen-1||itype[i+1]!=C2OP) @@ -4539,6 +5133,7 @@ void multdiv_assemble_arm(int i,struct regstat *i_regs) } } else // 64-bit +#ifndef FORCE32 { if(opcode2[i]==0x1C) // DMULT { @@ -4712,6 +5307,9 @@ void multdiv_assemble_arm(int i,struct regstat *i_regs) if(lol>=0) emit_loadreg(LOREG,lol); } } +#else + assert(0); +#endif } else {