u_int ba[MAXBLOCK];
char likely[MAXBLOCK];
char is_ds[MAXBLOCK];
+ char ooo[MAXBLOCK];
uint64_t unneeded_reg[MAXBLOCK];
uint64_t unneeded_reg_upper[MAXBLOCK];
uint64_t branch_unneeded_reg[MAXBLOCK];
signed char regmap[MAXBLOCK][HOST_REGS];
signed char regmap_entry[MAXBLOCK][HOST_REGS];
uint64_t constmap[MAXBLOCK][HOST_REGS];
- uint64_t known_value[HOST_REGS];
- u_int known_reg;
struct regstat regs[MAXBLOCK];
struct regstat branch_regs[MAXBLOCK];
+ signed char minimum_free_regs[MAXBLOCK];
u_int needed_reg[MAXBLOCK];
uint64_t requires_32bit[MAXBLOCK];
u_int wont_dirty[MAXBLOCK];
char shadow[1048576] __attribute__((aligned(16)));
void *copy;
int expirep;
+#ifndef PCSX
u_int using_tlb;
+#else
+ static const u_int using_tlb=0;
+#endif
+ static u_int sp_in_mirror;
u_int stop_after_jal;
extern u_char restore_candidate[512];
extern int cycle_count;
#define CSREG 35 // Coprocessor status
#define CCREG 36 // Cycle count
#define INVCP 37 // Pointer to invalid_code
-#define TEMPREG 38
-#define FTEMP 38 // FPU/LDL/LDR temporary register
-#define PTEMP 39 // Prefetch temporary register
-#define TLREG 40 // TLB mapping offset
-#define RHASH 41 // Return address hash
-#define RHTBL 42 // Return address hash table address
-#define RTEMP 43 // JR/JALR address register
-#define MAXREG 43
-#define AGEN1 44 // Address generation temporary register
-#define AGEN2 45 // Address generation temporary register
-#define MGEN1 46 // Maptable address generation temporary register
-#define MGEN2 47 // Maptable address generation temporary register
-#define BTREG 48 // Branch target temporary register
+#define MMREG 38 // Pointer to memory_map
+#define ROREG 39 // ram offset (if rdram!=0x80000000)
+#define TEMPREG 40
+#define FTEMP 40 // FPU temporary register
+#define PTEMP 41 // Prefetch temporary register
+#define TLREG 42 // TLB mapping offset
+#define RHASH 43 // Return address hash
+#define RHTBL 44 // Return address hash table address
+#define RTEMP 45 // JR/JALR address register
+#define MAXREG 45
+#define AGEN1 46 // Address generation temporary register
+#define AGEN2 47 // Address generation temporary register
+#define MGEN1 48 // Maptable address generation temporary register
+#define MGEN2 49 // Maptable address generation temporary register
+#define BTREG 50 // Branch target temporary register
/* instruction types */
#define NOP 0 // No operation
// Don't trap writes
invalid_code[block]=1;
+#ifdef PCSX
+ invalid_code[((u_int)0x80000000>>12)|page]=1;
+#endif
#ifndef DISABLE_TLB
// If there is a valid TLB entry for this page, remove write protect
if(tlb_LUT_w[block]) {
if(rs1[i]) alloc_reg(current,i,rs1[i]);
if(rs2[i]) alloc_reg(current,i,rs2[i]);
alloc_reg(current,i,rt1[i]);
- if(rt1[i]==rs2[i]) alloc_reg_temp(current,i,-1);
+ if(rt1[i]==rs2[i]) {
+ alloc_reg_temp(current,i,-1);
+ minimum_free_regs[i]=1;
+ }
current->is32|=1LL<<rt1[i];
} else { // DSLLV/DSRLV/DSRAV
if(rs1[i]) alloc_reg64(current,i,rs1[i]);
alloc_reg64(current,i,rt1[i]);
current->is32&=~(1LL<<rt1[i]);
if(opcode2[i]==0x16||opcode2[i]==0x17) // DSRLV and DSRAV need a temporary register
+ {
alloc_reg_temp(current,i,-1);
+ minimum_free_regs[i]=1;
+ }
}
clear_const(current,rs1[i]);
clear_const(current,rs2[i]);
if(get_reg(current->regmap,rt1[i])<0) {
// dummy load, but we still need a register to calculate the address
alloc_reg_temp(current,i,-1);
+ minimum_free_regs[i]=1;
}
if(opcode[i]==0x27||opcode[i]==0x37) // LWU/LD
{
alloc_reg64(current,i,rt1[i]);
alloc_all(current,i);
alloc_reg64(current,i,FTEMP);
+ minimum_free_regs[i]=HOST_REGS;
}
else current->is32|=1LL<<rt1[i];
dirty_reg(current,rt1[i]);
{
alloc_reg(current,i,FTEMP);
alloc_reg_temp(current,i,-1);
+ minimum_free_regs[i]=1;
}
}
else
alloc_reg(current,i,FTEMP); // LWL/LWR need another temporary
}
alloc_reg_temp(current,i,-1);
+ minimum_free_regs[i]=1;
if(opcode[i]==0x1A||opcode[i]==0x1B) // LDL/LDR
{
alloc_all(current,i);
alloc_reg64(current,i,FTEMP);
+ minimum_free_regs[i]=HOST_REGS;
}
}
}
}
// We need a temporary register for address generation
alloc_reg_temp(current,i,-1);
+ minimum_free_regs[i]=1;
}
void c1ls_alloc(struct regstat *current,int i)
#endif
// We need a temporary register for address generation
alloc_reg_temp(current,i,-1);
+ minimum_free_regs[i]=1;
}
#ifndef multdiv_alloc
current->is32&=~(1LL<<LOREG);
dirty_reg(current,HIREG);
dirty_reg(current,LOREG);
+ minimum_free_regs[i]=HOST_REGS;
}
}
else
assert(opcode2[i]==0x10);
alloc_all(current,i);
}
+ minimum_free_regs[i]=HOST_REGS;
}
void cop1_alloc(struct regstat *current,int i)
alloc_reg_temp(current,i,-1);
}
}
+ minimum_free_regs[i]=1;
}
void fconv_alloc(struct regstat *current,int i)
{
alloc_reg(current,i,CSREG); // Load status
alloc_reg_temp(current,i,-1);
+ minimum_free_regs[i]=1;
}
void float_alloc(struct regstat *current,int i)
{
alloc_reg(current,i,CSREG); // Load status
alloc_reg_temp(current,i,-1);
+ minimum_free_regs[i]=1;
}
void c2op_alloc(struct regstat *current,int i)
{
alloc_reg(current,i,FSREG); // Load flags
dirty_reg(current,FSREG); // Flag will be modified
alloc_reg_temp(current,i,-1);
+ minimum_free_regs[i]=1;
}
void syscall_alloc(struct regstat *current,int i)
alloc_cc(current,i);
dirty_reg(current,CCREG);
alloc_all(current,i);
+ minimum_free_regs[i]=HOST_REGS;
current->isconst=0;
}
current->isconst=0;
current->wasconst=0;
regs[i].wasconst=0;
+ minimum_free_regs[i]=HOST_REGS;
alloc_all(current,i);
alloc_cc(current,i);
dirty_reg(current,CCREG);
if(i_regs->regmap[HOST_CCREG]==CCREG) reglist&=~(1<<HOST_CCREG);
if(s>=0) {
c=(i_regs->wasconst>>s)&1;
- memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
- if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1;
+ if (c) {
+ memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
+ if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1;
+ }
}
//printf("load_assemble: c=%d\n",c);
//if(c) printf("load_assemble: const=%x\n",(int)constmap[i][s]+offset);
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);
+ }
+ else
+ #endif
emit_cmpimm(addr,RAM_SIZE);
jaddr=(int)out;
#ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
else x=((constmap[i][s]+offset)^3)-(constmap[i][s]+offset);
#else
if(!c) a=addr;
+#endif
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
#endif
emit_movsbl_indexed_tlb(x,a,map,tl);
}
else x=((constmap[i][s]+offset)^2)-(constmap[i][s]+offset);
#else
if(!c) a=addr;
+#endif
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
#endif
//#ifdef
//emit_movswl_indexed_tlb(x,tl,map,tl);
if (opcode[i]==0x23) { // LW
if(!c||memtarget) {
if(!dummy) {
+ int a=addr;
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
+#endif
//emit_readword_indexed((int)rdram-0x80000000,addr,tl);
#ifdef HOST_IMM_ADDR32
if(c)
emit_readword_tlb(constmap[i][s]+offset,map,tl);
else
#endif
- emit_readword_indexed_tlb(0,addr,map,tl);
+ emit_readword_indexed_tlb(0,a,map,tl);
}
if(jaddr)
add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
else x=((constmap[i][s]+offset)^3)-(constmap[i][s]+offset);
#else
if(!c) a=addr;
+#endif
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
#endif
emit_movzbl_indexed_tlb(x,a,map,tl);
}
else x=((constmap[i][s]+offset)^2)-(constmap[i][s]+offset);
#else
if(!c) a=addr;
+#endif
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
#endif
//#ifdef
//emit_movzwl_indexed_tlb(x,tl,map,tl);
assert(th>=0);
if(!c||memtarget) {
if(!dummy) {
+ int a=addr;
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
+#endif
//emit_readword_indexed((int)rdram-0x80000000,addr,tl);
#ifdef HOST_IMM_ADDR32
if(c)
emit_readword_tlb(constmap[i][s]+offset,map,tl);
else
#endif
- emit_readword_indexed_tlb(0,addr,map,tl);
+ emit_readword_indexed_tlb(0,a,map,tl);
}
if(jaddr)
add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
if (opcode[i]==0x37) { // LD
if(!c||memtarget) {
if(!dummy) {
+ int a=addr;
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
+#endif
//gen_tlb_addr_r(tl,map);
//if(th>=0) emit_readword_indexed((int)rdram-0x80000000,addr,th);
//emit_readword_indexed((int)rdram-0x7FFFFFFC,addr,tl);
emit_readdword_tlb(constmap[i][s]+offset,map,th,tl);
else
#endif
- emit_readdword_indexed_tlb(0,addr,map,th,tl);
+ emit_readdword_indexed_tlb(0,a,map,th,tl);
}
if(jaddr)
add_stub(LOADD_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
offset=imm[i];
if(s>=0) {
c=(i_regs->wasconst>>s)&1;
- memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
- if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1;
+ if(c) {
+ memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
+ if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1;
+ }
}
assert(tl>=0);
assert(temp>=0);
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);
+ }
+ else
+ #endif
#ifdef R29_HACK
// Strmnnrmn's speed hack
- memtarget=1;
if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE)
#endif
emit_cmpimm(addr,RAM_SIZE);
if(s==addr) emit_mov(s,temp);
#endif
#ifdef R29_HACK
+ memtarget=1;
if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE)
#endif
{
if (opcode[i]==0x28) { // SB
if(!c||memtarget) {
- int x=0;
+ int x=0,a=temp;
#ifdef BIG_ENDIAN_MIPS
if(!c) emit_xorimm(addr,3,temp);
else x=((constmap[i][s]+offset)^3)-(constmap[i][s]+offset);
#else
- if(c) x=(constmap[i][s]+offset)-(constmap[i][s]+offset);
- else if (addr!=temp) emit_mov(addr,temp);
+ if(!c) a=addr;
+#endif
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
#endif
//gen_tlb_addr_w(temp,map);
//emit_writebyte_indexed(tl,(int)rdram-0x80000000,temp);
- emit_writebyte_indexed_tlb(tl,x,temp,map,temp);
+ emit_writebyte_indexed_tlb(tl,x,a,map,a);
}
type=STOREB_STUB;
}
if (opcode[i]==0x29) { // SH
if(!c||memtarget) {
- int x=0;
+ int x=0,a=temp;
#ifdef BIG_ENDIAN_MIPS
if(!c) emit_xorimm(addr,2,temp);
else x=((constmap[i][s]+offset)^2)-(constmap[i][s]+offset);
#else
- if(c) x=(constmap[i][s]+offset)-(constmap[i][s]+offset);
- else if (addr!=temp) emit_mov(addr,temp);
+ if(!c) a=addr;
+#endif
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
#endif
//#ifdef
//emit_writehword_indexed_tlb(tl,x,temp,map,temp);
//#else
if(map>=0) {
- gen_tlb_addr_w(temp,map);
- emit_writehword_indexed(tl,x,temp);
+ gen_tlb_addr_w(a,map);
+ emit_writehword_indexed(tl,x,a);
}else
- emit_writehword_indexed(tl,(int)rdram-0x80000000+x,temp);
+ emit_writehword_indexed(tl,(int)rdram-0x80000000+x,a);
}
type=STOREH_STUB;
}
if (opcode[i]==0x2B) { // SW
- if(!c||memtarget)
+ if(!c||memtarget) {
+ int a=addr;
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
+#endif
//emit_writeword_indexed(tl,(int)rdram-0x80000000,addr);
- emit_writeword_indexed_tlb(tl,0,addr,map,temp);
+ emit_writeword_indexed_tlb(tl,0,a,map,temp);
+ }
type=STOREW_STUB;
}
if (opcode[i]==0x3F) { // SD
if(!c||memtarget) {
+ int a=addr;
+#ifdef PCSX
+ if(sp_in_mirror&&rs1[i]==29) a=HOST_TEMPREG;
+#endif
if(rs2[i]) {
assert(th>=0);
//emit_writeword_indexed(th,(int)rdram-0x80000000,addr);
//emit_writeword_indexed(tl,(int)rdram-0x7FFFFFFC,addr);
- emit_writedword_indexed_tlb(th,tl,0,addr,map,temp);
+ emit_writedword_indexed_tlb(th,tl,0,a,map,temp);
}else{
// Store zero
//emit_writeword_indexed(tl,(int)rdram-0x80000000,temp);
//emit_writeword_indexed(tl,(int)rdram-0x7FFFFFFC,temp);
- emit_writedword_indexed_tlb(tl,tl,0,addr,map,temp);
+ emit_writedword_indexed_tlb(tl,tl,0,a,map,temp);
}
}
type=STORED_STUB;
}
- if(!using_tlb&&(!c||memtarget))
- // addr could be a temp, make sure it survives STORE*_STUB
- reglist|=1<<addr;
- if(jaddr) {
- add_stub(type,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
- } else if(!memtarget) {
- inline_writestub(type,i,constmap[i][s]+offset,i_regs->regmap,rs2[i],ccadj[i],reglist);
- }
if(!using_tlb) {
if(!c||memtarget) {
#ifdef DESTRUCTIVE_SHIFT
#else
emit_cmpmem_indexedsr12_imm((int)invalid_code,addr,1);
#endif
+ #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT)
+ emit_callne(invalidate_addr_reg[addr]);
+ #else
jaddr2=(int)out;
emit_jne(0);
add_stub(INVCODE_STUB,jaddr2,(int)out,reglist|(1<<HOST_CCREG),addr,0,0,0);
+ #endif
}
}
+ if(jaddr) {
+ add_stub(type,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
+ } else if(c&&!memtarget) {
+ inline_writestub(type,i,constmap[i][s]+offset,i_regs->regmap,rs2[i],ccadj[i],reglist);
+ }
//if(opcode[i]==0x2B || opcode[i]==0x3F)
//if(opcode[i]==0x2B || opcode[i]==0x28)
//if(opcode[i]==0x2B || opcode[i]==0x29)
int jaddr=0,jaddr2;
int case1,case2,case3;
int done0,done1,done2;
- int memtarget,c=0;
+ int memtarget=0,c=0;
int agr=AGEN1+(i&1);
u_int hr,reglist=0;
th=get_reg(i_regs->regmap,rs2[i]|64);
offset=imm[i];
if(s>=0) {
c=(i_regs->isconst>>s)&1;
- memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
- if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1;
+ if(c) {
+ memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
+ if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1;
+ }
}
assert(tl>=0);
for(hr=0;hr<HOST_REGS;hr++) {
#else
emit_cmpmem_indexedsr12_imm((int)invalid_code,temp,1);
#endif
+ #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT)
+ emit_callne(invalidate_addr_reg[temp]);
+ #else
jaddr3=(int)out;
emit_jne(0);
add_stub(INVCODE_STUB,jaddr3,(int)out,reglist|(1<<HOST_CCREG),temp,0,0,0);
+ #endif
}
}
if(jaddr2) add_stub(type,jaddr2,(int)out,i,offset||c||s<0?ar:s,(int)i_regs,ccadj[i],reglist);
int ar;
int offset;
int memtarget=0,c=0;
- int jaddr,jaddr2=0,jaddr3,type;
+ int jaddr2=0,jaddr3,type;
int agr=AGEN1+(i&1);
u_int hr,reglist=0;
u_int copr=(source[i]>>16)&0x1f;
#else
emit_cmpmem_indexedsr12_imm((int)invalid_code,ar,1);
#endif
+ #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT)
+ emit_callne(invalidate_addr_reg[ar]);
+ #else
jaddr3=(int)out;
emit_jne(0);
add_stub(INVCODE_STUB,jaddr3,(int)out,reglist|(1<<HOST_CCREG),ar,0,0,0);
+ #endif
}
if (opcode[i]==0x32) { // LWC2
cop2_put_dreg(copr,tl,HOST_TEMPREG);
void address_generation(int i,struct regstat *i_regs,signed char entry[])
{
if(itype[i]==LOAD||itype[i]==LOADLR||itype[i]==STORE||itype[i]==STORELR||itype[i]==C1LS||itype[i]==C2LS) {
- int ra;
+ int ra=-1;
int agr=AGEN1+(i&1);
int mgr=MGEN1+(i&1);
if(itype[i]==LOAD) {
emit_loadreg(rs2[i],s2l);
#endif
int hr=0;
- int addr,alt,ntaddr;
+ int addr=-1,alt=-1,ntaddr=-1;
while(hr<HOST_REGS)
{
if(hr!=EXCLUDE_REG && hr!=HOST_CCREG &&
if(i_regmap[temp]==PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp);
}
#endif
- ds_assemble(i+1,i_regs);
- uint64_t bc_unneeded=branch_regs[i].u;
- uint64_t bc_unneeded_upper=branch_regs[i].uu;
- bc_unneeded|=1|(1LL<<rt1[i]);
- bc_unneeded_upper|=1|(1LL<<rt1[i]);
- wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32,
- bc_unneeded,bc_unneeded_upper);
- load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG);
if(rt1[i]==31) {
int rt;
unsigned int return_address;
- assert(rt1[i+1]!=31);
- assert(rt2[i+1]!=31);
rt=get_reg(branch_regs[i].regmap,31);
assem_debug("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]);
//assert(rt>=0);
return_address=start+i*4+8;
if(rt>=0) {
#ifdef USE_MINI_HT
- if(internal_branch(branch_regs[i].is32,return_address)) {
- int temp=rt+1;
- if(temp==EXCLUDE_REG||temp>=HOST_REGS||
- branch_regs[i].regmap[temp]>=0)
- {
- temp=get_reg(branch_regs[i].regmap,-1);
- }
+ if(internal_branch(branch_regs[i].is32,return_address)&&rt1[i+1]!=31) {
+ int temp=-1; // note: must be ds-safe
#ifdef HOST_TEMPREG
- if(temp<0) temp=HOST_TEMPREG;
+ temp=HOST_TEMPREG;
#endif
if(temp>=0) do_miniht_insert(return_address,rt,temp);
else emit_movimm(return_address,rt);
}
}
}
+ ds_assemble(i+1,i_regs);
+ uint64_t bc_unneeded=branch_regs[i].u;
+ uint64_t bc_unneeded_upper=branch_regs[i].uu;
+ bc_unneeded|=1|(1LL<<rt1[i]);
+ bc_unneeded_upper|=1|(1LL<<rt1[i]);
+ wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32,
+ bc_unneeded,bc_unneeded_upper);
+ load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG);
int cc,adj;
cc=get_reg(branch_regs[i].regmap,CCREG);
assert(cc==HOST_CCREG);
int prev_cop1_usable=cop1_usable;
int unconditional=0,nop=0;
int only32=0;
- int ooo=1;
int invert=0;
int internal=internal_branch(branch_regs[i].is32,ba[i]);
if(i==(ba[i]-start)>>2) assem_debug("idle loop\n");
- if(likely[i]) ooo=0;
if(!match) invert=1;
#ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
if(i>(ba[i]-start)>>2) invert=1;
#endif
-
- if(ooo)
- if((rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]))||
- (rs2[i]&&(rs2[i]==rt1[i+1]||rs2[i]==rt2[i+1])))
- {
- // Write-after-read dependency prevents out of order execution
- // First test branch condition, then execute delay slot, then branch
- ooo=0;
- }
-
- if(ooo) {
+
+ if(ooo[i]) {
s1l=get_reg(branch_regs[i].regmap,rs1[i]);
s1h=get_reg(branch_regs[i].regmap,rs1[i]|64);
s2l=get_reg(branch_regs[i].regmap,rs2[i]);
only32=(regs[i].was32>>rs1[i])&(regs[i].was32>>rs2[i])&1;
}
- if(ooo) {
+ if(ooo[i]) {
// Out of order execution (delay slot first)
//printf("OOOE\n");
address_generation(i+1,i_regs,regs[i].regmap_entry);
int prev_cop1_usable=cop1_usable;
int unconditional=0,nevertaken=0;
int only32=0;
- int ooo=1;
int invert=0;
int internal=internal_branch(branch_regs[i].is32,ba[i]);
if(i==(ba[i]-start)>>2) assem_debug("idle loop\n");
- if(likely[i]) ooo=0;
if(!match) invert=1;
#ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
if(i>(ba[i]-start)>>2) invert=1;
//if(opcode2[i]>=0x10) return; // FIXME (BxxZAL)
//assert(opcode2[i]<0x10||rs1[i]==0); // FIXME (BxxZAL)
- if(ooo) {
- if(rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]))
- {
- // Write-after-read dependency prevents out of order execution
- // First test branch condition, then execute delay slot, then branch
- ooo=0;
- }
- if(rt1[i]==31&&(rs1[i+1]==31||rs2[i+1]==31||rt1[i+1]==31||rt2[i+1]==31))
- // BxxZAL $ra is available to delay insn, so do it in order
- ooo=0;
- }
-
- if(ooo) {
+ if(ooo[i]) {
s1l=get_reg(branch_regs[i].regmap,rs1[i]);
s1h=get_reg(branch_regs[i].regmap,rs1[i]|64);
}
only32=(regs[i].was32>>rs1[i])&1;
}
- if(ooo) {
+ if(ooo[i]) {
// Out of order execution (delay slot first)
//printf("OOOE\n");
address_generation(i+1,i_regs,regs[i].regmap_entry);
assem_debug("fmatch=%d\n",match);
int fs,cs;
int eaddr;
- int ooo=1;
int invert=0;
int internal=internal_branch(branch_regs[i].is32,ba[i]);
if(i==(ba[i]-start)>>2) assem_debug("idle loop\n");
- if(likely[i]) ooo=0;
if(!match) invert=1;
#ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
if(i>(ba[i]-start)>>2) invert=1;
#endif
- if(ooo)
- if(itype[i+1]==FCOMP)
- {
- // Write-after-read dependency prevents out of order execution
- // First test branch condition, then execute delay slot, then branch
- ooo=0;
- }
-
- if(ooo) {
+ if(ooo[i]) {
fs=get_reg(branch_regs[i].regmap,FSREG);
address_generation(i+1,i_regs,regs[i].regmap_entry); // Is this okay?
}
cop1_usable=1;
}
- if(ooo) {
+ if(ooo[i]) {
// Out of order execution (delay slot first)
//printf("OOOE\n");
ds_assemble(i+1,i_regs);
}
}
+// clear the state completely, instead of just marking
+// things invalid like invalidate_all_pages() does
+void new_dynarec_clear_full()
+{
+ int n;
+ out=(u_char *)BASE_ADDR;
+ memset(invalid_code,1,sizeof(invalid_code));
+ memset(hash_table,0xff,sizeof(hash_table));
+ memset(mini_ht,-1,sizeof(mini_ht));
+ memset(restore_candidate,0,sizeof(restore_candidate));
+ memset(shadow,0,sizeof(shadow));
+ copy=shadow;
+ expirep=16384; // Expiry pointer, +2 blocks
+ pending_exception=0;
+ literalcount=0;
+ stop_after_jal=0;
+ // TLB
+#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
+ memory_map[n]=((u_int)rdram-0x80000000)>>2;
+ for(n=526336;n<1048576;n++) // 0x80800000 .. 0xFFFFFFFF
+ memory_map[n]=-1;
+ for(n=0;n<4096;n++) ll_clear(jump_in+n);
+ for(n=0;n<4096;n++) ll_clear(jump_out+n);
+ for(n=0;n<4096;n++) ll_clear(jump_dirty+n);
+}
+
void new_dynarec_init()
{
printf("Init new dynarec\n");
fake_pc.f.r.rd=&readmem_dword;
#endif
int n;
- for(n=0x80000;n<0x80800;n++)
- invalid_code[n]=1;
- for(n=0;n<65536;n++)
- hash_table[n][0]=hash_table[n][2]=-1;
- memset(mini_ht,-1,sizeof(mini_ht));
- memset(restore_candidate,0,sizeof(restore_candidate));
- copy=shadow;
- expirep=16384; // Expiry pointer, +2 blocks
- pending_exception=0;
- literalcount=0;
+ new_dynarec_clear_full();
#ifdef HOST_IMM8
// Copy this into local area so we don't have to put it in every literal pool
invc_ptr=invalid_code;
#endif
- stop_after_jal=0;
- // TLB
- using_tlb=0;
- for(n=0;n<524288;n++) // 0 .. 0x7FFFFFFF
- memory_map[n]=-1;
- for(n=524288;n<526336;n++) // 0x80000000 .. 0x807FFFFF
- memory_map[n]=((u_int)rdram-0x80000000)>>2;
- for(n=526336;n<1048576;n++) // 0x80800000 .. 0xFFFFFFFF
- memory_map[n]=-1;
#ifdef MUPEN64
for(n=0;n<0x8000;n++) { // 0 .. 0x7FFFFFFF
writemem[n] = write_nomem_new;
start = (u_int)addr&~3;
//assert(((u_int)addr&1)==0);
#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?
/* Pass 1 disassembly */
for(i=0;!done;i++) {
- bt[i]=0;likely[i]=0;op2=0;
+ bt[i]=0;likely[i]=0;ooo[i]=0;op2=0;
+ minimum_free_regs[i]=0;
opcode[i]=op=source[i]>>26;
switch(op)
{
case 0x11: strcpy(insn[i],"MTHI"); type=MOV; break;
case 0x12: strcpy(insn[i],"MFLO"); type=MOV; break;
case 0x13: strcpy(insn[i],"MTLO"); type=MOV; break;
- case 0x14: strcpy(insn[i],"DSLLV"); type=SHIFT; break;
- case 0x16: strcpy(insn[i],"DSRLV"); type=SHIFT; break;
- case 0x17: strcpy(insn[i],"DSRAV"); type=SHIFT; break;
case 0x18: strcpy(insn[i],"MULT"); type=MULTDIV; break;
case 0x19: strcpy(insn[i],"MULTU"); type=MULTDIV; break;
case 0x1A: strcpy(insn[i],"DIV"); type=MULTDIV; break;
case 0x1B: strcpy(insn[i],"DIVU"); type=MULTDIV; break;
- case 0x1C: strcpy(insn[i],"DMULT"); type=MULTDIV; break;
- case 0x1D: strcpy(insn[i],"DMULTU"); type=MULTDIV; break;
- case 0x1E: strcpy(insn[i],"DDIV"); type=MULTDIV; break;
- case 0x1F: strcpy(insn[i],"DDIVU"); type=MULTDIV; break;
case 0x20: strcpy(insn[i],"ADD"); type=ALU; break;
case 0x21: strcpy(insn[i],"ADDU"); type=ALU; break;
case 0x22: strcpy(insn[i],"SUB"); type=ALU; break;
case 0x27: strcpy(insn[i],"NOR"); type=ALU; break;
case 0x2A: strcpy(insn[i],"SLT"); type=ALU; break;
case 0x2B: strcpy(insn[i],"SLTU"); type=ALU; break;
- case 0x2C: strcpy(insn[i],"DADD"); type=ALU; break;
- case 0x2D: strcpy(insn[i],"DADDU"); type=ALU; break;
- case 0x2E: strcpy(insn[i],"DSUB"); type=ALU; break;
- case 0x2F: strcpy(insn[i],"DSUBU"); type=ALU; break;
case 0x30: strcpy(insn[i],"TGE"); type=NI; break;
case 0x31: strcpy(insn[i],"TGEU"); type=NI; break;
case 0x32: strcpy(insn[i],"TLT"); type=NI; break;
case 0x33: strcpy(insn[i],"TLTU"); type=NI; break;
case 0x34: strcpy(insn[i],"TEQ"); type=NI; break;
case 0x36: strcpy(insn[i],"TNE"); type=NI; break;
+#ifndef FORCE32
+ case 0x14: strcpy(insn[i],"DSLLV"); type=SHIFT; break;
+ case 0x16: strcpy(insn[i],"DSRLV"); type=SHIFT; break;
+ case 0x17: strcpy(insn[i],"DSRAV"); type=SHIFT; break;
+ case 0x1C: strcpy(insn[i],"DMULT"); type=MULTDIV; break;
+ case 0x1D: strcpy(insn[i],"DMULTU"); type=MULTDIV; break;
+ case 0x1E: strcpy(insn[i],"DDIV"); type=MULTDIV; break;
+ case 0x1F: strcpy(insn[i],"DDIVU"); type=MULTDIV; break;
+ case 0x2C: strcpy(insn[i],"DADD"); type=ALU; break;
+ case 0x2D: strcpy(insn[i],"DADDU"); type=ALU; break;
+ case 0x2E: strcpy(insn[i],"DSUB"); type=ALU; break;
+ case 0x2F: strcpy(insn[i],"DSUBU"); type=ALU; break;
case 0x38: strcpy(insn[i],"DSLL"); type=SHIFTIMM; break;
case 0x3A: strcpy(insn[i],"DSRL"); type=SHIFTIMM; break;
case 0x3B: strcpy(insn[i],"DSRA"); type=SHIFTIMM; break;
case 0x3C: strcpy(insn[i],"DSLL32"); type=SHIFTIMM; break;
case 0x3E: strcpy(insn[i],"DSRL32"); type=SHIFTIMM; break;
case 0x3F: strcpy(insn[i],"DSRA32"); type=SHIFTIMM; break;
+#endif
}
break;
case 0x01: strcpy(insn[i],"regimm"); type=NI;
printf("NI %08x @%08x (%08x)\n", source[i], addr + i*4, addr);
break;
}
-#ifdef PCSX
- /* detect branch in delay slot early */
- if(type==RJUMP||type==UJUMP||type==CJUMP||type==SJUMP||type==FJUMP) {
- opcode[i+1]=source[i+1]>>26;
- opcode2[i+1]=source[i+1]&0x3f;
- if((0<opcode[i+1]&&opcode[i+1]<8)||(opcode[i+1]==0&&(opcode2[i+1]==8||opcode2[i+1]==9))) {
- printf("branch in delay slot @%08x (%08x)\n", addr + i*4+4, addr);
- // don't handle first branch and call interpreter if it's hit
- type=INTCALL;
- }
- }
-#endif
itype[i]=type;
opcode2[i]=op2;
/* Get registers/immediates */
else if(type==CJUMP||type==SJUMP||type==FJUMP)
ba[i]=start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14);
else ba[i]=-1;
- /* Is this the end of the block? */
- if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) {
#ifdef PCSX
- // check for link register access in delay slot
- int rt1_=rt1[i-1];
- if(rt1_!=0&&(rs1[i]==rt1_||rs2[i]==rt1_||rt1[i]==rt1_||rt2[i]==rt1_)) {
- printf("link access in delay slot @%08x (%08x)\n", addr + i*4, addr);
+ if(i>0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP)) {
+ int do_in_intrp=0;
+ // branch in delay slot?
+ if(type==RJUMP||type==UJUMP||type==CJUMP||type==SJUMP||type==FJUMP) {
+ // don't handle first branch and call interpreter if it's hit
+ printf("branch in delay slot @%08x (%08x)\n", addr + i*4, addr);
+ do_in_intrp=1;
+ }
+ // basic load delay detection
+ else if((type==LOAD||type==LOADLR||type==COP0||type==COP2||type==C2LS)&&rt1[i]!=0) {
+ int t=(ba[i-1]-start)/4;
+ if(0 <= t && t < i &&(rt1[i]==rs1[t]||rt1[i]==rs2[t])&&itype[t]!=CJUMP&&itype[t]!=SJUMP) {
+ // jump target wants DS result - potential load delay effect
+ printf("load delay @%08x (%08x)\n", addr + i*4, addr);
+ do_in_intrp=1;
+ bt[t+1]=1; // expected return from interpreter
+ }
+ else if(i>=2&&rt1[i-2]==2&&rt1[i]==2&&rs1[i]!=2&&rs2[i]!=2&&rs1[i-1]!=2&&rs2[i-1]!=2&&
+ !(i>=3&&(itype[i-3]==RJUMP||itype[i-3]==UJUMP||itype[i-3]==CJUMP||itype[i-3]==SJUMP))) {
+ // v0 overwrite like this is a sign of trouble, bail out
+ printf("v0 overwrite @%08x (%08x)\n", addr + i*4, addr);
+ do_in_intrp=1;
+ }
+ }
+ if(do_in_intrp) {
+ rs1[i-1]=CCREG;
+ rs2[i-1]=rt1[i-1]=rt2[i-1]=0;
ba[i-1]=-1;
itype[i-1]=INTCALL;
done=2;
+ i--; // don't compile the DS
}
- else
+ }
#endif
+ /* Is this the end of the block? */
+ if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) {
if(rt1[i-1]==0) { // Continue past subroutine call (JAL)
done=2;
}
current.wasconst=0;
int ds=0;
int cc=0;
- int hr;
+ int hr=-1;
#ifndef FORCE32
provisional_32bit();
clear_const(¤t,rt1[i]);
alloc_cc(¤t,i);
dirty_reg(¤t,CCREG);
+ ooo[i]=1;
+ delayslot_alloc(¤t,i+1);
if (rt1[i]==31) {
alloc_reg(¤t,i,31);
dirty_reg(¤t,31);
- assert(rs1[i+1]!=31&&rs2[i+1]!=31);
- assert(rt1[i+1]!=rt1[i]);
+ //assert(rs1[i+1]!=31&&rs2[i+1]!=31);
+ //assert(rt1[i+1]!=rt1[i]);
#ifdef REG_PREFETCH
alloc_reg(¤t,i,PTEMP);
#endif
//current.is32|=1LL<<rt1[i];
}
- delayslot_alloc(¤t,i+1);
//current.isconst=0; // DEBUG
ds=1;
//printf("i=%d, isconst=%x\n",i,current.isconst);
alloc_reg(¤t,i,RTEMP);
}
//current.isconst=0; // DEBUG
+ ooo[i]=1;
ds=1;
break;
case CJUMP:
(rs2[i]&&(rs2[i]==rt1[i+1]||rs2[i]==rt2[i+1]))) {
// The delay slot overwrites one of our conditions.
// Allocate the branch condition registers instead.
- // Note that such a sequence of instructions could
- // be considered a bug since the branch can not be
- // re-executed if an exception occurs.
current.isconst=0;
current.wasconst=0;
regs[i].wasconst=0;
if(rs2[i]) alloc_reg64(¤t,i,rs2[i]);
}
}
- else delayslot_alloc(¤t,i+1);
+ else
+ {
+ ooo[i]=1;
+ delayslot_alloc(¤t,i+1);
+ }
}
else
if((opcode[i]&0x3E)==6) // BLEZ/BGTZ
if(rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1])) {
// The delay slot overwrites one of our conditions.
// Allocate the branch condition registers instead.
- // Note that such a sequence of instructions could
- // be considered a bug since the branch can not be
- // re-executed if an exception occurs.
current.isconst=0;
current.wasconst=0;
regs[i].wasconst=0;
if(rs1[i]) alloc_reg64(¤t,i,rs1[i]);
}
}
- else delayslot_alloc(¤t,i+1);
+ else
+ {
+ ooo[i]=1;
+ delayslot_alloc(¤t,i+1);
+ }
}
else
// Don't alloc the delay slot yet because we might not execute it
//#endif
//current.is32|=1LL<<rt1[i];
}
- if(rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1])) {
- // The delay slot overwrites the branch condition.
+ if((rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1])) // The delay slot overwrites the branch condition.
+ ||(rt1[i]==31&&(rs1[i+1]==31||rs2[i+1]==31||rt1[i+1]==31||rt2[i+1]==31))) { // DS touches $ra
// Allocate the branch condition registers instead.
- // Note that such a sequence of instructions could
- // be considered a bug since the branch can not be
- // re-executed if an exception occurs.
current.isconst=0;
current.wasconst=0;
regs[i].wasconst=0;
if(rs1[i]) alloc_reg64(¤t,i,rs1[i]);
}
}
- else delayslot_alloc(¤t,i+1);
+ else
+ {
+ ooo[i]=1;
+ delayslot_alloc(¤t,i+1);
+ }
}
else
// Don't alloc the delay slot yet because we might not execute it
if(itype[i+1]==FCOMP) {
// The delay slot overwrites the branch condition.
// Allocate the branch condition registers instead.
- // Note that such a sequence of instructions could
- // be considered a bug since the branch can not be
- // re-executed if an exception occurs.
alloc_cc(¤t,i);
dirty_reg(¤t,CCREG);
alloc_reg(¤t,i,CSREG);
alloc_reg(¤t,i,FSREG);
}
else {
+ ooo[i]=1;
delayslot_alloc(¤t,i+1);
alloc_reg(¤t,i+1,CSREG);
}
{
cc=0;
}
+#ifdef PCSX
+ else if(/*itype[i]==LOAD||*/itype[i]==STORE||itype[i]==C1LS) // load causes weird timing issues
+ {
+ cc+=2; // 2 cycle penalty (after CLOCK_DIVIDER)
+ }
+ else if(itype[i]==C2LS)
+ {
+ cc+=4;
+ }
+#endif
else
{
cc++;
f_regmap[hr]=branch_regs[i].regmap[hr];
}
}
- if(itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS
- ||itype[i+1]==SHIFT||itype[i+1]==COP1||itype[i+1]==FLOAT
- ||itype[i+1]==FCOMP||itype[i+1]==FCONV
- ||itype[i+1]==COP2||itype[i+1]==C2LS||itype[i+1]==C2OP)
- {
- // Test both in case the delay slot is ooo,
- // could be done better...
- if(count_free_regs(branch_regs[i].regmap)<2
- ||count_free_regs(regs[i].regmap)<2)
+ if(ooo[i]) {
+ if(count_free_regs(regs[i].regmap)<=minimum_free_regs[i+1])
+ f_regmap[hr]=branch_regs[i].regmap[hr];
+ }else{
+ if(count_free_regs(branch_regs[i].regmap)<=minimum_free_regs[i+1])
f_regmap[hr]=branch_regs[i].regmap[hr];
}
// Avoid dirty->clean transition
- // #ifdef DESTRUCTIVE_WRITEBACK here?
+ #ifdef DESTRUCTIVE_WRITEBACK
if(t>0) if(get_reg(regmap_pre[t],f_regmap[hr])>=0) if((regs[t].wasdirty>>get_reg(regmap_pre[t],f_regmap[hr]))&1) f_regmap[hr]=-1;
+ #endif
+ // This check is only strictly required in the DESTRUCTIVE_WRITEBACK
+ // case above, however it's always a good idea. We can't hoist the
+ // load if the register was already allocated, so there's no point
+ // wasting time analyzing most of these cases. It only "succeeds"
+ // when the mapping was different and the load can be replaced with
+ // a mov, which is of negligible benefit. So such cases are
+ // skipped below.
if(f_regmap[hr]>0) {
- if(regs[t].regmap_entry[hr]<0) {
+ if(regs[t].regmap_entry[hr]<0&&get_reg(regmap_pre[t],f_regmap[hr])<0) {
int r=f_regmap[hr];
for(j=t;j<=i;j++)
{
// register is lower numbered than the lower-half
// register. Not sure if it's worth fixing...
if(get_reg(regs[j].regmap,r&63)<0) break;
+ if(get_reg(regs[j].regmap_entry,r&63)<0) break;
if(regs[j].is32&(1LL<<(r&63))) break;
}
if(regs[j].regmap[hr]==f_regmap[hr]&&(f_regmap[hr]&63)<TEMPREG) {
}
k=i;
while(k>1&®s[k-1].regmap[hr]==-1) {
- if(itype[k-1]==STORE||itype[k-1]==STORELR
- ||itype[k-1]==C1LS||itype[k-1]==SHIFT||itype[k-1]==COP1
- ||itype[k-1]==FLOAT||itype[k-1]==FCONV||itype[k-1]==FCOMP
- ||itype[k-1]==COP2||itype[k-1]==C2LS||itype[k-1]==C2OP) {
- if(count_free_regs(regs[k-1].regmap)<2) {
- //printf("no free regs for store %x\n",start+(k-1)*4);
- break;
- }
+ if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) {
+ //printf("no free regs for store %x\n",start+(k-1)*4);
+ break;
}
- else
- if(itype[k-1]!=NOP&&itype[k-1]!=MOV&&itype[k-1]!=ALU&&itype[k-1]!=SHIFTIMM&&itype[k-1]!=IMM16&&itype[k-1]!=LOAD) break;
if(get_reg(regs[k-1].regmap,f_regmap[hr])>=0) {
//printf("no-match due to different register\n");
break;
}
}
for(k=t;k<j;k++) {
+ // Alloc register clean at beginning of loop,
+ // but may dirty it in pass 6
regs[k].regmap_entry[hr]=f_regmap[hr];
regs[k].regmap[hr]=f_regmap[hr];
- regmap_pre[k+1][hr]=f_regmap[hr];
- regs[k+1].wasdirty&=~(1<<hr);
regs[k].dirty&=~(1<<hr);
regs[k].wasconst&=~(1<<hr);
regs[k].isconst&=~(1<<hr);
+ if(itype[k]==UJUMP||itype[k]==RJUMP||itype[k]==CJUMP||itype[k]==SJUMP||itype[k]==FJUMP) {
+ branch_regs[k].regmap_entry[hr]=f_regmap[hr];
+ branch_regs[k].regmap[hr]=f_regmap[hr];
+ branch_regs[k].dirty&=~(1<<hr);
+ branch_regs[k].wasconst&=~(1<<hr);
+ branch_regs[k].isconst&=~(1<<hr);
+ if(itype[k]!=RJUMP&&itype[k]!=UJUMP&&(source[k]>>16)!=0x1000) {
+ regmap_pre[k+2][hr]=f_regmap[hr];
+ regs[k+2].wasdirty&=~(1<<hr);
+ assert((branch_regs[k].is32&(1LL<<f_regmap[hr]))==
+ (regs[k+2].was32&(1LL<<f_regmap[hr])));
+ }
+ }
+ else
+ {
+ regmap_pre[k+1][hr]=f_regmap[hr];
+ regs[k+1].wasdirty&=~(1<<hr);
+ }
}
if(regs[j].regmap[hr]==f_regmap[hr])
regs[j].regmap_entry[hr]=f_regmap[hr];
//printf("32/64 mismatch %x %d\n",start+j*4,hr);
break;
}
- if(itype[j]==STORE||itype[j]==STORELR||itype[j]==C1LS
- ||itype[j]==SHIFT||itype[j]==COP1||itype[j]==FLOAT
- ||itype[j]==FCOMP||itype[j]==FCONV
- ||itype[j]==COP2||itype[j]==C2LS||itype[j]==C2OP) {
- if(count_free_regs(regs[j].regmap)<2) {
- //printf("No free regs for store %x\n",start+j*4);
+ if(itype[j]==UJUMP||itype[j]==RJUMP||(source[j]>>16)==0x1000)
+ {
+ // Stop on unconditional branch
+ break;
+ }
+ if(itype[j]==CJUMP||itype[j]==SJUMP||itype[j]==FJUMP)
+ {
+ if(ooo[j]) {
+ if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j+1])
+ break;
+ }else{
+ if(count_free_regs(branch_regs[j].regmap)<=minimum_free_regs[j+1])
+ break;
+ }
+ if(get_reg(branch_regs[j].regmap,f_regmap[hr])>=0) {
+ //printf("no-match due to different register (branch)\n");
break;
}
}
- else if(itype[j]!=NOP&&itype[j]!=MOV&&itype[j]!=ALU&&itype[j]!=SHIFTIMM&&itype[j]!=IMM16&&itype[j]!=LOAD) break;
+ if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j]) {
+ //printf("No free regs for store %x\n",start+j*4);
+ break;
+ }
if(f_regmap[hr]>=64) {
if(regs[j].is32&(1LL<<(f_regmap[hr]&63))) {
break;
if(bt[i]) {
for(j=i;j<slen-1;j++) {
if(regs[j].regmap[HOST_CCREG]!=-1) break;
- if(itype[j]==STORE||itype[j]==STORELR||itype[j]==C1LS
- ||itype[j]==SHIFT||itype[j]==COP1||itype[j]==FLOAT
- ||itype[j]==FCOMP||itype[j]==FCONV
- ||itype[j]==COP2||itype[j]==C2LS||itype[j]==C2OP) {
- if(count_free_regs(regs[j].regmap)<2) {
- //printf("no free regs for store %x\n",start+j*4);
- break;
- }
+ if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j]) {
+ //printf("no free regs for store %x\n",start+j*4);
+ break;
}
- else
- if(itype[j]!=NOP&&itype[j]!=MOV&&itype[j]!=ALU&&itype[j]!=SHIFTIMM&&itype[j]!=IMM16&&itype[j]!=LOAD) break;
}
if(regs[j].regmap[HOST_CCREG]==CCREG) {
int k=i;
int k;
k=i;
while(regs[k-1].regmap[HOST_CCREG]==-1) {
- if(itype[k-1]==STORE||itype[k-1]==STORELR||itype[k-1]==C1LS
- ||itype[k-1]==SHIFT||itype[k-1]==COP1||itype[k-1]==FLOAT
- ||itype[k-1]==FCONV||itype[k-1]==FCOMP
- ||itype[k-1]==COP2||itype[k-1]==C2LS||itype[k-1]==C2OP) {
- if(count_free_regs(regs[k-1].regmap)<2) {
- //printf("no free regs for store %x\n",start+(k-1)*4);
- break;
- }
+ if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) {
+ //printf("no free regs for store %x\n",start+(k-1)*4);
+ break;
}
- else
- if(itype[k-1]!=NOP&&itype[k-1]!=MOV&&itype[k-1]!=ALU&&itype[k-1]!=SHIFTIMM&&itype[k-1]!=IMM16&&itype[k-1]!=LOAD) break;
k--;
}
if(regs[k-1].regmap[HOST_CCREG]==CCREG) {
if(itype[i]!=STORE&&itype[i]!=STORELR&&itype[i]!=C1LS&&itype[i]!=SHIFT&&
itype[i]!=NOP&&itype[i]!=MOV&&itype[i]!=ALU&&itype[i]!=SHIFTIMM&&
itype[i]!=IMM16&&itype[i]!=LOAD&&itype[i]!=COP1&&itype[i]!=FLOAT&&
- itype[i]!=FCONV&&itype[i]!=FCOMP&&
- itype[i]!=COP2&&itype[i]!=C2LS&&itype[i]!=C2OP)
+ itype[i]!=FCONV&&itype[i]!=FCOMP)
{
memcpy(f_regmap,regs[i].regmap,sizeof(f_regmap));
}
if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP)
{
// Load the delay slot registers if necessary
- if(rs1[i+1]!=rs1[i]&&rs1[i+1]!=rs2[i])
+ if(rs1[i+1]!=rs1[i]&&rs1[i+1]!=rs2[i]&&(rs1[i+1]!=rt1[i]||rt1[i]==0))
load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs1[i+1],rs1[i+1]);
- if(rs2[i+1]!=rs1[i+1]&&rs2[i+1]!=rs1[i]&&rs2[i+1]!=rs2[i])
+ if(rs2[i+1]!=rs1[i+1]&&rs2[i+1]!=rs1[i]&&rs2[i+1]!=rs2[i]&&(rs2[i+1]!=rt1[i]||rt1[i]==0))
load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs2[i+1],rs2[i+1]);
if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a)
load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,INVCP,INVCP);
}
#endif
}
+#ifdef PCSX
+ // PCSX maps all RAM mirror invalid_code tests to 0x80000000..0x80000000+RAM_SIZE
+ if(get_page(start)<(RAM_SIZE>>12))
+ for(i=start>>12;i<=(start+slen*4)>>12;i++)
+ invalid_code[((u_int)0x80000000>>12)|i]=0;
+#endif
/* Pass 10 - Free memory by expiring oldest blocks */