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
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
#define COP2 27 // Coprocessor 2 move
#define C2LS 28 // Coprocessor 2 load/store
#define C2OP 29 // Coprocessor 2 operation
+#define INTCALL 30// Call interpreter to handle rare corner cases
/* stubs */
#define CC_STUB 1
void jump_syscall_hle();
void jump_eret();
void jump_hlecall();
+void jump_intcall();
void new_dyna_leave();
// TLB
static u_int get_page(u_int vaddr)
{
+#ifndef PCSX
u_int page=(vaddr^0x80000000)>>12;
+#else
+ u_int page=vaddr&~0xe0000000;
+ if (page < 0x1000000)
+ page &= ~0x0e00000; // RAM mirrors
+ page>>=12;
+#endif
#ifndef DISABLE_TLB
if(page>262143&&tlb_LUT_r[vaddr>>12]) page=(tlb_LUT_r[vaddr>>12]^0x80000000)>>12;
#endif
{
#ifdef FORCE32
return get_addr(vaddr);
-#endif
+#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];
Context=(Context&0xFF80000F)|((BadVAddr>>9)&0x007FFFF0);
EntryHi=BadVAddr&0xFFFFE000;
return get_addr_ht(0x80000000);
+#endif
}
void clear_all_regs(signed char regmap[])
if(itype[i]==LOADLR) {
hsn[FTEMP]=0;
}
- // Also 64-bit SDL/SDR
- if(opcode[i]==0x2c||opcode[i]==0x2d) {
+ // Also SWL/SWR/SDL/SDR
+ if(opcode[i]==0x2a||opcode[i]==0x2e||opcode[i]==0x2c||opcode[i]==0x2d) {
hsn[FTEMP]=0;
}
// Don't remove the TLB registers either
j++;
break;
}
- if(itype[i+j]==SYSCALL||itype[i+j]==HLECALL||((source[i+j]&0xfc00003f)==0x0d))
+ if(itype[i+j]==SYSCALL||itype[i+j]==HLECALL||itype[i+j]==INTCALL||((source[i+j]&0xfc00003f)==0x0d))
{
break;
}
(((ptr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==(addr>>shift)))
{
inv_debug("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr);
- kill_pointer(head->addr);
+ u_int host_addr=(u_int)kill_pointer(head->addr);
+ #ifdef __arm__
+ needs_clear_cache[(host_addr-(u_int)BASE_ADDR)>>17]|=1<<(((host_addr-(u_int)BASE_ADDR)>>12)&31);
+ #endif
}
head=head->next;
}
}
// This is called when we write to a compiled block (see do_invstub)
-int invalidate_page(u_int page)
+void invalidate_page(u_int page)
{
- int modified=0;
struct ll_entry *head;
struct ll_entry *next;
head=jump_in[page];
jump_out[page]=0;
while(head!=NULL) {
inv_debug("INVALIDATE: kill pointer to %x (%x)\n",head->vaddr,(int)head->addr);
- kill_pointer(head->addr);
- modified=1;
+ u_int host_addr=(u_int)kill_pointer(head->addr);
+ #ifdef __arm__
+ needs_clear_cache[(host_addr-(u_int)BASE_ADDR)>>17]|=1<<(((host_addr-(u_int)BASE_ADDR)>>12)&31);
+ #endif
next=head->next;
free(head);
head=next;
}
- return modified;
}
void invalidate_block(u_int block)
{
- int modified;
u_int page=get_page(block<<12);
u_int vpage=get_vpage(block<<12);
inv_debug("INVALIDATE: %x (%d)\n",block<<12,page);
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<0x80800000) {
+ if(page<2048&&start>=0x80000000&&end<0x80000000+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;
head=head->next;
}
//printf("first=%d last=%d\n",first,last);
- modified=invalidate_page(page);
+ invalidate_page(page);
assert(first+5>page); // NB: this assumes MAXBLOCK<=4096 (4 pages)
assert(last<page+5);
// Invalidate the adjacent pages if a block crosses a 4K boundary
for(first=page+1;first<last;first++) {
invalidate_page(first);
}
+ #ifdef __arm__
+ do_clear_cache();
+ #endif
// 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]) {
}
else if(block>=0x80000&&block<0x80800) memory_map[block]=((u_int)rdram-0x80000000)>>2;
#endif
- #ifdef __arm__
- if(modified)
- __clear_cache((void *)BASE_ADDR,(void *)BASE_ADDR+(1<<TARGET_SIZE_2));
- #endif
+
#ifdef USE_MINI_HT
memset(mini_ht,-1,sizeof(mini_ht));
#endif
{
invalidate_block(addr>>12);
}
+// This is called when loading a save state.
+// Anything could have changed, so invalidate everything.
void invalidate_all_pages()
{
u_int page,n;
u_int i;
u_int inv=0;
get_bounds((int)head->addr,&start,&end);
- if(start-(u_int)rdram<0x800000) {
+ if(start-(u_int)rdram<RAM_SIZE) {
for(i=(start-(u_int)rdram+0x80000000)>>12;i<=(end-1-(u_int)rdram+0x80000000)>>12;i++) {
inv|=invalid_code[i];
}
//printf("addr=%x start=%x end=%x\n",addr,start,end);
if(addr<start||addr>=end) inv=1;
}
- else if((signed int)head->vaddr>=(signed int)0x80800000) {
+ else if((signed int)head->vaddr>=(signed int)0x80000000+RAM_SIZE) {
inv=1;
}
if(!inv) {
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(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]);
if(rt1[i]) {
alloc_reg(current,i,rt1[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
{
current->is32&=~(1LL<<rt1[i]);
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
{
// Load to r0 (dummy load)
// but we still need a register to calculate the address
+ if(opcode[i]==0x22||opcode[i]==0x26)
+ {
+ 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;
+ }
}
}
// On CPUs without 32-bit immediates we need a pointer to invalid_code
else alloc_reg(current,i,INVCP);
#endif
- if(opcode[i]==0x2c||opcode[i]==0x2d) { // 64-bit SDL/SDR
+ if(opcode[i]==0x2a||opcode[i]==0x2e||opcode[i]==0x2c||opcode[i]==0x2d) { // SWL/SWL/SDL/SDR
alloc_reg(current,i,FTEMP);
}
// 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(current,i,CSREG); // Load status
if(opcode2[i]<3) // MFC1/DMFC1/CFC1
{
- assert(rt1[i]);
- clear_const(current,rt1[i]);
- if(opcode2[i]==1) {
- alloc_reg64(current,i,rt1[i]); // DMFC1
- current->is32&=~(1LL<<rt1[i]);
- }else{
- alloc_reg(current,i,rt1[i]); // MFC1/CFC1
- current->is32|=1LL<<rt1[i];
+ if(rt1[i]){
+ clear_const(current,rt1[i]);
+ if(opcode2[i]==1) {
+ alloc_reg64(current,i,rt1[i]); // DMFC1
+ current->is32&=~(1LL<<rt1[i]);
+ }else{
+ alloc_reg(current,i,rt1[i]); // MFC1/CFC1
+ current->is32|=1LL<<rt1[i];
+ }
+ dirty_reg(current,rt1[i]);
}
- dirty_reg(current,rt1[i]);
alloc_reg_temp(current,i,-1);
}
else if(opcode2[i]>3) // MTC1/DMTC1/CTC1
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(opcode[i]==0&&(opcode2[i]&0x3E)==8) // JR/JALR
{
alloc_reg(current,i,rs1[i]);
- if (rt1[i]==31) {
- alloc_reg(current,i,31);
- dirty_reg(current,31);
+ if (rt1[i]!=0) {
+ alloc_reg(current,i,rt1[i]);
+ dirty_reg(current,rt1[i]);
}
}
if((opcode[i]&0x2E)==4) // BEQ/BNE/BEQL/BNEL
int s,th,tl,addr,map=-1;
int offset;
int jaddr=0;
- int memtarget,c=0;
+ int memtarget=0,c=0;
u_int hr,reglist=0;
th=get_reg(i_regs->regmap,rt1[i]|64);
tl=get_reg(i_regs->regmap,rt1[i]);
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)0x80800000;
- 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);
+ // FIXME: Even if the load is a NOP, we should check for pagefaults...
+#ifdef PCSX
+ if(tl<0&&(!c||(((u_int)constmap[i][s]+offset)>>16)==0x1f80)
+ ||rt1[i]==0) {
+ // could be FIFO, must perform the read
+ // ||dummy read
+ assem_debug("(forced read)\n");
+ tl=get_reg(i_regs->regmap,-1);
+ assert(tl>=0);
}
+#endif
if(offset||s<0||c) addr=tl;
else addr=s;
+ //if(tl<0) tl=get_reg(i_regs->regmap,-1);
+ if(tl>=0) {
//printf("load_assemble: c=%d\n",c);
//if(c) printf("load_assemble: const=%x\n",(int)constmap[i][s]+offset);
- // FIXME: Even if the load is a NOP, we should check for pagefaults...
- if(tl>=0) {
- //assert(tl>=0);
- //assert(rt1[i]);
- reglist&=~(1<<tl);
- if(th>=0) reglist&=~(1<<th);
- if(!using_tlb) {
- if(!c) {
+ assert(tl>=0); // Even if the load is a NOP, we must check for pagefaults and I/O
+ reglist&=~(1<<tl);
+ if(th>=0) reglist&=~(1<<th);
+ if(!using_tlb) {
+ if(!c) {
+ #ifdef RAM_OFFSET
+ map=get_reg(i_regs->regmap,ROREG);
+ if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG);
+ #endif
//#define R29_HACK 1
- #ifdef R29_HACK
- // Strmnnrmn's speed hack
- if(rs1[i]!=29||start<0x80001000||start>=0x80800000)
+ #ifdef R29_HACK
+ // Strmnnrmn's speed hack
+ if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE)
+ #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_cmpimm(addr,0x800000);
- 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);
- }
+ emit_jno(0);
}
- }else{ // using tlb
- int x=0;
- if (opcode[i]==0x20||opcode[i]==0x24) x=3; // LB/LBU
- if (opcode[i]==0x21||opcode[i]==0x25) x=2; // LH/LHU
- map=get_reg(i_regs->regmap,TLREG);
- assert(map>=0);
- map=do_tlb_r(addr,tl,map,x,-1,-1,c,constmap[i][s]+offset);
- do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr);
}
- if (opcode[i]==0x20) { // LB
- if(!c||memtarget) {
+ }else{ // using tlb
+ int x=0;
+ if (opcode[i]==0x20||opcode[i]==0x24) x=3; // LB/LBU
+ if (opcode[i]==0x21||opcode[i]==0x25) x=2; // LH/LHU
+ map=get_reg(i_regs->regmap,TLREG);
+ assert(map>=0);
+ map=do_tlb_r(addr,tl,map,x,-1,-1,c,constmap[i][s]+offset);
+ do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr);
+ }
+ int dummy=(rt1[i]==0)||(tl!=get_reg(i_regs->regmap,rt1[i])); // ignore loads to r0 and unneeded reg
+ if (opcode[i]==0x20) { // LB
+ if(!c||memtarget) {
+ if(!dummy) {
#ifdef HOST_IMM_ADDR32
if(c)
emit_movsbl_tlb((constmap[i][s]+offset)^3,map,tl);
//emit_xorimm(addr,3,tl);
//gen_tlb_addr_r(tl,map);
//emit_movsbl_indexed((int)rdram-0x80000000,tl,tl);
- int x=0;
+ int x=0,a=tl;
#ifdef BIG_ENDIAN_MIPS
if(!c) emit_xorimm(addr,3,tl);
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 (tl!=addr) emit_mov(addr,tl);
+ if(!c) a=addr;
#endif
- emit_movsbl_indexed_tlb(x,tl,map,tl);
+ emit_movsbl_indexed_tlb(x,a,map,tl);
}
- if(jaddr)
- add_stub(LOADB_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- else
- inline_readstub(LOADB_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ if(jaddr)
+ add_stub(LOADB_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- if (opcode[i]==0x21) { // LH
- if(!c||memtarget) {
+ else
+ inline_readstub(LOADB_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ }
+ if (opcode[i]==0x21) { // LH
+ if(!c||memtarget) {
+ if(!dummy) {
#ifdef HOST_IMM_ADDR32
if(c)
emit_movswl_tlb((constmap[i][s]+offset)^2,map,tl);
else
#endif
{
- int x=0;
+ int x=0,a=tl;
#ifdef BIG_ENDIAN_MIPS
if(!c) emit_xorimm(addr,2,tl);
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 (tl!=addr) emit_mov(addr,tl);
+ if(!c) a=addr;
#endif
//#ifdef
//emit_movswl_indexed_tlb(x,tl,map,tl);
//else
if(map>=0) {
- gen_tlb_addr_r(tl,map);
- emit_movswl_indexed(x,tl,tl);
- }else
- emit_movswl_indexed((int)rdram-0x80000000+x,tl,tl);
+ gen_tlb_addr_r(a,map);
+ emit_movswl_indexed(x,a,tl);
+ }else{
+ #ifdef RAM_OFFSET
+ emit_movswl_indexed(x,a,tl);
+ #else
+ emit_movswl_indexed((int)rdram-0x80000000+x,a,tl);
+ #endif
+ }
}
- if(jaddr)
- add_stub(LOADH_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- else
- inline_readstub(LOADH_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ if(jaddr)
+ add_stub(LOADH_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- if (opcode[i]==0x23) { // LW
- if(!c||memtarget) {
+ else
+ inline_readstub(LOADH_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ }
+ if (opcode[i]==0x23) { // LW
+ if(!c||memtarget) {
+ if(!dummy) {
//emit_readword_indexed((int)rdram-0x80000000,addr,tl);
#ifdef HOST_IMM_ADDR32
if(c)
else
#endif
emit_readword_indexed_tlb(0,addr,map,tl);
- if(jaddr)
- add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- else
- inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ if(jaddr)
+ add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- if (opcode[i]==0x24) { // LBU
- if(!c||memtarget) {
+ else
+ inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ }
+ if (opcode[i]==0x24) { // LBU
+ if(!c||memtarget) {
+ if(!dummy) {
#ifdef HOST_IMM_ADDR32
if(c)
emit_movzbl_tlb((constmap[i][s]+offset)^3,map,tl);
//emit_xorimm(addr,3,tl);
//gen_tlb_addr_r(tl,map);
//emit_movzbl_indexed((int)rdram-0x80000000,tl,tl);
- int x=0;
+ int x=0,a=tl;
#ifdef BIG_ENDIAN_MIPS
if(!c) emit_xorimm(addr,3,tl);
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 (tl!=addr) emit_mov(addr,tl);
+ if(!c) a=addr;
#endif
- emit_movzbl_indexed_tlb(x,tl,map,tl);
+ emit_movzbl_indexed_tlb(x,a,map,tl);
}
- if(jaddr)
- add_stub(LOADBU_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- else
- inline_readstub(LOADBU_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ if(jaddr)
+ add_stub(LOADBU_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- if (opcode[i]==0x25) { // LHU
- if(!c||memtarget) {
+ else
+ inline_readstub(LOADBU_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ }
+ if (opcode[i]==0x25) { // LHU
+ if(!c||memtarget) {
+ if(!dummy) {
#ifdef HOST_IMM_ADDR32
if(c)
emit_movzwl_tlb((constmap[i][s]+offset)^2,map,tl);
else
#endif
{
- int x=0;
+ int x=0,a=tl;
#ifdef BIG_ENDIAN_MIPS
if(!c) emit_xorimm(addr,2,tl);
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 (tl!=addr) emit_mov(addr,tl);
+ if(!c) a=addr;
#endif
//#ifdef
//emit_movzwl_indexed_tlb(x,tl,map,tl);
//#else
if(map>=0) {
- gen_tlb_addr_r(tl,map);
- emit_movzwl_indexed(x,tl,tl);
- }else
- emit_movzwl_indexed((int)rdram-0x80000000+x,tl,tl);
- if(jaddr)
- add_stub(LOADHU_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
+ gen_tlb_addr_r(a,map);
+ emit_movzwl_indexed(x,a,tl);
+ }else{
+ #ifdef RAM_OFFSET
+ emit_movzwl_indexed(x,a,tl);
+ #else
+ emit_movzwl_indexed((int)rdram-0x80000000+x,a,tl);
+ #endif
+ }
}
}
- else
- inline_readstub(LOADHU_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ if(jaddr)
+ add_stub(LOADHU_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- if (opcode[i]==0x27) { // LWU
- assert(th>=0);
- if(!c||memtarget) {
+ else
+ inline_readstub(LOADHU_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ }
+ if (opcode[i]==0x27) { // LWU
+ assert(th>=0);
+ if(!c||memtarget) {
+ if(!dummy) {
//emit_readword_indexed((int)rdram-0x80000000,addr,tl);
#ifdef HOST_IMM_ADDR32
if(c)
else
#endif
emit_readword_indexed_tlb(0,addr,map,tl);
- if(jaddr)
- add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- else {
- inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
- }
- emit_zeroreg(th);
+ if(jaddr)
+ add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
+ }
+ else {
+ inline_readstub(LOADW_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
}
- if (opcode[i]==0x37) { // LD
- if(!c||memtarget) {
+ emit_zeroreg(th);
+ }
+ if (opcode[i]==0x37) { // LD
+ if(!c||memtarget) {
+ if(!dummy) {
//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);
else
#endif
emit_readdword_indexed_tlb(0,addr,map,th,tl);
- if(jaddr)
- add_stub(LOADD_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- else
- inline_readstub(LOADD_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
+ if(jaddr)
+ add_stub(LOADD_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist);
}
- //emit_storereg(rt1[i],tl); // DEBUG
+ else
+ inline_readstub(LOADD_STUB,i,constmap[i][s]+offset,i_regs->regmap,rt1[i],ccadj[i],reglist);
}
+ }
+ //emit_storereg(rt1[i],tl); // DEBUG
//if(opcode[i]==0x23)
//if(opcode[i]==0x24)
//if(opcode[i]==0x23||opcode[i]==0x24)
offset=imm[i];
if(s>=0) {
c=(i_regs->wasconst>>s)&1;
- memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000;
- 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);
#ifdef R29_HACK
// Strmnnrmn's speed hack
memtarget=1;
- if(rs1[i]!=29||start<0x80001000||start>=0x80800000)
+ if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE)
#endif
- emit_cmpimm(addr,0x800000);
+ emit_cmpimm(addr,RAM_SIZE);
#ifdef DESTRUCTIVE_SHIFT
if(s==addr) emit_mov(s,temp);
#endif
#ifdef R29_HACK
- if(rs1[i]!=29||start<0x80001000||start>=0x80800000)
+ if(rs1[i]!=29||start<0x80001000||start>=0x80000000+RAM_SIZE)
#endif
{
jaddr=(int)out;
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
//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
//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;
}
}
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);
tl=get_reg(i_regs->regmap,rs2[i]);
s=get_reg(i_regs->regmap,rs1[i]);
- temp=get_reg(i_regs->regmap,-1);
+ temp=get_reg(i_regs->regmap,agr);
+ if(temp<0) temp=get_reg(i_regs->regmap,-1);
offset=imm[i];
if(s>=0) {
c=(i_regs->isconst>>s)&1;
- memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000;
- 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++) {
if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
}
- if(tl>=0) {
- assert(temp>=0);
- if(!using_tlb) {
- if(!c) {
- emit_cmpimm(s<0||offset?temp:s,0x800000);
- if(!offset&&s!=temp) emit_mov(s,temp);
- jaddr=(int)out;
- emit_jno(0);
- }
- else
- {
- if(!memtarget||!rs1[i]) {
- jaddr=(int)out;
- emit_jmp(0);
- }
- }
- if((u_int)rdram!=0x80000000)
- emit_addimm_no_flags((u_int)rdram-(u_int)0x80000000,temp);
- }else{ // using tlb
- int map=get_reg(i_regs->regmap,TLREG);
- assert(map>=0);
- map=do_tlb_w(c||s<0||offset?temp:s,temp,map,0,c,constmap[i][s]+offset);
- if(!c&&!offset&&s>=0) emit_mov(s,temp);
- do_tlb_w_branch(map,c,constmap[i][s]+offset,&jaddr);
- if(!jaddr&&!memtarget) {
+ assert(temp>=0);
+ if(!using_tlb) {
+ if(!c) {
+ emit_cmpimm(s<0||offset?temp:s,RAM_SIZE);
+ if(!offset&&s!=temp) emit_mov(s,temp);
+ jaddr=(int)out;
+ emit_jno(0);
+ }
+ else
+ {
+ if(!memtarget||!rs1[i]) {
jaddr=(int)out;
emit_jmp(0);
}
- gen_tlb_addr_w(temp,map);
}
-
- if (opcode[i]==0x2C||opcode[i]==0x2D) { // SDL/SDR
- temp2=get_reg(i_regs->regmap,FTEMP);
- if(!rs2[i]) temp2=th=tl;
+ #ifdef RAM_OFFSET
+ int map=get_reg(i_regs->regmap,ROREG);
+ if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG);
+ gen_tlb_addr_w(temp,map);
+ #else
+ if((u_int)rdram!=0x80000000)
+ emit_addimm_no_flags((u_int)rdram-(u_int)0x80000000,temp);
+ #endif
+ }else{ // using tlb
+ int map=get_reg(i_regs->regmap,TLREG);
+ assert(map>=0);
+ map=do_tlb_w(c||s<0||offset?temp:s,temp,map,0,c,constmap[i][s]+offset);
+ if(!c&&!offset&&s>=0) emit_mov(s,temp);
+ do_tlb_w_branch(map,c,constmap[i][s]+offset,&jaddr);
+ if(!jaddr&&!memtarget) {
+ jaddr=(int)out;
+ emit_jmp(0);
}
+ gen_tlb_addr_w(temp,map);
+ }
+
+ if (opcode[i]==0x2C||opcode[i]==0x2D) { // SDL/SDR
+ temp2=get_reg(i_regs->regmap,FTEMP);
+ if(!rs2[i]) temp2=th=tl;
+ }
#ifndef BIG_ENDIAN_MIPS
emit_xorimm(temp,3,temp);
#endif
- emit_testimm(temp,2);
- case2=(int)out;
- emit_jne(0);
- emit_testimm(temp,1);
- case1=(int)out;
- emit_jne(0);
- // 0
- if (opcode[i]==0x2A) { // SWL
- emit_writeword_indexed(tl,0,temp);
- }
- if (opcode[i]==0x2E) { // SWR
- emit_writebyte_indexed(tl,3,temp);
- }
- if (opcode[i]==0x2C) { // SDL
- emit_writeword_indexed(th,0,temp);
- if(rs2[i]) emit_mov(tl,temp2);
- }
- if (opcode[i]==0x2D) { // SDR
- emit_writebyte_indexed(tl,3,temp);
- if(rs2[i]) emit_shldimm(th,tl,24,temp2);
- }
+ emit_testimm(temp,2);
+ case2=(int)out;
+ emit_jne(0);
+ emit_testimm(temp,1);
+ case1=(int)out;
+ emit_jne(0);
+ // 0
+ if (opcode[i]==0x2A) { // SWL
+ emit_writeword_indexed(tl,0,temp);
+ }
+ if (opcode[i]==0x2E) { // SWR
+ emit_writebyte_indexed(tl,3,temp);
+ }
+ if (opcode[i]==0x2C) { // SDL
+ emit_writeword_indexed(th,0,temp);
+ if(rs2[i]) emit_mov(tl,temp2);
+ }
+ if (opcode[i]==0x2D) { // SDR
+ emit_writebyte_indexed(tl,3,temp);
+ if(rs2[i]) emit_shldimm(th,tl,24,temp2);
+ }
+ done0=(int)out;
+ emit_jmp(0);
+ // 1
+ set_jump_target(case1,(int)out);
+ if (opcode[i]==0x2A) { // SWL
+ // Write 3 msb into three least significant bytes
+ if(rs2[i]) emit_rorimm(tl,8,tl);
+ emit_writehword_indexed(tl,-1,temp);
+ if(rs2[i]) emit_rorimm(tl,16,tl);
+ emit_writebyte_indexed(tl,1,temp);
+ if(rs2[i]) emit_rorimm(tl,8,tl);
+ }
+ if (opcode[i]==0x2E) { // SWR
+ // Write two lsb into two most significant bytes
+ emit_writehword_indexed(tl,1,temp);
+ }
+ if (opcode[i]==0x2C) { // SDL
+ if(rs2[i]) emit_shrdimm(tl,th,8,temp2);
+ // Write 3 msb into three least significant bytes
+ if(rs2[i]) emit_rorimm(th,8,th);
+ emit_writehword_indexed(th,-1,temp);
+ if(rs2[i]) emit_rorimm(th,16,th);
+ emit_writebyte_indexed(th,1,temp);
+ if(rs2[i]) emit_rorimm(th,8,th);
+ }
+ if (opcode[i]==0x2D) { // SDR
+ if(rs2[i]) emit_shldimm(th,tl,16,temp2);
+ // Write two lsb into two most significant bytes
+ emit_writehword_indexed(tl,1,temp);
+ }
+ done1=(int)out;
+ emit_jmp(0);
+ // 2
+ set_jump_target(case2,(int)out);
+ emit_testimm(temp,1);
+ case3=(int)out;
+ emit_jne(0);
+ if (opcode[i]==0x2A) { // SWL
+ // Write two msb into two least significant bytes
+ if(rs2[i]) emit_rorimm(tl,16,tl);
+ emit_writehword_indexed(tl,-2,temp);
+ if(rs2[i]) emit_rorimm(tl,16,tl);
+ }
+ if (opcode[i]==0x2E) { // SWR
+ // Write 3 lsb into three most significant bytes
+ emit_writebyte_indexed(tl,-1,temp);
+ if(rs2[i]) emit_rorimm(tl,8,tl);
+ emit_writehword_indexed(tl,0,temp);
+ if(rs2[i]) emit_rorimm(tl,24,tl);
+ }
+ if (opcode[i]==0x2C) { // SDL
+ if(rs2[i]) emit_shrdimm(tl,th,16,temp2);
+ // Write two msb into two least significant bytes
+ if(rs2[i]) emit_rorimm(th,16,th);
+ emit_writehword_indexed(th,-2,temp);
+ if(rs2[i]) emit_rorimm(th,16,th);
+ }
+ if (opcode[i]==0x2D) { // SDR
+ if(rs2[i]) emit_shldimm(th,tl,8,temp2);
+ // Write 3 lsb into three most significant bytes
+ emit_writebyte_indexed(tl,-1,temp);
+ if(rs2[i]) emit_rorimm(tl,8,tl);
+ emit_writehword_indexed(tl,0,temp);
+ if(rs2[i]) emit_rorimm(tl,24,tl);
+ }
+ done2=(int)out;
+ emit_jmp(0);
+ // 3
+ set_jump_target(case3,(int)out);
+ if (opcode[i]==0x2A) { // SWL
+ // Write msb into least significant byte
+ if(rs2[i]) emit_rorimm(tl,24,tl);
+ emit_writebyte_indexed(tl,-3,temp);
+ if(rs2[i]) emit_rorimm(tl,8,tl);
+ }
+ if (opcode[i]==0x2E) { // SWR
+ // Write entire word
+ emit_writeword_indexed(tl,-3,temp);
+ }
+ if (opcode[i]==0x2C) { // SDL
+ if(rs2[i]) emit_shrdimm(tl,th,24,temp2);
+ // Write msb into least significant byte
+ if(rs2[i]) emit_rorimm(th,24,th);
+ emit_writebyte_indexed(th,-3,temp);
+ if(rs2[i]) emit_rorimm(th,8,th);
+ }
+ if (opcode[i]==0x2D) { // SDR
+ if(rs2[i]) emit_mov(th,temp2);
+ // Write entire word
+ emit_writeword_indexed(tl,-3,temp);
+ }
+ set_jump_target(done0,(int)out);
+ set_jump_target(done1,(int)out);
+ set_jump_target(done2,(int)out);
+ if (opcode[i]==0x2C) { // SDL
+ emit_testimm(temp,4);
done0=(int)out;
- emit_jmp(0);
- // 1
- set_jump_target(case1,(int)out);
- if (opcode[i]==0x2A) { // SWL
- // Write 3 msb into three least significant bytes
- if(rs2[i]) emit_rorimm(tl,8,tl);
- emit_writehword_indexed(tl,-1,temp);
- if(rs2[i]) emit_rorimm(tl,16,tl);
- emit_writebyte_indexed(tl,1,temp);
- if(rs2[i]) emit_rorimm(tl,8,tl);
- }
- if (opcode[i]==0x2E) { // SWR
- // Write two lsb into two most significant bytes
- emit_writehword_indexed(tl,1,temp);
- }
- if (opcode[i]==0x2C) { // SDL
- if(rs2[i]) emit_shrdimm(tl,th,8,temp2);
- // Write 3 msb into three least significant bytes
- if(rs2[i]) emit_rorimm(th,8,th);
- emit_writehword_indexed(th,-1,temp);
- if(rs2[i]) emit_rorimm(th,16,th);
- emit_writebyte_indexed(th,1,temp);
- if(rs2[i]) emit_rorimm(th,8,th);
- }
- if (opcode[i]==0x2D) { // SDR
- if(rs2[i]) emit_shldimm(th,tl,16,temp2);
- // Write two lsb into two most significant bytes
- emit_writehword_indexed(tl,1,temp);
- }
- done1=(int)out;
- emit_jmp(0);
- // 2
- set_jump_target(case2,(int)out);
- emit_testimm(temp,1);
- case3=(int)out;
emit_jne(0);
- if (opcode[i]==0x2A) { // SWL
- // Write two msb into two least significant bytes
- if(rs2[i]) emit_rorimm(tl,16,tl);
- emit_writehword_indexed(tl,-2,temp);
- if(rs2[i]) emit_rorimm(tl,16,tl);
- }
- if (opcode[i]==0x2E) { // SWR
- // Write 3 lsb into three most significant bytes
- emit_writebyte_indexed(tl,-1,temp);
- if(rs2[i]) emit_rorimm(tl,8,tl);
- emit_writehword_indexed(tl,0,temp);
- if(rs2[i]) emit_rorimm(tl,24,tl);
- }
- if (opcode[i]==0x2C) { // SDL
- if(rs2[i]) emit_shrdimm(tl,th,16,temp2);
- // Write two msb into two least significant bytes
- if(rs2[i]) emit_rorimm(th,16,th);
- emit_writehword_indexed(th,-2,temp);
- if(rs2[i]) emit_rorimm(th,16,th);
- }
- if (opcode[i]==0x2D) { // SDR
- if(rs2[i]) emit_shldimm(th,tl,8,temp2);
- // Write 3 lsb into three most significant bytes
- emit_writebyte_indexed(tl,-1,temp);
- if(rs2[i]) emit_rorimm(tl,8,tl);
- emit_writehword_indexed(tl,0,temp);
- if(rs2[i]) emit_rorimm(tl,24,tl);
- }
- done2=(int)out;
- emit_jmp(0);
- // 3
- set_jump_target(case3,(int)out);
- if (opcode[i]==0x2A) { // SWL
- // Write msb into least significant byte
- if(rs2[i]) emit_rorimm(tl,24,tl);
- emit_writebyte_indexed(tl,-3,temp);
- if(rs2[i]) emit_rorimm(tl,8,tl);
- }
- if (opcode[i]==0x2E) { // SWR
- // Write entire word
- emit_writeword_indexed(tl,-3,temp);
- }
- if (opcode[i]==0x2C) { // SDL
- if(rs2[i]) emit_shrdimm(tl,th,24,temp2);
- // Write msb into least significant byte
- if(rs2[i]) emit_rorimm(th,24,th);
- emit_writebyte_indexed(th,-3,temp);
- if(rs2[i]) emit_rorimm(th,8,th);
- }
- if (opcode[i]==0x2D) { // SDR
- if(rs2[i]) emit_mov(th,temp2);
- // Write entire word
- emit_writeword_indexed(tl,-3,temp);
- }
+ emit_andimm(temp,~3,temp);
+ emit_writeword_indexed(temp2,4,temp);
+ set_jump_target(done0,(int)out);
+ }
+ if (opcode[i]==0x2D) { // SDR
+ emit_testimm(temp,4);
+ done0=(int)out;
+ emit_jeq(0);
+ emit_andimm(temp,~3,temp);
+ emit_writeword_indexed(temp2,-4,temp);
set_jump_target(done0,(int)out);
- set_jump_target(done1,(int)out);
- set_jump_target(done2,(int)out);
- if (opcode[i]==0x2C) { // SDL
- emit_testimm(temp,4);
- done0=(int)out;
- emit_jne(0);
- emit_andimm(temp,~3,temp);
- emit_writeword_indexed(temp2,4,temp);
- set_jump_target(done0,(int)out);
- }
- if (opcode[i]==0x2D) { // SDR
- emit_testimm(temp,4);
- done0=(int)out;
- emit_jeq(0);
- emit_andimm(temp,~3,temp);
- emit_writeword_indexed(temp2,-4,temp);
- set_jump_target(done0,(int)out);
- }
- if(!c||!memtarget)
- add_stub(STORELR_STUB,jaddr,(int)out,0,(int)i_regs,rs2[i],ccadj[i],reglist);
}
+ if(!c||!memtarget)
+ add_stub(STORELR_STUB,jaddr,(int)out,i,(int)i_regs,temp,ccadj[i],reglist);
if(!using_tlb) {
+ #ifdef RAM_OFFSET
+ int map=get_reg(i_regs->regmap,ROREG);
+ if(map<0) map=HOST_TEMPREG;
+ gen_orig_addr_w(temp,map);
+ #else
emit_addimm_no_flags((u_int)0x80000000-(u_int)rdram,temp);
+ #endif
#if defined(HOST_IMM8)
int ir=get_reg(i_regs->regmap,INVCP);
assert(ir>=0);
#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
jaddr2=(int)out;
emit_jne(0);
add_stub(INVCODE_STUB,jaddr2,(int)out,reglist|(1<<HOST_CCREG),temp,0,0,0);
+ #endif
}
/*
emit_pusha();
// Generate address + offset
if(!using_tlb) {
if(!c)
- emit_cmpimm(offset||c||s<0?ar:s,0x800000);
+ emit_cmpimm(offset||c||s<0?ar:s,RAM_SIZE);
}
else
{
jaddr2=(int)out;
emit_jno(0);
}
- else if(((signed int)(constmap[i][s]+offset))>=(signed int)0x80800000) {
+ else if(((signed int)(constmap[i][s]+offset))>=(signed int)0x80000000+RAM_SIZE) {
jaddr2=(int)out;
emit_jmp(0); // inline_readstub/inline_writestub? Very rare case
}
#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 s,tl;
int ar;
int offset;
- int c=0;
+ int memtarget=0,c=0;
int jaddr,jaddr2=0,jaddr3,type;
int agr=AGEN1+(i&1);
u_int hr,reglist=0;
} else { // LWC2
ar=tl;
}
+ if(s>=0) c=(i_regs->wasconst>>s)&1;
+ memtarget=c&&(((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE);
if (!offset&&!c&&s>=0) ar=s;
assert(ar>=0);
if (opcode[i]==0x3a) { // SWC2
cop2_get_dreg(copr,tl,HOST_TEMPREG);
+ type=STOREW_STUB;
}
- if(s>=0) c=(i_regs->wasconst>>s)&1;
- if(!c) {
- emit_cmpimm(offset||c||s<0?ar:s,0x800000);
- jaddr2=(int)out;
- emit_jno(0);
- }
- else if(((signed int)(constmap[i][s]+offset))>=(signed int)0x80800000) {
- jaddr2=(int)out;
- emit_jmp(0); // inline_readstub/inline_writestub? Very rare case
- }
- 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);
+ else
type=LOADW_STUB;
+
+ if(c&&!memtarget) {
+ jaddr2=(int)out;
+ emit_jmp(0); // inline_readstub/inline_writestub?
}
- if (opcode[i]==0x3a) { // SWC2
-#ifdef DESTRUCTIVE_SHIFT
- if(!offset&&!c&&s>=0) emit_mov(s,ar);
-#endif
- emit_writeword_indexed(tl,0,ar);
- type=STOREW_STUB;
+ else {
+ if(!c) {
+ emit_cmpimm(offset||c||s<0?ar:s,RAM_SIZE);
+ jaddr2=(int)out;
+ emit_jno(0);
+ }
+ 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);
+ }
+ if (opcode[i]==0x3a) { // SWC2
+ #ifdef DESTRUCTIVE_SHIFT
+ if(!offset&&!c&&s>=0) emit_mov(s,ar);
+ #endif
+ emit_writeword_indexed(tl,0,ar);
+ }
}
if(jaddr2)
add_stub(type,jaddr2,(int)out,i,ar,(int)i_regs,ccadj[i],reglist);
#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);
{
//if(opcode2[i]==0x10||opcode2[i]==0x12) { // MFHI/MFLO
//if(opcode2[i]==0x11||opcode2[i]==0x13) { // MTHI/MTLO
- assert(rt1[i]>0);
if(rt1[i]) {
signed char sh,sl,th,tl;
th=get_reg(i_regs->regmap,rt1[i]|64);
assert(ccreg==HOST_CCREG);
assert(!is_delayslot);
emit_movimm(start+i*4+4,0); // Get PC
- emit_movimm(source[i],1); // opcode
+ emit_movimm((int)psxHLEt[source[i]&7],1);
emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // XXX
- emit_jmp((int)jump_hlecall); // XXX
+ emit_jmp((int)jump_hlecall);
+}
+
+void intcall_assemble(int i,struct regstat *i_regs)
+{
+ signed char ccreg=get_reg(i_regs->regmap,CCREG);
+ assert(ccreg==HOST_CCREG);
+ assert(!is_delayslot);
+ emit_movimm(start+i*4,0); // Get PC
+ emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG);
+ emit_jmp((int)jump_intcall);
}
void ds_assemble(int i,struct regstat *i_regs)
mov_assemble(i,i_regs);break;
case SYSCALL:
case HLECALL:
+ case INTCALL:
case SPAN:
case UJUMP:
case RJUMP:
else printf("optimizable: yes\n");
}*/
//if(is32[t]&~unneeded_reg_upper[t]&~i_is32) return 0;
+#ifndef FORCE32
if(requires_32bit[t]&~i_is32) return 0;
- else return 1;
+ else
+#endif
+ return 1;
}
return 0;
}
int mgr=MGEN1+(i&1);
if(itype[i]==LOAD) {
ra=get_reg(i_regs->regmap,rt1[i]);
- //if(rt1[i]) assert(ra>=0);
+ if(ra<0) ra=get_reg(i_regs->regmap,-1);
+ assert(ra>=0);
}
if(itype[i]==LOADLR) {
ra=get_reg(i_regs->regmap,FTEMP);
if(itype[i]==C1LS||itype[i]==C2LS) {
if ((opcode[i]&0x3b)==0x31||(opcode[i]&0x3b)==0x32) // LWC1/LDC1/LWC2/LDC2
ra=get_reg(i_regs->regmap,FTEMP);
- else { // SWC1/SDC1
+ else { // SWC1/SDC1/SWC2/SDC2
ra=get_reg(i_regs->regmap,agr);
if(ra<0) ra=get_reg(i_regs->regmap,-1);
}
// Stores to memory go thru the mapper to detect self-modifying
// code, loads don't.
if((unsigned int)(constmap[i][rs]+offset)>=0xC0000000 ||
- (unsigned int)(constmap[i][rs]+offset)<0x80800000 )
+ (unsigned int)(constmap[i][rs]+offset)<0x80000000+RAM_SIZE )
generate_map_const(constmap[i][rs]+offset,rm);
}else{
if((signed int)(constmap[i][rs]+offset)>=(signed int)0xC0000000)
// Stores to memory go thru the mapper to detect self-modifying
// code, loads don't.
if((unsigned int)(constmap[i+1][rs]+offset)>=0xC0000000 ||
- (unsigned int)(constmap[i+1][rs]+offset)<0x80800000 )
+ (unsigned int)(constmap[i+1][rs]+offset)<0x80000000+RAM_SIZE )
generate_map_const(constmap[i+1][rs]+offset,ra);
}else{
if((signed int)(constmap[i+1][rs]+offset)>=(signed int)0xC0000000)
}
}
//if(is32[t]&~unneeded_reg_upper[t]&~i_is32) return 0;
+#ifndef FORCE32
if(requires_32bit[t]&~i_is32) return 0;
+#endif
// Delay slots are not valid branch targets
//if(t>0&&(itype[t-1]==RJUMP||itype[t-1]==UJUMP||itype[t-1]==CJUMP||itype[t-1]==SJUMP||itype[t-1]==FJUMP)) return 0;
// Delay slots require additional processing, so do not match
mov_assemble(t,®s[t]);break;
case SYSCALL:
case HLECALL:
+ case INTCALL:
case SPAN:
case UJUMP:
case RJUMP:
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);
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,rs1[i],CCREG);
- if(rt1[i]==31) {
+ if(rt1[i]!=0) {
int rt,return_address;
- assert(rt1[i+1]!=31);
- assert(rt2[i+1]!=31);
- rt=get_reg(branch_regs[i].regmap,31);
+ assert(rt1[i+1]!=rt1[i]);
+ assert(rt2[i+1]!=rt1[i]);
+ rt=get_reg(branch_regs[i].regmap,rt1[i]);
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;
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;
#endif
//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;
- }
- // TODO: Conditional branches w/link must execute in-order so that
- // condition test and write to r31 occur before cycle count test
+ //assert(opcode2[i]<0x10||rs1[i]==0); // FIXME (BxxZAL)
- 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);
load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG);
if(rt1[i]==31) {
int rt,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]);
if(rt>=0) {
if(!only32)
{
assert(s1h>=0);
- if(opcode2[i]==0) // BLTZ
+ if((opcode2[i]&0xf)==0) // BLTZ/BLTZAL
{
emit_test(s1h,s1h);
if(invert){
emit_js(0);
}
}
- if(opcode2[i]==1) // BGEZ
+ if((opcode2[i]&0xf)==1) // BGEZ/BLTZAL
{
emit_test(s1h,s1h);
if(invert){
else
{
assert(s1l>=0);
- if(opcode2[i]==0) // BLTZ
+ if((opcode2[i]&0xf)==0) // BLTZ/BLTZAL
{
emit_test(s1l,s1l);
if(invert){
emit_js(0);
}
}
- if(opcode2[i]==1) // BGEZ
+ if((opcode2[i]&0xf)==1) // BGEZ/BLTZAL
{
emit_test(s1l,s1l);
if(invert){
// In-order execution (branch first)
//printf("IOE\n");
int nottaken=0;
+ if(rt1[i]==31) {
+ int rt,return_address;
+ rt=get_reg(branch_regs[i].regmap,31);
+ if(rt>=0) {
+ // Save the PC even if the branch is not taken
+ return_address=start+i*4+8;
+ emit_movimm(return_address,rt); // PC into link register
+ #ifdef IMM_PREFETCH
+ emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]);
+ #endif
+ }
+ }
if(!unconditional) {
//printf("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]);
if(!only32)
{
assert(s1h>=0);
- if((opcode2[i]&0x1d)==0) // BLTZ/BLTZL
+ if((opcode2[i]&0x0d)==0) // BLTZ/BLTZL/BLTZAL/BLTZALL
{
emit_test(s1h,s1h);
nottaken=(int)out;
emit_jns(1);
}
- if((opcode2[i]&0x1d)==1) // BGEZ/BGEZL
+ if((opcode2[i]&0x0d)==1) // BGEZ/BGEZL/BGEZAL/BGEZALL
{
emit_test(s1h,s1h);
nottaken=(int)out;
else
{
assert(s1l>=0);
- if((opcode2[i]&0x1d)==0) // BLTZ/BLTZL
+ if((opcode2[i]&0x0d)==0) // BLTZ/BLTZL/BLTZAL/BLTZALL
{
emit_test(s1l,s1l);
nottaken=(int)out;
emit_jns(1);
}
- if((opcode2[i]&0x1d)==1) // BGEZ/BGEZL
+ if((opcode2[i]&0x0d)==1) // BGEZ/BGEZL/BGEZAL/BGEZALL
{
emit_test(s1l,s1l);
nottaken=(int)out;
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);
emit_mov(s1l,addr);
if(opcode2[i]==9) // JALR
{
- int rt=get_reg(i_regs->regmap,31);
+ int rt=get_reg(i_regs->regmap,rt1[i]);
emit_movimm(start+i*4+8,rt);
}
}
mov_assemble(0,®s[0]);break;
case SYSCALL:
case HLECALL:
+ case INTCALL:
case SPAN:
case UJUMP:
case RJUMP:
{
uu=u=0x300C0F3; // Discard at, a0-a3, t6-t9
}
- if(start>0x80000400&&start<0x80800000) {
+ if(start>0x80000400&&start<0x80000000+RAM_SIZE) {
if(itype[i]==UJUMP&&rt1[i]==31)
{
//uu=u=0x30300FF0FLL; // Discard at, v0-v1, t0-t9, lo, hi
}
}
}
- else if(itype[i]==SYSCALL||itype[i]==HLECALL)
+ else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
{
// SYSCALL instruction (software interrupt)
u=1;
// Save it
unneeded_reg[i]=u;
unneeded_reg_upper[i]=uu;
-#ifdef FORCE32
- unneeded_reg_upper[i]=-1LL;
-#endif
/*
printf("ur (%d,%d) %x: ",istart,iend,start+i*4);
printf("U:");
}
printf("\n");*/
}
+#ifdef FORCE32
+ for (i=iend;i>=istart;i--)
+ {
+ unneeded_reg_upper[i]=branch_unneeded_reg_upper[i]=-1LL;
+ }
+#endif
}
// Identify registers which are likely to contain 32-bit values
if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<<dep2[i+1];
}
}
- else if(itype[i]==SYSCALL||itype[i]==HLECALL)
+ else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
{
// SYSCALL instruction (software interrupt)
r32=0;
}
}
}
- else if(itype[i]==SYSCALL||itype[i]==HLECALL)
+ else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
{
// SYSCALL instruction (software interrupt)
will_dirty_i=0;
case FJUMP:
printf (" %x: %s %8x\n",start+i*4,insn[i],ba[i]);break;
case RJUMP:
- printf (" %x: %s r%d\n",start+i*4,insn[i],rs1[i]);break;
+ if (opcode[i]==0x9&&rt1[i]!=31)
+ printf (" %x: %s r%d,r%d\n",start+i*4,insn[i],rt1[i],rs1[i]);
+ else
+ printf (" %x: %s r%d\n",start+i*4,insn[i],rs1[i]);
+ break;
case SPAN:
printf (" %x: %s (pagespan) r%d,r%d,%8x\n",start+i*4,insn[i],rs1[i],rs2[i],ba[i]);break;
case IMM16:
case C2LS:
printf (" %x: %s cpr2[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]);
break;
+ case INTCALL:
+ printf (" %x: %s (INTCALL)\n",start+i*4,insn[i]);
+ break;
default:
//printf (" %s %8x\n",insn[i],source[i]);
printf (" %x: %s\n",start+i*4,insn[i]);
}
}
-void new_dynarec_init()
+// clear the state completely, instead of just marking
+// things invalid like invalidate_all_pages() does
+void new_dynarec_clear_full()
{
- printf("Init new dynarec\n");
- out=(u_char *)BASE_ADDR;
- 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");}
-#ifdef MUPEN64
- rdword=&readmem_dword;
- fake_pc.f.r.rs=&readmem_dword;
- fake_pc.f.r.rt=&readmem_dword;
- fake_pc.f.r.rd=&readmem_dword;
-#endif
int n;
for(n=0x80000;n<0x80800;n++)
invalid_code[n]=1;
hash_table[n][0]=hash_table[n][2]=-1;
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;
-#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
+#ifndef DISABLE_TLB
using_tlb=0;
+#endif
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");
+ out=(u_char *)BASE_ADDR;
+ 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");}
+#ifdef MUPEN64
+ rdword=&readmem_dword;
+ fake_pc.f.r.rs=&readmem_dword;
+ fake_pc.f.r.rt=&readmem_dword;
+ fake_pc.f.r.rd=&readmem_dword;
+#endif
+ int n;
+ 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
#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 (Config.HLE && start == 0x80001000) {
+ if (Config.HLE && start == 0x80001000) // hlecall
+ {
// XXX: is this enough? Maybe check hleSoftCall?
+ u_int beginning=(u_int)out;
u_int page=get_page(start);
- ll_add(jump_in+page,start,out);
invalid_code[start>>12]=0;
emit_movimm(start,0);
emit_writeword(0,(int)&pcaddr);
- emit_jmp((int)new_dyna_leave); // enough??
+ emit_jmp((int)new_dyna_leave);
+#ifdef __arm__
+ __clear_cache((void *)beginning,out);
+#endif
+ ll_add(jump_in+page,start,(void *)beginning);
return 0;
}
- else if ((u_int)addr < 0x00200000) {
+ else if ((u_int)addr < 0x00200000 ||
+ (0xa0000000 <= addr && addr < 0xa0200000)) {
// used for BIOS calls mostly?
- source = (u_int *)((u_int)rdram+start-0);
- pagelimit = 0x00200000;
+ 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
}
else
#endif
- if ((int)addr >= 0x80000000 && (int)addr < 0x80800000) {
+ if ((int)addr >= 0x80000000 && (int)addr < 0x80000000+RAM_SIZE) {
source = (u_int *)((u_int)rdram+start-0x80000000);
- pagelimit = 0x80800000;
+ pagelimit = 0x80000000+RAM_SIZE;
}
#ifndef DISABLE_TLB
else if ((signed int)addr >= (signed int)0xC0000000) {
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
+ return -1; // Caller will invoke exception handler
}
//printf("source= %x\n",(int)source);
}
/* 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 0x02: strcpy(insn[i],"TLBWI"); type=COP0; break;
case 0x06: strcpy(insn[i],"TLBWR"); type=COP0; break;
case 0x08: strcpy(insn[i],"TLBP"); type=COP0; break;
+#ifdef PCSX
+ case 0x10: strcpy(insn[i],"RFE"); type=COP0; break;
+#else
case 0x18: strcpy(insn[i],"ERET"); type=COP0; break;
+#endif
}
}
break;
break;
}
break;
+#ifndef FORCE32
case 0x14: strcpy(insn[i],"BEQL"); type=CJUMP; break;
case 0x15: strcpy(insn[i],"BNEL"); type=CJUMP; break;
case 0x16: strcpy(insn[i],"BLEZL"); type=CJUMP; break;
case 0x19: strcpy(insn[i],"DADDIU"); type=IMM16; break;
case 0x1A: strcpy(insn[i],"LDL"); type=LOADLR; break;
case 0x1B: strcpy(insn[i],"LDR"); type=LOADLR; break;
+#endif
case 0x20: strcpy(insn[i],"LB"); type=LOAD; break;
case 0x21: strcpy(insn[i],"LH"); type=LOAD; break;
case 0x22: strcpy(insn[i],"LWL"); type=LOADLR; break;
case 0x29: strcpy(insn[i],"SH"); type=STORE; break;
case 0x2A: strcpy(insn[i],"SWL"); type=STORELR; break;
case 0x2B: strcpy(insn[i],"SW"); type=STORE; break;
+#ifndef FORCE32
case 0x2C: strcpy(insn[i],"SDL"); type=STORELR; break;
case 0x2D: strcpy(insn[i],"SDR"); type=STORELR; break;
+#endif
case 0x2E: strcpy(insn[i],"SWR"); type=STORELR; break;
case 0x2F: strcpy(insn[i],"CACHE"); type=NOP; break;
case 0x30: strcpy(insn[i],"LL"); type=NI; break;
case 0x31: strcpy(insn[i],"LWC1"); type=C1LS; break;
+#ifndef FORCE32
case 0x34: strcpy(insn[i],"LLD"); type=NI; break;
case 0x35: strcpy(insn[i],"LDC1"); type=C1LS; break;
case 0x37: strcpy(insn[i],"LD"); type=LOAD; break;
+#endif
case 0x38: strcpy(insn[i],"SC"); type=NI; break;
case 0x39: strcpy(insn[i],"SWC1"); type=C1LS; break;
+#ifndef FORCE32
case 0x3C: strcpy(insn[i],"SCD"); type=NI; break;
case 0x3D: strcpy(insn[i],"SDC1"); type=C1LS; break;
case 0x3F: strcpy(insn[i],"SD"); type=STORE; break;
+#endif
#ifdef PCSX
case 0x12: strcpy(insn[i],"COP2"); type=NI;
+ // note: COP MIPS-1 encoding differs from MIPS32
op2=(source[i]>>21)&0x1f;
- switch(op2)
+ if (source[i]&0x3f) {
+ if (gte_handlers[source[i]&0x3f]!=NULL) {
+ snprintf(insn[i], sizeof(insn[i]), "COP2 %x", source[i]&0x3f);
+ type=C2OP;
+ }
+ }
+ else switch(op2)
{
case 0x00: strcpy(insn[i],"MFC2"); type=COP2; break;
case 0x02: strcpy(insn[i],"CFC2"); type=COP2; break;
case 0x04: strcpy(insn[i],"MTC2"); type=COP2; break;
case 0x06: strcpy(insn[i],"CTC2"); type=COP2; break;
- default:
- if (gte_handlers[source[i]&0x3f]!=NULL) {
- snprintf(insn[i], sizeof(insn[i]), "COP2 %x", source[i]&0x3f);
- type=C2OP;
- }
- break;
}
break;
case 0x32: strcpy(insn[i],"LWC2"); type=C2LS; break;
case 0x3B: strcpy(insn[i],"HLECALL"); type=HLECALL; break;
#endif
default: strcpy(insn[i],"???"); type=NI;
- printf("NI %08x @%08x\n", source[i], addr + i*4);
+ printf("NI %08x @%08x (%08x)\n", source[i], addr + i*4, addr);
break;
}
itype[i]=type;
rs2[i]=0;
rt1[i]=0;
rt2[i]=0;
- // The JALR instruction writes to r31.
+ // The JALR instruction writes to rd.
if (op2&1) {
- rt1[i]=31;
+ rt1[i]=(source[i]>>11)&0x1f;
}
rs2[i]=CCREG;
break;
break;
case SYSCALL:
case HLECALL:
+ case INTCALL:
rs1[i]=CCREG;
rs2[i]=0;
rt1[i]=0;
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;
+#ifdef PCSX
+ 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
+ }
+ }
+#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]!=31) { // Continue past subroutine call (JAL)
- done=1;
- // Does the block continue due to a branch?
- for(j=i-1;j>=0;j--)
- {
- if(ba[j]==start+i*4+4) done=j=0;
- if(ba[j]==start+i*4+8) done=j=0;
- }
+ if(rt1[i-1]==0) { // Continue past subroutine call (JAL)
+ done=2;
}
else {
if(stop_after_jal) done=1;
// Don't get too close to the limit
if(i>MAXBLOCK/2) done=1;
}
- if(i>0&&itype[i-1]==SYSCALL&&stop_after_jal) done=1;
- if(itype[i-1]==HLECALL) done=1;
- assert(i<MAXBLOCK-1);
+ if(itype[i]==SYSCALL&&stop_after_jal) done=1;
+ if(itype[i]==HLECALL||itype[i]==INTCALL) done=2;
+ if(done==2) {
+ // Does the block continue due to a branch?
+ for(j=i-1;j>=0;j--)
+ {
+ if(ba[j]==start+i*4+4) done=j=0;
+ if(ba[j]==start+i*4+8) done=j=0;
+ }
+ }
+ //assert(i<MAXBLOCK-1);
if(start+i*4==pagelimit-4) done=1;
assert(start+i*4<pagelimit);
if (i==MAXBLOCK-1) done=1;
int ds=0;
int cc=0;
int hr;
-
+
+#ifndef FORCE32
provisional_32bit();
-
+#endif
if((u_int)addr&1) {
// First instruction is delay slot
cc=-1;
}
}
}
+#ifndef FORCE32
// If something jumps here with 64-bit values
// then promote those registers to 64 bits
if(bt[i])
current.is32=temp_is32;
}
}
-#ifdef FORCE32
- memset(p32, 0xff, sizeof(p32));
+#else
current.is32=-1LL;
#endif
regs[i].wasconst=current.isconst;
regs[i].was32=current.is32;
regs[i].wasdirty=current.dirty;
- #ifdef DESTRUCTIVE_WRITEBACK
+ #if defined(DESTRUCTIVE_WRITEBACK) && !defined(FORCE32)
// To change a dirty register from 32 to 64 bits, we must write
// it out during the previous cycle (for branches, 2 cycles)
if(i<slen-1&&bt[i+1]&&itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=RJUMP&&itype[i-1]!=FJUMP)
if (rt1[i]==31) {
alloc_reg(¤t,i,31);
dirty_reg(¤t,31);
- assert(rs1[i+1]!=31&&rs2[i+1]!=31);
+ //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];
}
+ ooo[i]=1;
delayslot_alloc(¤t,i+1);
//current.isconst=0; // DEBUG
ds=1;
dirty_reg(¤t,CCREG);
if(rs1[i]!=rt1[i+1]&&rs1[i]!=rt2[i+1]) {
alloc_reg(¤t,i,rs1[i]);
- if (rt1[i]==31) {
- alloc_reg(¤t,i,31);
- dirty_reg(¤t,31);
- assert(rs1[i+1]!=31&&rs2[i+1]!=31);
+ if (rt1[i]!=0) {
+ alloc_reg(¤t,i,rt1[i]);
+ dirty_reg(¤t,rt1[i]);
+ assert(rs1[i+1]!=rt1[i]&&rs2[i+1]!=rt1[i]);
+ assert(rt1[i+1]!=rt1[i]);
#ifdef REG_PREFETCH
alloc_reg(¤t,i,PTEMP);
#endif
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
if (rt1[i]==31) { // BLTZAL/BGEZAL
alloc_reg(¤t,i,31);
dirty_reg(¤t,31);
- assert(rs1[i+1]!=31&&rs2[i+1]!=31);
//#ifdef REG_PREFETCH
//alloc_reg(¤t,i,PTEMP);
//#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);
}
break;
case SYSCALL:
case HLECALL:
+ case INTCALL:
syscall_alloc(¤t,i);
break;
case SPAN:
alloc_cc(&branch_regs[i-1],i-1);
dirty_reg(&branch_regs[i-1],CCREG);
alloc_reg(&branch_regs[i-1],i-1,rs1[i-1]);
- if(rt1[i-1]==31) { // JALR
- alloc_reg(&branch_regs[i-1],i-1,31);
- dirty_reg(&branch_regs[i-1],31);
- branch_regs[i-1].is32|=1LL<<31;
+ if(rt1[i-1]!=0) { // JALR
+ alloc_reg(&branch_regs[i-1],i-1,rt1[i-1]);
+ dirty_reg(&branch_regs[i-1],rt1[i-1]);
+ branch_regs[i-1].is32|=1LL<<rt1[i-1];
}
#ifdef USE_MINI_HT
if(rs1[i-1]==31) { // JALR
{
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++;
}
}
}
- else if(itype[i]==SYSCALL||itype[i]==HLECALL)
+ else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
{
// SYSCALL instruction (software interrupt)
nr=0;
f_regmap[hr]=regs[i].regmap[hr];
else f_regmap[hr]=-1;
}
- else if(regs[i].regmap[hr]>=0) f_regmap[hr]=regs[i].regmap[hr];
+ else if(regs[i].regmap[hr]>=0) {
+ if(f_regmap[hr]!=regs[i].regmap[hr]) {
+ // dealloc old register
+ int n;
+ for(n=0;n<HOST_REGS;n++)
+ {
+ if(f_regmap[n]==regs[i].regmap[hr]) {f_regmap[n]=-1;}
+ }
+ // and alloc new one
+ f_regmap[hr]=regs[i].regmap[hr];
+ }
+ }
if(branch_regs[i].regmap[hr]>64) {
if(!((branch_regs[i].dirty>>hr)&1))
f_regmap[hr]=branch_regs[i].regmap[hr];
else f_regmap[hr]=-1;
}
- else if(branch_regs[i].regmap[hr]>=0) 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)
+ else if(branch_regs[i].regmap[hr]>=0) {
+ if(f_regmap[hr]!=branch_regs[i].regmap[hr]) {
+ // dealloc old register
+ int n;
+ for(n=0;n<HOST_REGS;n++)
+ {
+ if(f_regmap[n]==branch_regs[i].regmap[hr]) {f_regmap[n]=-1;}
+ }
+ // and alloc new one
+ f_regmap[hr]=branch_regs[i].regmap[hr];
+ }
+ }
+ 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(!((regs[i].dirty>>hr)&1))
f_regmap[hr]=regs[i].regmap[hr];
}
- else if(regs[i].regmap[hr]>=0) f_regmap[hr]=regs[i].regmap[hr];
+ else if(regs[i].regmap[hr]>=0) {
+ if(f_regmap[hr]!=regs[i].regmap[hr]) {
+ // dealloc old register
+ int n;
+ for(n=0;n<HOST_REGS;n++)
+ {
+ if(f_regmap[n]==regs[i].regmap[hr]) {f_regmap[n]=-1;}
+ }
+ // and alloc new one
+ f_regmap[hr]=regs[i].regmap[hr];
+ }
+ }
else if(regs[i].regmap[hr]<0) count++;
}
}
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));
}
clean_registers(0,slen-1,1);
/* Pass 7 - Identify 32-bit registers */
-
+#ifndef FORCE32
provisional_r32();
u_int r32=0;
if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<<dep2[i+1];
}
}
- else if(itype[i]==SYSCALL||itype[i]==HLECALL)
+ else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
{
// SYSCALL instruction (software interrupt)
r32=0;
}
//requires_32bit[i]=is32[i]&~unneeded_reg_upper[i]; // DEBUG
}
+#endif
if(itype[slen-1]==SPAN) {
bt[slen-1]=1; // Mark as a branch target so instruction can restart after exception
ds=1;
pagespan_ds();
}
+ u_int instr_addr0_override=0;
+
+#ifdef PCSX
+ if (start == 0x80030000) {
+ // nasty hack for fastbios thing
+ instr_addr0_override=(u_int)out;
+ emit_movimm(start,0);
+ emit_readword((int)&pcaddr,1);
+ emit_writeword(0,(int)&pcaddr);
+ emit_cmp(0,1);
+ emit_jne((int)new_dyna_leave);
+ }
+#endif
for(i=0;i<slen;i++)
{
//if(ds) printf("ds: ");
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);
syscall_assemble(i,®s[i]);break;
case HLECALL:
hlecall_assemble(i,®s[i]);break;
+ case INTCALL:
+ intcall_assemble(i,®s[i]);break;
case UJUMP:
ujump_assemble(i,®s[i]);ds=1;break;
case RJUMP:
}
}
+ if (instr_addr0_override)
+ instr_addr[0] = instr_addr0_override;
+
/* Pass 9 - Linker */
for(i=0;i<linkcount;i++)
{
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);
}
#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 */
case 3:
// Clear jump_out
#ifdef __arm__
- if((expirep&2047)==0)
- __clear_cache((void *)BASE_ADDR,(void *)BASE_ADDR+(1<<TARGET_SIZE_2));
+ if((expirep&2047)==0)
+ do_clear_cache();
#endif
ll_remove_matching_addrs(jump_out+(expirep&2047),base,shift);
ll_remove_matching_addrs(jump_out+2048+(expirep&2047),base,shift);