/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - assem_arm.c *
- * Copyright (C) 2009-2010 Ari64 *
+ * Copyright (C) 2009-2011 Ari64 *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
0,
0};
+void invalidate_addr_r0();
+void invalidate_addr_r1();
+void invalidate_addr_r2();
+void invalidate_addr_r3();
+void invalidate_addr_r4();
+void invalidate_addr_r5();
+void invalidate_addr_r6();
+void invalidate_addr_r7();
+void invalidate_addr_r8();
+void invalidate_addr_r9();
+void invalidate_addr_r10();
+void invalidate_addr_r12();
+
+const u_int invalidate_addr_reg[16] = {
+ (int)invalidate_addr_r0,
+ (int)invalidate_addr_r1,
+ (int)invalidate_addr_r2,
+ (int)invalidate_addr_r3,
+ (int)invalidate_addr_r4,
+ (int)invalidate_addr_r5,
+ (int)invalidate_addr_r6,
+ (int)invalidate_addr_r7,
+ (int)invalidate_addr_r8,
+ (int)invalidate_addr_r9,
+ (int)invalidate_addr_r10,
+ 0,
+ (int)invalidate_addr_r12,
+ 0,
+ 0,
+ 0};
+
#include "fpu.h"
+unsigned int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
+
/* Linker */
void set_jump_target(int addr,u_int target)
literalcount++;
}
-void kill_pointer(void *stub)
+void *kill_pointer(void *stub)
{
int *ptr=(int *)(stub+4);
assert((*ptr&0x0ff00000)==0x05900000);
int **l_ptr=(void *)ptr+offset+8;
int *i_ptr=*l_ptr;
set_jump_target((int)i_ptr,(int)stub);
+ return i_ptr;
}
+// find where external branch is liked to using addr of it's stub:
+// get address that insn one after stub loads (dyna_linker arg1),
+// treat it as a pointer to branch insn,
+// return addr where that branch jumps to
int get_pointer(void *stub)
{
//printf("get_pointer(%x)\n",(int)stub);
int *ptr=(int *)(stub+4);
- assert((*ptr&0x0ff00000)==0x05900000);
+ assert((*ptr&0x0fff0000)==0x059f0000);
u_int offset=*ptr&0xfff;
int **l_ptr=(void *)ptr+offset+8;
int *i_ptr=*l_ptr;
void alloc_arm_reg(struct regstat *cur,int i,signed char reg,char hr)
{
int n;
+ int dirty=0;
// see if it's already allocated (and dealloc it)
for(n=0;n<HOST_REGS;n++)
{
- if(n!=EXCLUDE_REG&&cur->regmap[n]==reg) {cur->regmap[n]=-1;}
+ if(n!=EXCLUDE_REG&&cur->regmap[n]==reg) {
+ dirty=(cur->dirty>>n)&1;
+ cur->regmap[n]=-1;
+ }
}
cur->regmap[hr]=reg;
cur->dirty&=~(1<<hr);
+ cur->dirty|=dirty<<hr;
cur->isconst&=~(1<<hr);
}
}
u_int genimm(u_int imm,u_int *encoded)
{
- if(imm==0) {*encoded=0;return 1;}
+ *encoded=0;
+ if(imm==0) return 1;
int i=32;
while(i>0)
{
}
return 0;
}
+void genimm_checked(u_int imm,u_int *encoded)
+{
+ u_int ret=genimm(imm,encoded);
+ assert(ret);
+}
u_int genjmp(u_int addr)
{
int offset=addr-(int)out-8;
output_w32(0xe3a00000|rd_rn_rm(rt,0,0));
}
+void emit_loadlp(u_int imm,u_int rt)
+{
+ add_literal((int)out,imm);
+ assem_debug("ldr %s,pc+? [=%x]\n",regname[rt],imm);
+ output_w32(0xe5900000|rd_rn_rm(rt,15,0));
+}
+void emit_movw(u_int imm,u_int rt)
+{
+ assert(imm<65536);
+ assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm);
+ output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000));
+}
+void emit_movt(u_int imm,u_int rt)
+{
+ assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000);
+ output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000));
+}
+void emit_movimm(u_int imm,u_int rt)
+{
+ u_int armval;
+ if(genimm(imm,&armval)) {
+ assem_debug("mov %s,#%d\n",regname[rt],imm);
+ output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
+ }else if(genimm(~imm,&armval)) {
+ assem_debug("mvn %s,#%d\n",regname[rt],imm);
+ output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
+ }else if(imm<65536) {
+ #ifdef ARMv5_ONLY
+ assem_debug("mov %s,#%d\n",regname[rt],imm&0xFF00);
+ output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8));
+ assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
+ output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
+ #else
+ emit_movw(imm,rt);
+ #endif
+ }else{
+ #ifdef ARMv5_ONLY
+ emit_loadlp(imm,rt);
+ #else
+ emit_movw(imm&0x0000FFFF,rt);
+ emit_movt(imm&0xFFFF0000,rt);
+ #endif
+ }
+}
+void emit_pcreladdr(u_int rt)
+{
+ assem_debug("add %s,pc,#?\n",regname[rt]);
+ output_w32(0xe2800000|rd_rn_rm(rt,15,0));
+}
+
void emit_loadreg(int r, int hr)
{
#ifdef FORCE32
if(r&64) {
printf("64bit load in 32bit mode!\n");
- exit(1);
+ assert(0);
+ return;
}
#endif
if((r&63)==0)
#ifdef FORCE32
if(r&64) {
printf("64bit store in 32bit mode!\n");
- exit(1);
+ assert(0);
+ return;
}
#endif
int addr=((int)reg)+((r&63)<<REG_SHIFT)+((r&64)>>4);
void emit_testimm(int rs,int imm)
{
u_int armval;
- assem_debug("tst %s,$%d\n",regname[rs],imm);
- assert(genimm(imm,&armval));
+ assem_debug("tst %s,#%d\n",regname[rs],imm);
+ genimm_checked(imm,&armval);
output_w32(0xe3100000|rd_rn_rm(0,rs,0)|armval);
}
+void emit_testeqimm(int rs,int imm)
+{
+ u_int armval;
+ assem_debug("tsteq %s,$%d\n",regname[rs],imm);
+ genimm_checked(imm,&armval);
+ output_w32(0x03100000|rd_rn_rm(0,rs,0)|armval);
+}
+
void emit_not(int rs,int rt)
{
assem_debug("mvn %s,%s\n",regname[rt],regname[rs]);
output_w32(0xe1e00000|rd_rn_rm(rt,0,rs));
}
+void emit_mvnmi(int rs,int rt)
+{
+ assem_debug("mvnmi %s,%s\n",regname[rt],regname[rs]);
+ output_w32(0x41e00000|rd_rn_rm(rt,0,rs));
+}
+
void emit_and(u_int rs1,u_int rs2,u_int rt)
{
assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
output_w32(0xe1900000|rd_rn_rm(rt,rs1,rs2));
}
-void emit_xor(u_int rs1,u_int rs2,u_int rt)
+void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
{
- assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
- output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2));
+ assert(rs<16);
+ assert(rt<16);
+ assert(imm<32);
+ assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
+ output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|(imm<<7));
}
-void emit_loadlp(u_int imm,u_int rt)
+void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
{
- add_literal((int)out,imm);
- assem_debug("ldr %s,pc+? [=%x]\n",regname[rt],imm);
- output_w32(0xe5900000|rd_rn_rm(rt,15,0));
-}
-void emit_movw(u_int imm,u_int rt)
-{
- assert(imm<65536);
- assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm);
- output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000));
-}
-void emit_movt(u_int imm,u_int rt)
-{
- assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000);
- output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000));
-}
-void emit_movimm(u_int imm,u_int rt)
-{
- u_int armval;
- if(genimm(imm,&armval)) {
- assem_debug("mov %s,#%d\n",regname[rt],imm);
- output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
- }else if(genimm(~imm,&armval)) {
- assem_debug("mvn %s,#%d\n",regname[rt],imm);
- output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
- }else if(imm<65536) {
- #ifdef ARMv5_ONLY
- assem_debug("mov %s,#%d\n",regname[rt],imm&0xFF00);
- output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8));
- assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
- output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
- #else
- emit_movw(imm,rt);
- #endif
- }else{
- #ifdef ARMv5_ONLY
- emit_loadlp(imm,rt);
- #else
- emit_movw(imm&0x0000FFFF,rt);
- emit_movt(imm&0xFFFF0000,rt);
- #endif
- }
+ assert(rs<16);
+ assert(rt<16);
+ assert(imm<32);
+ assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs],imm);
+ output_w32(0xe1800020|rd_rn_rm(rt,rt,rs)|(imm<<7));
}
-void emit_pcreladdr(u_int rt)
+
+void emit_xor(u_int rs1,u_int rs2,u_int rt)
{
- assem_debug("add %s,pc,#?\n",regname[rt]);
- output_w32(0xe2800000|rd_rn_rm(rt,15,0));
+ assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
+ output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2));
}
void emit_addimm(u_int rs,int imm,u_int rt)
void emit_adcimm(u_int rs,int imm,u_int rt)
{
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
assem_debug("adc %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0xe2a00000|rd_rn_rm(rt,rs,0)|armval);
}
/*void emit_sbcimm(int imm,u_int rt)
{
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
assem_debug("sbc %s,%s,#%d\n",regname[rt],regname[rt],imm);
output_w32(0xe2c00000|rd_rn_rm(rt,rt,0)|armval);
}*/
{
assert(0);
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
assem_debug("rsc %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0xe2e00000|rd_rn_rm(rt,rs,0)|armval);
}
void emit_andimm(int rs,int imm,int rt)
{
u_int armval;
- if(genimm(imm,&armval)) {
+ if(imm==0) {
+ emit_zeroreg(rt);
+ }else if(genimm(imm,&armval)) {
assem_debug("and %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0xe2000000|rd_rn_rm(rt,rs,0)|armval);
}else if(genimm(~imm,&armval)) {
void emit_orimm(int rs,int imm,int rt)
{
u_int armval;
- if(genimm(imm,&armval)) {
+ if(imm==0) {
+ if(rs!=rt) emit_mov(rs,rt);
+ }else if(genimm(imm,&armval)) {
assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0xe3800000|rd_rn_rm(rt,rs,0)|armval);
}else{
void emit_xorimm(int rs,int imm,int rt)
{
- assert(imm>0&&imm<65536);
u_int armval;
- if(genimm(imm,&armval)) {
+ if(imm==0) {
+ if(rs!=rt) emit_mov(rs,rt);
+ }else if(genimm(imm,&armval)) {
assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0xe2200000|rd_rn_rm(rt,rs,0)|armval);
}else{
- assert(imm>0);
+ assert(imm>0&&imm<65536);
assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF);
output_w32(0xe2200000|rd_rn_imm_shift(rt,rs,imm>>8,8));
output_w32(0xe1800000|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7));
}
+void emit_signextend16(int rs,int rt)
+{
+ #ifdef ARMv5_ONLY
+ emit_shlimm(rs,16,rt);
+ emit_sarimm(rt,16,rt);
+ #else
+ assem_debug("sxth %s,%s\n",regname[rt],regname[rs]);
+ output_w32(0xe6bf0070|rd_rn_rm(rt,0,rs));
+ #endif
+}
+
void emit_shl(u_int rs,u_int shift,u_int rt)
{
assert(rs<16);
{
u_int armval;
if(genimm(imm,&armval)) {
- assem_debug("cmp %s,$%d\n",regname[rs],imm);
+ assem_debug("cmp %s,#%d\n",regname[rs],imm);
output_w32(0xe3500000|rd_rn_rm(0,rs,0)|armval);
}else if(genimm(-imm,&armval)) {
- assem_debug("cmn %s,$%d\n",regname[rs],imm);
+ assem_debug("cmn %s,#%d\n",regname[rs],imm);
output_w32(0xe3700000|rd_rn_rm(0,rs,0)|armval);
}else if(imm>0) {
assert(imm<65536);
{
assem_debug("movne %s,#%d\n",regname[rt],imm);
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
output_w32(0x13a00000|rd_rn_rm(rt,0,0)|armval);
}
void emit_cmovl_imm(int imm,int rt)
{
assem_debug("movlt %s,#%d\n",regname[rt],imm);
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
output_w32(0xb3a00000|rd_rn_rm(rt,0,0)|armval);
}
void emit_cmovb_imm(int imm,int rt)
{
assem_debug("movcc %s,#%d\n",regname[rt],imm);
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
output_w32(0x33a00000|rd_rn_rm(rt,0,0)|armval);
}
void emit_cmovs_imm(int imm,int rt)
{
assem_debug("movmi %s,#%d\n",regname[rt],imm);
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
output_w32(0x43a00000|rd_rn_rm(rt,0,0)|armval);
}
void emit_cmove_reg(int rs,int rt)
{
u_int offset = addr-(u_int)&dynarec_local;
assert(offset<4096);
- assem_debug("str %s,fp+%d\n",regname[rt],offset);
+ assem_debug("strb %s,fp+%d\n",regname[rt],offset);
output_w32(0xe5c00000|rd_rn_rm(rt,FP,0)|offset);
}
void emit_writeword_imm(int imm, int addr)
void emit_rsbimm(int rs, int imm, int rt)
{
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
assem_debug("rsb %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0xe2600000|rd_rn_rm(rt,rs,0)|armval);
}
output_w32(0xe0800620|rd_rn_rm(rt,rs1,rs2));
}
+void emit_callne(int a)
+{
+ assem_debug("blne %x\n",a);
+ u_int offset=genjmp(a);
+ output_w32(0x1b000000|offset);
+}
+
// Used to preload hash table entries
void emit_prefetch(void *addr)
{
void emit_bicne_imm(int rs,int imm,int rt)
{
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
assem_debug("bicne %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0x13c00000|rd_rn_rm(rt,rs,0)|armval);
}
void emit_biccs_imm(int rs,int imm,int rt)
{
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
assem_debug("biccs %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0x23c00000|rd_rn_rm(rt,rs,0)|armval);
}
void emit_bicvc_imm(int rs,int imm,int rt)
{
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
assem_debug("bicvc %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0x73c00000|rd_rn_rm(rt,rs,0)|armval);
}
void emit_bichi_imm(int rs,int imm,int rt)
{
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
assem_debug("bichi %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0x83c00000|rd_rn_rm(rt,rs,0)|armval);
}
void emit_orrvs_imm(int rs,int imm,int rt)
{
u_int armval;
- assert(genimm(imm,&armval));
+ genimm_checked(imm,&armval);
assem_debug("orrvs %s,%s,#%d\n",regname[rt],regname[rs],imm);
output_w32(0x63800000|rd_rn_rm(rt,rs,0)|armval);
}
+void emit_orrne_imm(int rs,int imm,int rt)
+{
+ u_int armval;
+ genimm_checked(imm,&armval);
+ assem_debug("orrne %s,%s,#%d\n",regname[rt],regname[rs],imm);
+ output_w32(0x13800000|rd_rn_rm(rt,rs,0)|armval);
+}
+
+void emit_andne_imm(int rs,int imm,int rt)
+{
+ u_int armval;
+ genimm_checked(imm,&armval);
+ assem_debug("andne %s,%s,#%d\n",regname[rt],regname[rs],imm);
+ output_w32(0x12000000|rd_rn_rm(rt,rs,0)|armval);
+}
+
void emit_jno_unlikely(int a)
{
//emit_jno(a);
emit_extjump2(addr, target, (int)dyna_linker_ds);
}
+#ifdef PCSX
+#include "pcsxmem_inline.c"
+#endif
+
do_readstub(int n)
{
assem_debug("do_readstub %x\n",start+stubs[n][3]*4);
int addr=get_reg(i_regmap,AGEN1+(i&1));
int rth,rt;
int ds;
- if(itype[i]==C1LS||itype[i]==LOADLR) {
+ if(itype[i]==C1LS||itype[i]==C2LS||itype[i]==LOADLR) {
rth=get_reg(i_regmap,FTEMP|64);
rt=get_reg(i_regmap,FTEMP);
}else{
rt=get_reg(i_regmap,rt1[i]);
}
assert(rs>=0);
- assert(rt>=0);
if(addr<0) addr=rt;
+ if(addr<0&&itype[i]!=C1LS&&itype[i]!=C2LS&&itype[i]!=LOADLR) addr=get_reg(i_regmap,-1);
assert(addr>=0);
int ftable=0;
if(type==LOADB_STUB||type==LOADBU_STUB)
emit_writeword(rs,(int)&address);
//emit_pusha();
save_regs(reglist);
+#ifndef PCSX
ds=i_regs!=®s[i];
int real_rs=(itype[i]==LOADLR)?-1:get_reg(i_regmap,rs1[i]);
u_int cmask=ds?-1:(0x100f|~i_regs->wasconst);
if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs))&0x100f,i);
wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs)));
if(!ds) wb_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs))&~0x100f,i);
+#endif
emit_shrimm(rs,16,1);
int cc=get_reg(i_regmap,CCREG);
if(cc<0) {
}
emit_movimm(ftable,0);
emit_addimm(cc<0?2:cc,2*stubs[n][6]+2,2);
+#ifndef PCSX
emit_movimm(start+stubs[n][3]*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
+#endif
//emit_readword((int)&last_count,temp);
//emit_add(cc,temp,cc);
//emit_writeword(cc,(int)&Count);
emit_call((int)&indirect_jump_indexed);
//emit_callreg(rs);
//emit_readword_dualindexedx4(rs,HOST_TEMPREG,15);
+#ifndef PCSX
// We really shouldn't need to update the count here,
// but not doing so causes random crashes...
emit_readword((int)&Count,HOST_TEMPREG);
if(cc<0) {
emit_storereg(CCREG,HOST_TEMPREG);
}
+#endif
//emit_popa();
restore_regs(reglist);
//if((cc=get_reg(regmap,CCREG))>=0) {
// emit_loadreg(CCREG,cc);
//}
- if(type==LOADB_STUB)
- emit_movsbl((int)&readmem_dword,rt);
- if(type==LOADBU_STUB)
- emit_movzbl((int)&readmem_dword,rt);
- if(type==LOADH_STUB)
- emit_movswl((int)&readmem_dword,rt);
- if(type==LOADHU_STUB)
- emit_movzwl((int)&readmem_dword,rt);
- if(type==LOADW_STUB)
- emit_readword((int)&readmem_dword,rt);
- if(type==LOADD_STUB) {
- emit_readword((int)&readmem_dword,rt);
- if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth);
+ if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
+ assert(rt>=0);
+ if(type==LOADB_STUB)
+ emit_movsbl((int)&readmem_dword,rt);
+ if(type==LOADBU_STUB)
+ emit_movzbl((int)&readmem_dword,rt);
+ if(type==LOADH_STUB)
+ emit_movswl((int)&readmem_dword,rt);
+ if(type==LOADHU_STUB)
+ emit_movzwl((int)&readmem_dword,rt);
+ if(type==LOADW_STUB)
+ emit_readword((int)&readmem_dword,rt);
+ if(type==LOADD_STUB) {
+ emit_readword((int)&readmem_dword,rt);
+ if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth);
+ }
}
emit_jmp(stubs[n][2]); // return address
}
int rs=get_reg(regmap,target);
int rth=get_reg(regmap,target|64);
int rt=get_reg(regmap,target);
+ if(rs<0) rs=get_reg(regmap,-1);
assert(rs>=0);
- assert(rt>=0);
int ftable=0;
if(type==LOADB_STUB||type==LOADBU_STUB)
ftable=(int)readmemb;
ftable=(int)readmemd;
#endif
assert(ftable!=0);
+#ifdef PCSX
+ if(pcsx_direct_read(type,addr,target?rs:-1,rt))
+ return;
+#endif
+ if(target==0)
+ emit_movimm(addr,rs);
emit_writeword(rs,(int)&address);
//emit_pusha();
save_regs(reglist);
+#ifndef PCSX
+ if((signed int)addr>=(signed int)0xC0000000) {
+ // Theoretically we can have a pagefault here, if the TLB has never
+ // been enabled and the address is outside the range 80000000..BFFFFFFF
+ // Write out the registers so the pagefault can be handled. This is
+ // a very rare case and likely represents a bug.
+ int ds=regmap!=regs[i].regmap;
+ if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i);
+ if(!ds) wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty);
+ else wb_dirtys(branch_regs[i-1].regmap_entry,branch_regs[i-1].was32,branch_regs[i-1].wasdirty);
+ }
+#endif
//emit_shrimm(rs,16,1);
int cc=get_reg(regmap,CCREG);
if(cc<0) {
emit_movimm(((u_int *)ftable)[addr>>16],0);
//emit_readword((int)&last_count,12);
emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2);
+#ifndef PCSX
if((signed int)addr>=(signed int)0xC0000000) {
// Pagefault address
int ds=regmap!=regs[i].regmap;
emit_movimm(start+i*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
}
+#endif
//emit_add(12,2,2);
//emit_writeword(2,(int)&Count);
//emit_call(((u_int *)ftable)[addr>>16]);
emit_call((int)&indirect_jump);
+#ifndef PCSX
// We really shouldn't need to update the count here,
// but not doing so causes random crashes...
emit_readword((int)&Count,HOST_TEMPREG);
if(cc<0) {
emit_storereg(CCREG,HOST_TEMPREG);
}
+#endif
//emit_popa();
restore_regs(reglist);
- if(type==LOADB_STUB)
- emit_movsbl((int)&readmem_dword,rt);
- if(type==LOADBU_STUB)
- emit_movzbl((int)&readmem_dword,rt);
- if(type==LOADH_STUB)
- emit_movswl((int)&readmem_dword,rt);
- if(type==LOADHU_STUB)
- emit_movzwl((int)&readmem_dword,rt);
- if(type==LOADW_STUB)
- emit_readword((int)&readmem_dword,rt);
- if(type==LOADD_STUB) {
- emit_readword((int)&readmem_dword,rt);
- if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth);
+ if(rt>=0) {
+ if(type==LOADB_STUB)
+ emit_movsbl((int)&readmem_dword,rt);
+ if(type==LOADBU_STUB)
+ emit_movzbl((int)&readmem_dword,rt);
+ if(type==LOADH_STUB)
+ emit_movswl((int)&readmem_dword,rt);
+ if(type==LOADHU_STUB)
+ emit_movzwl((int)&readmem_dword,rt);
+ if(type==LOADW_STUB)
+ emit_readword((int)&readmem_dword,rt);
+ if(type==LOADD_STUB) {
+ emit_readword((int)&readmem_dword,rt);
+ if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth);
+ }
}
}
int addr=get_reg(i_regmap,AGEN1+(i&1));
int rth,rt,r;
int ds;
- if(itype[i]==C1LS) {
+ if(itype[i]==C1LS||itype[i]==C2LS) {
rth=get_reg(i_regmap,FTEMP|64);
rt=get_reg(i_regmap,r=FTEMP);
}else{
}
//emit_pusha();
save_regs(reglist);
+#ifndef PCSX
ds=i_regs!=®s[i];
int real_rs=get_reg(i_regmap,rs1[i]);
u_int cmask=ds?-1:(0x100f|~i_regs->wasconst);
if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs))&0x100f,i);
wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs)));
if(!ds) wb_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs))&~0x100f,i);
+#endif
emit_shrimm(rs,16,1);
int cc=get_reg(i_regmap,CCREG);
if(cc<0) {
}
emit_movimm(ftable,0);
emit_addimm(cc<0?2:cc,2*stubs[n][6]+2,2);
+#ifndef PCSX
emit_movimm(start+stubs[n][3]*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
+#endif
//emit_readword((int)&last_count,temp);
//emit_addimm(cc,2*stubs[n][5]+2,cc);
//emit_add(cc,temp,cc);
int rt=get_reg(regmap,target);
assert(rs>=0);
assert(rt>=0);
+#ifdef PCSX
+ if(pcsx_direct_write(type,addr,rs,rt,regmap))
+ return;
+#endif
int ftable=0;
if(type==STOREB_STUB)
ftable=(int)writememb;
}
//emit_pusha();
save_regs(reglist);
+#ifndef PCSX
+ // rearmed note: load_all_consts prevents BIOS boot, some bug?
+ if((signed int)addr>=(signed int)0xC0000000) {
+ // Theoretically we can have a pagefault here, if the TLB has never
+ // been enabled and the address is outside the range 80000000..BFFFFFFF
+ // Write out the registers so the pagefault can be handled. This is
+ // a very rare case and likely represents a bug.
+ int ds=regmap!=regs[i].regmap;
+ if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i);
+ if(!ds) wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty);
+ else wb_dirtys(branch_regs[i-1].regmap_entry,branch_regs[i-1].was32,branch_regs[i-1].wasdirty);
+ }
+#endif
//emit_shrimm(rs,16,1);
int cc=get_reg(regmap,CCREG);
if(cc<0) {
emit_movimm(((u_int *)ftable)[addr>>16],0);
//emit_readword((int)&last_count,12);
emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2);
+#ifndef PCSX
if((signed int)addr>=(signed int)0xC0000000) {
// Pagefault address
int ds=regmap!=regs[i].regmap;
emit_movimm(start+i*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
}
+#endif
//emit_add(12,2,2);
//emit_writeword(2,(int)&Count);
//emit_call(((u_int *)ftable)[addr>>16]);
do_unalignedwritestub(int n)
{
+ assem_debug("do_unalignedwritestub %x\n",start+stubs[n][3]*4);
+ literal_pool(256);
set_jump_target(stubs[n][1],(int)out);
- output_w32(0xef000000);
+
+ int i=stubs[n][3];
+ struct regstat *i_regs=(struct regstat *)stubs[n][4];
+ int addr=stubs[n][5];
+ u_int reglist=stubs[n][7];
+ signed char *i_regmap=i_regs->regmap;
+ int temp2=get_reg(i_regmap,FTEMP);
+ int rt;
+ int ds, real_rs;
+ rt=get_reg(i_regmap,rs2[i]);
+ assert(rt>=0);
+ assert(addr>=0);
+ assert(opcode[i]==0x2a||opcode[i]==0x2e); // SWL/SWR only implemented
+ reglist|=(1<<addr);
+ reglist&=~(1<<temp2);
+
+ emit_andimm(addr,0xfffffffc,temp2);
+ emit_writeword(temp2,(int)&address);
+
+ save_regs(reglist);
+#ifndef PCSX
+ ds=i_regs!=®s[i];
+ real_rs=get_reg(i_regmap,rs1[i]);
+ u_int cmask=ds?-1:(0x100f|~i_regs->wasconst);
+ if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs))&0x100f,i);
+ wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs)));
+ if(!ds) wb_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs))&~0x100f,i);
+#endif
+ emit_shrimm(addr,16,1);
+ int cc=get_reg(i_regmap,CCREG);
+ if(cc<0) {
+ emit_loadreg(CCREG,2);
+ }
+ emit_movimm((u_int)readmem,0);
+ emit_addimm(cc<0?2:cc,2*stubs[n][6]+2,2);
+#ifndef PCSX
+ // pagefault address
+ emit_movimm(start+stubs[n][3]*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
+#endif
+ emit_call((int)&indirect_jump_indexed);
+ restore_regs(reglist);
+
+ emit_readword((int)&readmem_dword,temp2);
+ int temp=addr; //hmh
+ emit_shlimm(addr,3,temp);
+ emit_andimm(temp,24,temp);
+#ifdef BIG_ENDIAN_MIPS
+ if (opcode[i]==0x2e) // SWR
+#else
+ if (opcode[i]==0x2a) // SWL
+#endif
+ emit_xorimm(temp,24,temp);
+ emit_movimm(-1,HOST_TEMPREG);
+ if (opcode[i]==0x2a) { // SWL
+ emit_bic_lsr(temp2,HOST_TEMPREG,temp,temp2);
+ emit_orrshr(rt,temp,temp2);
+ }else{
+ emit_bic_lsl(temp2,HOST_TEMPREG,temp,temp2);
+ emit_orrshl(rt,temp,temp2);
+ }
+ emit_readword((int)&address,addr);
+ emit_writeword(temp2,(int)&word);
+ //save_regs(reglist); // don't need to, no state changes
+ emit_shrimm(addr,16,1);
+ emit_movimm((u_int)writemem,0);
+ //emit_call((int)&indirect_jump_indexed);
+ emit_mov(15,14);
+ emit_readword_dualindexedx4(0,1,15);
+ emit_readword((int)&Count,HOST_TEMPREG);
+ emit_readword((int)&next_interupt,2);
+ emit_addimm(HOST_TEMPREG,-2*stubs[n][6]-2,HOST_TEMPREG);
+ emit_writeword(2,(int)&last_count);
+ emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
+ if(cc<0) {
+ emit_storereg(CCREG,HOST_TEMPREG);
+ }
+ restore_regs(reglist);
emit_jmp(stubs[n][2]); // return address
}
int do_dirty_stub(int i)
{
assem_debug("do_dirty_stub %x\n",start+i*4);
+ u_int addr=(int)start<(int)0xC0000000?(u_int)source:(u_int)start;
+ #ifdef PCSX
+ addr=(u_int)source;
+ #endif
// Careful about the code output here, verify_dirty needs to parse it.
#ifdef ARMv5_ONLY
- emit_loadlp((int)start<(int)0xC0000000?(int)source:(int)start,1);
+ emit_loadlp(addr,1);
emit_loadlp((int)copy,2);
emit_loadlp(slen*4,3);
#else
- emit_movw(((int)start<(int)0xC0000000?(u_int)source:(u_int)start)&0x0000FFFF,1);
+ emit_movw(addr&0x0000FFFF,1);
emit_movw(((u_int)copy)&0x0000FFFF,2);
- emit_movt(((int)start<(int)0xC0000000?(u_int)source:(u_int)start)&0xFFFF0000,1);
+ emit_movt(addr&0xFFFF0000,1);
emit_movt(((u_int)copy)&0xFFFF0000,2);
emit_movw(slen*4,3);
#endif
int s,th,tl,temp,temp2,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]);
else addr=s;
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(tl>=0) {
- //assert(tl>=0);
- //assert(rt1[i]);
- if(!using_tlb) {
- if(!c) {
- emit_shlimm(addr,3,temp);
- if (opcode[i]==0x22||opcode[i]==0x26) {
- emit_andimm(addr,0xFFFFFFFC,temp2); // LWL/LWR
- }else{
- emit_andimm(addr,0xFFFFFFF8,temp2); // LDL/LDR
- }
- emit_cmpimm(addr,0x800000);
- jaddr=(int)out;
- emit_jno(0);
- }
- else {
- if (opcode[i]==0x22||opcode[i]==0x26) {
- emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
- }else{
- emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR
- }
- }
- }else{ // using tlb
- int a;
- if(c) {
- a=-1;
- }else if (opcode[i]==0x22||opcode[i]==0x26) {
- a=0xFFFFFFFC; // LWL/LWR
+ 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;
+ }
+ }
+ 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
+ emit_shlimm(addr,3,temp);
+ if (opcode[i]==0x22||opcode[i]==0x26) {
+ emit_andimm(addr,0xFFFFFFFC,temp2); // LWL/LWR
}else{
- a=0xFFFFFFF8; // LDL/LDR
+ emit_andimm(addr,0xFFFFFFF8,temp2); // LDL/LDR
}
- map=get_reg(i_regs->regmap,TLREG);
- assert(map>=0);
- map=do_tlb_r(addr,temp2,map,0,a,c?-1:temp,c,constmap[i][s]+offset);
- if(c) {
- if (opcode[i]==0x22||opcode[i]==0x26) {
- emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
- }else{
- emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR
- }
+ emit_cmpimm(addr,RAM_SIZE);
+ jaddr=(int)out;
+ emit_jno(0);
+ }
+ else {
+ if (opcode[i]==0x22||opcode[i]==0x26) {
+ emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
+ }else{
+ emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR
}
- do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr);
}
- if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR
- if(!c||memtarget) {
- //emit_readword_indexed((int)rdram-0x80000000,temp2,temp2);
- emit_readword_indexed_tlb((int)rdram-0x80000000,temp2,map,temp2);
- if(jaddr) add_stub(LOADW_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
+ }else{ // using tlb
+ int a;
+ if(c) {
+ a=-1;
+ }else if (opcode[i]==0x22||opcode[i]==0x26) {
+ a=0xFFFFFFFC; // LWL/LWR
+ }else{
+ a=0xFFFFFFF8; // LDL/LDR
+ }
+ map=get_reg(i_regs->regmap,TLREG);
+ assert(map>=0);
+ reglist&=~(1<<map);
+ map=do_tlb_r(addr,temp2,map,0,a,c?-1:temp,c,constmap[i][s]+offset);
+ if(c) {
+ if (opcode[i]==0x22||opcode[i]==0x26) {
+ emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
+ }else{
+ emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR
}
- else
- inline_readstub(LOADW_STUB,i,(constmap[i][s]+offset)&0xFFFFFFFC,i_regs->regmap,FTEMP,ccadj[i],reglist);
+ }
+ do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr);
+ }
+ if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR
+ if(!c||memtarget) {
+ //emit_readword_indexed((int)rdram-0x80000000,temp2,temp2);
+ emit_readword_indexed_tlb(0,temp2,map,temp2);
+ if(jaddr) add_stub(LOADW_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
+ }
+ else
+ inline_readstub(LOADW_STUB,i,(constmap[i][s]+offset)&0xFFFFFFFC,i_regs->regmap,FTEMP,ccadj[i],reglist);
+ if(rt1[i]) {
+ assert(tl>=0);
emit_andimm(temp,24,temp);
- if (opcode[i]==0x26) emit_xorimm(temp,24,temp); // LWR
+#ifdef BIG_ENDIAN_MIPS
+ if (opcode[i]==0x26) // LWR
+#else
+ if (opcode[i]==0x22) // LWL
+#endif
+ emit_xorimm(temp,24,temp);
emit_movimm(-1,HOST_TEMPREG);
if (opcode[i]==0x26) {
emit_shr(temp2,temp,temp2);
emit_bic_lsl(tl,HOST_TEMPREG,temp,tl);
}
emit_or(temp2,tl,tl);
- //emit_storereg(rt1[i],tl); // DEBUG
}
- if (opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR
- int temp2h=get_reg(i_regs->regmap,FTEMP|64);
- if(!c||memtarget) {
- //if(th>=0) emit_readword_indexed((int)rdram-0x80000000,temp2,temp2h);
- //emit_readword_indexed((int)rdram-0x7FFFFFFC,temp2,temp2);
- emit_readdword_indexed_tlb((int)rdram-0x80000000,temp2,map,temp2h,temp2);
- if(jaddr) add_stub(LOADD_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
- }
- else
- inline_readstub(LOADD_STUB,i,(constmap[i][s]+offset)&0xFFFFFFF8,i_regs->regmap,FTEMP,ccadj[i],reglist);
+ //emit_storereg(rt1[i],tl); // DEBUG
+ }
+ if (opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR
+ // FIXME: little endian
+ int temp2h=get_reg(i_regs->regmap,FTEMP|64);
+ if(!c||memtarget) {
+ //if(th>=0) emit_readword_indexed((int)rdram-0x80000000,temp2,temp2h);
+ //emit_readword_indexed((int)rdram-0x7FFFFFFC,temp2,temp2);
+ emit_readdword_indexed_tlb(0,temp2,map,temp2h,temp2);
+ if(jaddr) add_stub(LOADD_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
+ }
+ else
+ inline_readstub(LOADD_STUB,i,(constmap[i][s]+offset)&0xFFFFFFF8,i_regs->regmap,FTEMP,ccadj[i],reglist);
+ if(rt1[i]) {
+ assert(th>=0);
+ assert(tl>=0);
emit_testimm(temp,32);
emit_andimm(temp,24,temp);
if (opcode[i]==0x1A) { // LDL
signed char t=get_reg(i_regs->regmap,rt1[i]);
char copr=(source[i]>>11)&0x1f;
//assert(t>=0); // Why does this happen? OOT is weird
- if(t>=0) {
-#ifdef MUPEN64 /// FIXME
+ if(t>=0&&rt1[i]!=0) {
+#ifdef MUPEN64
emit_addimm(FP,(int)&fake_pc-(int)&dynarec_local,0);
emit_movimm((source[i]>>11)&0x1f,1);
emit_writeword(0,(int)&PC);
emit_writebyte(1,(int)&(fake_pc.f.r.nrd));
-#endif
if(copr==9) {
emit_readword((int)&last_count,ECX);
emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc
}
emit_call((int)MFC0);
emit_readword((int)&readmem_dword,t);
+#else
+ emit_readword((int)®_cop0+copr*4,t);
+#endif
}
}
else if(opcode2[i]==4) // MTC0
assert(s>=0);
emit_writeword(s,(int)&readmem_dword);
wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32);
-#ifdef MUPEN64 /// FIXME
+#ifdef MUPEN64
emit_addimm(FP,(int)&fake_pc-(int)&dynarec_local,0);
emit_movimm((source[i]>>11)&0x1f,1);
emit_writeword(0,(int)&PC);
emit_writebyte(1,(int)&(fake_pc.f.r.nrd));
#endif
- if(copr==9||copr==11||copr==12) {
+ if(copr==9||copr==11||copr==12||copr==13) {
emit_readword((int)&last_count,ECX);
emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc
emit_add(HOST_CCREG,ECX,HOST_CCREG);
// 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&&!is_delayslot) {
+ if(copr==12||copr==13) {
+#ifdef PCSX
+ 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,(int)&last_count);
+ emit_movimm(0,HOST_CCREG);
+ emit_storereg(CCREG,HOST_CCREG);
+ emit_movimm(copr,0);
+ emit_call((int)pcsx_mtc0_ds);
+ return;
+ }
+#endif
emit_movimm(start+i*4+4,0);
emit_movimm(0,1);
emit_writeword(0,(int)&pcaddr);
}
//else if(copr==12&&is_delayslot) emit_call((int)MTC0_R12);
//else
+#ifdef PCSX
+ emit_movimm(copr,0);
+ emit_call((int)pcsx_mtc0);
+#else
emit_call((int)MTC0);
- if(copr==9||copr==11||copr==12) {
+#endif
+ if(copr==9||copr==11||copr==12||copr==13) {
emit_readword((int)&Count,HOST_CCREG);
emit_readword((int)&next_interupt,ECX);
emit_addimm(HOST_CCREG,-CLOCK_DIVIDER*ccadj[i],HOST_CCREG);
emit_writeword(ECX,(int)&last_count);
emit_storereg(CCREG,HOST_CCREG);
}
- if(copr==12) {
+ if(copr==12||copr==13) {
assert(!is_delayslot);
emit_readword((int)&pending_exception,14);
}
emit_loadreg(rs1[i],s);
if(get_reg(i_regs->regmap,rs1[i]|64)>=0)
emit_loadreg(rs1[i]|64,get_reg(i_regs->regmap,rs1[i]|64));
- if(copr==12) {
+ if(copr==12||copr==13) {
emit_test(14,14);
emit_jne((int)&do_interrupt);
}
if((source[i]&0x3f)==0x08) // TLBP
emit_call((int)TLBP);
#endif
+#ifdef PCSX
+ if((source[i]&0x3f)==0x10) // RFE
+ {
+ emit_readword((int)&Status,0);
+ emit_andimm(0,0x3c,1);
+ emit_andimm(0,~0xf,0);
+ emit_orrshr_imm(1,2,0);
+ emit_writeword(0,(int)&Status);
+ }
+#else
if((source[i]&0x3f)==0x18) // ERET
{
int count=ccadj[i];
emit_addimm(HOST_CCREG,CLOCK_DIVIDER*count,HOST_CCREG); // TODO: Should there be an extra cycle here?
emit_jmp((int)jump_eret);
}
+#endif
+ }
+}
+
+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((int)®_cop2d[copr],tl);
+ emit_signextend16(tl,tl);
+ emit_writeword(tl,(int)®_cop2d[copr]); // hmh
+ break;
+ case 7:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ emit_readword((int)®_cop2d[copr],tl);
+ emit_andimm(tl,0xffff,tl);
+ emit_writeword(tl,(int)®_cop2d[copr]);
+ break;
+ case 15:
+ emit_readword((int)®_cop2d[14],tl); // SXY2
+ emit_writeword(tl,(int)®_cop2d[copr]);
+ break;
+ case 28:
+ case 29:
+ emit_readword((int)®_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((int)®_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((int)®_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,(int)®_cop2d[copr]);
+ break;
+ default:
+ emit_readword((int)®_cop2d[copr],tl);
+ break;
+ }
+}
+
+static void cop2_put_dreg(u_int copr,signed char sl,signed char temp)
+{
+ switch (copr) {
+ case 15:
+ emit_readword((int)®_cop2d[13],temp); // SXY1
+ emit_writeword(sl,(int)®_cop2d[copr]);
+ emit_writeword(temp,(int)®_cop2d[12]); // SXY0
+ emit_readword((int)®_cop2d[14],temp); // SXY2
+ emit_writeword(sl,(int)®_cop2d[14]);
+ emit_writeword(temp,(int)®_cop2d[13]); // SXY1
+ break;
+ case 28:
+ emit_andimm(sl,0x001f,temp);
+ emit_shlimm(temp,7,temp);
+ emit_writeword(temp,(int)®_cop2d[9]);
+ emit_andimm(sl,0x03e0,temp);
+ emit_shlimm(temp,2,temp);
+ emit_writeword(temp,(int)®_cop2d[10]);
+ emit_andimm(sl,0x7c00,temp);
+ emit_shrimm(temp,3,temp);
+ emit_writeword(temp,(int)®_cop2d[11]);
+ emit_writeword(sl,(int)®_cop2d[28]);
+ break;
+ case 30:
+ emit_movs(sl,temp);
+ emit_mvnmi(temp,temp);
+ emit_clz(temp,temp);
+ emit_writeword(sl,(int)®_cop2d[30]);
+ emit_writeword(temp,(int)®_cop2d[31]);
+ break;
+ case 31:
+ break;
+ default:
+ emit_writeword(sl,(int)®_cop2d[copr]);
+ break;
+ }
+}
+
+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((int)®_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,(int)®_cop2c[copr]);
+ assert(sl>=0);
}
}
-void cop1_unusable(int i, struct regstat *i_regs)
+void c2op_assemble(int i,struct regstat *i_regs)
+{
+ signed char temp=get_reg(i_regs->regmap,-1);
+ u_int c2op=source[i]&0x3f;
+ u_int hr,reglist=0;
+ for(hr=0;hr<HOST_REGS;hr++) {
+ if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
+ }
+ if(i==0||itype[i-1]!=C2OP)
+ save_regs(reglist);
+
+ if (gte_handlers[c2op]!=NULL) {
+ int cc=get_reg(i_regs->regmap,CCREG);
+ emit_movimm(source[i],1); // opcode
+ if (cc>=0&>e_cycletab[c2op])
+ emit_addimm(cc,gte_cycletab[c2op]/2,cc); // XXX: could just adjust ccadj?
+ emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs
+ emit_writeword(1,(int)&psxRegs.code);
+ emit_call((int)gte_handlers[c2op]);
+ }
+
+ if(i>=slen-1||itype[i+1]!=C2OP)
+ restore_regs(reglist);
+}
+
+void cop1_unusable(int i,struct regstat *i_regs)
{
// XXX: should just just do the exception instead
if(!cop1_usable) {
assert(quotient>=0);
assert(remainder>=0);
emit_movs(d1,remainder);
- emit_negmi(remainder,remainder);
+ emit_movimm(0xffffffff,quotient);
+ emit_negmi(quotient,quotient); // .. quotient and ..
+ emit_negmi(remainder,remainder); // .. remainder for div0 case (will be negated back after jump)
emit_movs(d2,HOST_TEMPREG);
emit_jeq((int)out+52); // Division by zero
emit_negmi(HOST_TEMPREG,HOST_TEMPREG);
signed char remainder=get_reg(i_regs->regmap,HIREG);
assert(quotient>=0);
assert(remainder>=0);
+ emit_mov(d1,remainder);
+ emit_movimm(0xffffffff,quotient); // div0 case
emit_test(d2,d2);
- emit_jeq((int)out+44); // Division by zero
+ emit_jeq((int)out+40); // Division by zero
emit_clz(d2,HOST_TEMPREG);
emit_movimm(1<<31,quotient);
emit_shl(d2,HOST_TEMPREG,d2);
- emit_mov(d1,remainder);
emit_shr(quotient,HOST_TEMPREG,quotient);
emit_cmp(remainder,d2);
emit_subcs(remainder,d2,remainder);
if(hr!=EXCLUDE_REG) {
reg=pre[hr];
if(((~u)>>(reg&63))&1) {
- if(reg==entry[hr]||(reg>0&&entry[hr]<0)) {
+ if(reg>0) {
if(((dirty_pre&~dirty)>>hr)&1) {
if(reg>0&®<34) {
emit_storereg(reg,hr);
}
}
}
- else // Check if register moved to a different register
- if((new_hr=get_reg(entry,reg))>=0) {
- if((dirty_pre>>hr)&(~dirty>>new_hr)&1) {
- if(reg>0&®<34) {
- emit_storereg(reg,hr);
- if( ((is32_pre&~uu)>>reg)&1 ) {
- emit_sarimm(hr,31,HOST_TEMPREG);
- emit_storereg(reg|64,HOST_TEMPREG);
- }
- }
- else if(reg>=64) {
- emit_storereg(reg,hr);
- }
- }
- }
}
}
}
#define wb_invalidate wb_invalidate_arm
*/
+// Clearing the cache is rather slow on ARM Linux, so mark the areas
+// that need to be cleared, and then only clear these areas once.
+void do_clear_cache()
+{
+ int i,j;
+ for (i=0;i<(1<<(TARGET_SIZE_2-17));i++)
+ {
+ u_int bitmap=needs_clear_cache[i];
+ if(bitmap) {
+ u_int start,end;
+ for(j=0;j<32;j++)
+ {
+ if(bitmap&(1<<j)) {
+ start=BASE_ADDR+i*131072+j*4096;
+ end=start+4095;
+ j++;
+ while(j<32) {
+ if(bitmap&(1<<j)) {
+ end+=4096;
+ j++;
+ }else{
+ __clear_cache((void *)start,(void *)end);
+ break;
+ }
+ }
+ }
+ }
+ needs_clear_cache[i]=0;
+ }
+ }
+}
+
// CPU-architecture-specific initialization
void arch_init() {
#ifndef DISABLE_COP1
rounding_modes[3]=0x2<<22; // floor
#endif
}
+
+// vim:shiftwidth=2:expandtab