#include "pcnt.h"
#include "arm_features.h"
-#if !BASE_ADDR_FIXED
+#if defined(BASE_ADDR_FIXED)
+#elif defined(BASE_ADDR_DYNAMIC)
+char *translation_cache;
+#else
char translation_cache[1 << TARGET_SIZE_2] __attribute__((aligned(4096)));
#endif
#define unused __attribute__((unused))
+#ifdef DRC_DBG
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif
+
extern int cycle_count;
extern int last_count;
extern int pcaddr;
0,
0};
-static unsigned int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
+static u_int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
/* Linker */
-static void set_jump_target(int addr,u_int target)
+static void set_jump_target(void *addr, void *target_)
{
- u_char *ptr=(u_char *)addr;
+ u_int target = (u_int)target_;
+ u_char *ptr = addr;
u_int *ptr2=(u_int *)ptr;
if(ptr[3]==0xe2) {
assert((target-(u_int)ptr2-8)<1024);
- assert((addr&3)==0);
+ assert(((uintptr_t)addr&3)==0);
assert((target&3)==0);
*ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00;
- //printf("target=%x addr=%x insn=%x\n",target,addr,*ptr2);
+ //printf("target=%x addr=%p insn=%x\n",target,addr,*ptr2);
}
else if(ptr[3]==0x72) {
// generated by emit_jno_unlikely
if((target-(u_int)ptr2-8)<1024) {
- assert((addr&3)==0);
+ assert(((uintptr_t)addr&3)==0);
assert((target&3)==0);
*ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00;
}
else if((target-(u_int)ptr2-8)<4096&&!((target-(u_int)ptr2-8)&15)) {
- assert((addr&3)==0);
+ assert(((uintptr_t)addr&3)==0);
assert((target&3)==0);
*ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>4)|0xE00;
}
literalcount++;
}
-static void *kill_pointer(void *stub)
+// from a pointer to external jump stub (which was produced by emit_extjump2)
+// find where the jumping insn is
+static void *find_extjump_insn(void *stub)
{
int *ptr=(int *)(stub+4);
- assert((*ptr&0x0ff00000)==0x05900000);
+ assert((*ptr&0x0fff0000)==0x059f0000); // ldr rx, [pc, #ofs]
u_int offset=*ptr&0xfff;
- int **l_ptr=(void *)ptr+offset+8;
- int *i_ptr=*l_ptr;
- set_jump_target((int)i_ptr,(int)stub);
- return i_ptr;
+ void **l_ptr=(void *)ptr+offset+8;
+ return *l_ptr;
}
// find where external branch is liked to using addr of it's stub:
static int get_pointer(void *stub)
{
//printf("get_pointer(%x)\n",(int)stub);
- int *ptr=(int *)(stub+4);
- assert((*ptr&0x0fff0000)==0x059f0000);
- u_int offset=*ptr&0xfff;
- int **l_ptr=(void *)ptr+offset+8;
- int *i_ptr=*l_ptr;
+ int *i_ptr=find_extjump_insn(stub);
assert((*i_ptr&0x0f000000)==0x0a000000);
return (int)i_ptr+((*i_ptr<<8)>>6)+8;
}
// Find the "clean" entry point from a "dirty" entry point
// by skipping past the call to verify_code
-static u_int get_clean_addr(int addr)
+static void *get_clean_addr(void *addr)
{
- int *ptr=(int *)addr;
+ signed int *ptr = addr;
#ifndef HAVE_ARMV7
ptr+=4;
#else
assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
ptr++;
if((*ptr&0xFF000000)==0xea000000) {
- return (int)ptr+((*ptr<<8)>>6)+8; // follow jump
+ return (char *)ptr+((*ptr<<8)>>6)+8; // follow jump
}
- return (u_int)ptr;
+ return ptr;
}
static int verify_dirty(u_int *ptr)
{
- u_int *ptr=(u_int *)addr;
#ifndef HAVE_ARMV7
+ u_int offset;
// get from literal pool
assert((*ptr&0xFFFF0000)==0xe59f0000);
- u_int offset=*ptr&0xfff;
- u_int *l_ptr=(void *)ptr+offset+8;
- u_int source=l_ptr[0];
- u_int copy=l_ptr[1];
- u_int len=l_ptr[2];
- ptr+=4;
+ offset=*ptr&0xfff;
+ u_int source=*(u_int*)((void *)ptr+offset+8);
+ ptr++;
+ assert((*ptr&0xFFFF0000)==0xe59f0000);
+ offset=*ptr&0xfff;
+ u_int copy=*(u_int*)((void *)ptr+offset+8);
+ ptr++;
+ assert((*ptr&0xFFFF0000)==0xe59f0000);
+ offset=*ptr&0xfff;
+ u_int len=*(u_int*)((void *)ptr+offset+8);
+ ptr++;
+ ptr++;
#else
// ARMv7 movw/movt
assert((*ptr&0xFFF00000)==0xe3000000);
// This doesn't necessarily find all clean entry points, just
// guarantees that it's not dirty
-static int isclean(int addr)
+static int isclean(void *addr)
{
#ifndef HAVE_ARMV7
- int *ptr=((u_int *)addr)+4;
+ u_int *ptr=((u_int *)addr)+4;
#else
- int *ptr=((u_int *)addr)+6;
+ u_int *ptr=((u_int *)addr)+6;
#endif
if((*ptr&0xFF000000)!=0xeb000000) ptr++;
if((*ptr&0xFF000000)!=0xeb000000) return 1; // bl instruction
{
u_int *ptr=(u_int *)addr;
#ifndef HAVE_ARMV7
+ u_int offset;
// get from literal pool
assert((*ptr&0xFFFF0000)==0xe59f0000);
- u_int offset=*ptr&0xfff;
- u_int *l_ptr=(void *)ptr+offset+8;
- u_int source=l_ptr[0];
- //u_int copy=l_ptr[1];
- u_int len=l_ptr[2];
- ptr+=4;
+ offset=*ptr&0xfff;
+ u_int source=*(u_int*)((void *)ptr+offset+8);
+ ptr++;
+ //assert((*ptr&0xFFFF0000)==0xe59f0000);
+ //offset=*ptr&0xfff;
+ //u_int copy=*(u_int*)((void *)ptr+offset+8);
+ ptr++;
+ assert((*ptr&0xFFFF0000)==0xe59f0000);
+ offset=*ptr&0xfff;
+ u_int len=*(u_int*)((void *)ptr+offset+8);
+ ptr++;
+ ptr++;
#else
// ARMv7 movw/movt
assert((*ptr&0xFFF00000)==0xe3000000);
{
u_int ret=genimm(imm,encoded);
assert(ret);
+ (void)ret;
}
static u_int genjmp(u_int addr)
emit_cmovb_imm(1,rt);
}
+#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_vm),
+ 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
+
static void emit_call(int a)
{
- assem_debug("bl %x (%x+%x)\n",a,(int)out,a-(int)out-8);
+ assem_debug("bl %x (%x+%x)%s\n",a,(int)out,a-(int)out-8,func_name(a));
u_int offset=genjmp(a);
output_w32(0xeb000000|offset);
}
static void emit_jmp(int a)
{
- assem_debug("b %x (%x+%x)\n",a,(int)out,a-(int)out-8);
+ assem_debug("b %x (%x+%x)%s\n",a,(int)out,a-(int)out-8,func_name(a));
u_int offset=genjmp(a);
output_w32(0xea000000|offset);
}
if(n) {
if((int)out-literals[0][0]<4096-n) return;
}
- int jaddr=(int)out;
+ void *jaddr = out;
emit_jmp(0);
literal_pool(0);
- set_jump_target(jaddr,(int)out);
+ set_jump_target(jaddr, out);
}
static void emit_extjump2(u_int addr, int target, int linker)
{
assem_debug("do_readstub %x\n",start+stubs[n][3]*4);
literal_pool(256);
- set_jump_target(stubs[n][1],(int)out);
+ set_jump_target(stubs[n][1], out);
int type=stubs[n][0];
int i=stubs[n][3];
int rs=stubs[n][4];
struct regstat *i_regs=(struct regstat *)stubs[n][5];
u_int reglist=stubs[n][7];
signed char *i_regmap=i_regs->regmap;
- int addr=get_reg(i_regmap,AGEN1+(i&1));
- int rth,rt;
- int ds;
+ int rt;
if(itype[i]==C1LS||itype[i]==C2LS||itype[i]==LOADLR) {
- rth=get_reg(i_regmap,FTEMP|64);
rt=get_reg(i_regmap,FTEMP);
}else{
- rth=get_reg(i_regmap,rt1[i]|64);
rt=get_reg(i_regmap,rt1[i]);
}
assert(rs>=0);
- int r,temp=-1,temp2=HOST_TEMPREG,regs_saved=0,restore_jump=0;
+ int r,temp=-1,temp2=HOST_TEMPREG,regs_saved=0;
+ void *restore_jump = NULL;
reglist|=(1<<rs);
for(r=0;r<=12;r++) {
if(((1<<r)&0x13ff)&&((1<<r)®list)==0) {
}
}
if(regs_saved) {
- restore_jump=(int)out;
+ restore_jump=out;
emit_jcc(0); // jump to reg restore
}
else
mov_loadtype_adj(type,0,rt);
}
if(restore_jump)
- set_jump_target(restore_jump,(int)out);
+ set_jump_target(restore_jump, out);
restore_regs(reglist);
emit_jmp(stubs[n][2]); // return address
}
static void inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
{
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);
{
assem_debug("do_writestub %x\n",start+stubs[n][3]*4);
literal_pool(256);
- set_jump_target(stubs[n][1],(int)out);
+ set_jump_target(stubs[n][1], out);
int type=stubs[n][0];
int i=stubs[n][3];
int rs=stubs[n][4];
struct regstat *i_regs=(struct regstat *)stubs[n][5];
u_int reglist=stubs[n][7];
signed char *i_regmap=i_regs->regmap;
- int addr=get_reg(i_regmap,AGEN1+(i&1));
- int rth,rt,r;
- int ds;
+ int rt,r;
if(itype[i]==C1LS||itype[i]==C2LS) {
- rth=get_reg(i_regmap,FTEMP|64);
rt=get_reg(i_regmap,r=FTEMP);
}else{
- rth=get_reg(i_regmap,rs2[i]|64);
rt=get_reg(i_regmap,r=rs2[i]);
}
assert(rs>=0);
assert(rt>=0);
- int rtmp,temp=-1,temp2=HOST_TEMPREG,regs_saved=0,restore_jump=0,ra;
+ int rtmp,temp=-1,temp2=HOST_TEMPREG,regs_saved=0,ra;
+ void *restore_jump = NULL;
int reglist2=reglist|(1<<rs)|(1<<rt);
for(rtmp=0;rtmp<=12;rtmp++) {
if(((1<<rtmp)&0x13ff)&&((1<<rtmp)®list2)==0) {
default: assert(0);
}
if(regs_saved) {
- restore_jump=(int)out;
+ restore_jump=out;
emit_jcc(0); // jump to reg restore
}
else
if(cc<0)
emit_storereg(CCREG,2);
if(restore_jump)
- set_jump_target(restore_jump,(int)out);
+ set_jump_target(restore_jump, out);
restore_regs(reglist);
ra=stubs[n][2];
emit_jmp(ra);
static void inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
{
int rs=get_reg(regmap,-1);
- int rth=get_reg(regmap,target|64);
int rt=get_reg(regmap,target);
assert(rs>=0);
assert(rt>=0);
{
assem_debug("do_unalignedwritestub %x\n",start+stubs[n][3]*4);
literal_pool(256);
- set_jump_target(stubs[n][1],(int)out);
+ set_jump_target(stubs[n][1], out);
int i=stubs[n][3];
struct regstat *i_regs=(struct regstat *)stubs[n][4];
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);
{
literal_pool(20);
u_int reglist=stubs[n][3];
- set_jump_target(stubs[n][1],(int)out);
+ set_jump_target(stubs[n][1], out);
save_regs(reglist);
if(stubs[n][4]!=0) emit_mov(stubs[n][4],0);
emit_call((int)&invalidate_addr);
emit_jmp(stubs[n][2]); // return address
}
-int do_dirty_stub(int i)
+void *do_dirty_stub(int i)
{
assem_debug("do_dirty_stub %x\n",start+i*4);
u_int addr=(u_int)source;
#endif
emit_movimm(start+i*4,0);
emit_call((int)start<(int)0xC0000000?(int)&verify_code:(int)&verify_code_vm);
- int entry=(int)out;
+ void *entry = out;
load_regs_entry(i);
- if(entry==(int)out) entry=instr_addr[i];
+ if (entry == out)
+ entry = instr_addr[i];
emit_jmp(instr_addr[i]);
return entry;
}
{
literal_pool(256);
assem_debug("do_cop1stub %x\n",start+stubs[n][3]*4);
- set_jump_target(stubs[n][1],(int)out);
+ set_jump_target(stubs[n][1], out);
int i=stubs[n][3];
// int rs=stubs[n][4];
struct regstat *i_regs=(struct regstat *)stubs[n][5];
static int emit_fastpath_cmp_jump(int i,int addr,int *addr_reg_override)
{
- int jaddr,type=0;
+ int jaddr=0,type=0;
int mr=rs1[i];
if(((smrv_strong|smrv_weak)>>mr)&1) {
type=get_ptr_mem_type(smrv[mr]);
static 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_full=0,reglist;
int need_flags,need_ir;
static void wb_valid(signed char pre[],signed char entry[],u_int dirty_pre,u_int dirty,uint64_t is32_pre,uint64_t u,uint64_t uu)
{
//if(dirty_pre==dirty) return;
- int hr,reg,new_hr;
+ int hr,reg;
for(hr=0;hr<HOST_REGS;hr++) {
if(hr!=EXCLUDE_REG) {
reg=pre[hr];
#define wb_invalidate wb_invalidate_arm
*/
+static void mark_clear_cache(void *target)
+{
+ u_long offset = (char *)target - (char *)BASE_ADDR;
+ u_int mask = 1u << ((offset >> 12) & 31);
+ if (!(needs_clear_cache[offset >> 17] & mask)) {
+ char *start = (char *)((u_long)target & ~4095ul);
+ start_tcache_write(start, start + 4096);
+ needs_clear_cache[offset >> 17] |= mask;
+ }
+}
+
// 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.
static void do_clear_cache()
end+=4096;
j++;
}else{
- __clear_cache((void *)start,(void *)end);
+ end_tcache_write((void *)start,(void *)end);
break;
}
}