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);
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));
}
}
}
+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;
#include "pcsxmem_inline.c"
#endif
+// 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);
+ }
+}
+
do_readstub(int n)
{
assem_debug("do_readstub %x\n",start+stubs[n][3]*4);
if(type==LOADW_STUB)
handler=(int)jump_handler_read32;
assert(handler!=0);
- if(rs!=0)
- emit_mov(rs,0);
- if(temp2!=1)
- emit_mov(temp2,1);
+ pass_args(rs,temp2);
int cc=get_reg(i_regmap,CCREG);
if(cc<0)
emit_loadreg(CCREG,2);
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==STOREW_STUB)
+ 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];
}
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<<rs)|(1<<rt);
+ for(rtmp=0;rtmp<=12;rtmp++) {
+ if(((1<<rtmp)&0x13ff)&&((1<<rtmp)®list2)==0) {
+ temp=rtmp; break;
+ }
+ }
+ if(temp==-1) {
+ save_regs(reglist);
+ regs_saved=1;
+ for(rtmp=0;rtmp<=3;rtmp++)
+ if(rtmp!=rs&&rtmp!=rt)
+ {temp=rtmp;break;}
+ }
+ if((regs_saved||(reglist2&8)==0)&&temp!=3&&rs!=3&&rt!=3)
+ temp2=3;
+ emit_readword((int)&mem_wtab,temp);
+ emit_shrimm(rs,12,temp2);
+ emit_readword_dualindexedx4(temp,temp2,temp2);
+ emit_lsls_imm(temp2,1,temp2);
+ switch(type) {
+ case STOREB_STUB: emit_strccb_dualindexed(temp2,rs,rt); break;
+ case STOREH_STUB: emit_strcch_dualindexed(temp2,rs,rt); break;
+ case STOREW_STUB: emit_strcc_dualindexed(temp2,rs,rt); break;
+ default: assert(0);
+ }
+ if(regs_saved) {
+ restore_jump=(int)out;
+ emit_jcc(0); // jump to reg restore
+ }
+ else
+ emit_jcc(stubs[n][2]); // return address (invcode check)
+
+ if(!regs_saved)
+ save_regs(reglist);
+ int handler=0;
+ switch(type) {
+ case STOREB_STUB: handler=(int)jump_handler_write8; break;
+ case STOREH_STUB: handler=(int)jump_handler_write16; break;
+ case STOREW_STUB: handler=(int)jump_handler_write32; break;
+ }
+ assert(handler!=0);
+ pass_args(rs,rt);
+ if(temp2!=3)
+ emit_mov(temp2,3);
+ 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);
+ // returns new cycle_count
+ emit_call(handler);
+ emit_addimm(0,-CLOCK_DIVIDER*stubs[n][6]-2,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);
assert(addr>=0);
int ftable=0;
// 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)
assert(rs>=0);
assert(rt>=0);
#ifdef PCSX
+ u_int handler,host_addr=0;
if(pcsx_direct_write(type,addr,rs,rt,regmap))
return;
-#endif
+ handler=get_direct_memhandler(mem_wtab,addr,type,&host_addr);
+ if (handler==0) {
+ if(target==0||addr!=host_addr)
+ emit_movimm(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;
+ }
+
+ // call a memhandler
+ save_regs(reglist);
+ pass_args(target!=0?rs:-1,rt);
+ if(target==0)
+ emit_movimm(addr,0);
+ 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_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);
+ if(cc<0)
+ emit_storereg(CCREG,2);
+ restore_regs(reglist);
+#else // if !pcsx
int ftable=0;
if(type==STOREB_STUB)
ftable=(int)writememb;
}
//emit_popa();
restore_regs(reglist);
+#endif
}
do_unalignedwritestub(int n)
reglist|=(1<<addr);
reglist&=~(1<<temp2);
+#if 1
+ // don't bother with it and call write handler
+ save_regs(reglist);
+ pass_args(addr,rt);
+ 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_call((int)(opcode[i]==0x2a?jump_handle_swl:jump_handle_swr));
+ emit_addimm(0,-CLOCK_DIVIDER*stubs[n][6]-2,cc<0?2:cc);
+ if(cc<0)
+ emit_storereg(CCREG,2);
+ restore_regs(reglist);
+ emit_jmp(stubs[n][2]); // return address
+#else
emit_andimm(addr,0xfffffffc,temp2);
emit_writeword(temp2,(int)&address);
}
restore_regs(reglist);
emit_jmp(stubs[n][2]); // return address
+#endif
}
void printregs(int edi,int esi,int ebp,int esp,int b,int d,int c,int a)
}
}
}
+
+#ifdef PCSX
+static void speculate_mov(int rs,int rt)
+{
+ if(rt!=0) {
+ smrv_strong_next|=1<<rt;
+ smrv[rt]=smrv[rs];
+ }
+}
+
+static void speculate_mov_weak(int rs,int rt)
+{
+ if(rt!=0) {
+ smrv_weak_next|=1<<rt;
+ smrv[rt]=smrv[rs];
+ }
+}
+
+static void speculate_register_values(int i)
+{
+ if(i==0) {
+ memcpy(smrv,psxRegs.GPR.r,sizeof(smrv));
+ // gp,sp are likely to stay the same throughout the block
+ smrv_strong_next=(1<<28)|(1<<29)|(1<<30);
+ smrv_weak_next=~smrv_strong_next;
+ //printf(" llr %08x\n", smrv[4]);
+ }
+ smrv_strong=smrv_strong_next;
+ smrv_weak=smrv_weak_next;
+ switch(itype[i]) {
+ case ALU:
+ if ((smrv_strong>>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<<rt1[i]);
+ smrv_weak_next&=~(1<<rt1[i]);
+ }
+ break;
+ case SHIFTIMM:
+ smrv_strong_next&=~(1<<rt1[i]);
+ smrv_weak_next&=~(1<<rt1[i]);
+ // fallthrough
+ case IMM16:
+ if(rt1[i]&&is_const(®s[i],rt1[i])) {
+ int value,hr=get_reg(regs[i].regmap,rt1[i]);
+ if(hr>=0) {
+ if(get_final_value(hr,i,&value))
+ smrv[rt1[i]]=value;
+ else smrv[rt1[i]]=constmap[i][hr];
+ smrv_strong_next|=1<<rt1[i];
+ }
+ }
+ else {
+ if ((smrv_strong>>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<<rt1[i];
+ break;
+ }
+ // fallthrough
+ case SHIFT:
+ case LOADLR:
+ case MOV:
+ smrv_strong_next&=~(1<<rt1[i]);
+ smrv_weak_next&=~(1<<rt1[i]);
+ break;
+ case COP0:
+ case COP2:
+ if(opcode2[i]==0||opcode2[i]==2) { // MFC/CFC
+ smrv_strong_next&=~(1<<rt1[i]);
+ smrv_weak_next&=~(1<<rt1[i]);
+ }
+ break;
+ case C2LS:
+ if (opcode[i]==0x32) { // LWC2
+ smrv_strong_next&=~(1<<rt1[i]);
+ smrv_weak_next&=~(1<<rt1[i]);
+ }
+ break;
+ }
+#if 0
+ int r=4;
+ printf("x %08x %08x %d %d c %08x %08x\n",smrv[r],start+i*4,
+ ((smrv_strong>>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)
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]);
}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) {
}
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
//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);
}
}
else // 64-bit
+#ifndef FORCE32
{
if(opcode2[i]==0x1C) // DMULT
{
if(lol>=0) emit_loadreg(LOREG,lol);
}
}
+#else
+ assert(0);
+#endif
}
else
{