#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
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];
int new_dynarec_did_compile;
int new_dynarec_hacks;
u_int stop_after_jal;
+#ifndef RAM_FIXED
+ static u_int ram_offset;
+#else
+ static const u_int ram_offset=0;
+#endif
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);
if(vpage>2047||(head->vaddr>>12)==block) { // Ignore vaddr hash collision
get_bounds((int)head->addr,&start,&end);
//printf("start: %x end: %x\n",start,end);
- if(page<2048&&start>=0x80000000&&end<0x80000000+RAM_SIZE) {
+ if(page<2048&&start>=(u_int)rdram&&end<(u_int)rdram+RAM_SIZE) {
if(((start-(u_int)rdram)>>12)<=page&&((end-1-(u_int)rdram)>>12)>=page) {
if((((start-(u_int)rdram)>>12)&2047)<first) first=((start-(u_int)rdram)>>12)&2047;
if((((end-1-(u_int)rdram)>>12)&2047)>last) last=((end-1-(u_int)rdram)>>12)&2047;
//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;
- int mask=RAM_SIZE-1;
+ u_int mask=RAM_SIZE-1;
+ u_int addr_main=0x80000000|(addr&mask);
int pg1;
- inv_code_start=addr&~0xfff;
- inv_code_end=addr|0xfff;
+ inv_code_start=addr_main&~0xfff;
+ inv_code_end=addr_main|0xfff;
pg1=page;
if (pg1>0) {
// must check previous page too because of spans..
for(head=jump_dirty[pg1];head!=NULL;head=head->next) {
u_int start,end;
get_bounds((int)head->addr,&start,&end);
- if((start&mask)<=(addr&mask)&&(addr&mask)<(end&mask)) {
+ if(ram_offset) {
+ start-=ram_offset;
+ end-=ram_offset;
+ }
+ if(start<=addr_main&&addr_main<end) {
if(start<addr_min) addr_min=start;
if(end>addr_max) addr_max=end;
}
- else if(addr<start) {
+ else if(addr_main<start) {
if(start<inv_code_end)
inv_code_end=start-1;
}
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_code_start=(addr&~mask)|(inv_code_start&mask);
+ inv_code_end=(addr&~mask)|(inv_code_end&mask);
+ 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=emit_fastpath_cmp_jump(i,addr,&fastload_reg_override);
}
}
+ else if(ram_offset&&memtarget) {
+ emit_addimm(addr,ram_offset,HOST_TEMPREG);
+ fastload_reg_override=HOST_TEMPREG;
+ }
}else{ // using tlb
int x=0;
if (opcode[i]==0x20||opcode[i]==0x24) x=3; // LB/LBU
gen_tlb_addr_r(a,map);
emit_movswl_indexed(x,a,tl);
}else{
- #ifdef RAM_OFFSET
+ #if 1 //def RAM_OFFSET
emit_movswl_indexed(x,a,tl);
#else
emit_movswl_indexed((int)rdram-0x80000000+x,a,tl);
gen_tlb_addr_r(a,map);
emit_movzwl_indexed(x,a,tl);
}else{
- #ifdef RAM_OFFSET
+ #if 1 //def RAM_OFFSET
emit_movzwl_indexed(x,a,tl);
#else
emit_movzwl_indexed((int)rdram-0x80000000+x,a,tl);
jaddr=emit_fastpath_cmp_jump(i,addr,&faststore_reg_override);
#endif
}
+ else if(ram_offset&&memtarget) {
+ emit_addimm(addr,ram_offset,HOST_TEMPREG);
+ faststore_reg_override=HOST_TEMPREG;
+ }
}else{ // using tlb
int x=0;
if (opcode[i]==0x28) x=3; // SB
gen_tlb_addr_w(a,map);
emit_writehword_indexed(tl,x,a);
}else
- emit_writehword_indexed(tl,(int)rdram-0x80000000+x,a);
+ //emit_writehword_indexed(tl,(int)rdram-0x80000000+x,a);
+ emit_writehword_indexed(tl,x,a);
}
type=STOREH_STUB;
}
#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) {
jaddr2=emit_fastpath_cmp_jump(i,ar,&fastio_reg_override);
}
+ else if(ram_offset&&memtarget) {
+ emit_addimm(ar,ram_offset,HOST_TEMPREG);
+ fastio_reg_override=HOST_TEMPREG;
+ }
if (opcode[i]==0x32) { // LWC2
#ifdef HOST_IMM_ADDR32
if(c) emit_readword_tlb(constmap[i][s]+offset,-1,tl);
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]; // MFC2/CFC2 to dead register, unneeded
+ 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]);
{
printf("Init new dynarec\n");
out=(u_char *)BASE_ADDR;
+#if 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;
#endif
tlb_hacks();
arch_init();
+#ifndef RAM_FIXED
+ ram_offset=(u_int)rdram-0x80000000;
+#endif
}
void new_dynarec_cleanup()
{
int n;
+ #if 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);
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)
{