* 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
+#include "arm_features.h"
+
+#if !BASE_ADDR_FIXED
+char translation_cache[1 << TARGET_SIZE_2] __attribute__((aligned(4096)));
+#endif
+
+#ifndef __MACH__
+#define CALLER_SAVE_REGS 0x100f
+#else
+#define CALLER_SAVE_REGS 0x120f
+#endif
+
extern int cycle_count;
extern int last_count;
extern int pcaddr;
u_int get_clean_addr(int addr)
{
int *ptr=(int *)addr;
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
ptr+=4;
#else
ptr+=6;
int verify_dirty(int addr)
{
u_int *ptr=(u_int *)addr;
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
// get from literal pool
assert((*ptr&0xFFFF0000)==0xe59f0000);
u_int offset=*ptr&0xfff;
#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;
}
source = source+(map_value<<2);
}
+#endif
//printf("verify_dirty: %x %x %x\n",source,copy,len);
return !memcmp((void *)source,(void *)copy,len);
}
// guarantees that it's not dirty
int isclean(int addr)
{
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
int *ptr=((u_int *)addr)+4;
#else
int *ptr=((u_int *)addr)+6;
return 1;
}
+// get source that block at addr was compiled from (host pointers)
void get_bounds(int addr,u_int *start,u_int *end)
{
u_int *ptr=(u_int *)addr;
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
// get from literal pool
assert((*ptr&0xFFFF0000)==0xe59f0000);
u_int offset=*ptr&0xfff;
#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;
}
}
}
}
- printf("This shouldn't happen (alloc_reg)");exit(1);
+ SysPrintf("This shouldn't happen (alloc_reg)");exit(1);
}
void alloc_reg64(struct regstat *cur,int i,signed char reg)
}
}
}
- printf("This shouldn't happen");exit(1);
+ SysPrintf("This shouldn't happen");exit(1);
}
// Allocate a temporary register. This is done without regard to
}
}
}
- printf("This shouldn't happen");exit(1);
+ SysPrintf("This shouldn't happen");exit(1);
}
// Allocate a specific ARM register.
void alloc_arm_reg(struct regstat *cur,int i,signed char reg,char hr)
int offset=addr-(int)out-8;
if(offset<-33554432||offset>=33554432) {
if (addr>2) {
- printf("genjmp: out of range: %08x\n", offset);
+ SysPrintf("genjmp: out of range: %08x\n", offset);
exit(1);
}
return 0;
assem_debug("mvn %s,#%d\n",regname[rt],imm);
output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
}else if(imm<65536) {
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
assem_debug("mov %s,#%d\n",regname[rt],imm&0xFF00);
output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8));
assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
emit_movw(imm,rt);
#endif
}else{
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
emit_loadlp(imm,rt);
#else
emit_movw(imm&0x0000FFFF,rt);
{
#ifdef FORCE32
if(r&64) {
- printf("64bit load in 32bit mode!\n");
+ SysPrintf("64bit load in 32bit mode!\n");
assert(0);
return;
}
{
#ifdef FORCE32
if(r&64) {
- printf("64bit store in 32bit mode!\n");
+ SysPrintf("64bit store in 32bit mode!\n");
assert(0);
return;
}
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("bic %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|armval);
}else if(imm==65535) {
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
assem_debug("bic %s,%s,#FF000000\n",regname[rt],regname[rs]);
output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|0x4FF);
assem_debug("bic %s,%s,#00FF0000\n",regname[rt],regname[rt]);
#endif
}else{
assert(imm>0&&imm<65535);
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
assem_debug("mov r14,#%d\n",imm&0xFF00);
output_w32(0xe3a00000|rd_rn_imm_shift(HOST_TEMPREG,0,imm>>8,8));
assem_debug("add r14,r14,#%d\n",imm&0xFF);
output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
}
+void emit_lslpls_imm(int rs,int imm,int rt)
+{
+ assert(imm>0);
+ assert(imm<32);
+ assem_debug("lslpls %s,%s,#%d\n",regname[rt],regname[rs],imm);
+ output_w32(0x51b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
+}
+
void emit_shrimm(int rs,u_int imm,int rt)
{
assert(imm>0);
void emit_signextend16(int rs,int rt)
{
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
emit_shlimm(rs,16,rt);
emit_sarimm(rt,16,rt);
#else
void emit_signextend8(int rs,int rt)
{
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
emit_shlimm(rs,24,rt);
emit_sarimm(rt,24,rt);
#else
output_w32(0xe3700000|rd_rn_rm(0,rs,0)|armval);
}else if(imm>0) {
assert(imm<65536);
- #ifdef ARMv5_ONLY
emit_movimm(imm,HOST_TEMPREG);
- #else
- emit_movw(imm,HOST_TEMPREG);
- #endif
assem_debug("cmp %s,r14\n",regname[rs]);
output_w32(0xe1500000|rd_rn_rm(0,rs,HOST_TEMPREG));
}else{
assert(imm>-65536);
- #ifdef ARMv5_ONLY
emit_movimm(-imm,HOST_TEMPREG);
- #else
- emit_movw(-imm,HOST_TEMPREG);
- #endif
assem_debug("cmn %s,r14\n",regname[rs]);
output_w32(0xe1700000|rd_rn_rm(0,rs,HOST_TEMPREG));
}
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;
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]);
output_w32(0x12400000|rd_rn_rm(rt,rt,0)|armval);
}
else {
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
emit_movimm(imm1,rt);
add_literal((int)out,imm2);
assem_debug("ldrne %s,pc+? [=%x]\n",regname[rt],imm2);
output_w32(0x12000000|rd_rn_rm(rt,rs,0)|armval);
}
+void emit_addpl_imm(int rs,int imm,int rt)
+{
+ u_int armval;
+ genimm_checked(imm,&armval);
+ assem_debug("addpl %s,%s,#%d\n",regname[rt],regname[rs],imm);
+ output_w32(0x52800000|rd_rn_rm(rt,rs,0)|armval);
+}
+
void emit_jno_unlikely(int a)
{
//emit_jno(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<<i))
+ assem_debug("r%d,",i);
assem_debug("}\n");
output_w32(0xe88b0000|reglist);
}
-// Restore registers after function call
-void restore_regs(u_int reglist)
+static void restore_regs_all(u_int reglist)
{
- reglist&=0x100f; // only restore the caller-save registers, r0-r3, r12
+ int i;
if(!reglist) return;
assem_debug("ldmia 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<<i))
+ assem_debug("r%d,",i);
assem_debug("}\n");
output_w32(0xe89b0000|reglist);
}
+// Save registers before function call
+static void save_regs(u_int reglist)
+{
+ reglist&=CALLER_SAVE_REGS; // only save the caller-save registers, r0-r3, r12
+ save_regs_all(reglist);
+}
+// Restore registers after function call
+static void restore_regs(u_int reglist)
+{
+ reglist&=CALLER_SAVE_REGS;
+ restore_regs_all(reglist);
+}
// Write back consts using r14 so we don't disturb the other registers
void wb_consts(signed char i_regmap[],uint64_t i_is32,u_int i_dirty,int i)
int i;
for(i=0;i<literalcount;i++)
{
+ u_int l_addr=(u_int)out;
+ int j;
+ for(j=0;j<i;j++) {
+ if(literals[j][1]==literals[i][1]) {
+ //printf("dup %08x\n",literals[i][1]);
+ l_addr=literals[j][0];
+ break;
+ }
+ }
ptr=(u_int *)literals[i][0];
- u_int offset=(u_int)out-(u_int)ptr-8;
+ u_int offset=l_addr-(u_int)ptr-8;
assert(offset<4096);
assert(!(offset&3));
*ptr|=offset;
- output_w32(literals[i][1]);
+ if(l_addr==(u_int)out) {
+ literals[i][0]=l_addr; // remember for dupes
+ output_w32(literals[i][1]);
+ }
}
literalcount=0;
}
set_jump_target(jaddr,(int)out);
}
-emit_extjump2(int addr, int target, int linker)
+emit_extjump2(u_int addr, int target, int linker)
{
u_char *ptr=(u_char *)addr;
assert((ptr[3]&0x0e)==0xa);
emit_extjump2(addr, target, (int)dyna_linker_ds);
}
-#ifdef PCSX
-#include "pcsxmem_inline.c"
-#endif
+// 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 armval;
+ int diff;
+ if(genimm(rt_val,&armval)) {
+ assem_debug("mov %s,#%d\n",regname[rt],rt_val);
+ output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
+ return;
+ }
+ if(genimm(~rt_val,&armval)) {
+ assem_debug("mvn %s,#%d\n",regname[rt],rt_val);
+ output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
+ return;
+ }
+ diff=rt_val-rs_val;
+ if(genimm(diff,&armval)) {
+ assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],diff);
+ output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
+ return;
+ }else if(genimm(-diff,&armval)) {
+ assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],-diff);
+ output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval);
+ return;
+ }
+ emit_movimm(rt_val,rt);
+}
+
+// return 1 if above function can do it's job cheaply
+static int is_similar_value(u_int v1,u_int v2)
+{
+ u_int xs;
+ int diff;
+ if(v1==v2) return 1;
+ diff=v2-v1;
+ for(xs=diff;xs!=0&&(xs&3)==0;xs>>=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)
}
}
+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
+
do_readstub(int n)
{
assem_debug("do_readstub %x\n",start+stubs[n][3]*4);
temp=r; break;
}
}
- if(rt>=0)
+ if(rt>=0&&rt1[i]!=0)
reglist&=~(1<<rt);
if(temp==-1) {
save_regs(reglist);
int cc=get_reg(i_regmap,CCREG);
if(cc<0)
emit_loadreg(CCREG,2);
- emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*stubs[n][6]+2,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)) {
- 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;
- }
+ mov_loadtype_adj(type,0,rt);
}
if(restore_jump)
set_jump_target(restore_jump,(int)out);
if(rs<0) rs=get_reg(regmap,-1);
assert(rs>=0);
#ifdef PCSX
- u_int handler,host_addr=0;
- if(pcsx_direct_read(type,addr,target?rs:-1,rt))
+ 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)
+ if(rt<0||rt1[i]==0)
return;
- if(target==0||addr!=host_addr)
- emit_movimm(host_addr,rs);
+ 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;
}
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)
+ if(rt>=0&&rt1[i]!=0)
reglist&=~(1<<rt);
save_regs(reglist);
if(target==0)
emit_movimm(addr,0);
else if(rs!=0)
emit_mov(rs,0);
- int cc=get_reg(regmap,CCREG);
- if(cc<0)
- emit_loadreg(CCREG,2);
- emit_readword((int)&last_count,3);
- emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2);
- emit_add(2,3,3);
- emit_writeword(3,(int)&Count);
-
int offset=(int)handler-(int)out-8;
if(offset<-33554432||offset>=33554432) {
// unreachable memhandler, a plugin func perhaps
- emit_movimm(handler,1);
- emit_callreg(1);
+ 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) {
+
+ if(rt>=0&&rt1[i]!=0) {
switch(type) {
case LOADB_STUB: emit_signextend8(0,rt); break;
case LOADBU_STUB: emit_andimm(0,0xff,rt); break;
//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
// 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) {
int cc=get_reg(i_regmap,CCREG);
if(cc<0)
emit_loadreg(CCREG,2);
- emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*stubs[n][6]+2,2);
+ emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n][6]+1),2);
// returns new cycle_count
emit_call(handler);
- emit_addimm(0,-CLOCK_DIVIDER*stubs[n][6]-2,cc<0?2:cc);
+ emit_addimm(0,-CLOCK_ADJUST((int)stubs[n][6]+1),cc<0?2:cc);
if(cc<0)
emit_storereg(CCREG,2);
if(restore_jump)
set_jump_target(restore_jump,(int)out);
restore_regs(reglist);
ra=stubs[n][2];
- if(!restore_jump) ra+=4*3; // skip invcode check
emit_jmp(ra);
#else // if !PCSX
if(addr<0) addr=get_reg(i_regmap,-1);
emit_writeword(rt,(int)&dword);
emit_writeword(r?rth:rt,(int)&dword+4);
#else
- printf("STORED_STUB\n");
+ SysPrintf("STORED_STUB\n");
#endif
}
//emit_pusha();
assert(rt>=0);
#ifdef PCSX
u_int handler,host_addr=0;
- if(pcsx_direct_write(type,addr,rs,rt,regmap))
- return;
handler=get_direct_memhandler(mem_wtab,addr,type,&host_addr);
if (handler==0) {
- if(target==0||addr!=host_addr)
- emit_movimm(host_addr,rs);
+ 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;
// call a memhandler
save_regs(reglist);
- pass_args(target!=0?rs:-1,rt);
- if(target==0)
- emit_movimm(addr,0);
+ pass_args(rs,rt);
int cc=get_reg(regmap,CCREG);
if(cc<0)
emit_loadreg(CCREG,2);
- emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),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_DIVIDER*(adj+1),cc<0?2:cc);
+ emit_addimm(0,-CLOCK_ADJUST(adj+1),cc<0?2:cc);
if(cc<0)
emit_storereg(CCREG,2);
restore_regs(reglist);
emit_writeword(rt,(int)&dword);
emit_writeword(target?rth:rt,(int)&dword+4);
#else
- printf("STORED_STUB\n");
+ SysPrintf("STORED_STUB\n");
#endif
}
//emit_pusha();
//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
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) {
int cc=get_reg(i_regmap,CCREG);
if(cc<0)
emit_loadreg(CCREG,2);
- emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*stubs[n][6]+2,2);
+ emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n][6]+1),2);
emit_call((int)(opcode[i]==0x2a?jump_handle_swl:jump_handle_swr));
- emit_addimm(0,-CLOCK_DIVIDER*stubs[n][6]-2,cc<0?2:cc);
+ emit_addimm(0,-CLOCK_ADJUST((int)stubs[n][6]+1),cc<0?2:cc);
if(cc<0)
emit_storereg(CCREG,2);
restore_regs(reglist);
addr=(u_int)source;
#endif
// Careful about the code output here, verify_dirty needs to parse it.
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
emit_loadlp(addr,1);
emit_loadlp((int)copy,2);
emit_loadlp(slen*4,3);
void do_dirty_stub_ds()
{
// Careful about the code output here, verify_dirty needs to parse it.
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
emit_loadlp((int)start<(int)0xC0000000?(int)source:(int)start,1);
emit_loadlp((int)copy,2);
emit_loadlp(slen*4,3);
wb_dirtys(i_regs->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)
emit_movimm((addr>>12)+(((u_int)memory_map-(u_int)&dynarec_local)>>2),reg);
}
+#else
+
+static int do_tlb_r(int a, ...) { return 0; }
+static int do_tlb_r_branch(int a, ...) { return 0; }
+static int gen_tlb_addr_r(int a, ...) { return 0; }
+static int do_tlb_w(int a, ...) { return 0; }
+static int do_tlb_w_branch(int a, ...) { return 0; }
+static int gen_tlb_addr_w(int a, ...) { return 0; }
+
+#endif // DISABLE_TLB
+
/* Special assem */
void shift_assemble_arm(int i,struct regstat *i_regs)
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);
+ if (psxH == (void *)0x1f800000) {
+ emit_addimm(addr,-0x1f800000,HOST_TEMPREG);
+ emit_cmpimm(HOST_TEMPREG,0x1000);
+ jaddr=(int)out;
+ emit_jc(0);
+ }
+ else {
+ // do usual RAM check, jump will go to the right handler
+ type=0;
+ }
}
#endif
else
#endif
emit_jno(0);
+ if(ram_offset!=0) {
+ emit_addimm(addr,ram_offset,HOST_TEMPREG);
+ addr=*addr_reg_override=HOST_TEMPREG;
+ }
}
return jaddr;
jaddr=emit_fastpath_cmp_jump(i,temp2,&fastload_reg_override);
}
else {
+ if(ram_offset&&memtarget) {
+ emit_addimm(temp2,ram_offset,HOST_TEMPREG);
+ fastload_reg_override=HOST_TEMPREG;
+ }
if (opcode[i]==0x22||opcode[i]==0x26) {
emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
}else{
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);
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,
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
#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
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);
}
{
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
case 30:
emit_movs(sl,temp);
emit_mvnmi(temp,temp);
+#ifdef HAVE_ARMV5
emit_clz(temp,temp);
+#else
+ emit_movs(temp,HOST_TEMPREG);
+ emit_movimm(0,temp);
+ emit_jeq((int)out+4*4);
+ emit_addpl_imm(temp,1,temp);
+ emit_lslpls_imm(HOST_TEMPREG,1,HOST_TEMPREG);
+ emit_jns((int)out-2*4);
+#endif
emit_writeword(sl,(int)®_cop2d[30]);
emit_writeword(temp,(int)®_cop2d[31]);
break;
}
}
-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;hr<HOST_REGS;hr++) {
- if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
+ if(i_regs->regmap[hr]>=0) reglist_full|=1<<hr;
}
- if(i==0||itype[i-1]!=C2OP)
- save_regs(reglist);
+ reglist=reglist_full&CALLER_SAVE_REGS;
if (gte_handlers[c2op]!=NULL) {
- int cc=get_reg(i_regs->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: {
+#ifdef HAVE_ARMV5
+ int v = (source[i] >> 15) & 3;
+ int cv = (source[i] >> 13) & 3;
+ int mx = (source[i] >> 17) & 3;
+ reglist=reglist_full&(CALLER_SAVE_REGS|0xf0); // +{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]));
+#else /* if not HAVE_ARMV5 */
+ c2op_prologue(c2op,reglist);
+ emit_movimm(source[i],1); // opcode
+ emit_writeword(1,(int)&psxRegs.code);
+ emit_call((int)(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]));
+#endif
+ 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)
emit_negmi(remainder,remainder); // .. remainder for div0 case (will be negated back after jump)
emit_movs(d2,HOST_TEMPREG);
emit_jeq((int)out+52); // Division by zero
- emit_negmi(HOST_TEMPREG,HOST_TEMPREG);
+ emit_negsmi(HOST_TEMPREG,HOST_TEMPREG);
+#ifdef HAVE_ARMV5
emit_clz(HOST_TEMPREG,quotient);
emit_shl(HOST_TEMPREG,quotient,HOST_TEMPREG);
+#else
+ emit_movimm(0,quotient);
+ emit_addpl_imm(quotient,1,quotient);
+ emit_lslpls_imm(HOST_TEMPREG,1,HOST_TEMPREG);
+ emit_jns((int)out-2*4);
+#endif
emit_orimm(quotient,1<<31,quotient);
emit_shr(quotient,quotient,quotient);
emit_cmp(remainder,HOST_TEMPREG);
emit_movimm(0xffffffff,quotient); // div0 case
emit_test(d2,d2);
emit_jeq((int)out+40); // Division by zero
+#ifdef HAVE_ARMV5
emit_clz(d2,HOST_TEMPREG);
emit_movimm(1<<31,quotient);
emit_shl(d2,HOST_TEMPREG,d2);
+#else
+ emit_movimm(0,HOST_TEMPREG);
+ emit_addpl_imm(HOST_TEMPREG,1,HOST_TEMPREG);
+ emit_lslpls_imm(d2,1,d2);
+ emit_jns((int)out-2*4);
+ emit_movimm(1<<31,quotient);
+#endif
emit_shr(quotient,HOST_TEMPREG,quotient);
emit_cmp(remainder,d2);
emit_subcs(remainder,d2,remainder);
assert(m2h>=0);
assert(m1l>=0);
assert(m2l>=0);
- save_regs(0x100f);
+ save_regs(CALLER_SAVE_REGS);
if(m1l!=0) emit_mov(m1l,0);
if(m1h==0) emit_readword((int)&dynarec_local,1);
else if(m1h>1) emit_mov(m1h,1);
if(m2h<3) emit_readword((int)&dynarec_local+m2h*4,3);
else if(m2h>3) emit_mov(m2h,3);
emit_call((int)&multu64);
- restore_regs(0x100f);
+ restore_regs(CALLER_SAVE_REGS);
signed char hih=get_reg(i_regs->regmap,HIREG|64);
signed char hil=get_reg(i_regs->regmap,HIREG);
signed char loh=get_reg(i_regs->regmap,LOREG|64);
assert(d2h>=0);
assert(d1l>=0);
assert(d2l>=0);
- save_regs(0x100f);
+ save_regs(CALLER_SAVE_REGS);
if(d1l!=0) emit_mov(d1l,0);
if(d1h==0) emit_readword((int)&dynarec_local,1);
else if(d1h>1) emit_mov(d1h,1);
if(d2h<3) emit_readword((int)&dynarec_local+d2h*4,3);
else if(d2h>3) emit_mov(d2h,3);
emit_call((int)&div64);
- restore_regs(0x100f);
+ restore_regs(CALLER_SAVE_REGS);
signed char hih=get_reg(i_regs->regmap,HIREG|64);
signed char hil=get_reg(i_regs->regmap,HIREG);
signed char loh=get_reg(i_regs->regmap,LOREG|64);
assert(d2h>=0);
assert(d1l>=0);
assert(d2l>=0);
- save_regs(0x100f);
+ save_regs(CALLER_SAVE_REGS);
if(d1l!=0) emit_mov(d1l,0);
if(d1h==0) emit_readword((int)&dynarec_local,1);
else if(d1h>1) emit_mov(d1h,1);
if(d2h<3) emit_readword((int)&dynarec_local+d2h*4,3);
else if(d2h>3) emit_mov(d2h,3);
emit_call((int)&divu64);
- restore_regs(0x100f);
+ restore_regs(CALLER_SAVE_REGS);
signed char hih=get_reg(i_regs->regmap,HIREG|64);
signed char hil=get_reg(i_regs->regmap,HIREG);
signed char loh=get_reg(i_regs->regmap,LOREG|64);
}
void do_miniht_insert(u_int return_address,int rt,int temp) {
- #ifdef ARMv5_ONLY
+ #ifndef HAVE_ARMV7
emit_movimm(return_address,rt); // PC into link register
add_to_linker((int)out,return_address,1);
emit_pcreladdr(temp);
for(j=0;j<32;j++)
{
if(bitmap&(1<<j)) {
- start=BASE_ADDR+i*131072+j*4096;
+ start=(u_int)BASE_ADDR+i*131072+j*4096;
end=start+4095;
j++;
while(j<32) {