* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+#include <strings.h> // ffs
#define FLAGLESS
#include "../gte.h"
#undef FLAGLESS
#include "pcnt.h"
#include "arm_features.h"
+#ifdef TC_WRITE_OFFSET
+#error "not implemented"
+#endif
+
#ifdef DRC_DBG
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wunused-variable"
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,
+const void *invalidate_addr_reg[16] = {
+ invalidate_addr_r0,
+ invalidate_addr_r1,
+ invalidate_addr_r2,
+ invalidate_addr_r3,
+ invalidate_addr_r4,
+ invalidate_addr_r5,
+ invalidate_addr_r6,
+ invalidate_addr_r7,
+ invalidate_addr_r8,
+ invalidate_addr_r9,
+ invalidate_addr_r10,
0,
- (int)invalidate_addr_r12,
+ invalidate_addr_r12,
0,
0,
- 0};
+ 0
+};
/* Linker */
+static void set_jump_target_far1(u_int *insn, void *target)
+{
+ u_int ni = *insn & 0xff000000;
+ ni |= (((u_int)target - (u_int)insn - 8u) << 6) >> 8;
+ assert((ni & 0x0e000000) == 0x0a000000);
+ *insn = ni;
+}
+
static void set_jump_target(void *addr, void *target_)
{
- u_int target = (u_int)target_;
- u_char *ptr = addr;
- u_int *ptr2=(u_int *)ptr;
+ const u_int target = (u_int)target_;
+ const u_char *ptr = addr;
+ u_int *ptr2 = (u_int *)ptr;
if(ptr[3]==0xe2) {
assert((target-(u_int)ptr2-8)<1024);
assert(((uintptr_t)addr&3)==0);
else *ptr2=(0x7A000000)|(((target-(u_int)ptr2-8)<<6)>>8);
}
else {
- assert((ptr[3]&0x0e)==0xa);
- *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8);
+ set_jump_target_far1(ptr2, target_);
}
}
return *l_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
-#if 0
-static void *get_pointer(void *stub)
-{
- //printf("get_pointer(%x)\n",(int)stub);
- int *i_ptr=find_extjump_insn(stub);
- assert((*i_ptr&0x0f000000)==0x0a000000); // b
- return (u_char *)i_ptr+((*i_ptr<<8)>>6)+8;
-}
-#endif
-
// Allocate a specific ARM register.
static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr)
{
}
}
- cur->regmap[hr]=reg;
- cur->dirty&=~(1<<hr);
- cur->dirty|=dirty<<hr;
- cur->isconst&=~(1<<hr);
+ assert(n == hr || cur->regmap[hr] < 0 || !((cur->noevict >> hr) & 1));
+ cur->regmap[hr] = reg;
+ cur->dirty &= ~(1 << hr);
+ cur->dirty |= dirty << hr;
+ cur->isconst &= ~(1u << hr);
+ cur->noevict |= 1u << hr;
}
// Alloc cycle count into dedicated register
-static void alloc_cc(struct regstat *cur,int i)
+static void alloc_cc(struct regstat *cur, int i)
{
- alloc_arm_reg(cur,i,CCREG,HOST_CCREG);
+ alloc_arm_reg(cur, i, CCREG, HOST_CCREG);
+}
+
+static void alloc_cc_optional(struct regstat *cur, int i)
+{
+ if (cur->regmap[HOST_CCREG] < 0) {
+ alloc_arm_reg(cur, i, CCREG, HOST_CCREG);
+ cur->noevict &= ~(1u << HOST_CCREG);
+ }
}
/* Assembler */
-static unused char regname[16][4] = {
+static attr_unused char regname[16][4] = {
"r0",
"r1",
"r2",
return ((u_int)offset>>2)&0xffffff;
}
-static unused void emit_breakpoint(void)
+static attr_unused void emit_breakpoint(void)
{
assem_debug("bkpt #0\n");
//output_w32(0xe1200070);
static void emit_storereg(int r, int hr)
{
assert(hr != EXCLUDE_REG);
- int addr = (int)&psxRegs.GPR.r[r];
+ void *addr;
switch (r) {
//case HIREG: addr = &hi; break;
//case LOREG: addr = &lo; break;
- case CCREG: addr = (int)&cycle_count; break;
- default: assert(r < 34); break;
+ case CCREG: addr = &cycle_count; break;
+ default: assert(r < 34u); addr = &psxRegs.GPR.r[r]; break;
}
- u_int offset = addr-(u_int)&dynarec_local;
- assert(offset<4096);
+ uintptr_t offset = (char *)addr - (char *)&dynarec_local;
+ assert(offset < 4096u);
assem_debug("str %s,fp+%d # r%d\n",regname[hr],offset,r);
output_w32(0xe5800000|rd_rn_rm(hr,FP,0)|offset);
}
output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
}
-static unused void emit_lslpls_imm(int rs,int imm,int rt)
+static attr_unused void emit_lslpls_imm(int rs,int imm,int rt)
{
assert(imm>0);
assert(imm<32);
output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x50|(shift<<8));
}
-static unused void emit_orrshl(u_int rs,u_int shift,u_int rt)
+static attr_unused void emit_orrshl(u_int rs,u_int shift,u_int rt)
{
assert(rs<16);
assert(rt<16);
output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x10|(shift<<8));
}
-static unused void emit_orrshr(u_int rs,u_int shift,u_int rt)
+static attr_unused void emit_orrshr(u_int rs,u_int shift,u_int rt)
{
assert(rs<16);
assert(rt<16);
output_w32(0x43a00000|rd_rn_rm(rt,0,0)|armval);
}
-static unused void emit_cmovne_reg(int rs,int rt)
+static attr_unused void emit_cmovne_reg(int rs,int rt)
{
assem_debug("movne %s,%s\n",regname[rt],regname[rs]);
output_w32(0x11a00000|rd_rn_rm(rt,0,rs));
static void emit_call(const void *a_)
{
int a = (int)a_;
- assem_debug("bl %x (%x+%x)%s\n",a,(int)out,a-(int)out-8,func_name(a_));
+ assem_debug("bl %p%s\n", log_addr(a), func_name(a_));
u_int offset=genjmp(a);
output_w32(0xeb000000|offset);
}
static void emit_jmp(const void *a_)
{
int a = (int)a_;
- assem_debug("b %x (%x+%x)%s\n",a,(int)out,a-(int)out-8,func_name(a_));
+ assem_debug("b %p%s\n", log_addr(a_), func_name(a_));
u_int offset=genjmp(a);
output_w32(0xea000000|offset);
}
static void emit_jne(const void *a_)
{
int a = (int)a_;
- assem_debug("bne %x\n",a);
+ assem_debug("bne %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0x1a000000|offset);
}
static void emit_jeq(const void *a_)
{
int a = (int)a_;
- assem_debug("beq %x\n",a);
+ assem_debug("beq %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0x0a000000|offset);
}
static void emit_js(const void *a_)
{
int a = (int)a_;
- assem_debug("bmi %x\n",a);
+ assem_debug("bmi %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0x4a000000|offset);
}
static void emit_jns(const void *a_)
{
int a = (int)a_;
- assem_debug("bpl %x\n",a);
+ assem_debug("bpl %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0x5a000000|offset);
}
static void emit_jl(const void *a_)
{
int a = (int)a_;
- assem_debug("blt %x\n",a);
+ assem_debug("blt %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0xba000000|offset);
}
static void emit_jge(const void *a_)
{
int a = (int)a_;
- assem_debug("bge %x\n",a);
+ assem_debug("bge %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0xaa000000|offset);
}
static void emit_jo(const void *a_)
{
int a = (int)a_;
- assem_debug("bvs %x\n",a);
+ assem_debug("bvs %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0x6a000000|offset);
}
static void emit_jno(const void *a_)
{
int a = (int)a_;
- assem_debug("bvc %x\n",a);
+ assem_debug("bvc %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0x7a000000|offset);
}
static void emit_jc(const void *a_)
{
int a = (int)a_;
- assem_debug("bcs %x\n",a);
+ assem_debug("bcs %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0x2a000000|offset);
}
static void emit_jcc(const void *a_)
{
int a = (int)a_;
- assem_debug("bcc %x\n",a);
+ assem_debug("bcc %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0x3a000000|offset);
}
return ret;
}
-static unused void emit_callreg(u_int r)
+static attr_unused void emit_callreg(u_int r)
{
assert(r<15);
assem_debug("blx %s\n",regname[r]);
output_w32(0xe1300000|rd_rn_rm(0,rs,rt));
}
-static unused void emit_rsbimm(int rs, int imm, int rt)
+static attr_unused void emit_rsbimm(int rs, int imm, int rt)
{
u_int armval;
genimm_checked(imm,&armval);
output_w32(0xe7d00000|rd_rn_rm(rt,base,r)|0x620);
}
-static void emit_callne(int a)
+static void emit_callne(const void *a_)
{
- assem_debug("blne %x\n",a);
+ int a = (int)a_;
+ assem_debug("blne %p\n", log_addr(a_));
u_int offset=genjmp(a);
output_w32(0x1b000000|offset);
}
// Used to preload hash table entries
-static unused void emit_prefetchreg(int r)
+static attr_unused void emit_prefetchreg(int r)
{
assem_debug("pld %s\n",regname[r]);
output_w32(0xf5d0f000|rd_rn_rm(0,r,0));
output_w32(0x13800000|rd_rn_rm(rt,rs,0)|armval);
}
-static unused void emit_addpl_imm(int rs,int imm,int rt)
+static attr_unused void emit_addpl_imm(int rs,int imm,int rt)
{
u_int armval;
genimm_checked(imm,&armval);
output_w32(0x52800000|rd_rn_rm(rt,rs,0)|armval);
}
-static void emit_jno_unlikely(int a)
+static void emit_jno_unlikely(void *a_)
{
- //emit_jno(a);
- assem_debug("addvc pc,pc,#? (%x)\n",/*a-(int)out-8,*/a);
+ //emit_jno(a_);
+ assert(a_ == NULL);
+ assem_debug("addvc pc,pc,#? (%p)\n", /*a-(int)out-8,*/ log_addr(a_));
output_w32(0x72800000|rd_rn_rm(15,15,0));
}
set_jump_target(jaddr, out);
}
-// parsed by get_pointer, find_extjump_insn
+// parsed by find_extjump_insn, check_extjump2
static void emit_extjump(u_char *addr, u_int target)
{
u_char *ptr=(u_char *)addr;
static void do_readstub(int n)
{
- assem_debug("do_readstub %x\n",start+stubs[n].a*4);
+ assem_debug("do_readstub %p\n", log_addr(start + stubs[n].a*4));
literal_pool(256);
set_jump_target(stubs[n].addr, out);
enum stub_type type=stubs[n].type;
emit_loadreg(CCREG,2);
emit_addimm(cc<0?2:cc,(int)stubs[n].d,2);
emit_far_call(handler);
+#if 0
+ if (type == LOADW_STUB) {
+ // new cycle_count returned in r2
+ emit_addimm(2, -(int)stubs[n].d, cc<0?2:cc);
+ if (cc < 0)
+ emit_storereg(CCREG, 2);
+ }
+#endif
if(dops[i].itype==C2LS||(rt>=0&&dops[i].rt1!=0)) {
mov_loadtype_adj(type,0,rt);
}
emit_far_call(handler);
+#if 0
+ if (type == LOADW_STUB) {
+ // new cycle_count returned in r2
+ emit_addimm(2, -adj, cc<0?2:cc);
+ if (cc < 0)
+ emit_storereg(CCREG, 2);
+ }
+#endif
if(rt>=0&&dops[i].rt1!=0) {
switch(type) {
case LOADB_STUB: emit_signextend8(0,rt); break;
static void do_writestub(int n)
{
- assem_debug("do_writestub %x\n",start+stubs[n].a*4);
+ assem_debug("do_writestub %p\n", log_addr(start + stubs[n].a*4));
literal_pool(256);
set_jump_target(stubs[n].addr, out);
enum stub_type type=stubs[n].type;
if(cc<0)
emit_loadreg(CCREG,2);
emit_addimm(cc<0?2:cc,(int)stubs[n].d,2);
- // returns new cycle_count
emit_far_call(handler);
- emit_addimm(0,-(int)stubs[n].d,cc<0?2:cc);
+ // new cycle_count returned in r2
+ emit_addimm(2,-(int)stubs[n].d,cc<0?2:cc);
if(cc<0)
emit_storereg(CCREG,2);
if(restore_jump)
emit_loadreg(CCREG,2);
emit_addimm(cc<0?2:cc,adj,2);
emit_movimm((u_int)handler,3);
- // returns new cycle_count
emit_far_call(jump_handler_write_h);
- emit_addimm(0,-adj,cc<0?2:cc);
+ // new cycle_count returned in r2
+ emit_addimm(2,-adj,cc<0?2:cc);
if(cc<0)
emit_storereg(CCREG,2);
restore_regs(reglist);