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=ebf733b09113d5b6bf2ca5722abba05112eddf86;hp=adbde599f3c6c33b56452cef0413f1095a1a28c6;hb=cbbd8dd7705d5cb7c748a7ffaf2ccc74893b3910;hpb=bedfea3863c3c48699048ea0d6dd07893221403c diff --git a/libpcsxcore/new_dynarec/assem_arm.c b/libpcsxcore/new_dynarec/assem_arm.c index adbde599..ebf733b0 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 * @@ -18,6 +19,16 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#ifdef PCSX +#include "../gte.h" +#define FLAGLESS +#include "../gte.h" +#undef FLAGLESS +#include "../gte_arm.h" +#include "../gte_neon.h" +#include "pcnt.h" +#endif + extern int cycle_count; extern int last_count; extern int pcaddr; @@ -244,6 +255,7 @@ int verify_dirty(int addr) #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) { unsigned int page=source>>12; @@ -254,6 +266,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); } @@ -297,11 +310,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; } @@ -1133,20 +1148,21 @@ 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); output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval); }else if(genimm(-imm,&armval)) { - assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],imm); + 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)); @@ -1324,6 +1340,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); @@ -1383,6 +1407,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); @@ -1756,8 +1791,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) { @@ -1780,6 +1816,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); @@ -1873,6 +1934,16 @@ void emit_movzwl_indexed(int offset, int rs, int rt) output_w32(0xe15000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); } } +static void emit_ldrd(int offset, int rs, int rt) +{ + assert(offset>-256&&offset<256); + assem_debug("ldrd %s,%s+%d\n",regname[rt],regname[rs],offset); + if(offset>=0) { + output_w32(0xe1c000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); + }else{ + output_w32(0xe14000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); + } +} void emit_readword(int addr, int rt) { u_int offset = addr-(u_int)&dynarec_local; @@ -1995,6 +2066,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; @@ -2092,6 +2178,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]); @@ -2494,34 +2588,40 @@ void emit_jno_unlikely(int a) output_w32(0x72800000|rd_rn_rm(15,15,0)); } -// Save registers before function call -void save_regs(u_int reglist) +static void save_regs_all(u_int reglist) { - reglist&=0x100f; // only save the caller-save registers, r0-r3, r12 + int i; if(!reglist) return; assem_debug("stmia fp,{"); - if(reglist&1) assem_debug("r0, "); - if(reglist&2) assem_debug("r1, "); - if(reglist&4) assem_debug("r2, "); - if(reglist&8) assem_debug("r3, "); - if(reglist&0x1000) assem_debug("r12"); + for(i=0;i<16;i++) + if(reglist&(1<>=2) + ; + if(xs<0x100) return 1; + for(xs=-diff;xs!=0&&(xs&3)==0;xs>>=2) + ; + if(xs<0x100) return 1; + return 0; +} + +// 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 @@ -2641,6 +2827,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); @@ -2719,8 +2966,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); @@ -2728,6 +3005,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; @@ -2740,10 +3092,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); @@ -2769,7 +3117,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 @@ -2786,7 +3134,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) { @@ -2811,6 +3159,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) @@ -2836,6 +3185,67 @@ 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; @@ -2907,6 +3317,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) @@ -2917,9 +3328,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; @@ -2972,7 +3409,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 @@ -2986,7 +3423,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) { @@ -2994,6 +3431,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) @@ -3017,6 +3455,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) @@ -3248,6 +3704,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) @@ -3359,6 +3826,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) @@ -3367,6 +4010,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]); @@ -3401,9 +4045,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) { @@ -3436,8 +4078,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 @@ -3464,7 +4108,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); @@ -3526,7 +4170,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); @@ -3541,19 +4185,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, @@ -3569,19 +4215,25 @@ 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); + emit_loadreg(rs1[i],1); emit_movimm(copr,0); emit_call((int)pcsx_mtc0_ds); + emit_loadreg(rs1[i],s); 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==HOST_CCREG) + emit_loadreg(rs1[i],1); + else if(s!=1) + emit_mov(s,1); emit_movimm(copr,0); emit_call((int)pcsx_mtc0); #else @@ -3589,23 +4241,21 @@ void cop0_assemble(int i,struct regstat *i_regs) #endif if(copr==9||copr==11||copr==12||copr==13) { emit_readword((int)&Count,HOST_CCREG); - emit_readword((int)&next_interupt,ECX); - emit_addimm(HOST_CCREG,-CLOCK_DIVIDER*ccadj[i],HOST_CCREG); - emit_sub(HOST_CCREG,ECX,HOST_CCREG); - emit_writeword(ECX,(int)&last_count); + emit_readword((int)&next_interupt,HOST_TEMPREG); + emit_addimm(HOST_CCREG,-CLOCK_ADJUST(ccadj[i]),HOST_CCREG); + emit_sub(HOST_CCREG,HOST_TEMPREG,HOST_CCREG); + emit_writeword(HOST_TEMPREG,(int)&last_count); emit_storereg(CCREG,HOST_CCREG); } if(copr==12||copr==13) { assert(!is_delayslot); emit_readword((int)&pending_exception,14); + emit_test(14,14); + emit_jne((int)&do_interrupt); } emit_loadreg(rs1[i],s); if(get_reg(i_regs->regmap,rs1[i]|64)>=0) emit_loadreg(rs1[i]|64,get_reg(i_regs->regmap,rs1[i]|64)); - if(copr==12||copr==13) { - emit_test(14,14); - emit_jne((int)&do_interrupt); - } cop1_usable=0; } else @@ -3622,7 +4272,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); } @@ -3643,7 +4293,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,36 +4441,155 @@ void cop2_assemble(int i,struct regstat *i_regs) } } -void c2op_assemble(int i,struct regstat *i_regs) +static void c2op_prologue(u_int op,u_int reglist) +{ + save_regs_all(reglist); +#ifdef PCNT + emit_movimm(op,0); + emit_call((int)pcnt_gte_start); +#endif + emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs +} + +static void c2op_epilogue(u_int op,u_int reglist) +{ +#ifdef PCNT + emit_movimm(op,0); + emit_call((int)pcnt_gte_end); +#endif + restore_regs_all(reglist); +} + +static void c2op_call_MACtoIR(int lm,int need_flags) +{ + if(need_flags) + emit_call((int)(lm?gteMACtoIR_lm1:gteMACtoIR_lm0)); + else + emit_call((int)(lm?gteMACtoIR_lm1_nf:gteMACtoIR_lm0_nf)); +} + +static void c2op_call_rgb_func(void *func,int lm,int need_ir,int need_flags) +{ + emit_call((int)func); + // func is C code and trashes r0 + emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); + if(need_flags||need_ir) + c2op_call_MACtoIR(lm,need_flags); + emit_call((int)(need_flags?gteMACtoRGB:gteMACtoRGB_nf)); +} + +static 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; + u_int hr,reglist_full=0,reglist; + int need_flags,need_ir; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[hr]>=0) reglist_full|=1<regmap,CCREG); - emit_movimm(source[i],1); // opcode - if (cc>=0&>e_cycletab[c2op]) - emit_addimm(cc,gte_cycletab[c2op]/2,cc); // XXX: could just adjust ccadj? - emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs - emit_writeword(1,(int)&psxRegs.code); need_flags=!(gte_unneeded[i+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; + need_ir=(gte_unneeded[i+1]&0xe00)!=0xe00; + assem_debug("gte op %08x, unneeded %016llx, need_flags %d, need_ir %d\n", + source[i],gte_unneeded[i+1],need_flags,need_ir); + if(new_dynarec_hacks&NDHACK_GTE_NO_FLAGS) + need_flags=0; + int shift = (source[i] >> 19) & 1; + int lm = (source[i] >> 10) & 1; + switch(c2op) { +#ifndef DRC_DBG + case GTE_MVMVA: { + int v = (source[i] >> 15) & 3; + int cv = (source[i] >> 13) & 3; + int mx = (source[i] >> 17) & 3; + reglist=reglist_full&0x10ff; // +{r4-r7} + c2op_prologue(c2op,reglist); + /* r4,r5 = VXYZ(v) packed; r6 = &MX11(mx); r7 = &CV1(cv) */ + if(v<3) + emit_ldrd(v*8,0,4); + else { + emit_movzwl_indexed(9*4,0,4); // gteIR + emit_movzwl_indexed(10*4,0,6); + emit_movzwl_indexed(11*4,0,5); + emit_orrshl_imm(6,16,4); + } + if(mx<3) + emit_addimm(0,32*4+mx*8*4,6); + else + emit_readword((int)&zeromem_ptr,6); + if(cv<3) + emit_addimm(0,32*4+(cv*8+5)*4,7); + else + emit_readword((int)&zeromem_ptr,7); +#ifdef __ARM_NEON__ + emit_movimm(source[i],1); // opcode + emit_call((int)gteMVMVA_part_neon); + if(need_flags) { + emit_movimm(lm,1); + emit_call((int)gteMACtoIR_flags_neon); + } +#else + if(cv==3&&shift) + emit_call((int)gteMVMVA_part_cv3sh12_arm); + else { + emit_movimm(shift,1); + emit_call((int)(need_flags?gteMVMVA_part_arm:gteMVMVA_part_nf_arm)); + } + if(need_flags||need_ir) + c2op_call_MACtoIR(lm,need_flags); #endif - emit_call((int)(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op])); + break; + } + case GTE_OP: + c2op_prologue(c2op,reglist); + emit_call((int)(shift?gteOP_part_shift:gteOP_part_noshift)); + if(need_flags||need_ir) { + emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); + c2op_call_MACtoIR(lm,need_flags); + } + break; + case GTE_DPCS: + c2op_prologue(c2op,reglist); + c2op_call_rgb_func(shift?gteDPCS_part_shift:gteDPCS_part_noshift,lm,need_ir,need_flags); + break; + case GTE_INTPL: + c2op_prologue(c2op,reglist); + c2op_call_rgb_func(shift?gteINTPL_part_shift:gteINTPL_part_noshift,lm,need_ir,need_flags); + break; + case GTE_SQR: + c2op_prologue(c2op,reglist); + emit_call((int)(shift?gteSQR_part_shift:gteSQR_part_noshift)); + if(need_flags||need_ir) { + emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); + c2op_call_MACtoIR(lm,need_flags); + } + break; + case GTE_DCPL: + c2op_prologue(c2op,reglist); + c2op_call_rgb_func(gteDCPL_part,lm,need_ir,need_flags); + break; + case GTE_GPF: + c2op_prologue(c2op,reglist); + c2op_call_rgb_func(shift?gteGPF_part_shift:gteGPF_part_noshift,lm,need_ir,need_flags); + break; + case GTE_GPL: + c2op_prologue(c2op,reglist); + c2op_call_rgb_func(shift?gteGPL_part_shift:gteGPL_part_noshift,lm,need_ir,need_flags); + break; +#endif + default: + c2op_prologue(c2op,reglist); +#ifdef DRC_DBG + emit_movimm(source[i],1); // opcode + emit_writeword(1,(int)&psxRegs.code); +#endif + emit_call((int)(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op])); + break; + } + c2op_epilogue(c2op,reglist); } - - if(i>=slen-1||itype[i+1]!=C2OP) - restore_regs(reglist); } void cop1_unusable(int i,struct regstat *i_regs) @@ -4551,6 +5320,7 @@ void multdiv_assemble_arm(int i,struct regstat *i_regs) } } else // 64-bit +#ifndef FORCE32 { if(opcode2[i]==0x1C) // DMULT { @@ -4724,6 +5494,9 @@ void multdiv_assemble_arm(int i,struct regstat *i_regs) if(lol>=0) emit_loadreg(LOREG,lol); } } +#else + assert(0); +#endif } else {