X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Fnew_dynarec%2Fnew_dynarec.c;h=7c59a7e8a707d1032e55659edc0675d3494b1f8e;hb=7c3a5182da4384e21a6ace037583fae399de5a02;hp=78a342d262b71cbfc703894cfc4d28104235b62b;hpb=ad49de8937ff55b6295a8065d1b942c29726a363;p=pcsx_rearmed.git
diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c
index 78a342d2..7c59a7e8 100644
--- a/libpcsxcore/new_dynarec/new_dynarec.c
+++ b/libpcsxcore/new_dynarec/new_dynarec.c
@@ -57,6 +57,9 @@ static int sceBlock;
#ifdef __arm__
#include "assem_arm.h"
#endif
+#ifdef __aarch64__
+#include "assem_arm64.h"
+#endif
#define MAXBLOCK 4096
#define MAX_OUTPUT_BLOCK_SIZE 262144
@@ -144,8 +147,6 @@ struct link_entry
static u_char rs2[MAXBLOCK];
static u_char rt1[MAXBLOCK];
static u_char rt2[MAXBLOCK];
- static u_char us1[MAXBLOCK];
- static u_char us2[MAXBLOCK];
static u_char dep1[MAXBLOCK];
static u_char dep2[MAXBLOCK];
static u_char lt1[MAXBLOCK];
@@ -195,13 +196,19 @@ struct link_entry
int new_dynarec_hacks;
int new_dynarec_did_compile;
+
+ extern int cycle_count; // ... until end of the timeslice, counts -N -> 0
+ extern int last_count; // last absolute target, often = next_interupt
+ extern int pcaddr;
+ extern int pending_exception;
+ extern int branch_target;
+ extern u_int mini_ht[32][2];
extern u_char restore_candidate[512];
- extern int cycle_count;
/* registers that may be allocated */
/* 1-31 gpr */
-#define HIREG 32 // hi
-#define LOREG 33 // lo
+#define LOREG 32 // lo
+#define HIREG 33 // hi
//#define FSREG 34 // FPU status (FCSR)
#define CSREG 35 // Coprocessor status
#define CCREG 36 // Cycle count
@@ -260,6 +267,9 @@ struct link_entry
#define NOTTAKEN 2
#define NULLDS 3
+#define DJT_1 (void *)1l // no function, just a label in assem_debug log
+#define DJT_2 (void *)2l
+
// asm linkage
int new_recompile_block(int addr);
void *get_addr_ht(u_int vaddr);
@@ -269,7 +279,6 @@ void remove_hash(int vaddr);
void dyna_linker();
void dyna_linker_ds();
void verify_code();
-void verify_code_vm();
void verify_code_ds();
void cc_interrupt();
void fp_exception();
@@ -295,6 +304,10 @@ static void add_stub(enum stub_type type, void *addr, void *retaddr,
static void add_stub_r(enum stub_type type, void *addr, void *retaddr,
int i, int addr_reg, struct regstat *i_regs, int ccadj, u_int reglist);
static void add_to_linker(void *addr, u_int target, int ext);
+static void *emit_fastpath_cmp_jump(int i,int addr,int *addr_reg_override);
+static void *get_direct_memhandler(void *table, u_int addr,
+ enum stub_type type, uintptr_t *addr_host);
+static void pass_args(int a0, int a1);
static void mprotect_w_x(void *start, void *end, int is_x)
{
@@ -337,6 +350,8 @@ static void end_tcache_write(void *start, void *end)
__clear_cache(start, end);
#endif
(void)len;
+#else
+ __clear_cache(start, end);
#endif
mprotect_w_x(start, end, 1);
@@ -522,10 +537,6 @@ void set_const(struct regstat *cur,signed char reg,uint64_t value)
cur->isconst|=1<
regmap[hr]^64)==reg) {
- cur->isconst|=1<
>32;
- }
}
}
@@ -562,7 +573,7 @@ uint64_t get_const(struct regstat *cur,signed char reg)
}
}
SysPrintf("Unknown constant in r%d\n",reg);
- exit(1);
+ abort();
}
// Least soon needed registers
@@ -783,6 +794,46 @@ void alloc_all(struct regstat *cur,int i)
}
}
+#ifdef DRC_DBG
+extern void gen_interupt();
+extern void do_insn_cmp();
+#define FUNCNAME(f) { (intptr_t)f, " " #f }
+static const struct {
+ intptr_t addr;
+ const char *name;
+} function_names[] = {
+ FUNCNAME(cc_interrupt),
+ FUNCNAME(gen_interupt),
+ FUNCNAME(get_addr_ht),
+ FUNCNAME(get_addr),
+ FUNCNAME(jump_handler_read8),
+ FUNCNAME(jump_handler_read16),
+ FUNCNAME(jump_handler_read32),
+ FUNCNAME(jump_handler_write8),
+ FUNCNAME(jump_handler_write16),
+ FUNCNAME(jump_handler_write32),
+ FUNCNAME(invalidate_addr),
+ FUNCNAME(verify_code),
+ FUNCNAME(jump_hlecall),
+ FUNCNAME(jump_syscall_hle),
+ FUNCNAME(new_dyna_leave),
+ FUNCNAME(pcsx_mtc0),
+ FUNCNAME(pcsx_mtc0_ds),
+ FUNCNAME(do_insn_cmp),
+};
+
+static const char *func_name(intptr_t a)
+{
+ int i;
+ for (i = 0; i < sizeof(function_names)/sizeof(function_names[0]); i++)
+ if (function_names[i].addr == a)
+ return function_names[i].name;
+ return "";
+}
+#else
+#define func_name(x) ""
+#endif
+
#ifdef __i386__
#include "assem_x86.c"
#endif
@@ -792,6 +843,9 @@ void alloc_all(struct regstat *cur,int i)
#ifdef __arm__
#include "assem_arm.c"
#endif
+#ifdef __aarch64__
+#include "assem_arm64.c"
+#endif
// Add virtual address mapping to linked list
void ll_add(struct ll_entry **head,int vaddr,void *addr)
@@ -920,7 +974,7 @@ static void ll_kill_pointers(struct ll_entry *head,uintptr_t addr,int shift)
{
inv_debug("EXP: Kill pointer at %p (%x)\n",head->addr,head->vaddr);
void *host_addr=find_extjump_insn(head->addr);
- #ifdef __arm__
+ #if defined(__arm__) || defined(__aarch64__)
mark_clear_cache(host_addr);
#endif
set_jump_target(host_addr, head->addr);
@@ -948,7 +1002,7 @@ void invalidate_page(u_int page)
while(head!=NULL) {
inv_debug("INVALIDATE: kill pointer to %x (%p)\n",head->vaddr,head->addr);
void *host_addr=find_extjump_insn(head->addr);
- #ifdef __arm__
+ #if defined(__arm__) || defined(__aarch64__)
mark_clear_cache(host_addr);
#endif
set_jump_target(host_addr, head->addr);
@@ -973,7 +1027,7 @@ static void invalidate_block_range(u_int block, u_int first, u_int last)
for(first=page+1;firstu>>reg)&1) return;
+
+ // see if it's already allocated
+ for(hr=0;hrregmap[hr]==reg) return;
+ }
+
+ // Keep the same mapping if the register was already allocated in a loop
+ preferred_reg = loop_reg(i,reg,preferred_reg);
+
+ // Try to allocate the preferred register
+ if(cur->regmap[preferred_reg]==-1) {
+ cur->regmap[preferred_reg]=reg;
+ cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg];
+ assert(r < 64);
+ if((cur->u>>r)&1) {
+ cur->regmap[preferred_reg]=reg;
+ cur->dirty&=~(1<isconst&=~(1<regmap[hr];
+ if(r>=0) {
+ assert(r < 64);
+ if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;}
+ }
+ }
+ // Try to allocate any available register, but prefer
+ // registers that have not been used recently.
+ if(i>0) {
+ for(hr=0;hrregmap[hr]==-1) {
+ if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<
isconst&=~(1<
regmap[hr]==-1) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<
isconst&=~(1<
regmap[0],cur->regmap[1],cur->regmap[2],cur->regmap[3],cur->regmap[5],cur->regmap[6],cur->regmap[7]);
+ //printf("hsn(%x): %d %d %d %d %d %d %d\n",start+i*4,hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]);
+ if(i>0) {
+ // Don't evict the cycle count at entry points, otherwise the entry
+ // stub will have to write it.
+ if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2;
+ if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP)) hsn[CCREG]=2;
+ for(j=10;j>=3;j--)
+ {
+ // Alloc preferred register if available
+ if(hsn[r=cur->regmap[preferred_reg]&63]==j) {
+ for(hr=0;hrregmap[hr]&63)==r) {
+ cur->regmap[hr]=-1;
+ cur->dirty&=~(1<
isconst&=~(1<
regmap[preferred_reg]=reg;
+ return;
+ }
+ for(r=1;r<=MAXREG;r++)
+ {
+ if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) {
+ for(hr=0;hrregmap[hr]==r) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<
isconst&=~(1<
=0;j--)
+ {
+ for(r=1;r<=MAXREG;r++)
+ {
+ if(hsn[r]==j) {
+ for(hr=0;hrregmap[hr]==r) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<
isconst&=~(1<
regmap[hr]==reg) return;
+ }
+
+ // Try to allocate any available register
+ for(hr=HOST_REGS-1;hr>=0;hr--) {
+ if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<
isconst&=~(1<
=0;hr--)
+ {
+ r=cur->regmap[hr];
+ if(r>=0) {
+ assert(r < 64);
+ if((cur->u>>r)&1) {
+ if(i==0||((unneeded_reg[i-1]>>r)&1)) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<
isconst&=~(1<
regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]);
+ if(i>0) {
+ // Don't evict the cycle count at entry points, otherwise the entry
+ // stub will have to write it.
+ if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2;
+ if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP)) hsn[CCREG]=2;
+ for(j=10;j>=3;j--)
+ {
+ for(r=1;r<=MAXREG;r++)
+ {
+ if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) {
+ for(hr=0;hr2) {
+ if(cur->regmap[hr]==r) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<
isconst&=~(1<
=0;j--)
+ {
+ for(r=1;r<=MAXREG;r++)
+ {
+ if(hsn[r]==j) {
+ for(hr=0;hrregmap[hr]==r) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<
isconst&=~(1<
>(reg&63))&1) {
+ if(reg>0) {
+ if(((dirty_pre&~dirty)>>hr)&1) {
+ if(reg>0&®<34) {
+ emit_storereg(reg,hr);
+ }
+ else if(reg>=64) {
+ assert(0);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// trashes r2
+static void pass_args(int a0, int a1)
+{
+ if(a0==1&&a1==0) {
+ // must swap
+ emit_mov(a0,2); emit_mov(a1,1); emit_mov(2,0);
+ }
+ else if(a0!=0&&a1==0) {
+ emit_mov(a1,1);
+ if (a0>=0) emit_mov(a0,0);
+ }
+ else {
+ if(a0>=0&&a0!=0) emit_mov(a0,0);
+ if(a1>=0&&a1!=1) emit_mov(a1,1);
+ }
}
-void alu_assemble(int i,struct regstat *i_regs)
+static void alu_assemble(int i,struct regstat *i_regs)
{
if(opcode2[i]>=0x20&&opcode2[i]<=0x23) { // ADD/ADDU/SUB/SUBU
if(rt1[i]) {
@@ -1843,24 +2162,15 @@ void imm16_assemble(int i,struct regstat *i_regs)
}
if(opcode[i]==0x18||opcode[i]==0x19) { // DADDI/DADDIU
if(rt1[i]) {
- signed char sh,sl,th,tl;
- th=get_reg(i_regs->regmap,rt1[i]|64);
+ signed char sl,tl;
tl=get_reg(i_regs->regmap,rt1[i]);
- sh=get_reg(i_regs->regmap,rs1[i]|64);
sl=get_reg(i_regs->regmap,rs1[i]);
if(tl>=0) {
if(rs1[i]) {
- assert(sh>=0);
assert(sl>=0);
- if(th>=0) {
- emit_addimm64_32(sh,sl,imm[i],th,tl);
- }
- else {
- emit_addimm(sl,imm[i],tl);
- }
+ emit_addimm(sl,imm[i],tl);
} else {
emit_movimm(imm[i],tl);
- if(th>=0) emit_movimm(((signed int)imm[i])>>31,th);
}
}
}
@@ -1907,10 +2217,8 @@ void imm16_assemble(int i,struct regstat *i_regs)
}
else if(opcode[i]>=0x0c&&opcode[i]<=0x0e) { // ANDI/ORI/XORI
if(rt1[i]) {
- signed char sh,sl,th,tl;
- th=get_reg(i_regs->regmap,rt1[i]|64);
+ signed char sl,tl;
tl=get_reg(i_regs->regmap,rt1[i]);
- sh=get_reg(i_regs->regmap,rs1[i]|64);
sl=get_reg(i_regs->regmap,rs1[i]);
if(tl>=0 && !((i_regs->isconst>>tl)&1)) {
if(opcode[i]==0x0c) //ANDI
@@ -1928,7 +2236,6 @@ void imm16_assemble(int i,struct regstat *i_regs)
}
else
emit_zeroreg(tl);
- if(th>=0) emit_zeroreg(th);
}
else
{
@@ -1936,13 +2243,6 @@ void imm16_assemble(int i,struct regstat *i_regs)
if(sl<0) {
if(i_regs->regmap_entry[tl]!=rs1[i]) emit_loadreg(rs1[i],tl);
}
- if(th>=0) {
- if(sh<0) {
- emit_loadreg(rs1[i]|64,th);
- }else{
- emit_mov(sh,th);
- }
- }
if(opcode[i]==0x0d) { // ORI
if(sl<0) {
emit_orimm(tl,imm[i],tl);
@@ -1966,7 +2266,6 @@ void imm16_assemble(int i,struct regstat *i_regs)
}
else {
emit_movimm(imm[i],tl);
- if(th>=0) emit_zeroreg(th);
}
}
}
@@ -2035,19 +2334,135 @@ void shiftimm_assemble(int i,struct regstat *i_regs)
void shift_assemble(int i,struct regstat *i_regs)
{
printf("Need shift_assemble for this architecture.\n");
- exit(1);
+ abort();
}
#endif
-void load_assemble(int i,struct regstat *i_regs)
+enum {
+ MTYPE_8000 = 0,
+ MTYPE_8020,
+ MTYPE_0000,
+ MTYPE_A000,
+ MTYPE_1F80,
+};
+
+static int get_ptr_mem_type(u_int a)
+{
+ if(a < 0x00200000) {
+ if(a<0x1000&&((start>>20)==0xbfc||(start>>24)==0xa0))
+ // return wrong, must use memhandler for BIOS self-test to pass
+ // 007 does similar stuff from a00 mirror, weird stuff
+ return MTYPE_8000;
+ return MTYPE_0000;
+ }
+ if(0x1f800000 <= a && a < 0x1f801000)
+ return MTYPE_1F80;
+ if(0x80200000 <= a && a < 0x80800000)
+ return MTYPE_8020;
+ if(0xa0000000 <= a && a < 0xa0200000)
+ return MTYPE_A000;
+ return MTYPE_8000;
+}
+
+static void *emit_fastpath_cmp_jump(int i,int addr,int *addr_reg_override)
{
- int s,th,tl,addr;
+ void *jaddr = NULL;
+ int type=0;
+ int mr=rs1[i];
+ if(((smrv_strong|smrv_weak)>>mr)&1) {
+ type=get_ptr_mem_type(smrv[mr]);
+ //printf("set %08x @%08x r%d %d\n", smrv[mr], start+i*4, mr, type);
+ }
+ else {
+ // use the mirror we are running on
+ type=get_ptr_mem_type(start);
+ //printf("set nospec @%08x r%d %d\n", start+i*4, mr, type);
+ }
+
+ if(type==MTYPE_8020) { // RAM 80200000+ mirror
+ emit_andimm(addr,~0x00e00000,HOST_TEMPREG);
+ addr=*addr_reg_override=HOST_TEMPREG;
+ type=0;
+ }
+ else if(type==MTYPE_0000) { // RAM 0 mirror
+ emit_orimm(addr,0x80000000,HOST_TEMPREG);
+ addr=*addr_reg_override=HOST_TEMPREG;
+ type=0;
+ }
+ else if(type==MTYPE_A000) { // RAM A mirror
+ emit_andimm(addr,~0x20000000,HOST_TEMPREG);
+ addr=*addr_reg_override=HOST_TEMPREG;
+ type=0;
+ }
+ else if(type==MTYPE_1F80) { // scratchpad
+ if (psxH == (void *)0x1f800000) {
+ emit_addimm(addr,-0x1f800000,HOST_TEMPREG);
+ emit_cmpimm(HOST_TEMPREG,0x1000);
+ jaddr=out;
+ emit_jc(0);
+ }
+ else {
+ // do the usual RAM check, jump will go to the right handler
+ type=0;
+ }
+ }
+
+ if(type==0)
+ {
+ emit_cmpimm(addr,RAM_SIZE);
+ jaddr=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);
+ if(ram_offset!=0) {
+ emit_addimm(addr,ram_offset,HOST_TEMPREG);
+ addr=*addr_reg_override=HOST_TEMPREG;
+ }
+ }
+
+ return jaddr;
+}
+
+// return memhandler, or get directly accessable address and return 0
+static void *get_direct_memhandler(void *table, u_int addr,
+ enum stub_type type, uintptr_t *addr_host)
+{
+ uintptr_t l1, l2 = 0;
+ l1 = ((uintptr_t *)table)[addr>>12];
+ if ((l1 & (1ul << (sizeof(l1)*8-1))) == 0) {
+ uintptr_t v = l1 << 1;
+ *addr_host = v + addr;
+ return NULL;
+ }
+ else {
+ l1 <<= 1;
+ if (type == LOADB_STUB || type == LOADBU_STUB || type == STOREB_STUB)
+ l2 = ((uintptr_t *)l1)[0x1000/4 + 0x1000/2 + (addr&0xfff)];
+ else if (type == LOADH_STUB || type == LOADHU_STUB || type == STOREH_STUB)
+ l2=((uintptr_t *)l1)[0x1000/4 + (addr&0xfff)/2];
+ else
+ l2=((uintptr_t *)l1)[(addr&0xfff)/4];
+ if ((l2 & (1<<31)) == 0) {
+ uintptr_t v = l2 << 1;
+ *addr_host = v + (addr&0xfff);
+ return NULL;
+ }
+ return (void *)(l2 << 1);
+ }
+}
+
+static void load_assemble(int i,struct regstat *i_regs)
+{
+ int s,tl,addr;
int offset;
void *jaddr=0;
int memtarget=0,c=0;
int fastload_reg_override=0;
u_int hr,reglist=0;
- th=get_reg(i_regs->regmap,rt1[i]|64);
tl=get_reg(i_regs->regmap,rt1[i]);
s=get_reg(i_regs->regmap,rs1[i]);
offset=imm[i];
@@ -2080,7 +2495,6 @@ void load_assemble(int i,struct regstat *i_regs)
//if(c) printf("load_assemble: const=%lx\n",(long)constmap[i][s]+offset);
assert(tl>=0); // Even if the load is a NOP, we must check for pagefaults and I/O
reglist&=~(1<=0) reglist&=~(1<regmap,rt1[i],ccadj[i],reglist);
}
if (opcode[i]==0x27) { // LWU
- assert(th>=0);
- if(!c||memtarget) {
- if(!dummy) {
- int a=addr;
- if(fastload_reg_override) a=fastload_reg_override;
- emit_readword_indexed(0,a,tl);
- }
- if(jaddr)
- add_stub_r(LOADW_STUB,jaddr,out,i,addr,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);
+ assert(0);
}
if (opcode[i]==0x37) { // LD
assert(0);
@@ -2194,7 +2595,7 @@ void load_assemble(int i,struct regstat *i_regs)
void loadlr_assemble(int i,struct regstat *i_regs)
{
printf("Need loadlr_assemble for this architecture.\n");
- exit(1);
+ abort();
}
#endif
@@ -2480,12 +2881,234 @@ void storelr_assemble(int i,struct regstat *i_regs)
}
}
-void c1ls_assemble(int i,struct regstat *i_regs)
+static void cop0_assemble(int i,struct regstat *i_regs)
+{
+ if(opcode2[i]==0) // MFC0
+ {
+ signed char t=get_reg(i_regs->regmap,rt1[i]);
+ u_int copr=(source[i]>>11)&0x1f;
+ //assert(t>=0); // Why does this happen? OOT is weird
+ if(t>=0&&rt1[i]!=0) {
+ emit_readword(®_cop0[copr],t);
+ }
+ }
+ else if(opcode2[i]==4) // MTC0
+ {
+ signed char s=get_reg(i_regs->regmap,rs1[i]);
+ char copr=(source[i]>>11)&0x1f;
+ assert(s>=0);
+ wb_register(rs1[i],i_regs->regmap,i_regs->dirty);
+ if(copr==9||copr==11||copr==12||copr==13) {
+ emit_readword(&last_count,HOST_TEMPREG);
+ emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc
+ emit_add(HOST_CCREG,HOST_TEMPREG,HOST_CCREG);
+ emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
+ emit_writeword(HOST_CCREG,&Count);
+ }
+ // What a mess. The status register (12) can enable interrupts,
+ // so needs a special case to handle a pending interrupt.
+ // The interrupt must be taken immediately, because a subsequent
+ // instruction might disable interrupts again.
+ if(copr==12||copr==13) {
+ if (is_delayslot) {
+ // burn cycles to cause cc_interrupt, which will
+ // reschedule next_interupt. Relies on CCREG from above.
+ assem_debug("MTC0 DS %d\n", copr);
+ emit_writeword(HOST_CCREG,&last_count);
+ emit_movimm(0,HOST_CCREG);
+ emit_storereg(CCREG,HOST_CCREG);
+ emit_loadreg(rs1[i],1);
+ emit_movimm(copr,0);
+ emit_call(pcsx_mtc0_ds);
+ emit_loadreg(rs1[i],s);
+ return;
+ }
+ emit_movimm(start+i*4+4,HOST_TEMPREG);
+ emit_writeword(HOST_TEMPREG,&pcaddr);
+ emit_movimm(0,HOST_TEMPREG);
+ emit_writeword(HOST_TEMPREG,&pending_exception);
+ }
+ //else if(copr==12&&is_delayslot) emit_call((int)MTC0_R12);
+ //else
+ if(s==HOST_CCREG)
+ emit_loadreg(rs1[i],1);
+ else if(s!=1)
+ emit_mov(s,1);
+ emit_movimm(copr,0);
+ emit_call(pcsx_mtc0);
+ if(copr==9||copr==11||copr==12||copr==13) {
+ emit_readword(&Count,HOST_CCREG);
+ emit_readword(&next_interupt,HOST_TEMPREG);
+ emit_addimm(HOST_CCREG,-CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
+ emit_sub(HOST_CCREG,HOST_TEMPREG,HOST_CCREG);
+ emit_writeword(HOST_TEMPREG,&last_count);
+ emit_storereg(CCREG,HOST_CCREG);
+ }
+ if(copr==12||copr==13) {
+ assert(!is_delayslot);
+ emit_readword(&pending_exception,14);
+ emit_test(14,14);
+ emit_jne(&do_interrupt);
+ }
+ emit_loadreg(rs1[i],s);
+ }
+ else
+ {
+ assert(opcode2[i]==0x10);
+ //if((source[i]&0x3f)==0x10) // RFE
+ {
+ emit_readword(&Status,0);
+ emit_andimm(0,0x3c,1);
+ emit_andimm(0,~0xf,0);
+ emit_orrshr_imm(1,2,0);
+ emit_writeword(0,&Status);
+ }
+ }
+}
+
+static void cop1_unusable(int i,struct regstat *i_regs)
+{
+ // XXX: should just just do the exception instead
+ //if(!cop1_usable)
+ {
+ void *jaddr=out;
+ emit_jmp(0);
+ add_stub_r(FP_STUB,jaddr,out,i,0,i_regs,is_delayslot,0);
+ }
+}
+
+static void cop1_assemble(int i,struct regstat *i_regs)
{
cop1_unusable(i, i_regs);
}
-void c2ls_assemble(int i,struct regstat *i_regs)
+static void c1ls_assemble(int i,struct regstat *i_regs)
+{
+ cop1_unusable(i, i_regs);
+}
+
+// FP_STUB
+static void do_cop1stub(int n)
+{
+ literal_pool(256);
+ assem_debug("do_cop1stub %x\n",start+stubs[n].a*4);
+ set_jump_target(stubs[n].addr, out);
+ int i=stubs[n].a;
+// int rs=stubs[n].b;
+ struct regstat *i_regs=(struct regstat *)stubs[n].c;
+ int ds=stubs[n].d;
+ if(!ds) {
+ load_all_consts(regs[i].regmap_entry,regs[i].wasdirty,i);
+ //if(i_regs!=®s[i]) printf("oops: regs[i]=%x i_regs=%x",(int)®s[i],(int)i_regs);
+ }
+ //else {printf("fp exception in delay slot\n");}
+ wb_dirtys(i_regs->regmap_entry,i_regs->wasdirty);
+ if(regs[i].regmap_entry[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG);
+ emit_movimm(start+(i-ds)*4,EAX); // Get PC
+ emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle...
+ emit_jmp(ds?fp_exception_ds:fp_exception);
+}
+
+static void cop2_get_dreg(u_int copr,signed char tl,signed char temp)
+{
+ switch (copr) {
+ case 1:
+ case 3:
+ case 5:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ emit_readword(®_cop2d[copr],tl);
+ emit_signextend16(tl,tl);
+ emit_writeword(tl,®_cop2d[copr]); // hmh
+ break;
+ case 7:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ emit_readword(®_cop2d[copr],tl);
+ emit_andimm(tl,0xffff,tl);
+ emit_writeword(tl,®_cop2d[copr]);
+ break;
+ case 15:
+ emit_readword(®_cop2d[14],tl); // SXY2
+ emit_writeword(tl,®_cop2d[copr]);
+ break;
+ case 28:
+ case 29:
+ emit_readword(®_cop2d[9],temp);
+ emit_testimm(temp,0x8000); // do we need this?
+ emit_andimm(temp,0xf80,temp);
+ emit_andne_imm(temp,0,temp);
+ emit_shrimm(temp,7,tl);
+ emit_readword(®_cop2d[10],temp);
+ emit_testimm(temp,0x8000);
+ emit_andimm(temp,0xf80,temp);
+ emit_andne_imm(temp,0,temp);
+ emit_orrshr_imm(temp,2,tl);
+ emit_readword(®_cop2d[11],temp);
+ emit_testimm(temp,0x8000);
+ emit_andimm(temp,0xf80,temp);
+ emit_andne_imm(temp,0,temp);
+ emit_orrshl_imm(temp,3,tl);
+ emit_writeword(tl,®_cop2d[copr]);
+ break;
+ default:
+ emit_readword(®_cop2d[copr],tl);
+ break;
+ }
+}
+
+static void cop2_put_dreg(u_int copr,signed char sl,signed char temp)
+{
+ switch (copr) {
+ case 15:
+ emit_readword(®_cop2d[13],temp); // SXY1
+ emit_writeword(sl,®_cop2d[copr]);
+ emit_writeword(temp,®_cop2d[12]); // SXY0
+ emit_readword(®_cop2d[14],temp); // SXY2
+ emit_writeword(sl,®_cop2d[14]);
+ emit_writeword(temp,®_cop2d[13]); // SXY1
+ break;
+ case 28:
+ emit_andimm(sl,0x001f,temp);
+ emit_shlimm(temp,7,temp);
+ emit_writeword(temp,®_cop2d[9]);
+ emit_andimm(sl,0x03e0,temp);
+ emit_shlimm(temp,2,temp);
+ emit_writeword(temp,®_cop2d[10]);
+ emit_andimm(sl,0x7c00,temp);
+ emit_shrimm(temp,3,temp);
+ emit_writeword(temp,®_cop2d[11]);
+ emit_writeword(sl,®_cop2d[28]);
+ break;
+ case 30:
+ emit_movs(sl,temp);
+ emit_mvnmi(temp,temp);
+#if defined(HAVE_ARMV5) || defined(__aarch64__)
+ emit_clz(temp,temp);
+#else
+ emit_movs(temp,HOST_TEMPREG);
+ emit_movimm(0,temp);
+ emit_jeq((int)out+4*4);
+ emit_addpl_imm(temp,1,temp);
+ emit_lslpls_imm(HOST_TEMPREG,1,HOST_TEMPREG);
+ emit_jns((int)out-2*4);
+#endif
+ emit_writeword(sl,®_cop2d[30]);
+ emit_writeword(temp,®_cop2d[31]);
+ break;
+ case 31:
+ break;
+ default:
+ emit_writeword(sl,®_cop2d[copr]);
+ break;
+ }
+}
+
+static void c2ls_assemble(int i,struct regstat *i_regs)
{
int s,tl;
int ar;
@@ -2579,37 +3202,82 @@ void c2ls_assemble(int i,struct regstat *i_regs)
}
}
+static void cop2_assemble(int i,struct regstat *i_regs)
+{
+ u_int copr=(source[i]>>11)&0x1f;
+ signed char temp=get_reg(i_regs->regmap,-1);
+ if (opcode2[i]==0) { // MFC2
+ signed char tl=get_reg(i_regs->regmap,rt1[i]);
+ if(tl>=0&&rt1[i]!=0)
+ cop2_get_dreg(copr,tl,temp);
+ }
+ else if (opcode2[i]==4) { // MTC2
+ signed char sl=get_reg(i_regs->regmap,rs1[i]);
+ cop2_put_dreg(copr,sl,temp);
+ }
+ else if (opcode2[i]==2) // CFC2
+ {
+ signed char tl=get_reg(i_regs->regmap,rt1[i]);
+ if(tl>=0&&rt1[i]!=0)
+ emit_readword(®_cop2c[copr],tl);
+ }
+ else if (opcode2[i]==6) // CTC2
+ {
+ signed char sl=get_reg(i_regs->regmap,rs1[i]);
+ switch(copr) {
+ case 4:
+ case 12:
+ case 20:
+ case 26:
+ case 27:
+ case 29:
+ case 30:
+ emit_signextend16(sl,temp);
+ break;
+ case 31:
+ //value = value & 0x7ffff000;
+ //if (value & 0x7f87e000) value |= 0x80000000;
+ emit_shrimm(sl,12,temp);
+ emit_shlimm(temp,12,temp);
+ emit_testimm(temp,0x7f000000);
+ emit_testeqimm(temp,0x00870000);
+ emit_testeqimm(temp,0x0000e000);
+ emit_orrne_imm(temp,0x80000000,temp);
+ break;
+ default:
+ temp=sl;
+ break;
+ }
+ emit_writeword(temp,®_cop2c[copr]);
+ assert(sl>=0);
+ }
+}
+
#ifndef multdiv_assemble
void multdiv_assemble(int i,struct regstat *i_regs)
{
printf("Need multdiv_assemble for this architecture.\n");
- exit(1);
+ abort();
}
#endif
-void mov_assemble(int i,struct regstat *i_regs)
+static void mov_assemble(int i,struct regstat *i_regs)
{
//if(opcode2[i]==0x10||opcode2[i]==0x12) { // MFHI/MFLO
//if(opcode2[i]==0x11||opcode2[i]==0x13) { // MTHI/MTLO
if(rt1[i]) {
- signed char sh,sl,th,tl;
- th=get_reg(i_regs->regmap,rt1[i]|64);
+ signed char sl,tl;
tl=get_reg(i_regs->regmap,rt1[i]);
//assert(tl>=0);
if(tl>=0) {
- sh=get_reg(i_regs->regmap,rs1[i]|64);
sl=get_reg(i_regs->regmap,rs1[i]);
if(sl>=0) emit_mov(sl,tl);
else emit_loadreg(rs1[i],tl);
- if(th>=0) {
- if(sh>=0) emit_mov(sh,th);
- else emit_loadreg(rs1[i]|64,th);
- }
}
}
}
-void syscall_assemble(int i,struct regstat *i_regs)
+static void syscall_assemble(int i,struct regstat *i_regs)
{
signed char ccreg=get_reg(i_regs->regmap,CCREG);
assert(ccreg==HOST_CCREG);
@@ -2620,7 +3288,7 @@ void syscall_assemble(int i,struct regstat *i_regs)
emit_jmp(jump_syscall_hle); // XXX
}
-void hlecall_assemble(int i,struct regstat *i_regs)
+static void hlecall_assemble(int i,struct regstat *i_regs)
{
extern void psxNULL();
signed char ccreg=get_reg(i_regs->regmap,CCREG);
@@ -2637,7 +3305,7 @@ void hlecall_assemble(int i,struct regstat *i_regs)
emit_jmp(jump_hlecall);
}
-void intcall_assemble(int i,struct regstat *i_regs)
+static void intcall_assemble(int i,struct regstat *i_regs)
{
signed char ccreg=get_reg(i_regs->regmap,CCREG);
assert(ccreg==HOST_CCREG);
@@ -2648,7 +3316,99 @@ void intcall_assemble(int i,struct regstat *i_regs)
emit_jmp(jump_intcall);
}
-void ds_assemble(int i,struct regstat *i_regs)
+static void speculate_mov(int rs,int rt)
+{
+ if(rt!=0) {
+ smrv_strong_next|=1< |