+ set_jump_target(stubs[n].addr, out);
+ enum stub_type type = stubs[n].type;
+ int i = stubs[n].a;
+ int rs = stubs[n].b;
+ const struct regstat *i_regs = (void *)stubs[n].c;
+ u_int reglist = stubs[n].e;
+ const signed char *i_regmap = i_regs->regmap;
+ int rt;
+ if(dops[i].itype==C2LS||dops[i].itype==LOADLR) {
+ rt=get_reg(i_regmap,FTEMP);
+ }else{
+ rt=get_reg(i_regmap,dops[i].rt1);
+ }
+ assert(rs>=0);
+ int r,temp=-1,temp2=HOST_TEMPREG,regs_saved=0;
+ void *restore_jump = NULL, *handler_jump = NULL;
+ reglist|=(1<<rs);
+ for (r = 0; r < HOST_CCREG; r++) {
+ if (r != EXCLUDE_REG && ((1 << r) & reglist) == 0) {
+ temp = r;
+ break;
+ }
+ }
+ if(rt>=0&&dops[i].rt1!=0)
+ reglist&=~(1<<rt);
+ if(temp==-1) {
+ save_regs(reglist);
+ regs_saved=1;
+ temp=(rs==0)?2:0;
+ }
+ if((regs_saved||(reglist&2)==0)&&temp!=1&&rs!=1)
+ temp2=1;
+ emit_readdword(&mem_rtab,temp);
+ emit_shrimm(rs,12,temp2);
+ emit_readdword_dualindexedx8(temp,temp2,temp2);
+ emit_adds64(temp2,temp2,temp2);
+ handler_jump=out;
+ emit_jc(0);
+ if(dops[i].itype==C2LS||(rt>=0&&dops[i].rt1!=0)) {
+ switch(type) {
+ case LOADB_STUB: emit_ldrsb_dualindexed(temp2,rs,rt); break;
+ case LOADBU_STUB: emit_ldrb_dualindexed(temp2,rs,rt); break;
+ case LOADH_STUB: emit_ldrsh_dualindexed(temp2,rs,rt); break;
+ case LOADHU_STUB: emit_ldrh_dualindexed(temp2,rs,rt); break;
+ case LOADW_STUB: emit_ldr_dualindexed(temp2,rs,rt); break;
+ default: assert(0);
+ }
+ }
+ if(regs_saved) {
+ restore_jump=out;
+ emit_jmp(0); // jump to reg restore
+ }
+ else
+ emit_jmp(stubs[n].retaddr); // return address
+ set_jump_target(handler_jump, out);
+
+ if(!regs_saved)
+ save_regs(reglist);
+ void *handler=NULL;
+ if(type==LOADB_STUB||type==LOADBU_STUB)
+ handler=jump_handler_read8;
+ if(type==LOADH_STUB||type==LOADHU_STUB)
+ handler=jump_handler_read16;
+ if(type==LOADW_STUB)
+ handler=jump_handler_read32;
+ assert(handler);
+ pass_args64(rs,temp2);
+ int cc=get_reg(i_regmap,CCREG);
+ if(cc<0)
+ emit_loadreg(CCREG,2);
+ emit_addimm(cc<0?2:cc,(int)stubs[n].d,2);
+ emit_far_call(handler);
+ // (no cycle reload after read)
+ if(dops[i].itype==C2LS||(rt>=0&&dops[i].rt1!=0)) {
+ loadstore_extend(type,0,rt);
+ }
+ if(restore_jump)
+ set_jump_target(restore_jump, out);
+ restore_regs(reglist);
+ emit_jmp(stubs[n].retaddr);
+}
+
+static void inline_readstub(enum stub_type type, int i, u_int addr,
+ const signed char regmap[], int target, int adj, u_int reglist)
+{
+ int ra = cinfo[i].addr;
+ int rt = get_reg(regmap, target);
+ assert(ra >= 0);
+ u_int is_dynamic=0;
+ uintptr_t host_addr = 0;
+ void *handler;
+ int cc=get_reg(regmap,CCREG);
+ //if(pcsx_direct_read(type,addr,adj,cc,target?ra:-1,rt))
+ // return;
+ handler = get_direct_memhandler(mem_rtab, addr, type, &host_addr);
+ if (handler == NULL) {
+ if(rt<0||dops[i].rt1==0)
+ return;
+ if (addr != host_addr)
+ emit_movimm_from64(addr, ra, host_addr, ra);
+ switch(type) {
+ case LOADB_STUB: emit_movsbl_indexed(0,ra,rt); break;
+ case LOADBU_STUB: emit_movzbl_indexed(0,ra,rt); break;
+ case LOADH_STUB: emit_movswl_indexed(0,ra,rt); break;
+ case LOADHU_STUB: emit_movzwl_indexed(0,ra,rt); break;
+ case LOADW_STUB: emit_readword_indexed(0,ra,rt); break;
+ default: assert(0);
+ }
+ return;
+ }
+ is_dynamic = pcsxmem_is_handler_dynamic(addr);
+ if (is_dynamic) {
+ if(type==LOADB_STUB||type==LOADBU_STUB)
+ handler=jump_handler_read8;
+ if(type==LOADH_STUB||type==LOADHU_STUB)
+ handler=jump_handler_read16;
+ if(type==LOADW_STUB)
+ handler=jump_handler_read32;
+ }