DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/core_dynrec/risc_mipsel32.h
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