#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;
}
int get_pointer(void *stub)
}
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
{
u_int armval;
assem_debug("tst %s,$%d\n",regname[rs],imm);
- assert(genimm(imm,&armval));
+ 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);
{
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);
}
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);
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)
//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);
+ if(target==0)
+ emit_movimm(addr,rs);
emit_writeword(rs,(int)&address);
//emit_pusha();
save_regs(reglist);
}
//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{
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);
+ 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);
+ 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);
+ emit_movimm(start+stubs[n][3]*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3); // XXX: can be rm'd?
+ 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
else addr=s;
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(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(!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);
+ 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);
#ifdef BIG_ENDIAN_MIPS
if (opcode[i]==0x26) // LWR
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
- // 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((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
}
}
-void cop1_unusable(int i, struct regstat *i_regs)
+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 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],temp); // opcode
+ if (cc>=0&>e_cycletab[c2op])
+ emit_addimm(cc,gte_cycletab[c2op]/2,cc); // XXX: cound just adjust ccadj?
+ emit_writeword(temp,(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) {
#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