DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 00021 /* MIPS32 (little endian) backend by crazyc */ 00022 00023 00024 // some configuring defines that specify the capabilities of this architecture 00025 // or aspects of the recompiling 00026 00027 // protect FC_ADDR over function calls if necessaray 00028 // #define DRC_PROTECT_ADDR_REG 00029 00030 // try to use non-flags generating functions if possible 00031 #define DRC_FLAGS_INVALIDATION 00032 // try to replace _simple functions by code 00033 #define DRC_FLAGS_INVALIDATION_DCODE 00034 00035 // type with the same size as a pointer 00036 #define DRC_PTR_SIZE_IM Bit32u 00037 00038 // calling convention modifier 00039 #define DRC_CALL_CONV /* nothing */ 00040 #define DRC_FC /* nothing */ 00041 00042 // use FC_REGS_ADDR to hold the address of "cpu_regs" and to access it using FC_REGS_ADDR 00043 //#define DRC_USE_REGS_ADDR 00044 // use FC_SEGS_ADDR to hold the address of "Segs" and to access it using FC_SEGS_ADDR 00045 //#define DRC_USE_SEGS_ADDR 00046 00047 // register mapping 00048 typedef Bit8u HostReg; 00049 00050 #define HOST_v0 2 00051 #define HOST_v1 3 00052 #define HOST_a0 4 00053 #define HOST_a1 5 00054 #define HOST_t4 12 00055 #define HOST_t5 13 00056 #define HOST_t6 14 00057 #define HOST_t7 15 00058 #define HOST_s0 16 00059 #define HOST_t8 24 00060 #define HOST_t9 25 00061 #define temp1 HOST_v1 00062 #define temp2 HOST_t9 00063 00064 // register that holds function return values 00065 #define FC_RETOP HOST_v0 00066 00067 // register used for address calculations, 00068 #define FC_ADDR HOST_s0 // has to be saved across calls, see DRC_PROTECT_ADDR_REG 00069 00070 // register that holds the first parameter 00071 #define FC_OP1 HOST_a0 00072 00073 // register that holds the second parameter 00074 #define FC_OP2 HOST_a1 00075 00076 // special register that holds the third parameter for _R3 calls (byte accessible) 00077 #define FC_OP3 HOST_??? 00078 00079 // register that holds byte-accessible temporary values 00080 #define FC_TMP_BA1 HOST_t5 00081 00082 // register that holds byte-accessible temporary values 00083 #define FC_TMP_BA2 HOST_t6 00084 00085 // temporary register for LEA 00086 #define TEMP_REG_DRC HOST_t7 00087 00088 #ifdef DRC_USE_REGS_ADDR 00089 // used to hold the address of "cpu_regs" - preferably filled in function gen_run_code 00090 #define FC_REGS_ADDR HOST_??? 00091 #endif 00092 00093 #ifdef DRC_USE_SEGS_ADDR 00094 // used to hold the address of "Segs" - preferably filled in function gen_run_code 00095 #define FC_SEGS_ADDR HOST_??? 00096 #endif 00097 00098 // save some state to improve code gen 00099 static bool temp1_valid = false; 00100 static Bit32u temp1_value; 00101 00102 // move a full register from reg_src to reg_dst 00103 static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { 00104 if(reg_src == reg_dst) return; 00105 cache_addw((reg_dst<<11)+0x21); // addu reg_dst, $0, reg_src 00106 cache_addw(reg_src); 00107 } 00108 00109 // move a 32bit constant value into dest_reg 00110 static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { 00111 if(imm < 65536) { 00112 cache_addw((Bit16u)imm); // ori dest_reg, $0, imm 00113 cache_addw(0x3400+dest_reg); 00114 } else if(((Bit32s)imm < 0) && ((Bit32s)imm >= -32768)) { 00115 cache_addw((Bit16u)imm); // addiu dest_reg, $0, imm 00116 cache_addw(0x2400+dest_reg); 00117 } else if(!(imm & 0xffff)) { 00118 cache_addw((Bit16u)(imm >> 16)); // lui dest_reg, %hi(imm) 00119 cache_addw(0x3c00+dest_reg); 00120 } else { 00121 cache_addw((Bit16u)(imm >> 16)); // lui dest_reg, %hi(imm) 00122 cache_addw(0x3c00+dest_reg); 00123 cache_addw((Bit16u)imm); // ori dest_reg, dest_reg, %lo(imm) 00124 cache_addw(0x3400+(dest_reg<<5)+dest_reg); 00125 } 00126 } 00127 00128 // this is the only place temp1 should be modified 00129 static void INLINE mov_imm_to_temp1(Bit32u imm) { 00130 if (temp1_valid && (temp1_value == imm)) return; 00131 gen_mov_dword_to_reg_imm(temp1, imm); 00132 temp1_valid = true; 00133 temp1_value = imm; 00134 } 00135 00136 static Bit16s gen_addr_temp1(Bit32u addr) { 00137 Bit32u hihalf = addr & 0xffff0000; 00138 Bit16s lohalf = addr & 0xffff; 00139 if (lohalf > 32764) { // [l,s]wl will overflow 00140 hihalf = addr; 00141 lohalf = 0; 00142 } else if(lohalf < 0) hihalf += 0x10000; 00143 mov_imm_to_temp1(hihalf); 00144 return lohalf; 00145 } 00146 00147 // move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg 00148 // 16bit moves may destroy the upper 16bit of the destination register 00149 static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { 00150 Bit16s lohalf = gen_addr_temp1((Bit32u)data); 00151 // alignment.... 00152 if (dword) { 00153 if ((Bit32u)data & 3) { 00154 cache_addw(lohalf+3); // lwl dest_reg, 3(temp1) 00155 cache_addw(0x8800+(temp1<<5)+dest_reg); 00156 cache_addw(lohalf); // lwr dest_reg, 0(temp1) 00157 cache_addw(0x9800+(temp1<<5)+dest_reg); 00158 } else { 00159 cache_addw(lohalf); // lw dest_reg, 0(temp1) 00160 cache_addw(0x8C00+(temp1<<5)+dest_reg); 00161 } 00162 } else { 00163 if ((Bit32u)data & 1) { 00164 cache_addw(lohalf); // lbu dest_reg, 0(temp1) 00165 cache_addw(0x9000+(temp1<<5)+dest_reg); 00166 cache_addw(lohalf+1); // lbu temp2, 1(temp1) 00167 cache_addw(0x9000+(temp1<<5)+temp2); 00168 #if (_MIPS_ISA==MIPS32R2) || defined(PSP) 00169 cache_addw(0x7a04); // ins dest_reg, temp2, 8, 8 00170 cache_addw(0x7c00+(temp2<<5)+dest_reg); 00171 #else 00172 cache_addw((temp2<<11)+0x200); // sll temp2, temp2, 8 00173 cache_addw(temp2); 00174 cache_addw((dest_reg<<11)+0x25); // or dest_reg, temp2, dest_reg 00175 cache_addw((temp2<<5)+dest_reg); 00176 #endif 00177 } else { 00178 cache_addw(lohalf); // lhu dest_reg, 0(temp1); 00179 cache_addw(0x9400+(temp1<<5)+dest_reg); 00180 } 00181 } 00182 } 00183 00184 // move a 16bit constant value into dest_reg 00185 // the upper 16bit of the destination register may be destroyed 00186 static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { 00187 cache_addw(imm); // ori dest_reg, $0, imm 00188 cache_addw(0x3400+dest_reg); 00189 } 00190 00191 // move 32bit (dword==true) or 16bit (dword==false) of a register into memory 00192 static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { 00193 Bit16s lohalf = gen_addr_temp1((Bit32u)dest); 00194 // alignment.... 00195 if (dword) { 00196 if ((Bit32u)dest & 3) { 00197 cache_addw(lohalf+3); // swl src_reg, 3(temp1) 00198 cache_addw(0xA800+(temp1<<5)+src_reg); 00199 cache_addw(lohalf); // swr src_reg, 0(temp1) 00200 cache_addw(0xB800+(temp1<<5)+src_reg); 00201 } else { 00202 cache_addw(lohalf); // sw src_reg, 0(temp1) 00203 cache_addw(0xAC00+(temp1<<5)+src_reg); 00204 } 00205 } else { 00206 if((Bit32u)dest & 1) { 00207 cache_addw(lohalf); // sb src_reg, 0(temp1) 00208 cache_addw(0xA000+(temp1<<5)+src_reg); 00209 cache_addw((temp2<<11)+0x202); // srl temp2, src_reg, 8 00210 cache_addw(src_reg); 00211 cache_addw(lohalf+1); // sb temp2, 1(temp1) 00212 cache_addw(0xA000+(temp1<<5)+temp2); 00213 } else { 00214 cache_addw(lohalf); // sh src_reg, 0(temp1); 00215 cache_addw(0xA400+(temp1<<5)+src_reg); 00216 } 00217 } 00218 } 00219 00220 // move an 8bit value from memory into dest_reg 00221 // the upper 24bit of the destination register can be destroyed 00222 // this function does not use FC_OP1/FC_OP2 as dest_reg as these 00223 // registers might not be directly byte-accessible on some architectures 00224 static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { 00225 Bit16s lohalf = gen_addr_temp1((Bit32u)data); 00226 cache_addw(lohalf); // lbu dest_reg, 0(temp1) 00227 cache_addw(0x9000+(temp1<<5)+dest_reg); 00228 } 00229 00230 // move an 8bit value from memory into dest_reg 00231 // the upper 24bit of the destination register can be destroyed 00232 // this function can use FC_OP1/FC_OP2 as dest_reg which are 00233 // not directly byte-accessible on some architectures 00234 static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { 00235 gen_mov_byte_to_reg_low(dest_reg, data); 00236 } 00237 00238 // move an 8bit constant value into dest_reg 00239 // the upper 24bit of the destination register can be destroyed 00240 // this function does not use FC_OP1/FC_OP2 as dest_reg as these 00241 // registers might not be directly byte-accessible on some architectures 00242 static void INLINE gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { 00243 gen_mov_word_to_reg_imm(dest_reg, imm); 00244 } 00245 00246 // move an 8bit constant value into dest_reg 00247 // the upper 24bit of the destination register can be destroyed 00248 // this function can use FC_OP1/FC_OP2 as dest_reg which are 00249 // not directly byte-accessible on some architectures 00250 static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { 00251 gen_mov_byte_to_reg_low_imm(dest_reg, imm); 00252 } 00253 00254 // move the lowest 8bit of a register into memory 00255 static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { 00256 Bit16s lohalf = gen_addr_temp1((Bit32u)dest); 00257 cache_addw(lohalf); // sb src_reg, 0(temp1) 00258 cache_addw(0xA000+(temp1<<5)+src_reg); 00259 } 00260 00261 00262 00263 // convert an 8bit word to a 32bit dword 00264 // the register is zero-extended (sign==false) or sign-extended (sign==true) 00265 static void gen_extend_byte(bool sign,HostReg reg) { 00266 if (sign) { 00267 #if (_MIPS_ISA==MIPS32R2) || defined(PSP) 00268 cache_addw((reg<<11)+0x420); // seb reg, reg 00269 cache_addw(0x7c00+reg); 00270 #else 00271 arch that lacks seb 00272 #endif 00273 } else { 00274 cache_addw(0xff); // andi reg, reg, 0xff 00275 cache_addw(0x3000+(reg<<5)+reg); 00276 } 00277 } 00278 00279 // convert a 16bit word to a 32bit dword 00280 // the register is zero-extended (sign==false) or sign-extended (sign==true) 00281 static void gen_extend_word(bool sign,HostReg reg) { 00282 if (sign) { 00283 #if (_MIPS_ISA==MIPS32R2) || defined(PSP) 00284 cache_addw((reg<<11)+0x620); // seh reg, reg 00285 cache_addw(0x7c00+reg); 00286 #else 00287 arch that lacks seh 00288 #endif 00289 } else { 00290 cache_addw(0xffff); // andi reg, reg, 0xffff 00291 cache_addw(0x3000+(reg<<5)+reg); 00292 } 00293 } 00294 00295 // add a 32bit value from memory to a full register 00296 static void gen_add(HostReg reg,void* op) { 00297 gen_mov_word_to_reg(temp2, op, 1); 00298 cache_addw((reg<<11)+0x21); // addu reg, reg, temp2 00299 cache_addw((reg<<5)+temp2); 00300 } 00301 00302 // add a 32bit constant value to a full register 00303 static void gen_add_imm(HostReg reg,Bit32u imm) { 00304 if(!imm) return; 00305 if(((Bit32s)imm >= -32768) && ((Bit32s)imm < 32768)) { 00306 cache_addw((Bit16u)imm); // addiu reg, reg, imm 00307 cache_addw(0x2400+(reg<<5)+reg); 00308 } else { 00309 mov_imm_to_temp1(imm); 00310 cache_addw((reg<<11)+0x21); // addu reg, reg, temp1 00311 cache_addw((reg<<5)+temp1); 00312 } 00313 } 00314 00315 // and a 32bit constant value with a full register 00316 static void gen_and_imm(HostReg reg,Bit32u imm) { 00317 if(imm < 65536) { 00318 cache_addw((Bit16u)imm); // andi reg, reg, imm 00319 cache_addw(0x3000+(reg<<5)+reg); 00320 } else { 00321 mov_imm_to_temp1((Bit32u)imm); 00322 cache_addw((reg<<11)+0x24); // and reg, temp1, reg 00323 cache_addw((temp1<<5)+reg); 00324 } 00325 } 00326 00327 00328 // move a 32bit constant value into memory 00329 static void INLINE gen_mov_direct_dword(void* dest,Bit32u imm) { 00330 gen_mov_dword_to_reg_imm(temp2, imm); 00331 gen_mov_word_from_reg(temp2, dest, 1); 00332 } 00333 00334 // move an address into memory 00335 static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { 00336 gen_mov_direct_dword(dest,(Bit32u)imm); 00337 } 00338 00339 // add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value 00340 static void INLINE gen_add_direct_word(void* dest,Bit32u imm,bool dword) { 00341 if(!imm) return; 00342 gen_mov_word_to_reg(temp2, dest, dword); 00343 gen_add_imm(temp2, imm); 00344 gen_mov_word_from_reg(temp2, dest, dword); 00345 } 00346 00347 // add an 8bit constant value to a dword memory value 00348 static void INLINE gen_add_direct_byte(void* dest,Bit8s imm) { 00349 gen_add_direct_word(dest, (Bit32s)imm, 1); 00350 } 00351 00352 // subtract an 8bit constant value from a dword memory value 00353 static void INLINE gen_sub_direct_byte(void* dest,Bit8s imm) { 00354 gen_add_direct_word(dest, -((Bit32s)imm), 1); 00355 } 00356 00357 // subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value 00358 static void INLINE gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { 00359 gen_add_direct_word(dest, -(Bit32s)imm, dword); 00360 } 00361 00362 // effective address calculation, destination is dest_reg 00363 // scale_reg is scaled by scale (scale_reg*(2^scale)) and 00364 // added to dest_reg, then the immediate value is added 00365 static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { 00366 if (scale) { 00367 cache_addw((scale_reg<<11)+(scale<<6)); // sll scale_reg, scale_reg, scale 00368 cache_addw(scale_reg); 00369 } 00370 cache_addw((dest_reg<<11)+0x21); // addu dest_reg, dest_reg, scale_reg 00371 cache_addw((dest_reg<<5)+scale_reg); 00372 gen_add_imm(dest_reg, imm); 00373 } 00374 00375 // effective address calculation, destination is dest_reg 00376 // dest_reg is scaled by scale (dest_reg*(2^scale)), 00377 // then the immediate value is added 00378 static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { 00379 if (scale) { 00380 cache_addw((dest_reg<<11)+(scale<<6)); // sll dest_reg, dest_reg, scale 00381 cache_addw(dest_reg); 00382 } 00383 gen_add_imm(dest_reg, imm); 00384 } 00385 00386 #define DELAY cache_addd(0) // nop 00387 00388 // generate a call to a parameterless function 00389 template <typename T> static void INLINE gen_call_function_raw(const T func) { 00390 #if C_DEBUG 00391 if ((cache.pos ^ func) & 0xf0000000) LOG_MSG("jump overflow\n"); 00392 #endif 00393 temp1_valid = false; 00394 cache_addd(0x0c000000+(((Bit32u)func>>2)&0x3ffffff)); // jal func 00395 DELAY; 00396 } 00397 00398 // generate a call to a function with paramcount parameters 00399 // note: the parameters are loaded in the architecture specific way 00400 // using the gen_load_param_ functions below 00401 template <typename T> static Bit32u INLINE gen_call_function_setup(const T func,Bitu paramcount,bool fastcall=false) { 00402 Bit32u proc_addr = (Bit32u)cache.pos; 00403 gen_call_function_raw(func); 00404 return proc_addr; 00405 } 00406 00407 #ifdef __mips_eabi 00408 // max of 8 parameters in $a0-$a3 and $t0-$t3 00409 00410 // load an immediate value as param'th function parameter 00411 static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { 00412 gen_mov_dword_to_reg_imm(param+4, imm); 00413 } 00414 00415 // load an address as param'th function parameter 00416 static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { 00417 gen_mov_dword_to_reg_imm(param+4, addr); 00418 } 00419 00420 // load a host-register as param'th function parameter 00421 static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { 00422 gen_mov_regs(param+4, reg); 00423 } 00424 00425 // load a value from memory as param'th function parameter 00426 static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { 00427 gen_mov_word_to_reg(param+4, (void *)mem, 1); 00428 } 00429 #else 00430 other mips abis 00431 #endif 00432 00433 // jump to an address pointed at by ptr, offset is in imm 00434 static void INLINE gen_jmp_ptr(void * ptr,Bits imm=0) { 00435 gen_mov_word_to_reg(temp2, ptr, 1); 00436 if((imm < -32768) || (imm >= 32768)) { 00437 gen_add_imm(temp2, imm); 00438 imm = 0; 00439 } 00440 temp1_valid = false; 00441 cache_addw((Bit16u)imm); // lw temp2, imm(temp2) 00442 cache_addw(0x8C00+(temp2<<5)+temp2); 00443 cache_addd((temp2<<21)+8); // jr temp2 00444 DELAY; 00445 } 00446 00447 // short conditional jump (+-127 bytes) if register is zero 00448 // the destination is set by gen_fill_branch() later 00449 static Bit32u INLINE gen_create_branch_on_zero(HostReg reg,bool dword) { 00450 temp1_valid = false; 00451 if(!dword) { 00452 cache_addw(0xffff); // andi temp1, reg, 0xffff 00453 cache_addw(0x3000+(reg<<5)+temp1); 00454 } 00455 cache_addw(0); // beq $0, reg, 0 00456 cache_addw(0x1000+(dword?reg:temp1)); 00457 DELAY; 00458 return ((Bit32u)cache.pos-8); 00459 } 00460 00461 // short conditional jump (+-127 bytes) if register is nonzero 00462 // the destination is set by gen_fill_branch() later 00463 static Bit32u INLINE gen_create_branch_on_nonzero(HostReg reg,bool dword) { 00464 temp1_valid = false; 00465 if(!dword) { 00466 cache_addw(0xffff); // andi temp1, reg, 0xffff 00467 cache_addw(0x3000+(reg<<5)+temp1); 00468 } 00469 cache_addw(0); // bne $0, reg, 0 00470 cache_addw(0x1400+(dword?reg:temp1)); 00471 DELAY; 00472 return ((Bit32u)cache.pos-8); 00473 } 00474 00475 // calculate relative offset and fill it into the location pointed to by data 00476 static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { 00477 #if C_DEBUG 00478 Bits len=(Bit32u)cache.pos-data; 00479 if (len<0) len=-len; 00480 if (len>126) LOG_MSG("Big jump %d",len); 00481 #endif 00482 temp1_valid = false; // this is a branch target 00483 *(Bit16u*)data=((Bit16u)((Bit32u)cache.pos-data-4)>>2); 00484 } 00485 00486 #if 0 // assume for the moment no branch will go farther then +/- 128KB 00487 00488 // conditional jump if register is nonzero 00489 // for isdword==true the 32bit of the register are tested 00490 // for isdword==false the lowest 8bit of the register are tested 00491 static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { 00492 temp1_valid = false; 00493 if (!isdword) { 00494 cache_addw(0xff); // andi temp1, reg, 0xff 00495 cache_addw(0x3000+(reg<<5)+temp1); 00496 } 00497 cache_addw(3); // beq $0, reg, +12 00498 cache_addw(0x1000+(isdword?reg:temp1)); 00499 DELAY; 00500 cache_addd(0x00000000); // fill j 00501 DELAY; 00502 return ((Bit32u)cache.pos-8); 00503 } 00504 00505 // compare 32bit-register against zero and jump if value less/equal than zero 00506 static Bit32u INLINE gen_create_branch_long_leqzero(HostReg reg) { 00507 temp1_valid = false; 00508 cache_addw(3); // bgtz reg, +12 00509 cache_addw(0x1c00+(reg<<5)); 00510 DELAY; 00511 cache_addd(0x00000000); // fill j 00512 DELAY; 00513 return ((Bit32u)cache.pos-8); 00514 } 00515 00516 // calculate long relative offset and fill it into the location pointed to by data 00517 static void INLINE gen_fill_branch_long(Bit32u data) { 00518 temp1_valid = false; 00519 // this is an absolute branch 00520 *(Bit32u*)data=0x08000000+(((Bit32u)cache.pos>>2)&0x3ffffff); 00521 } 00522 #else 00523 // conditional jump if register is nonzero 00524 // for isdword==true the 32bit of the register are tested 00525 // for isdword==false the lowest 8bit of the register are tested 00526 static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { 00527 temp1_valid = false; 00528 if (!isdword) { 00529 cache_addw(0xff); // andi temp1, reg, 0xff 00530 cache_addw(0x3000+(reg<<5)+temp1); 00531 } 00532 cache_addw(0); // bne $0, reg, 0 00533 cache_addw(0x1400+(isdword?reg:temp1)); 00534 DELAY; 00535 return ((Bit32u)cache.pos-8); 00536 } 00537 00538 // compare 32bit-register against zero and jump if value less/equal than zero 00539 static Bit32u INLINE gen_create_branch_long_leqzero(HostReg reg) { 00540 temp1_valid = false; 00541 cache_addw(0); // blez reg, 0 00542 cache_addw(0x1800+(reg<<5)); 00543 DELAY; 00544 return ((Bit32u)cache.pos-8); 00545 } 00546 00547 // calculate long relative offset and fill it into the location pointed to by data 00548 static void INLINE gen_fill_branch_long(Bit32u data) { 00549 gen_fill_branch(data); 00550 } 00551 #endif 00552 00553 static void gen_run_code(void) { 00554 temp1_valid = false; 00555 cache_addd(0x27bdfff0); // addiu $sp, $sp, -16 00556 cache_addd(0xafb00004); // sw $s0, 4($sp) 00557 cache_addd(0x00800008); // jr $a0 00558 cache_addd(0xafbf0000); // sw $ra, 0($sp) 00559 } 00560 00561 // return from a function 00562 static void gen_return_function(void) { 00563 temp1_valid = false; 00564 cache_addd(0x8fbf0000); // lw $ra, 0($sp) 00565 cache_addd(0x8fb00004); // lw $s0, 4($sp) 00566 cache_addd(0x03e00008); // jr $ra 00567 cache_addd(0x27bd0010); // addiu $sp, $sp, 16 00568 } 00569 00570 #ifdef DRC_FLAGS_INVALIDATION 00571 // called when a call to a function can be replaced by a 00572 // call to a simpler function 00573 static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { 00574 #ifdef DRC_FLAGS_INVALIDATION_DCODE 00575 // try to avoid function calls but rather directly fill in code 00576 switch (flags_type) { 00577 case t_ADDb: 00578 case t_ADDw: 00579 case t_ADDd: 00580 *(Bit32u*)pos=0x00851021; // addu $v0, $a0, $a1 00581 break; 00582 case t_ORb: 00583 case t_ORw: 00584 case t_ORd: 00585 *(Bit32u*)pos=0x00851025; // or $v0, $a0, $a1 00586 break; 00587 case t_ANDb: 00588 case t_ANDw: 00589 case t_ANDd: 00590 *(Bit32u*)pos=0x00851024; // and $v0, $a0, $a1 00591 break; 00592 case t_SUBb: 00593 case t_SUBw: 00594 case t_SUBd: 00595 *(Bit32u*)pos=0x00851023; // subu $v0, $a0, $a1 00596 break; 00597 case t_XORb: 00598 case t_XORw: 00599 case t_XORd: 00600 *(Bit32u*)pos=0x00851026; // xor $v0, $a0, $a1 00601 break; 00602 case t_CMPb: 00603 case t_CMPw: 00604 case t_CMPd: 00605 case t_TESTb: 00606 case t_TESTw: 00607 case t_TESTd: 00608 *(Bit32u*)pos=0; // nop 00609 break; 00610 case t_INCb: 00611 case t_INCw: 00612 case t_INCd: 00613 *(Bit32u*)pos=0x24820001; // addiu $v0, $a0, 1 00614 break; 00615 case t_DECb: 00616 case t_DECw: 00617 case t_DECd: 00618 *(Bit32u*)pos=0x2482ffff; // addiu $v0, $a0, -1 00619 break; 00620 case t_SHLb: 00621 case t_SHLw: 00622 case t_SHLd: 00623 *(Bit32u*)pos=0x00a41004; // sllv $v0, $a0, $a1 00624 break; 00625 case t_SHRb: 00626 case t_SHRw: 00627 case t_SHRd: 00628 *(Bit32u*)pos=0x00a41006; // srlv $v0, $a0, $a1 00629 break; 00630 case t_SARd: 00631 *(Bit32u*)pos=0x00a41007; // srav $v0, $a0, $a1 00632 break; 00633 #if (_MIPS_ISA==MIPS32R2) || defined(PSP) 00634 case t_RORd: 00635 *(Bit32u*)pos=0x00a41046; // rotr $v0, $a0, $a1 00636 break; 00637 #endif 00638 case t_NEGb: 00639 case t_NEGw: 00640 case t_NEGd: 00641 *(Bit32u*)pos=0x00041023; // subu $v0, $0, $a0 00642 break; 00643 default: 00644 *(Bit32u*)pos=0x0c000000+((((Bit32u)fct_ptr)>>2)&0x3ffffff); // jal simple_func 00645 break; 00646 } 00647 #else 00648 *(Bit32u*)pos=0x0c000000+(((Bit32u)fct_ptr)>>2)&0x3ffffff); // jal simple_func 00649 #endif 00650 } 00651 #endif 00652 00653 static void cache_block_closing(Bit8u* block_start,Bitu block_size) { 00654 #ifdef PSP 00655 // writeback dcache and invalidate icache 00656 Bit32u inval_start = ((Bit32u)block_start) & ~63; 00657 Bit32u inval_end = (((Bit32u)block_start) + block_size + 64) & ~63; 00658 for (;inval_start < inval_end; inval_start+=64) { 00659 __builtin_allegrex_cache(0x1a, inval_start); 00660 __builtin_allegrex_cache(0x08, inval_start); 00661 } 00662 #endif 00663 } 00664 00665 static void cache_block_before_close(void) { } 00666 00667 00668 #ifdef DRC_USE_SEGS_ADDR 00669 00670 // mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) 00671 // 16bit moves may destroy the upper 16bit of the destination register 00672 static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { 00673 // stub 00674 } 00675 00676 // mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) 00677 static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { 00678 // stub 00679 } 00680 00681 // add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) 00682 static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { 00683 // stub 00684 } 00685 00686 #endif 00687 00688 #ifdef DRC_USE_REGS_ADDR 00689 00690 // mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) 00691 // 16bit moves may destroy the upper 16bit of the destination register 00692 static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { 00693 // stub 00694 } 00695 00696 // mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) 00697 static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { 00698 // stub 00699 } 00700 00701 // move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) 00702 // 16bit moves may destroy the upper 16bit of the destination register 00703 static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { 00704 // stub 00705 } 00706 00707 // move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR 00708 // the upper 24bit of the destination register can be destroyed 00709 // this function does not use FC_OP1/FC_OP2 as dest_reg as these 00710 // registers might not be directly byte-accessible on some architectures 00711 static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { 00712 // stub 00713 } 00714 00715 // move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR 00716 // the upper 24bit of the destination register can be destroyed 00717 // this function can use FC_OP1/FC_OP2 as dest_reg which are 00718 // not directly byte-accessible on some architectures 00719 static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { 00720 // stub 00721 } 00722 00723 00724 // add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) 00725 static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { 00726 // stub 00727 } 00728 00729 00730 // move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) 00731 static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { 00732 // stub 00733 } 00734 00735 // move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) 00736 static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { 00737 // stub 00738 } 00739 00740 // move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) 00741 static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { 00742 // stub 00743 } 00744 00745 // move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR 00746 static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { 00747 // stub 00748 } 00749 00750 #endif