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));
}
}
}
+
+#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);
static uint64_t gte_rt[MAXBLOCK];
static uint64_t gte_unneeded[MAXBLOCK];
static int gte_reads_flags; // gte flag read encountered
+ static u_int smrv[32]; // speculated MIPS register values
+ static u_int smrv_strong; // mask or regs that are likely to have correct values
+ static u_int smrv_weak; // same, but somewhat less likely
+ static u_int smrv_strong_next; // same, but after current insn executes
+ static u_int smrv_weak_next;
int imm[MAXBLOCK];
u_int ba[MAXBLOCK];
char likely[MAXBLOCK];
#else
static const u_int using_tlb=0;
#endif
- static u_int sp_in_mirror;
int new_dynarec_did_compile;
u_int stop_after_jal;
extern u_char restore_candidate[512];
if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE)
#endif
{
- #ifdef PCSX
- if(sp_in_mirror&&rs1[i]==29) {
- emit_andimm(addr,~0x00e00000,HOST_TEMPREG);
- emit_cmpimm(HOST_TEMPREG,RAM_SIZE);
- fastload_reg_override=HOST_TEMPREG;
- }
- else
- #endif
- emit_cmpimm(addr,RAM_SIZE);
- jaddr=(int)out;
- #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
- // Hint to branch predictor that the branch is unlikely to be taken
- if(rs1[i]>=28)
- emit_jno_unlikely(0);
- else
- #endif
- emit_jno(0);
+ jaddr=emit_fastpath_cmp_jump(i,addr,&fastload_reg_override);
}
}
}else{ // using tlb
else addr=s;
if(!using_tlb) {
if(!c) {
- #ifdef PCSX
- if(sp_in_mirror&&rs1[i]==29) {
- emit_andimm(addr,~0x00e00000,HOST_TEMPREG);
- emit_cmpimm(HOST_TEMPREG,RAM_SIZE);
- faststore_reg_override=HOST_TEMPREG;
- }
- else
- #endif
+ #ifndef PCSX
#ifdef R29_HACK
// Strmnnrmn's speed hack
if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE)
#endif
emit_jno(0);
}
+ #else
+ jaddr=emit_fastpath_cmp_jump(i,addr,&faststore_reg_override);
+ #endif
}
}else{ // using tlb
int x=0;
int memtarget=0,c=0;
int jaddr2=0,jaddr3,type;
int agr=AGEN1+(i&1);
+ int fastio_reg_override=0;
u_int hr,reglist=0;
u_int copr=(source[i]>>16)&0x1f;
s=get_reg(i_regs->regmap,rs1[i]);
}
else {
if(!c) {
- emit_cmpimm(offset||c||s<0?ar:s,RAM_SIZE);
- jaddr2=(int)out;
- emit_jno(0);
+ jaddr2=emit_fastpath_cmp_jump(i,ar,&fastio_reg_override);
}
if (opcode[i]==0x32) { // LWC2
#ifdef HOST_IMM_ADDR32
if(c) emit_readword_tlb(constmap[i][s]+offset,-1,tl);
else
#endif
- emit_readword_indexed(0,ar,tl);
+ int a=ar;
+ if(fastio_reg_override) a=fastio_reg_override;
+ emit_readword_indexed(0,a,tl);
}
if (opcode[i]==0x3a) { // SWC2
#ifdef DESTRUCTIVE_SHIFT
if(!offset&&!c&&s>=0) emit_mov(s,ar);
#endif
- emit_writeword_indexed(tl,0,ar);
+ int a=ar;
+ if(fastio_reg_override) a=fastio_reg_override;
+ emit_writeword_indexed(tl,0,a);
}
}
if(jaddr2)
void ds_assemble(int i,struct regstat *i_regs)
{
+ speculate_register_values(i);
is_delayslot=1;
switch(itype[i]) {
case ALU:
#ifndef DISABLE_TLB
using_tlb=0;
#endif
- sp_in_mirror=0;
for(n=0;n<524288;n++) // 0 .. 0x7FFFFFFF
memory_map[n]=-1;
for(n=524288;n<526336;n++) // 0x80000000 .. 0x807FFFFF
//assert(((u_int)addr&1)==0);
new_dynarec_did_compile=1;
#ifdef PCSX
- if(!sp_in_mirror&&(signed int)(psxRegs.GPR.n.sp&0xffe00000)>0x80200000&&
- 0x10000<=psxRegs.GPR.n.sp&&(psxRegs.GPR.n.sp&~0xe0e00000)<RAM_SIZE) {
- printf("SP hack enabled (%08x), @%08x\n", psxRegs.GPR.n.sp, psxRegs.pc);
- sp_in_mirror=1;
- }
if (Config.HLE && start == 0x80001000) // hlecall
{
// XXX: is this enough? Maybe check hleSoftCall?
if(bt[i]) assem_debug("OOPS - branch into delay slot\n");
instr_addr[i]=0;
} else {
+ speculate_register_values(i);
#ifndef DESTRUCTIVE_WRITEBACK
if(i<2||(itype[i-2]!=UJUMP&&itype[i-2]!=RJUMP&&(source[i-2]>>16)!=0x1000))
{