aboutsummaryrefslogtreecommitdiff
path: root/libpcsxcore/new_dynarec/new_dynarec.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpcsxcore/new_dynarec/new_dynarec.c')
-rw-r--r--libpcsxcore/new_dynarec/new_dynarec.c354
1 files changed, 157 insertions, 197 deletions
diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c
index d8d8991..5120df0 100644
--- a/libpcsxcore/new_dynarec/new_dynarec.c
+++ b/libpcsxcore/new_dynarec/new_dynarec.c
@@ -74,17 +74,17 @@ struct regstat
u_int waswritten; // MIPS regs that were used as store base before
};
+// note: asm depends on this layout
struct ll_entry
{
u_int vaddr;
- u_int reg32;
+ u_int reg_sv_flags;
void *addr;
struct ll_entry *next;
};
u_int start;
u_int *source;
- u_int pagelimit;
char insn[MAXBLOCK][10];
u_char itype[MAXBLOCK];
u_char opcode[MAXBLOCK];
@@ -140,7 +140,7 @@ struct ll_entry
int is_delayslot;
int cop1_usable;
u_char *out;
- struct ll_entry *jump_in[4096];
+ struct ll_entry *jump_in[4096] __attribute__((aligned(16)));
struct ll_entry *jump_out[4096];
struct ll_entry *jump_dirty[4096];
u_int hash_table[65536][4] __attribute__((aligned(16)));
@@ -395,7 +395,7 @@ void *get_addr(u_int vaddr)
//printf("TRACE: count=%d next=%d (get_addr %x,page %d)\n",Count,next_interupt,vaddr,page);
head=jump_in[page];
while(head!=NULL) {
- if(head->vaddr==vaddr&&head->reg32==0) {
+ if(head->vaddr==vaddr) {
//printf("TRACE: count=%d next=%d (get_addr match %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
ht_bin[3]=ht_bin[1];
@@ -408,7 +408,7 @@ void *get_addr(u_int vaddr)
}
head=jump_dirty[vpage];
while(head!=NULL) {
- if(head->vaddr==vaddr&&head->reg32==0) {
+ if(head->vaddr==vaddr) {
//printf("TRACE: count=%d next=%d (get_addr match dirty %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
// Don't restore blocks which are about to expire from the cache
if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2)))
@@ -467,94 +467,6 @@ void *get_addr_ht(u_int vaddr)
return get_addr(vaddr);
}
-void *get_addr_32(u_int vaddr,u_int flags)
-{
-#ifdef FORCE32
- return get_addr(vaddr);
-#else
- //printf("TRACE: count=%d next=%d (get_addr_32 %x,flags %x)\n",Count,next_interupt,vaddr,flags);
- int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
- if(ht_bin[0]==vaddr) return (void *)ht_bin[1];
- if(ht_bin[2]==vaddr) return (void *)ht_bin[3];
- u_int page=get_page(vaddr);
- u_int vpage=get_vpage(vaddr);
- struct ll_entry *head;
- head=jump_in[page];
- while(head!=NULL) {
- if(head->vaddr==vaddr&&(head->reg32&flags)==0) {
- //printf("TRACE: count=%d next=%d (get_addr_32 match %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
- if(head->reg32==0) {
- int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
- if(ht_bin[0]==-1) {
- ht_bin[1]=(int)head->addr;
- ht_bin[0]=vaddr;
- }else if(ht_bin[2]==-1) {
- ht_bin[3]=(int)head->addr;
- ht_bin[2]=vaddr;
- }
- //ht_bin[3]=ht_bin[1];
- //ht_bin[2]=ht_bin[0];
- //ht_bin[1]=(int)head->addr;
- //ht_bin[0]=vaddr;
- }
- return head->addr;
- }
- head=head->next;
- }
- head=jump_dirty[vpage];
- while(head!=NULL) {
- if(head->vaddr==vaddr&&(head->reg32&flags)==0) {
- //printf("TRACE: count=%d next=%d (get_addr_32 match dirty %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
- // Don't restore blocks which are about to expire from the cache
- if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2)))
- if(verify_dirty(head->addr)) {
- //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,invalid_code[vaddr>>12]);
- invalid_code[vaddr>>12]=0;
- inv_code_start=inv_code_end=~0;
- memory_map[vaddr>>12]|=0x40000000;
- if(vpage<2048) {
-#ifndef DISABLE_TLB
- if(tlb_LUT_r[vaddr>>12]) {
- invalid_code[tlb_LUT_r[vaddr>>12]>>12]=0;
- memory_map[tlb_LUT_r[vaddr>>12]>>12]|=0x40000000;
- }
-#endif
- restore_candidate[vpage>>3]|=1<<(vpage&7);
- }
- else restore_candidate[page>>3]|=1<<(page&7);
- if(head->reg32==0) {
- int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
- if(ht_bin[0]==-1) {
- ht_bin[1]=(int)head->addr;
- ht_bin[0]=vaddr;
- }else if(ht_bin[2]==-1) {
- ht_bin[3]=(int)head->addr;
- ht_bin[2]=vaddr;
- }
- //ht_bin[3]=ht_bin[1];
- //ht_bin[2]=ht_bin[0];
- //ht_bin[1]=(int)head->addr;
- //ht_bin[0]=vaddr;
- }
- return head->addr;
- }
- }
- head=head->next;
- }
- //printf("TRACE: count=%d next=%d (get_addr_32 no-match %x,flags %x)\n",Count,next_interupt,vaddr,flags);
- int r=new_recompile_block(vaddr);
- if(r==0) return get_addr(vaddr);
- // Execute in unmapped page, generate pagefault execption
- Status|=2;
- Cause=(vaddr<<31)|0x8;
- EPC=(vaddr&1)?vaddr-5:vaddr;
- BadVAddr=(vaddr&~1);
- Context=(Context&0xFF80000F)|((BadVAddr>>9)&0x007FFFF0);
- EntryHi=BadVAddr&0xFFFFE000;
- return get_addr_ht(0x80000000);
-#endif
-}
-
void clear_all_regs(signed char regmap[])
{
int hr;
@@ -1020,19 +932,16 @@ void ll_add(struct ll_entry **head,int vaddr,void *addr)
new_entry=malloc(sizeof(struct ll_entry));
assert(new_entry!=NULL);
new_entry->vaddr=vaddr;
- new_entry->reg32=0;
+ new_entry->reg_sv_flags=0;
new_entry->addr=addr;
new_entry->next=*head;
*head=new_entry;
}
-// Add virtual address mapping for 32-bit compiled block
-void ll_add_32(struct ll_entry **head,int vaddr,u_int reg32,void *addr)
+void ll_add_flags(struct ll_entry **head,int vaddr,u_int reg_sv_flags,void *addr)
{
ll_add(head,vaddr,addr);
-#ifndef FORCE32
- (*head)->reg32=reg32;
-#endif
+ (*head)->reg_sv_flags=reg_sv_flags;
}
// Check if an address is already compiled
@@ -1052,7 +961,7 @@ void *check_addr(u_int vaddr)
struct ll_entry *head;
head=jump_in[page];
while(head!=NULL) {
- if(head->vaddr==vaddr&&head->reg32==0) {
+ if(head->vaddr==vaddr) {
if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) {
// Update existing entry with current address
if(ht_bin[0]==vaddr) {
@@ -1401,15 +1310,13 @@ void clean_blocks(u_int page)
inv_debug("INV: Restored %x (%x/%x)\n",head->vaddr, (int)head->addr, (int)clean_addr);
//printf("page=%x, addr=%x\n",page,head->vaddr);
//assert(head->vaddr>>12==(page|0x80000));
- ll_add_32(jump_in+ppage,head->vaddr,head->reg32,clean_addr);
+ ll_add_flags(jump_in+ppage,head->vaddr,head->reg_sv_flags,clean_addr);
int *ht_bin=hash_table[((head->vaddr>>16)^head->vaddr)&0xFFFF];
- if(!head->reg32) {
- if(ht_bin[0]==head->vaddr) {
- ht_bin[1]=(int)clean_addr; // Replace existing entry
- }
- if(ht_bin[2]==head->vaddr) {
- ht_bin[3]=(int)clean_addr; // Replace existing entry
- }
+ if(ht_bin[0]==head->vaddr) {
+ ht_bin[1]=(int)clean_addr; // Replace existing entry
+ }
+ if(ht_bin[2]==head->vaddr) {
+ ht_bin[3]=(int)clean_addr; // Replace existing entry
}
}
}
@@ -8151,17 +8058,132 @@ void new_dynarec_cleanup()
#endif
}
-int new_recompile_block(int addr)
+static u_int *get_source_start(u_int addr, u_int *limit)
{
-/*
- if(addr==0x800cd050) {
- int block;
- for(block=0x80000;block<0x80800;block++) invalidate_block(block);
- int n;
- for(n=0;n<=2048;n++) ll_clear(jump_dirty+n);
+ if (addr < 0x00200000 ||
+ (0xa0000000 <= addr && addr < 0xa0200000)) {
+ // used for BIOS calls mostly?
+ *limit = (addr&0xa0000000)|0x00200000;
+ return (u_int *)((u_int)rdram + (addr&0x1fffff));
+ }
+ else if (!Config.HLE && (
+ /* (0x9fc00000 <= addr && addr < 0x9fc80000) ||*/
+ (0xbfc00000 <= addr && addr < 0xbfc80000))) {
+ // BIOS
+ *limit = (addr & 0xfff00000) | 0x80000;
+ return (u_int *)((u_int)psxR + (addr&0x7ffff));
+ }
+ else if (addr >= 0x80000000 && addr < 0x80000000+RAM_SIZE) {
+ *limit = (addr & 0x80600000) + 0x00200000;
+ return (u_int *)((u_int)rdram + (addr&0x1fffff));
+ }
+}
+
+static u_int scan_for_ret(u_int addr)
+{
+ u_int limit = 0;
+ u_int *mem;
+
+ mem = get_source_start(addr, &limit);
+ if (mem == NULL)
+ return addr;
+
+ if (limit > addr + 0x1000)
+ limit = addr + 0x1000;
+ for (; addr < limit; addr += 4, mem++) {
+ if (*mem == 0x03e00008) // jr $ra
+ return addr + 8;
+ }
+}
+
+struct savestate_block {
+ uint32_t addr;
+ uint32_t regflags;
+};
+
+static int addr_cmp(const void *p1_, const void *p2_)
+{
+ const struct savestate_block *p1 = p1_, *p2 = p2_;
+ return p1->addr - p2->addr;
+}
+
+int new_dynarec_save_blocks(void *save, int size)
+{
+ struct savestate_block *blocks = save;
+ int maxcount = size / sizeof(blocks[0]);
+ struct savestate_block tmp_blocks[1024];
+ struct ll_entry *head;
+ int p, s, d, o, bcnt;
+ u_int addr;
+
+ o = 0;
+ for (p = 0; p < sizeof(jump_in) / sizeof(jump_in[0]); p++) {
+ bcnt = 0;
+ for (head = jump_in[p]; head != NULL; head = head->next) {
+ tmp_blocks[bcnt].addr = head->vaddr;
+ tmp_blocks[bcnt].regflags = head->reg_sv_flags;
+ bcnt++;
+ }
+ if (bcnt < 1)
+ continue;
+ qsort(tmp_blocks, bcnt, sizeof(tmp_blocks[0]), addr_cmp);
+
+ addr = tmp_blocks[0].addr;
+ for (s = d = 0; s < bcnt; s++) {
+ if (tmp_blocks[s].addr < addr)
+ continue;
+ if (d == 0 || tmp_blocks[d-1].addr != tmp_blocks[s].addr)
+ tmp_blocks[d++] = tmp_blocks[s];
+ addr = scan_for_ret(tmp_blocks[s].addr);
+ }
+
+ if (o + d > maxcount)
+ d = maxcount - o;
+ memcpy(&blocks[o], tmp_blocks, d * sizeof(blocks[0]));
+ o += d;
}
-*/
- //if(Count==365117028) tracedebug=1;
+
+ return o * sizeof(blocks[0]);
+}
+
+void new_dynarec_load_blocks(const void *save, int size)
+{
+ const struct savestate_block *blocks = save;
+ int count = size / sizeof(blocks[0]);
+ u_int regs_save[32];
+ uint32_t f;
+ int i, b;
+
+ get_addr(psxRegs.pc);
+
+ // change GPRs for speculation to at least partially work..
+ memcpy(regs_save, &psxRegs.GPR, sizeof(regs_save));
+ for (i = 1; i < 32; i++)
+ psxRegs.GPR.r[i] = 0x80000000;
+
+ for (b = 0; b < count; b++) {
+ for (f = blocks[b].regflags, i = 0; f; f >>= 1, i++) {
+ if (f & 1)
+ psxRegs.GPR.r[i] = 0x1f800000;
+ }
+
+ get_addr(blocks[b].addr);
+
+ for (f = blocks[b].regflags, i = 0; f; f >>= 1, i++) {
+ if (f & 1)
+ psxRegs.GPR.r[i] = 0x80000000;
+ }
+ }
+
+ memcpy(&psxRegs.GPR, regs_save, sizeof(regs_save));
+}
+
+int new_recompile_block(int addr)
+{
+ u_int pagelimit = 0;
+ u_int state_rflags = 0;
+ int i;
+
assem_debug("NOTCOMPILED: addr = %x -> %x\n", (int)addr, (int)out);
//printf("NOTCOMPILED: addr = %x -> %x\n", (int)addr, (int)out);
//printf("TRACE: count=%d next=%d (compile %x)\n",Count,next_interupt,addr);
@@ -8172,10 +8194,16 @@ int new_recompile_block(int addr)
rlist();
}*/
//rlist();
+
+ // this is just for speculation
+ for (i = 1; i < 32; i++) {
+ if ((psxRegs.GPR.r[i] & 0xffff0000) == 0x1f800000)
+ state_rflags |= 1 << i;
+ }
+
start = (u_int)addr&~3;
//assert(((u_int)addr&1)==0);
new_dynarec_did_compile=1;
-#ifdef PCSX
if (Config.HLE && start == 0x80001000) // hlecall
{
// XXX: is this enough? Maybe check hleSoftCall?
@@ -8189,62 +8217,13 @@ int new_recompile_block(int addr)
#ifdef __arm__
__clear_cache((void *)beginning,out);
#endif
- ll_add(jump_in+page,start,(void *)beginning);
+ ll_add_flags(jump_in+page,start,state_rflags,(void *)beginning);
return 0;
}
- else if ((u_int)addr < 0x00200000 ||
- (0xa0000000 <= addr && addr < 0xa0200000)) {
- // used for BIOS calls mostly?
- source = (u_int *)((u_int)rdram+(start&0x1fffff));
- pagelimit = (addr&0xa0000000)|0x00200000;
- }
- else if (!Config.HLE && (
-/* (0x9fc00000 <= addr && addr < 0x9fc80000) ||*/
- (0xbfc00000 <= addr && addr < 0xbfc80000))) {
- // BIOS
- source = (u_int *)((u_int)psxR+(start&0x7ffff));
- pagelimit = (addr&0xfff00000)|0x80000;
- }
- else
-#endif
-#ifdef MUPEN64
- if ((int)addr >= 0xa4000000 && (int)addr < 0xa4001000) {
- source = (u_int *)((u_int)SP_DMEM+start-0xa4000000);
- pagelimit = 0xa4001000;
- }
- else
-#endif
- if ((int)addr >= 0x80000000 && (int)addr < 0x80000000+RAM_SIZE) {
- source = (u_int *)((u_int)rdram+start-0x80000000);
- pagelimit = 0x80000000+RAM_SIZE;
- }
-#ifndef DISABLE_TLB
- else if ((signed int)addr >= (signed int)0xC0000000) {
- //printf("addr=%x mm=%x\n",(u_int)addr,(memory_map[start>>12]<<2));
- //if(tlb_LUT_r[start>>12])
- //source = (u_int *)(((int)rdram)+(tlb_LUT_r[start>>12]&0xFFFFF000)+(((int)addr)&0xFFF)-0x80000000);
- if((signed int)memory_map[start>>12]>=0) {
- source = (u_int *)((u_int)(start+(memory_map[start>>12]<<2)));
- pagelimit=(start+4096)&0xFFFFF000;
- int map=memory_map[start>>12];
- int i;
- for(i=0;i<5;i++) {
- //printf("start: %x next: %x\n",map,memory_map[pagelimit>>12]);
- if((map&0xBFFFFFFF)==(memory_map[pagelimit>>12]&0xBFFFFFFF)) pagelimit+=4096;
- }
- assem_debug("pagelimit=%x\n",pagelimit);
- assem_debug("mapping=%x (%x)\n",memory_map[start>>12],(memory_map[start>>12]<<2)+start);
- }
- else {
- assem_debug("Compile at unmapped memory address: %x \n", (int)addr);
- //assem_debug("start: %x next: %x\n",memory_map[start>>12],memory_map[(start+4096)>>12]);
- return -1; // Caller will invoke exception handler
- }
- //printf("source= %x\n",(int)source);
- }
-#endif
- else {
- SysPrintf("Compile at bogus memory address: %x \n", (int)addr);
+
+ source = get_source_start(start, &pagelimit);
+ if (source == NULL) {
+ SysPrintf("Compile at bogus memory address: %08x\n", addr);
exit(1);
}
@@ -8259,7 +8238,7 @@ int new_recompile_block(int addr)
/* Pass 9: linker */
/* Pass 10: garbage collection / free memory */
- int i,j;
+ int j;
int done=0;
unsigned int type,op,op2;
@@ -9906,6 +9885,10 @@ int new_recompile_block(int addr)
{
cc+=2; // 2 cycle penalty (after CLOCK_DIVIDER)
}
+ else if(i>1&&itype[i]==STORE&&itype[i-1]==STORE&&itype[i-2]==STORE&&!bt[i])
+ {
+ cc+=4;
+ }
else if(itype[i]==C2LS)
{
cc+=4;
@@ -11569,18 +11552,12 @@ int new_recompile_block(int addr)
u_int page=get_page(vaddr);
u_int vpage=get_vpage(vaddr);
literal_pool(256);
- //if(!(is32[i]&(~unneeded_reg_upper[i])&~(1LL<<CCREG)))
-#ifndef FORCE32
- if(!requires_32bit[i])
-#else
- if(1)
-#endif
{
assem_debug("%8x (%d) <- %8x\n",instr_addr[i],i,start+i*4);
assem_debug("jump_in: %x\n",start+i*4);
ll_add(jump_dirty+vpage,vaddr,(void *)out);
int entry_point=do_dirty_stub(i);
- ll_add(jump_in+page,vaddr,(void *)entry_point);
+ ll_add_flags(jump_in+page,vaddr,state_rflags,(void *)entry_point);
// If there was an existing entry in the hash table,
// replace it with the new address.
// Don't add new entries. We'll insert the
@@ -11593,23 +11570,6 @@ int new_recompile_block(int addr)
ht_bin[3]=entry_point;
}
}
- else
- {
- u_int r=requires_32bit[i]|!!(requires_32bit[i]>>32);
- assem_debug("%8x (%d) <- %8x\n",instr_addr[i],i,start+i*4);
- assem_debug("jump_in: %x (restricted - %x)\n",start+i*4,r);
- //int entry_point=(int)out;
- ////assem_debug("entry_point: %x\n",entry_point);
- //load_regs_entry(i);
- //if(entry_point==(int)out)
- // entry_point=instr_addr[i];
- //else
- // emit_jmp(instr_addr[i]);
- //ll_add_32(jump_in+page,vaddr,r,(void *)entry_point);
- ll_add_32(jump_dirty+vpage,vaddr,r,(void *)out);
- int entry_point=do_dirty_stub(i);
- ll_add_32(jump_in+page,vaddr,r,(void *)entry_point);
- }
}
}
}