-#endif
- int ftable=0;
- if(type==STOREB_STUB)
- ftable=(int)writememb;
- if(type==STOREH_STUB)
- ftable=(int)writememh;
- if(type==STOREW_STUB)
- ftable=(int)writemem;
-#ifndef FORCE32
- if(type==STORED_STUB)
- ftable=(int)writememd;
-#endif
- assert(ftable!=0);
- emit_writeword(rs,(int)&address);
- //emit_shrimm(rs,16,rs);
- //emit_movmem_indexedx4(ftable,rs,rs);
- if(type==STOREB_STUB)
- emit_writebyte(rt,(int)&byte);
- if(type==STOREH_STUB)
- emit_writehword(rt,(int)&hword);
- if(type==STOREW_STUB)
- emit_writeword(rt,(int)&word);
- if(type==STORED_STUB) {
-#ifndef FORCE32
- emit_writeword(rt,(int)&dword);
- emit_writeword(target?rth:rt,(int)&dword+4);
-#else
- printf("STORED_STUB\n");
-#endif
- }
- //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_loadreg(CCREG,2);
- }
- //emit_movimm(ftable,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);
- emit_readword((int)&Count,HOST_TEMPREG);
- emit_readword((int)&next_interupt,2);
- emit_addimm(HOST_TEMPREG,-CLOCK_DIVIDER*(adj+1),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);
- }
- //emit_popa();
- restore_regs(reglist);
-}
-
-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);
-
- 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
-}
-
-void printregs(int edi,int esi,int ebp,int esp,int b,int d,int c,int a)
-{
- printf("regs: %x %x %x %x %x %x %x (%x)\n",a,b,c,d,ebp,esi,edi,(&edi)[-1]);
-}
-
-do_invstub(int n)
-{
- literal_pool(20);
- u_int reglist=stubs[n][3];
- set_jump_target(stubs[n][1],(int)out);
- save_regs(reglist);
- if(stubs[n][4]!=0) emit_mov(stubs[n][4],0);
- emit_call((int)&invalidate_addr);
- 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(addr,1);
- emit_loadlp((int)copy,2);
- emit_loadlp(slen*4,3);
- #else
- emit_movw(addr&0x0000FFFF,1);
- emit_movw(((u_int)copy)&0x0000FFFF,2);
- emit_movt(addr&0xFFFF0000,1);
- emit_movt(((u_int)copy)&0xFFFF0000,2);
- emit_movw(slen*4,3);
- #endif
- emit_movimm(start+i*4,0);
- emit_call((int)start<(int)0xC0000000?(int)&verify_code:(int)&verify_code_vm);
- int entry=(int)out;
- load_regs_entry(i);
- if(entry==(int)out) entry=instr_addr[i];
- emit_jmp(instr_addr[i]);
- return entry;
-}
-
-void do_dirty_stub_ds()
-{
- // 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((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(((u_int)copy)&0x0000FFFF,2);
- emit_movt(((int)start<(int)0xC0000000?(u_int)source:(u_int)start)&0xFFFF0000,1);
- emit_movt(((u_int)copy)&0xFFFF0000,2);
- emit_movw(slen*4,3);
- #endif
- emit_movimm(start+1,0);
- emit_call((int)&verify_code_ds);
-}
-
-do_cop1stub(int n)
-{
- literal_pool(256);
- assem_debug("do_cop1stub %x\n",start+stubs[n][3]*4);
- set_jump_target(stubs[n][1],(int)out);
- int i=stubs[n][3];
-// int rs=stubs[n][4];
- struct regstat *i_regs=(struct regstat *)stubs[n][5];
- int ds=stubs[n][6];
- if(!ds) {
- load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i);
- //if(i_regs!=®s[i]) printf("oops: regs[i]=%x i_regs=%x",(int)®s[i],(int)i_regs);
- }
- //else {printf("fp exception in delay slot\n");}
- wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty);
- if(regs[i].regmap_entry[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG);
- emit_movimm(start+(i-ds)*4,EAX); // Get PC
- emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle...
- emit_jmp(ds?(int)fp_exception_ds:(int)fp_exception);
-}
-
-/* TLB */
-
-int do_tlb_r(int s,int ar,int map,int x,int a,int shift,int c,u_int addr)
-{
- if(c) {
- if((signed int)addr>=(signed int)0xC0000000) {
- // address_generation already loaded the const
- emit_readword_dualindexedx4(FP,map,map);
- }
- else
- return -1; // No mapping
- }
- else {
- assert(s!=map);
- emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,map);
- emit_addsr12(map,s,map);
- // Schedule this while we wait on the load
- //if(x) emit_xorimm(s,x,ar);
- if(shift>=0) emit_shlimm(s,3,shift);
- if(~a) emit_andimm(s,a,ar);
- emit_readword_dualindexedx4(FP,map,map);
- }
- return map;
-}
-int do_tlb_r_branch(int map, int c, u_int addr, int *jaddr)
-{
- if(!c||(signed int)addr>=(signed int)0xC0000000) {
- emit_test(map,map);
- *jaddr=(int)out;
- emit_js(0);
- }
- return map;
-}
-
-int gen_tlb_addr_r(int ar, int map) {
- if(map>=0) {
- assem_debug("add %s,%s,%s lsl #2\n",regname[ar],regname[ar],regname[map]);
- output_w32(0xe0800100|rd_rn_rm(ar,ar,map));
- }
-}
-
-int do_tlb_w(int s,int ar,int map,int x,int c,u_int addr)
-{
- if(c) {
- if(addr<0x80800000||addr>=0xC0000000) {
- // address_generation already loaded the const
- emit_readword_dualindexedx4(FP,map,map);
- }
- else
- return -1; // No mapping
- }
- else {
- assert(s!=map);
- emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,map);
- emit_addsr12(map,s,map);
- // Schedule this while we wait on the load
- //if(x) emit_xorimm(s,x,ar);
- emit_readword_dualindexedx4(FP,map,map);
- }
- return map;
-}
-int do_tlb_w_branch(int map, int c, u_int addr, int *jaddr)
-{
- if(!c||addr<0x80800000||addr>=0xC0000000) {
- emit_testimm(map,0x40000000);
- *jaddr=(int)out;
- emit_jne(0);
- }
-}
-
-int gen_tlb_addr_w(int ar, int map) {
- if(map>=0) {
- assem_debug("add %s,%s,%s lsl #2\n",regname[ar],regname[ar],regname[map]);
- output_w32(0xe0800100|rd_rn_rm(ar,ar,map));
- }
-}
-
-// Generate the address of the memory_map entry, relative to dynarec_local
-generate_map_const(u_int addr,int reg) {
- //printf("generate_map_const(%x,%s)\n",addr,regname[reg]);
- emit_movimm((addr>>12)+(((u_int)memory_map-(u_int)&dynarec_local)>>2),reg);
-}
-
-/* Special assem */
-
-void shift_assemble_arm(int i,struct regstat *i_regs)
-{
- if(rt1[i]) {
- if(opcode2[i]<=0x07) // SLLV/SRLV/SRAV
- {
- signed char s,t,shift;
- t=get_reg(i_regs->regmap,rt1[i]);
- s=get_reg(i_regs->regmap,rs1[i]);
- shift=get_reg(i_regs->regmap,rs2[i]);
- if(t>=0){
- if(rs1[i]==0)
- {
- emit_zeroreg(t);
- }
- else if(rs2[i]==0)
- {
- assert(s>=0);
- if(s!=t) emit_mov(s,t);
- }
- else
- {
- emit_andimm(shift,31,HOST_TEMPREG);
- if(opcode2[i]==4) // SLLV
- {
- emit_shl(s,HOST_TEMPREG,t);
- }
- if(opcode2[i]==6) // SRLV
- {
- emit_shr(s,HOST_TEMPREG,t);
- }
- if(opcode2[i]==7) // SRAV
- {
- emit_sar(s,HOST_TEMPREG,t);
- }
- }
- }
- } else { // DSLLV/DSRLV/DSRAV
- signed char sh,sl,th,tl,shift;
- th=get_reg(i_regs->regmap,rt1[i]|64);
- tl=get_reg(i_regs->regmap,rt1[i]);
- sh=get_reg(i_regs->regmap,rs1[i]|64);
- sl=get_reg(i_regs->regmap,rs1[i]);
- shift=get_reg(i_regs->regmap,rs2[i]);
- if(tl>=0){
- if(rs1[i]==0)
- {
- emit_zeroreg(tl);
- if(th>=0) emit_zeroreg(th);
- }
- else if(rs2[i]==0)
- {
- assert(sl>=0);
- if(sl!=tl) emit_mov(sl,tl);
- if(th>=0&&sh!=th) emit_mov(sh,th);
- }
- else
- {
- // FIXME: What if shift==tl ?
- assert(shift!=tl);
- int temp=get_reg(i_regs->regmap,-1);
- int real_th=th;
- if(th<0&&opcode2[i]!=0x14) {th=temp;} // DSLLV doesn't need a temporary register
- assert(sl>=0);
- assert(sh>=0);
- emit_andimm(shift,31,HOST_TEMPREG);
- if(opcode2[i]==0x14) // DSLLV
- {
- if(th>=0) emit_shl(sh,HOST_TEMPREG,th);
- emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
- emit_orrshr(sl,HOST_TEMPREG,th);
- emit_andimm(shift,31,HOST_TEMPREG);
- emit_testimm(shift,32);
- emit_shl(sl,HOST_TEMPREG,tl);
- if(th>=0) emit_cmovne_reg(tl,th);
- emit_cmovne_imm(0,tl);
- }
- if(opcode2[i]==0x16) // DSRLV
- {
- assert(th>=0);
- emit_shr(sl,HOST_TEMPREG,tl);
- emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
- emit_orrshl(sh,HOST_TEMPREG,tl);
- emit_andimm(shift,31,HOST_TEMPREG);
- emit_testimm(shift,32);
- emit_shr(sh,HOST_TEMPREG,th);
- emit_cmovne_reg(th,tl);
- if(real_th>=0) emit_cmovne_imm(0,th);
- }
- if(opcode2[i]==0x17) // DSRAV
- {
- assert(th>=0);
- emit_shr(sl,HOST_TEMPREG,tl);
- emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
- if(real_th>=0) {
- assert(temp>=0);
- emit_sarimm(th,31,temp);
- }
- emit_orrshl(sh,HOST_TEMPREG,tl);
- emit_andimm(shift,31,HOST_TEMPREG);
- emit_testimm(shift,32);
- emit_sar(sh,HOST_TEMPREG,th);
- emit_cmovne_reg(th,tl);
- if(real_th>=0) emit_cmovne_reg(temp,th);
- }
- }
- }
- }
- }
-}
-#define shift_assemble shift_assemble_arm
-
-void loadlr_assemble_arm(int i,struct regstat *i_regs)
-{
- int s,th,tl,temp,temp2,addr,map=-1;
- int offset;
- int jaddr=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]);
- s=get_reg(i_regs->regmap,rs1[i]);
- temp=get_reg(i_regs->regmap,-1);
- temp2=get_reg(i_regs->regmap,FTEMP);
- addr=get_reg(i_regs->regmap,AGEN1+(i&1));
- assert(addr<0);
- offset=imm[i];
- for(hr=0;hr<HOST_REGS;hr++) {
- if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
- }
- reglist|=1<<temp;
- if(offset||s<0||c) addr=temp2;
- else addr=s;
- if(s>=0) {
- c=(i_regs->wasconst>>s)&1;
- 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{
- emit_andimm(addr,0xFFFFFFF8,temp2); // 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
- }
- }
- }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
- }
- }
- 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
-#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_lsr(tl,HOST_TEMPREG,temp,tl);
- }else{
- emit_shl(temp2,temp,temp2);
- emit_bic_lsl(tl,HOST_TEMPREG,temp,tl);
- }
- emit_or(temp2,tl,tl);
- }
- //emit_storereg(rt1[i],tl); // DEBUG