#define CCREG 36 // Cycle count
#define INVCP 37 // Pointer to invalid_code
#define TEMPREG 38
-#define FTEMP 38 // FPU temporary register
+#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 OTHER 23 // Other
#define SPAN 24 // Branch/delay slot spans 2 pages
#define NI 25 // Not implemented
+#define HLECALL 26// PCSX fake opcodes for HLE
+#define COP2 27 // Coprocessor 2 move
+#define C2LS 28 // Coprocessor 2 load/store
+#define C2OP 29 // Coprocessor 2 operation
/* stubs */
#define CC_STUB 1
void fp_exception();
void fp_exception_ds();
void jump_syscall();
+void jump_syscall_hle();
void jump_eret();
+void jump_hlecall();
+void new_dyna_leave();
// TLB
void TLBWI_new();
//printf("TRACE: count=%d next=%d (get_addr no-match %x)\n",Count,next_interupt,vaddr);
int r=new_recompile_block(vaddr);
if(r==0) return get_addr(vaddr);
+#ifdef PCSX
+ return (void *)r;
+#else
// Execute in unmapped page, generate pagefault execption
Status|=2;
Cause=(vaddr<<31)|0x8;
Context=(Context&0xFF80000F)|((BadVAddr>>9)&0x007FFFF0);
EntryHi=BadVAddr&0xFFFFE000;
return get_addr_ht(0x80000000);
+#endif
}
// Look up address in hash table first
void *get_addr_ht(u_int 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];
Context=(Context&0xFF80000F)|((BadVAddr>>9)&0x007FFFF0);
EntryHi=BadVAddr&0xFFFFE000;
return get_addr_ht(0x80000000);
+#endif
}
void clear_all_regs(signed char regmap[])
}
// On some architectures stores need invc_ptr
#if defined(HOST_IMM8)
- if(itype[i+j]==STORE || itype[i+j]==STORELR || (opcode[i+j]&0x3b)==0x39) {
+ if(itype[i+j]==STORE || itype[i+j]==STORELR || (opcode[i+j]&0x3b)==0x39 || (opcode[i+j]&0x3b)==0x3a) {
hsn[INVCP]=j;
}
#endif
hsn[RHTBL]=1;
}
// Coprocessor load/store needs FTEMP, even if not declared
- if(itype[i]==C1LS) {
+ if(itype[i]==C1LS||itype[i]==C2LS) {
hsn[FTEMP]=0;
}
// Load L/R also uses FTEMP as a temporary register
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
- if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS ) {
+ if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS || itype[i]==C2LS) {
hsn[TLREG]=0;
}
// Don't remove the miniht registers
j++;
break;
}
- if(itype[i+j]==SYSCALL||((source[i+j]&0xfc00003f)==0x0d))
+ if(itype[i+j]==SYSCALL||itype[i+j]==HLECALL||((source[i+j]&0xfc00003f)==0x0d))
{
break;
}
// Add virtual address mapping for 32-bit compiled block
void ll_add_32(struct ll_entry **head,int vaddr,u_int reg32,void *addr)
{
- struct ll_entry *new_entry;
- new_entry=malloc(sizeof(struct ll_entry));
- assert(new_entry!=NULL);
- new_entry->vaddr=vaddr;
- new_entry->reg32=reg32;
- new_entry->addr=addr;
- new_entry->next=*head;
- *head=new_entry;
+ ll_add(head,vaddr,addr);
+#ifndef FORCE32
+ (*head)->reg32=reg32;
+#endif
}
// Check if an address is already compiled
// Dereference the pointers and remove if it matches
void ll_kill_pointers(struct ll_entry *head,int addr,int shift)
{
+ u_int old_host_addr=0;
while(head) {
int ptr=get_pointer(head->addr);
inv_debug("EXP: Lookup pointer to %x at %x (%x)\n",(int)ptr,(int)head->addr,head->vaddr);
if(((ptr>>shift)==(addr>>shift)) ||
(((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);
+ printf("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr);
+ u_int host_addr=(u_int)kill_pointer(head->addr);
+
+ if((host_addr>>12)!=(old_host_addr>>12)) {
+ #ifdef __arm__
+ __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff));
+ #endif
+ old_host_addr=host_addr;
+ }
}
head=head->next;
}
+ #ifdef __arm__
+ if (old_host_addr)
+ __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff));
+ #endif
}
// 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;
+ u_int old_host_addr=0;
head=jump_in[page];
jump_in[page]=0;
while(head!=NULL) {
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);
+
+ if((host_addr>>12)!=(old_host_addr>>12)) {
+ #ifdef __arm__
+ __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff));
+ #endif
+ old_host_addr=host_addr;
+ }
next=head->next;
free(head);
head=next;
}
- return modified;
+ #ifdef __arm__
+ if (old_host_addr)
+ __clear_cache((void *)(old_host_addr&~0xfff),(void *)(old_host_addr|0xfff));
+ #endif
}
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;
}
}
+#ifndef DISABLE_TLB
if(page<2048&&(signed int)start>=(signed int)0xC0000000&&(signed int)end>=(signed int)0xC0000000) {
if(((start+memory_map[start>>12]-(u_int)rdram)>>12)<=page&&((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)>=page) {
if((((start+memory_map[start>>12]-(u_int)rdram)>>12)&2047)<first) first=((start+memory_map[start>>12]-(u_int)rdram)>>12)&2047;
if((((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)&2047)>last) last=((end-1+memory_map[(end-1)>>12]-(u_int)rdram)>>12)&2047;
}
}
+#endif
}
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
}
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
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) {
// 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);
}
+void c2ls_alloc(struct regstat *current,int i)
+{
+ clear_const(current,rt1[i]);
+ if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]);
+ alloc_reg(current,i,FTEMP);
+ // If using TLB, need a register for pointer to the mapping table
+ if(using_tlb) alloc_reg(current,i,TLREG);
+ #if defined(HOST_IMM8)
+ // On CPUs without 32-bit immediates we need a pointer to invalid_code
+ else if((opcode[i]&0x3b)==0x3a) // SWC2/SDC2
+ alloc_reg(current,i,INVCP);
+ #endif
+ // We need a temporary register for address generation
+ alloc_reg_temp(current,i,-1);
+}
+
#ifndef multdiv_alloc
void multdiv_alloc(struct regstat *current,int i)
{
alloc_reg(current,i,CSREG); // Load status
alloc_reg_temp(current,i,-1);
}
+void c2op_alloc(struct regstat *current,int i)
+{
+ alloc_reg_temp(current,i,-1);
+}
void fcomp_alloc(struct regstat *current,int i)
{
alloc_reg(current,i,CSREG); // Load status
case RJUMP:
case FJUMP:
case SYSCALL:
+ case HLECALL:
case SPAN:
assem_debug("jump in the delay slot. this shouldn't happen.\n");//exit(1);
printf("Disabled speculative precompilation\n");
cop0_alloc(current,i);
break;
case COP1:
+ case COP2:
cop1_alloc(current,i);
break;
case C1LS:
c1ls_alloc(current,i);
break;
+ case C2LS:
+ c2ls_alloc(current,i);
+ break;
case FCONV:
fconv_alloc(current,i);
break;
case FCOMP:
fcomp_alloc(current,i);
break;
+ case C2OP:
+ c2op_alloc(current,i);
+ break;
}
}
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
if((dirty>>hr)&1) {
if(regmap[hr]<64) {
emit_storereg(r,hr);
+#ifndef FORCE32
if((is32>>regmap[hr])&1) {
emit_sarimm(hr,31,hr);
emit_storereg(r|64,hr);
}
+#endif
}else{
emit_storereg(r|64,hr);
}
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;
+ memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1;
}
- if(offset||s<0||c) addr=tl;
- else addr=s;
//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) {
//assert(tl>=0);
//assert(rt1[i]);
//#define R29_HACK 1
#ifdef R29_HACK
// Strmnnrmn's speed hack
- 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);
jaddr=(int)out;
#ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
// Hint to branch predictor that the branch is unlikely to be taken
//gen_tlb_addr_r(tl,map);
//emit_movsbl_indexed((int)rdram-0x80000000,tl,tl);
int x=0;
+#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);
+#endif
emit_movsbl_indexed_tlb(x,tl,map,tl);
}
if(jaddr)
#endif
{
int x=0;
+#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);
+#endif
//#ifdef
//emit_movswl_indexed_tlb(x,tl,map,tl);
//else
//gen_tlb_addr_r(tl,map);
//emit_movzbl_indexed((int)rdram-0x80000000,tl,tl);
int x=0;
+#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);
+#endif
emit_movzbl_indexed_tlb(x,tl,map,tl);
}
if(jaddr)
#endif
{
int x=0;
+#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);
+#endif
//#ifdef
//emit_movzwl_indexed_tlb(x,tl,map,tl);
//#else
int addr,temp;
int offset;
int jaddr=0,jaddr2,type;
- int memtarget,c=0;
+ int memtarget=0,c=0;
int agr=AGEN1+(i&1);
u_int hr,reglist=0;
th=get_reg(i_regs->regmap,rs2[i]|64);
offset=imm[i];
if(s>=0) {
c=(i_regs->wasconst>>s)&1;
- memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80800000;
+ 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);
#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;
+#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);
+#endif
//gen_tlb_addr_w(temp,map);
//emit_writebyte_indexed(tl,(int)rdram-0x80000000,temp);
emit_writebyte_indexed_tlb(tl,x,temp,map,temp);
if (opcode[i]==0x29) { // SH
if(!c||memtarget) {
int x=0;
+#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);
+#endif
//#ifdef
//emit_writehword_indexed_tlb(tl,x,temp,map,temp);
//#else
}
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) {
int case1,case2,case3;
int done0,done1,done2;
int memtarget,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;
+ 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);
if(!using_tlb) {
if(!c) {
- emit_cmpimm(s<0||offset?temp:s,0x800000);
+ emit_cmpimm(s<0||offset?temp:s,RAM_SIZE);
if(!offset&&s!=temp) emit_mov(s,temp);
jaddr=(int)out;
emit_jno(0);
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);
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);
+ add_stub(STORELR_STUB,jaddr,(int)out,i,(int)i_regs,temp,ccadj[i],reglist);
}
if(!using_tlb) {
emit_addimm_no_flags((u_int)0x80000000-(u_int)rdram,temp);
// 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
}
#endif
}
+void c2ls_assemble(int i,struct regstat *i_regs)
+{
+ int s,tl;
+ int ar;
+ int offset;
+ int memtarget=0,c=0;
+ int jaddr,jaddr2=0,jaddr3,type;
+ int agr=AGEN1+(i&1);
+ u_int hr,reglist=0;
+ u_int copr=(source[i]>>16)&0x1f;
+ s=get_reg(i_regs->regmap,rs1[i]);
+ tl=get_reg(i_regs->regmap,FTEMP);
+ offset=imm[i];
+ assert(rs1[i]>0);
+ assert(tl>=0);
+ assert(!using_tlb);
+
+ for(hr=0;hr<HOST_REGS;hr++) {
+ if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
+ }
+ if(i_regs->regmap[HOST_CCREG]==CCREG)
+ reglist&=~(1<<HOST_CCREG);
+
+ // get the address
+ if (opcode[i]==0x3a) { // SWC2
+ ar=get_reg(i_regs->regmap,agr);
+ if(ar<0) ar=get_reg(i_regs->regmap,-1);
+ reglist|=1<<ar;
+ } 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;
+ }
+ else
+ type=LOADW_STUB;
+
+ if(c&&!memtarget) {
+ jaddr2=(int)out;
+ emit_jmp(0); // inline_readstub/inline_writestub?
+ }
+ 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);
+ if (opcode[i]==0x3a) { // SWC2
+#if defined(HOST_IMM8)
+ int ir=get_reg(i_regs->regmap,INVCP);
+ assert(ir>=0);
+ emit_cmpmem_indexedsr12_reg(ir,ar,1);
+#else
+ emit_cmpmem_indexedsr12_imm((int)invalid_code,ar,1);
+#endif
+ jaddr3=(int)out;
+ emit_jne(0);
+ add_stub(INVCODE_STUB,jaddr3,(int)out,reglist|(1<<HOST_CCREG),ar,0,0,0);
+ }
+ if (opcode[i]==0x32) { // LWC2
+ cop2_put_dreg(copr,tl,HOST_TEMPREG);
+ }
+}
+
#ifndef multdiv_assemble
void multdiv_assemble(int i,struct regstat *i_regs)
{
assert(!is_delayslot);
emit_movimm(start+i*4,EAX); // Get PC
emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle...
- emit_jmp((int)jump_syscall);
+ emit_jmp((int)jump_syscall_hle); // XXX
+}
+
+void hlecall_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+4,0); // Get PC
+ emit_movimm((int)psxHLEt[source[i]&7],1);
+ emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // XXX
+ emit_jmp((int)jump_hlecall);
}
void ds_assemble(int i,struct regstat *i_regs)
cop1_assemble(i,i_regs);break;
case C1LS:
c1ls_assemble(i,i_regs);break;
+ case COP2:
+ cop2_assemble(i,i_regs);break;
+ case C2LS:
+ c2ls_assemble(i,i_regs);break;
+ case C2OP:
+ c2op_assemble(i,i_regs);break;
case FCONV:
fconv_assemble(i,i_regs);break;
case FLOAT:
case MOV:
mov_assemble(i,i_regs);break;
case SYSCALL:
+ case HLECALL:
case SPAN:
case UJUMP:
case RJUMP:
}
// Generate address for load/store instruction
+// goes to AGEN for writes, FTEMP for LOADLR and cop1/2 loads
void address_generation(int i,struct regstat *i_regs,signed char entry[])
{
- if(itype[i]==LOAD||itype[i]==LOADLR||itype[i]==STORE||itype[i]==STORELR||itype[i]==C1LS) {
+ if(itype[i]==LOAD||itype[i]==LOADLR||itype[i]==STORE||itype[i]==STORELR||itype[i]==C1LS||itype[i]==C2LS) {
int ra;
int agr=AGEN1+(i&1);
int mgr=MGEN1+(i&1);
ra=get_reg(i_regs->regmap,agr);
if(ra<0) ra=get_reg(i_regs->regmap,-1);
}
- if(itype[i]==C1LS) {
- if (opcode[i]==0x31||opcode[i]==0x35) // LWC1/LDC1
+ 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);
}
else if(c) {
if(rm>=0) {
if(!entry||entry[rm]!=mgr) {
- if(itype[i]==STORE||itype[i]==STORELR||opcode[i]==0x39||opcode[i]==0x3D) {
+ if(itype[i]==STORE||itype[i]==STORELR||(opcode[i]&0x3b)==0x39||(opcode[i]&0x3b)==0x3a) {
// 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)
emit_movimm((constmap[i][rs]+offset)&0xFFFFFFF8,ra); // LDL/LDR
}else{
#ifdef HOST_IMM_ADDR32
- if((itype[i]!=LOAD&&opcode[i]!=0x31&&opcode[i]!=0x35) ||
+ if((itype[i]!=LOAD&&(opcode[i]&0x3b)!=0x31&&(opcode[i]&0x3b)!=0x32) || // LWC1/LDC1/LWC2/LDC2
(using_tlb&&((signed int)constmap[i][rs]+offset)>=(signed int)0xC0000000))
#endif
emit_movimm(constmap[i][rs]+offset,ra);
}
}
// Preload constants for next instruction
- if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) {
+ if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS||itype[i+1]==C2LS) {
int agr,ra;
#ifndef HOST_IMM_ADDR32
// Mapper entry
int offset=imm[i+1];
int c=(regs[i+1].wasconst>>rs)&1;
if(c) {
- if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) {
+ if(itype[i+1]==STORE||itype[i+1]==STORELR
+ ||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SWC1/SDC1, SWC2/SDC2
// 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)
emit_movimm((constmap[i+1][rs]+offset)&0xFFFFFFF8,ra); // LDL/LDR
}else{
#ifdef HOST_IMM_ADDR32
- if((itype[i+1]!=LOAD&&opcode[i+1]!=0x31&&opcode[i+1]!=0x35) ||
+ if((itype[i+1]!=LOAD&&(opcode[i+1]&0x3b)!=0x31&&(opcode[i+1]&0x3b)!=0x32) || // LWC1/LDC1/LWC2/LDC2
(using_tlb&&((signed int)constmap[i+1][rs]+offset)>=(signed int)0xC0000000))
#endif
emit_movimm(constmap[i+1][rs]+offset,ra);
if((i_dirty>>hr)&1) {
if(i_regmap[hr]<64) {
emit_storereg(i_regmap[hr],hr);
+#ifndef FORCE32
if( ((i_is32>>i_regmap[hr])&1) ) {
#ifdef DESTRUCTIVE_WRITEBACK
emit_sarimm(hr,31,hr);
emit_storereg(i_regmap[hr]|64,HOST_TEMPREG);
#endif
}
+#endif
}else{
if( !((i_is32>>(i_regmap[hr]&63))&1) ) {
emit_storereg(i_regmap[hr],hr);
if((i_dirty>>hr)&1) {
if(i_regmap[hr]<64) {
emit_storereg(i_regmap[hr],hr);
+#ifndef FORCE32
if( ((i_is32>>i_regmap[hr])&1) ) {
#ifdef DESTRUCTIVE_WRITEBACK
emit_sarimm(hr,31,hr);
emit_storereg(i_regmap[hr]|64,HOST_TEMPREG);
#endif
}
+#endif
}else{
if( !((i_is32>>(i_regmap[hr]&63))&1) ) {
emit_storereg(i_regmap[hr],hr);
wb_register(CCREG,regs[t].regmap_entry,regs[t].wasdirty,regs[t].was32);
load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,rs1[t],rs2[t]);
address_generation(t,®s[t],regs[t].regmap_entry);
- if(itype[t]==STORE||itype[t]==STORELR||(opcode[t]&0x3b)==0x39)
+ if(itype[t]==STORE||itype[t]==STORELR||(opcode[t]&0x3b)==0x39||(opcode[t]&0x3b)==0x3a)
load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,INVCP,INVCP);
cop1_usable=0;
is_delayslot=0;
cop1_assemble(t,®s[t]);break;
case C1LS:
c1ls_assemble(t,®s[t]);break;
+ case COP2:
+ cop2_assemble(t,®s[t]);break;
+ case C2LS:
+ c2ls_assemble(t,®s[t]);break;
+ case C2OP:
+ c2op_assemble(t,®s[t]);break;
case FCONV:
fconv_assemble(t,®s[t]);break;
case FLOAT:
case MOV:
mov_assemble(t,®s[t]);break;
case SYSCALL:
+ case HLECALL:
case SPAN:
case UJUMP:
case RJUMP:
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;
#endif
//if(opcode2[i]>=0x10) return; // FIXME (BxxZAL)
- assert(opcode2[i]<0x10||rs1[i]==0); // 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]))
// 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||ooo); // FIXME (BxxZALL)
if(ooo) {
s1l=get_reg(branch_regs[i].regmap,rs1[i]);
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){
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);
}
}
emit_writeword(HOST_BTREG,(int)&branch_target);
load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,rs1[0],rs2[0]);
address_generation(0,®s[0],regs[0].regmap_entry);
- if(itype[0]==STORE||itype[0]==STORELR||(opcode[0]&0x3b)==0x39)
+ if(itype[0]==STORE||itype[0]==STORELR||(opcode[0]&0x3b)==0x39||(opcode[0]&0x3b)==0x3a)
load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,INVCP,INVCP);
cop1_usable=0;
is_delayslot=0;
cop1_assemble(0,®s[0]);break;
case C1LS:
c1ls_assemble(0,®s[0]);break;
+ case COP2:
+ cop2_assemble(0,®s[0]);break;
+ case C2LS:
+ c2ls_assemble(0,®s[0]);break;
+ case C2OP:
+ c2op_assemble(0,®s[0]);break;
case FCONV:
fconv_assemble(0,®s[0]);break;
case FLOAT:
case MOV:
mov_assemble(0,®s[0]);break;
case SYSCALL:
+ case HLECALL:
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)
+ else if(itype[i]==SYSCALL||itype[i]==HLECALL)
{
// SYSCALL instruction (software interrupt)
u=1;
}
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(op2==0) is32|=1LL<<rt; // MFC0
break;
case COP1:
+ case COP2:
if(op2==0) is32|=1LL<<rt; // MFC1
if(op2==1) is32&=~(1LL<<rt); // DMFC1
if(op2==2) is32|=1LL<<rt; // CFC1
break;
case C1LS:
+ case C2LS:
break;
case FLOAT:
case FCONV:
break;
case FCOMP:
break;
+ case C2OP:
case SYSCALL:
+ case HLECALL:
break;
default:
break;
if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<<dep2[i+1];
}
}
- else if(itype[i]==SYSCALL)
+ else if(itype[i]==SYSCALL||itype[i]==HLECALL)
{
// SYSCALL instruction (software interrupt)
r32=0;
}
}
}
- else if(itype[i]==SYSCALL)
+ else if(itype[i]==SYSCALL||itype[i]==HLECALL)
{
// 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:
printf (" %x: %s r%d,cpr1[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC1
else printf (" %x: %s\n",start+i*4,insn[i]);
break;
+ case COP2:
+ if(opcode2[i]<3)
+ printf (" %x: %s r%d,cpr2[%d]\n",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC2
+ else if(opcode2[i]>3)
+ printf (" %x: %s r%d,cpr2[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC2
+ else printf (" %x: %s\n",start+i*4,insn[i]);
+ break;
case C1LS:
printf (" %x: %s cpr1[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]);
break;
+ 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;
default:
//printf (" %s %8x\n",insn[i],source[i]);
printf (" %x: %s\n",start+i*4,insn[i]);
memory_map[n]=((u_int)rdram-0x80000000)>>2;
for(n=526336;n<1048576;n++) // 0x80800000 .. 0xFFFFFFFF
memory_map[n]=-1;
+#ifdef MUPEN64
for(n=0;n<0x8000;n++) { // 0 .. 0x7FFFFFFF
writemem[n] = write_nomem_new;
writememb[n] = write_nomemb_new;
writememh[n] = write_nomemh_new;
+#ifndef FORCE32
writememd[n] = write_nomemd_new;
+#endif
readmem[n] = read_nomem_new;
readmemb[n] = read_nomemb_new;
readmemh[n] = read_nomemh_new;
+#ifndef FORCE32
readmemd[n] = read_nomemd_new;
+#endif
}
for(n=0x8000;n<0x8080;n++) { // 0x80000000 .. 0x807FFFFF
writemem[n] = write_rdram_new;
writememb[n] = write_rdramb_new;
writememh[n] = write_rdramh_new;
+#ifndef FORCE32
writememd[n] = write_rdramd_new;
+#endif
}
for(n=0xC000;n<0x10000;n++) { // 0xC0000000 .. 0xFFFFFFFF
writemem[n] = write_nomem_new;
writememb[n] = write_nomemb_new;
writememh[n] = write_nomemh_new;
+#ifndef FORCE32
writememd[n] = write_nomemd_new;
+#endif
readmem[n] = read_nomem_new;
readmemb[n] = read_nomemb_new;
readmemh[n] = read_nomemh_new;
+#ifndef FORCE32
readmemd[n] = read_nomemd_new;
+#endif
}
+#endif
tlb_hacks();
arch_init();
}
//rlist();
start = (u_int)addr&~3;
//assert(((u_int)addr&1)==0);
+#ifdef PCSX
+ if ((Config.HLE && start == 0x80001000) || // hlecall
+ (/*psxRegs.pc != 0x80030000 &&*/ start == 0x80030000)) // fastbios thing
+ {
+ // XXX: is this enough? Maybe check hleSoftCall?
+ u_int beginning=(u_int)out;
+ u_int page=get_page(start);
+ invalid_code[start>>12]=0;
+ emit_movimm(start,0);
+ emit_writeword(0,(int)&pcaddr);
+ emit_jmp((int)new_dyna_leave);
+#ifdef __arm__
+ __clear_cache((void *)beginning,out);
+#endif
+ if (start == 0x80030000)
+ return beginning;
+ else
+ ll_add(jump_in+page,start,(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);
}
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) {
//printf("addr=%x mm=%x\n",(u_int)addr,(memory_map[start>>12]<<2));
//if(tlb_LUT_r[start>>12])
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);
}
+#endif
else {
printf("Compile at bogus memory address: %x \n", (int)addr);
exit(1);
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;
case 0x15: strcpy(insn[i],"BNEL"); type=CJUMP; break;
case 0x16: strcpy(insn[i],"BLEZL"); type=CJUMP; break;
case 0x17: strcpy(insn[i],"BGTZL"); type=CJUMP; break;
+#ifndef FORCE32
case 0x18: strcpy(insn[i],"DADDI"); type=IMM16; 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;
- default: strcpy(insn[i],"???"); type=NI; break;
+#endif
+#ifdef PCSX
+ case 0x12: strcpy(insn[i],"COP2"); type=NI;
+ op2=(source[i]>>21)&0x1f;
+ 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 0x3A: strcpy(insn[i],"SWC2"); type=C2LS; break;
+ case 0x3B: strcpy(insn[i],"HLECALL"); type=HLECALL; break;
+#endif
+ default: strcpy(insn[i],"???"); type=NI;
+ printf("NI %08x @%08x (%08x)\n", source[i], addr + i*4, addr);
+ break;
}
itype[i]=type;
opcode2[i]=op2;
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;
if(op2==16) if((source[i]&0x3f)==0x18) rs2[i]=CCREG; // ERET
break;
case COP1:
+ case COP2:
rs1[i]=0;
rs2[i]=0;
rt1[i]=0;
rt2[i]=0;
imm[i]=(short)source[i];
break;
+ case C2LS:
+ rs1[i]=(source[i]>>21)&0x1F;
+ rs2[i]=0;
+ rt1[i]=0;
+ rt2[i]=0;
+ imm[i]=(short)source[i];
+ break;
case FLOAT:
case FCONV:
rs1[i]=0;
rt2[i]=0;
break;
case SYSCALL:
+ case HLECALL:
rs1[i]=CCREG;
rs2[i]=0;
rt1[i]=0;
else ba[i]=-1;
/* Is this the end of the block? */
if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) {
- if(rt1[i-1]!=31) { // Continue past subroutine call (JAL)
+ if(rt1[i-1]==0) { // Continue past subroutine call (JAL)
done=1;
// Does the block continue due to a branch?
for(j=i-1;j>=0;j--)
// 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;
- assert(i<MAXBLOCK-1);
+ if(itype[i]==SYSCALL&&stop_after_jal) done=1;
+ if(itype[i]==HLECALL) done=1;
+ //assert(i<MAXBLOCK-1);
if(start+i*4==pagelimit-4) done=1;
assert(start+i*4<pagelimit);
if (i==MAXBLOCK-1) done=1;
current.is32=temp_is32;
}
}
+#ifdef FORCE32
+ memset(p32, 0xff, sizeof(p32));
+ current.is32=-1LL;
+#endif
+
memcpy(regmap_pre[i],current.regmap,sizeof(current.regmap));
regs[i].wasconst=current.isconst;
regs[i].was32=current.is32;
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);
+ if (rt1[i]!=0) {
+ alloc_reg(¤t,i,rt1[i]);
+ dirty_reg(¤t,rt1[i]);
assert(rs1[i+1]!=31&&rs2[i+1]!=31);
#ifdef REG_PREFETCH
alloc_reg(¤t,i,PTEMP);
cop0_alloc(¤t,i);
break;
case COP1:
+ case COP2:
cop1_alloc(¤t,i);
break;
case C1LS:
c1ls_alloc(¤t,i);
break;
+ case C2LS:
+ c2ls_alloc(¤t,i);
+ break;
+ case C2OP:
+ c2op_alloc(¤t,i);
+ break;
case FCONV:
fconv_alloc(¤t,i);
break;
fcomp_alloc(¤t,i);
break;
case SYSCALL:
+ case HLECALL:
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
// Count cycles in between branches
ccadj[i]=cc;
- if(i>0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP||itype[i]==SYSCALL))
+ if(i>0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP||itype[i]==SYSCALL||itype[i]==HLECALL))
{
cc=0;
}
if(dep1[i+1]==(regs[i].regmap_entry[hr]&63)) nr|=1<<hr;
if(dep2[i+1]==(regs[i].regmap_entry[hr]&63)) nr|=1<<hr;
}
- if(itype[i+1]==STORE || itype[i+1]==STORELR || (opcode[i+1]&0x3b)==0x39) {
+ if(itype[i+1]==STORE || itype[i+1]==STORELR || (opcode[i+1]&0x3b)==0x39 || (opcode[i+1]&0x3b)==0x3a) {
if(regmap_pre[i][hr]==INVCP) nr|=1<<hr;
if(regs[i].regmap_entry[hr]==INVCP) nr|=1<<hr;
}
}
}
- else if(itype[i]==SYSCALL)
+ else if(itype[i]==SYSCALL||itype[i]==HLECALL)
{
// SYSCALL instruction (software interrupt)
nr=0;
if(dep2[i]==(regmap_pre[i][hr]&63)) nr|=1<<hr;
if(dep2[i]==(regs[i].regmap_entry[hr]&63)) nr|=1<<hr;
}
- if(itype[i]==STORE || itype[i]==STORELR || (opcode[i]&0x3b)==0x39) {
+ if(itype[i]==STORE || itype[i]==STORELR || (opcode[i]&0x3b)==0x39 || (opcode[i]&0x3b)==0x3a) {
if(regmap_pre[i][hr]==INVCP) nr|=1<<hr;
if(regs[i].regmap_entry[hr]==INVCP) nr|=1<<hr;
}
if(using_tlb) {
if(itype[i+1]==LOAD || itype[i+1]==LOADLR ||
itype[i+1]==STORE || itype[i+1]==STORELR ||
- itype[i+1]==C1LS )
+ itype[i+1]==C1LS || itype[i+1]==C2LS)
map=TLREG;
} else
- if(itype[i+1]==STORE || itype[i+1]==STORELR || (opcode[i+1]&0x3b)==0x39) {
+ if(itype[i+1]==STORE || itype[i+1]==STORELR ||
+ (opcode[i+1]&0x3b)==0x39 || (opcode[i+1]&0x3b)==0x3a) { // SWC1/SDC1 || SWC2/SDC2
map=INVCP;
}
if(itype[i+1]==LOADLR || itype[i+1]==STORELR ||
- itype[i+1]==C1LS )
+ itype[i+1]==C1LS || itype[i+1]==C2LS)
temp=FTEMP;
if((regs[i].regmap[hr]&63)!=rs1[i] && (regs[i].regmap[hr]&63)!=rs2[i] &&
(regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] &&
if(using_tlb) {
if(itype[i]==LOAD || itype[i]==LOADLR ||
itype[i]==STORE || itype[i]==STORELR ||
- itype[i]==C1LS )
+ itype[i]==C1LS || itype[i]==C2LS)
map=TLREG;
- } else if(itype[i]==STORE || itype[i]==STORELR || (opcode[i]&0x3b)==0x39) {
+ } else if(itype[i]==STORE || itype[i]==STORELR ||
+ (opcode[i]&0x3b)==0x39 || (opcode[i]&0x3b)==0x3a) { // SWC1/SDC1 || SWC2/SDC2
map=INVCP;
}
if(itype[i]==LOADLR || itype[i]==STORELR ||
- itype[i]==C1LS )
+ itype[i]==C1LS || itype[i]==C2LS)
temp=FTEMP;
if((regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] &&
(regs[i].regmap[hr]^64)!=us1[i] && (regs[i].regmap[hr]^64)!=us2[i] &&
||itype[i+1]==SHIFTIMM||itype[i+1]==IMM16||itype[i+1]==LOAD
||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]==FCOMP||itype[i+1]==FCONV
+ ||itype[i+1]==COP2||itype[i+1]==C2LS||itype[i+1]==C2OP)
{
int t=(ba[i]-start)>>2;
if(t>0&&(itype[t-1]!=UJUMP&&itype[t-1]!=RJUMP&&itype[t-1]!=CJUMP&&itype[t-1]!=SJUMP&&itype[t-1]!=FJUMP)) // loop_preload can't handle jumps into delay slots
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]==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...
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]==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(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]==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(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]==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;
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]==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(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]!=FCONV&&itype[i]!=FCOMP&&
+ itype[i]!=COP2&&itype[i]!=C2LS&&itype[i]!=C2OP)
{
memcpy(f_regmap,regs[i].regmap,sizeof(f_regmap));
}
{
if(!bt[i+1])
{
- if(itype[i]==ALU||itype[i]==MOV||itype[i]==LOAD||itype[i]==SHIFTIMM||itype[i]==IMM16||(itype[i]==COP1&&opcode2[i]<3))
+ if(itype[i]==ALU||itype[i]==MOV||itype[i]==LOAD||itype[i]==SHIFTIMM||itype[i]==IMM16
+ ||((itype[i]==COP1||itype[i]==COP2)&&opcode2[i]<3))
{
if(rs1[i+1]) {
if((hr=get_reg(regs[i+1].regmap,rs1[i+1]))>=0)
}
}
#ifndef HOST_IMM_ADDR32
- if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) {
+ if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS||itype[i+1]==C2LS) {
hr=get_reg(regs[i+1].regmap,TLREG);
if(hr>=0) {
int sr=get_reg(regs[i+1].regmap,rs1[i+1]);
}
}
#endif
- if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { // SB/SH/SW/SD/SWC1/SDC1
+ if(itype[i+1]==STORE||itype[i+1]==STORELR
+ ||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SB/SH/SW/SD/SWC1/SDC1/SWC2/SDC2
if(get_reg(regs[i+1].regmap,rs1[i+1])<0) {
hr=get_reg2(regs[i].regmap,regs[i+1].regmap,-1);
if(hr<0) hr=get_reg(regs[i+1].regmap,-1);
}
}
}
- if(itype[i+1]==LOADLR||opcode[i+1]==0x31||opcode[i+1]==0x35) { // LWC1/LDC1
+ if(itype[i+1]==LOADLR||(opcode[i+1]&0x3b)==0x31||(opcode[i+1]&0x3b)==0x32) { // LWC1/LDC1, LWC2/LDC2
if(get_reg(regs[i+1].regmap,rs1[i+1])<0) {
int nr;
hr=get_reg(regs[i+1].regmap,FTEMP);
}
}
}
- if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR/*||itype[i+1]==C1LS*/) {
+ if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR/*||itype[i+1]==C1LS||||itype[i+1]==C2LS*/) {
if(itype[i+1]==LOAD)
hr=get_reg(regs[i+1].regmap,rt1[i+1]);
- if(itype[i+1]==LOADLR||opcode[i+1]==0x31||opcode[i+1]==0x35) // LWC1/LDC1
+ if(itype[i+1]==LOADLR||(opcode[i+1]&0x3b)==0x31||(opcode[i+1]&0x3b)==0x32) // LWC1/LDC1, LWC2/LDC2
hr=get_reg(regs[i+1].regmap,FTEMP);
- if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { // SWC1/SDC1
+ if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SWC1/SDC1/SWC2/SDC2
hr=get_reg(regs[i+1].regmap,AGEN1+((i+1)&1));
if(hr<0) hr=get_reg(regs[i+1].regmap,-1);
}
if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<<dep2[i+1];
}
}
- else if(itype[i]==SYSCALL)
+ else if(itype[i]==SYSCALL||itype[i]==HLECALL)
{
// SYSCALL instruction (software interrupt)
r32=0;
else printf(" r%d",r);
}
}
+#ifndef FORCE32
printf(" UU:");
for(r=1;r<=CCREG;r++) {
if(((unneeded_reg_upper[i]&~unneeded_reg[i])>>r)&1) {
else printf(" r%d",r);
}
}
+#endif
printf("\n");
#if defined(__i386__) || defined(__x86_64__)
printf("pre: eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",regmap_pre[i][0],regmap_pre[i][1],regmap_pre[i][2],regmap_pre[i][3],regmap_pre[i][5],regmap_pre[i][6],regmap_pre[i][7]);
#endif
printf("\n");
}
+#ifndef FORCE32
printf(" 32:");
for(r=0;r<=CCREG;r++) {
if((regs[i].is32>>r)&1) {
}
}
printf("\n");
+#endif
/*printf(" p32:");
for(r=0;r<=CCREG;r++) {
if((p32[i]>>r)&1) {
if((branch_regs[i].dirty>>10)&1) printf("r10 ");
if((branch_regs[i].dirty>>12)&1) printf("r12 ");
#endif
+#ifndef FORCE32
printf(" 32:");
for(r=0;r<=CCREG;r++) {
if((branch_regs[i].is32>>r)&1) {
}
}
printf("\n");
+#endif
}
}
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])
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)
+ 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);
}
else if(i+1<slen)
// TODO: if(is_ooo(i)) address_generation(i+1);
if(itype[i]==CJUMP||itype[i]==FJUMP)
load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,CCREG,CCREG);
- if(itype[i]==STORE||itype[i]==STORELR||(opcode[i]&0x3b)==0x39)
+ if(itype[i]==STORE||itype[i]==STORELR||(opcode[i]&0x3b)==0x39||(opcode[i]&0x3b)==0x3a)
load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,INVCP,INVCP);
if(bt[i]) cop1_usable=0;
// assemble
cop1_assemble(i,®s[i]);break;
case C1LS:
c1ls_assemble(i,®s[i]);break;
+ case COP2:
+ cop2_assemble(i,®s[i]);break;
+ case C2LS:
+ c2ls_assemble(i,®s[i]);break;
+ case C2OP:
+ c2op_assemble(i,®s[i]);break;
case FCONV:
fconv_assemble(i,®s[i]);break;
case FLOAT:
mov_assemble(i,®s[i]);break;
case SYSCALL:
syscall_assemble(i,®s[i]);break;
+ case HLECALL:
+ hlecall_assemble(i,®s[i]);break;
case UJUMP:
ujump_assemble(i,®s[i]);ds=1;break;
case RJUMP:
// Trap writes to any of the pages we compiled
for(i=start>>12;i<=(start+slen*4)>>12;i++) {
invalid_code[i]=0;
+#ifndef DISABLE_TLB
memory_map[i]|=0x40000000;
if((signed int)start>=(signed int)0xC0000000) {
assert(using_tlb);
memory_map[j]|=0x40000000;
//printf("write protect physical page: %x (virtual %x)\n",j<<12,start);
}
+#endif
}
/* Pass 10 - Free memory by expiring oldest blocks */
break;
case 3:
// Clear jump_out
- #ifdef __arm__
- if((expirep&2047)==0)
- __clear_cache((void *)BASE_ADDR,(void *)BASE_ADDR+(1<<TARGET_SIZE_2));
- #endif
ll_remove_matching_addrs(jump_out+(expirep&2047),base,shift);
ll_remove_matching_addrs(jump_out+2048+(expirep&2047),base,shift);
break;
}
return 0;
}
+
+// vim:shiftwidth=2:expandtab