#define MAXBLOCK 4096
#define MAX_OUTPUT_BLOCK_SIZE 262144
-int cycle_multiplier; // 100 for 1.0
-#define CLOCK_ADJUST(x) (((x) * cycle_multiplier + 50) / 100)
-
struct regstat
{
signed char regmap_entry[HOST_REGS];
u_int isconst;
u_int loadedconst; // host regs that have constants loaded
u_int waswritten; // MIPS regs that were used as store base before
- uint64_t constmap[HOST_REGS];
};
struct ll_entry
static uint64_t gte_rs[MAXBLOCK]; // gte: 32 data and 32 ctl regs
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
uint64_t p32[MAXBLOCK];
uint64_t pr32[MAXBLOCK];
signed char regmap_pre[MAXBLOCK][HOST_REGS];
- signed char regmap[MAXBLOCK][HOST_REGS];
- signed char regmap_entry[MAXBLOCK][HOST_REGS];
- uint64_t constmap[MAXBLOCK][HOST_REGS];
- struct regstat regs[MAXBLOCK];
- struct regstat branch_regs[MAXBLOCK];
+ static uint64_t current_constmap[HOST_REGS];
+ static uint64_t constmap[MAXBLOCK][HOST_REGS];
+ static struct regstat regs[MAXBLOCK];
+ static struct regstat branch_regs[MAXBLOCK];
signed char minimum_free_regs[MAXBLOCK];
u_int needed_reg[MAXBLOCK];
uint64_t requires_32bit[MAXBLOCK];
static const u_int using_tlb=0;
#endif
int new_dynarec_did_compile;
+ int new_dynarec_hacks;
u_int stop_after_jal;
extern u_char restore_candidate[512];
extern int cycle_count;
//#define DEBUG_CYCLE_COUNT 1
+int cycle_multiplier; // 100 for 1.0
+
+static int CLOCK_ADJUST(int x)
+{
+ int s=(x>>31)|1;
+ return (x * cycle_multiplier + s * 50) / 100;
+}
+
static void tlb_hacks()
{
#ifndef DISABLE_TLB
return page;
}
+#ifndef PCSX
static u_int get_vpage(u_int vaddr)
{
u_int vpage=(vaddr^0x80000000)>>12;
if(vpage>2048) vpage=2048+(vpage&2047);
return vpage;
}
+#else
+// no virtual mem in PCSX
+static u_int get_vpage(u_int vaddr)
+{
+ return get_page(vaddr);
+}
+#endif
// Get address from virtual address
// This is called from the recompiled JR/JALR instructions
for (hr=0;hr<HOST_REGS;hr++) {
if(cur->regmap[hr]==reg) {
cur->isconst|=1<<hr;
- cur->constmap[hr]=value;
+ current_constmap[hr]=value;
}
else if((cur->regmap[hr]^64)==reg) {
cur->isconst|=1<<hr;
- cur->constmap[hr]=value>>32;
+ current_constmap[hr]=value>>32;
}
}
}
if(!reg) return 0;
for (hr=0;hr<HOST_REGS;hr++) {
if(cur->regmap[hr]==reg) {
- return cur->constmap[hr];
+ return current_constmap[hr];
}
}
printf("Unknown constant in r%d\n",reg);
//static int rhits;
// this check is done by the caller
//if (inv_code_start<=addr&&addr<=inv_code_end) { rhits++; return; }
- u_int page=get_page(addr);
+ u_int page=get_vpage(addr);
if(page<2048) { // RAM
struct ll_entry *head;
u_int addr_min=~0, addr_max=0;
return;
}
else {
- inv_debug("INV ADDR: %08x miss, inv %08x-%08x, sk %d\n", addr, inv_code_start, inv_code_end, 0);//rhits);
- }
- //rhits=0;
- if(page!=0) // FIXME: don't know what's up with page 0 (Klonoa)
+ inv_debug("INV ADDR: %08x miss, inv %08x-%08x, sk %d\n", addr, inv_code_start, inv_code_end, 0);
return;
+ }
}
#endif
invalidate_block(addr>>12);
jaddr=0;
}
#endif
- if(!using_tlb&&!(i_regs->waswritten&(1<<rs1[i]))) {
+ if(!using_tlb&&!(i_regs->waswritten&(1<<rs1[i]))&&!(new_dynarec_hacks&NDHACK_NO_SMC_CHECK)) {
if(!c||memtarget) {
#ifdef DESTRUCTIVE_SHIFT
// The x86 shift operation is 'destructive'; it overwrites the
#endif
}
}
+ u_int addr_val=constmap[i][s]+offset;
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);
+ inline_writestub(type,i,addr_val,i_regs->regmap,rs2[i],ccadj[i],reglist);
+ }
+ // basic current block modification detection..
+ // not looking back as that should be in mips cache already
+ if(c&&start+i*4<addr_val&&addr_val<start+slen*4) {
+ printf("write to %08x hits block %08x, pc=%08x\n",addr_val,start,start+i*4);
+ assert(i_regs->regmap==regs[i].regmap); // not delay slot
+ if(i_regs->regmap==regs[i].regmap) {
+ load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i);
+ wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty);
+ emit_movimm(start+i*4+4,0);
+ emit_writeword(0,(int)&pcaddr);
+ emit_jmp((int)do_interrupt);
+ }
}
//if(opcode[i]==0x2B || opcode[i]==0x3F)
//if(opcode[i]==0x2B || opcode[i]==0x28)
}
if(!c||!memtarget)
add_stub(STORELR_STUB,jaddr,(int)out,i,(int)i_regs,temp,ccadj[i],reglist);
- if(!using_tlb&&!(i_regs->waswritten&(1<<rs1[i]))) {
+ if(!using_tlb&&!(i_regs->waswritten&(1<<rs1[i]))&&!(new_dynarec_hacks&NDHACK_NO_SMC_CHECK)) {
#ifdef RAM_OFFSET
int map=get_reg(i_regs->regmap,ROREG);
if(map<0) map=HOST_TEMPREG;
emit_writedword_indexed_tlb(th,tl,0,offset||c||s<0?temp:s,map,temp);
type=STORED_STUB;
}
- if(!using_tlb&&!(i_regs->waswritten&(1<<rs1[i]))) {
+ if(!using_tlb&&!(i_regs->waswritten&(1<<rs1[i]))&&!(new_dynarec_hacks&NDHACK_NO_SMC_CHECK)) {
if (opcode[i]==0x39||opcode[i]==0x3D) { // SWC1/SDC1
#ifndef DESTRUCTIVE_SHIFT
temp=offset||c||s<0?ar:s;
}
if(jaddr2)
add_stub(type,jaddr2,(int)out,i,ar,(int)i_regs,ccadj[i],reglist);
- if (!(i_regs->waswritten&(1<<rs1[i]))&&opcode[i]==0x3a) { // SWC2
+ if(opcode[i]==0x3a) // SWC2
+ if(!(i_regs->waswritten&(1<<rs1[i]))&&!(new_dynarec_hacks&NDHACK_NO_SMC_CHECK)) {
#if defined(HOST_IMM8)
int ir=get_reg(i_regs->regmap,INVCP);
assert(ir>=0);
{
int i;
uint64_t u,uu,gte_u,b,bu,gte_bu;
- uint64_t temp_u,temp_uu,temp_gte_u;
+ uint64_t temp_u,temp_uu,temp_gte_u=0;
uint64_t tdep;
+ uint64_t gte_u_unknown=0;
+ if(new_dynarec_hacks&NDHACK_GTE_UNNEEDED)
+ gte_u_unknown=~0ll;
if(iend==slen-1) {
u=1;uu=1;
+ gte_u=gte_u_unknown;
}else{
u=unneeded_reg[iend+1];
uu=unneeded_reg_upper[iend+1];
u=1;uu=1;
+ gte_u=gte_unneeded[iend+1];
}
- gte_u=temp_gte_u=0;
for (i=iend;i>=istart;i--)
{
// Branch out of this block, flush all regs
u=1;
uu=1;
- gte_u=0;
+ gte_u=gte_u_unknown;
/* Hexagon hack
if(itype[i]==UJUMP&&rt1[i]==31)
{
{
u=1;
uu=1;
- gte_u=0;
+ gte_u=gte_u_unknown;
}
}
}
{
temp_u=1;
temp_uu=1;
- temp_gte_u=0;
+ temp_gte_u=gte_u_unknown;
}
}
tdep=(~temp_uu>>rt1[i])&1;
}else{
unneeded_reg[(ba[i]-start)>>2]=1;
unneeded_reg_upper[(ba[i]-start)>>2]=1;
- gte_unneeded[(ba[i]-start)>>2]=0;
+ gte_unneeded[(ba[i]-start)>>2]=gte_u_unknown;
}
} /*else*/ if(1) {
if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000)
uu&=~(1LL<<us1[i]);
uu&=~(1LL<<us2[i]);
gte_u&=~gte_rs[i];
+ if(gte_rs[i]&&rt1[i]&&(unneeded_reg[i+1]&(1ll<<rt1[i])))
+ gte_u|=gte_rs[i]>e_unneeded[i+1]; // MFC2/CFC2 to dead register, unneeded
// Source-target dependencies
uu&=~(tdep<<dep1[i]);
uu&=~(tdep<<dep2[i]);
literalcount=0;
stop_after_jal=0;
inv_code_start=inv_code_end=~0;
- gte_reads_flags=0;
// TLB
#ifndef DISABLE_TLB
using_tlb=0;
{
printf("Init new dynarec\n");
out=(u_char *)BASE_ADDR;
+#ifdef BASE_ADDR_FIXED
if (mmap (out, 1<<TARGET_SIZE_2,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0) <= 0) {printf("mmap() failed\n");}
+#else
+ // not all systems allow execute in data segment by default
+ if (mprotect(out, 1<<TARGET_SIZE_2, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+ printf("mprotect() failed\n");
+#endif
#ifdef MUPEN64
rdword=&readmem_dword;
fake_pc.f.r.rs=&readmem_dword;
void new_dynarec_cleanup()
{
int n;
+ #ifdef BASE_ADDR_FIXED
if (munmap ((void *)BASE_ADDR, 1<<TARGET_SIZE_2) < 0) {printf("munmap() failed\n");}
+ #endif
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);
{
case 0x00: gte_rs[i]=1ll<<gr; break; // MFC2
case 0x04: gte_rt[i]=1ll<<gr; break; // MTC2
- case 0x02: gte_rs[i]=1ll<<(gr+32); // CFC2
- if(gr==31&&!gte_reads_flags) {
- assem_debug("gte flag read encountered @%08x\n",addr + i*4);
- gte_reads_flags=1;
- }
- break;
+ case 0x02: gte_rs[i]=1ll<<(gr+32); break; // CFC2
case 0x06: gte_rt[i]=1ll<<(gr+32); break; // CTC2
}
break;
gte_rs[i]=gte_reg_reads[source[i]&0x3f];
gte_rt[i]=gte_reg_writes[source[i]&0x3f];
gte_rt[i]|=1ll<<63; // every op changes flags
+ if((source[i]&0x3f)==GTE_MVMVA) {
+ int v = (source[i] >> 15) & 3;
+ gte_rs[i]&=~0xe3fll;
+ if(v==3) gte_rs[i]|=0xe00ll;
+ else gte_rs[i]|=3ll<<(v*2);
+ }
break;
case FLOAT:
case FCONV:
branch_regs[i-1].is32|=1LL<<31;
}
memcpy(&branch_regs[i-1].regmap_entry,&branch_regs[i-1].regmap,sizeof(current.regmap));
- memcpy(constmap[i],constmap[i-1],sizeof(current.constmap));
+ memcpy(constmap[i],constmap[i-1],sizeof(current_constmap));
break;
case RJUMP:
memcpy(&branch_regs[i-1],¤t,sizeof(current));
}
#endif
memcpy(&branch_regs[i-1].regmap_entry,&branch_regs[i-1].regmap,sizeof(current.regmap));
- memcpy(constmap[i],constmap[i-1],sizeof(current.constmap));
+ memcpy(constmap[i],constmap[i-1],sizeof(current_constmap));
break;
case CJUMP:
if((opcode[i-1]&0x3E)==4) // BEQ/BNE
branch_regs[i-1].isconst=0;
branch_regs[i-1].wasconst=0;
memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap));
- memcpy(constmap[i],constmap[i-1],sizeof(current.constmap));
+ memcpy(constmap[i],constmap[i-1],sizeof(current_constmap));
}
else
if((opcode[i-1]&0x3E)==6) // BLEZ/BGTZ
branch_regs[i-1].isconst=0;
branch_regs[i-1].wasconst=0;
memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap));
- memcpy(constmap[i],constmap[i-1],sizeof(current.constmap));
+ memcpy(constmap[i],constmap[i-1],sizeof(current_constmap));
}
else
// Alloc the delay slot in case the branch is taken
branch_regs[i-1].isconst=0;
branch_regs[i-1].wasconst=0;
memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap));
- memcpy(constmap[i],constmap[i-1],sizeof(current.constmap));
+ memcpy(constmap[i],constmap[i-1],sizeof(current_constmap));
}
else
// Alloc the delay slot in case the branch is taken
{
cc=0;
}
-#ifdef PCSX
+#if defined(PCSX) && !defined(DRC_DBG)
else if(itype[i]==C2OP&>e_cycletab[source[i]&0x3f]>2)
{
// GTE runs in parallel until accessed, divide by 2 for a rough guess
regs[i].is32=current.is32;
regs[i].dirty=current.dirty;
regs[i].isconst=current.isconst;
- memcpy(constmap[i],current.constmap,sizeof(current.constmap));
+ memcpy(constmap[i],current_constmap,sizeof(current_constmap));
}
for(hr=0;hr<HOST_REGS;hr++) {
if(hr!=EXCLUDE_REG&®s[i].regmap[hr]>=0) {
// If we're within 256K of the end of the buffer,
// start over from the beginning. (Is 256K enough?)
- if((int)out>BASE_ADDR+(1<<TARGET_SIZE_2)-MAX_OUTPUT_BLOCK_SIZE) out=(u_char *)BASE_ADDR;
+ if((u_int)out>(u_int)BASE_ADDR+(1<<TARGET_SIZE_2)-MAX_OUTPUT_BLOCK_SIZE) out=(u_char *)BASE_ADDR;
// Trap writes to any of the pages we compiled
for(i=start>>12;i<=(start+slen*4)>>12;i++) {
/* Pass 10 - Free memory by expiring oldest blocks */
- int end=((((int)out-BASE_ADDR)>>(TARGET_SIZE_2-16))+16384)&65535;
+ int end=((((int)out-(int)BASE_ADDR)>>(TARGET_SIZE_2-16))+16384)&65535;
while(expirep!=end)
{
int shift=TARGET_SIZE_2-3; // Divide into 8 blocks
- int base=BASE_ADDR+((expirep>>13)<<shift); // Base address of this block
+ int base=(int)BASE_ADDR+((expirep>>13)<<shift); // Base address of this block
inv_debug("EXP: Phase %d\n",expirep);
switch((expirep>>11)&3)
{