DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/core_dynrec/risc_x64.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 // some configuring defines that specify the capabilities of this architecture
00022 // or aspects of the recompiling
00023 
00024 // protect FC_ADDR over function calls if necessaray
00025 // #define DRC_PROTECT_ADDR_REG
00026 
00027 // try to use non-flags generating functions if possible
00028 #define DRC_FLAGS_INVALIDATION
00029 // try to replace _simple functions by code
00030 #define DRC_FLAGS_INVALIDATION_DCODE
00031 
00032 // type with the same size as a pointer
00033 #define DRC_PTR_SIZE_IM Bit64u
00034 
00035 // calling convention modifier
00036 #define DRC_CALL_CONV   /* nothing */
00037 #define DRC_FC                  /* nothing */
00038 
00039 
00040 // register mapping
00041 typedef Bit8u HostReg;
00042 
00043 #define HOST_EAX 0
00044 #define HOST_ECX 1
00045 #define HOST_EDX 2
00046 #define HOST_EBX 3
00047 #define HOST_ESI 6
00048 #define HOST_EDI 7
00049 
00050 
00051 // register that holds function return values
00052 #define FC_RETOP HOST_EAX
00053 
00054 // register used for address calculations, if the ABI does not
00055 // state that this register is preserved across function calls
00056 // then define DRC_PROTECT_ADDR_REG above
00057 #define FC_ADDR HOST_EBX
00058 
00059 #if defined (_WIN64)
00060 #define FC_OP1 HOST_ECX
00061 #define FC_OP2 HOST_EDX
00062 #else
00063 // register that holds the first parameter
00064 #define FC_OP1 HOST_EDI
00065 
00066 // register that holds the second parameter
00067 #define FC_OP2 HOST_ESI
00068 #endif
00069 
00070 // special register that holds the third parameter for _R3 calls (byte accessible)
00071 #define FC_OP3 HOST_EAX
00072 
00073 // register that holds byte-accessible temporary values
00074 #define FC_TMP_BA1 HOST_ECX
00075 
00076 // register that holds byte-accessible temporary values
00077 #define FC_TMP_BA2 HOST_EDX
00078 
00079 
00080 // temporary register for LEA
00081 #define TEMP_REG_DRC HOST_ESI
00082 
00083 
00084 // move a full register from reg_src to reg_dst
00085 static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
00086         if (reg_dst==reg_src) return;
00087         cache_addb(0x8b);                                       // mov reg_dst,reg_src
00088         cache_addb(0xc0+(reg_dst<<3)+reg_src);
00089 }
00090 
00091 static void gen_mov_reg_qword(HostReg dest_reg,Bit64u imm);
00092 
00093 // This function generates an instruction with register addressing and a memory location
00094 static INLINE void gen_reg_memaddr(HostReg reg,void* data,Bit8u op,Bit8u prefix=0) {
00095         Bit64s diff = (Bit64s)data-((Bit64s)cache.pos+(prefix?7:6));
00096 //      if ((diff<0x80000000LL) && (diff>-0x80000000LL)) { //clang messes itself up on this...
00097         if ( (diff>>63) == (diff>>31) ) { //signed bit extend, test to see if value fits in a Bit32s
00098                 // mov reg,[rip+diff] (or similar, depending on the op) to fetch *data
00099                 if(prefix) cache_addb(prefix);
00100                 cache_addb(op);
00101                 cache_addb(0x05+(reg<<3));
00102                 // RIP-relative addressing is offset after the instruction 
00103                 cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL)); 
00104         } else if ((Bit64u)data<0x100000000LL) {
00105                 // mov reg,[data] (or similar, depending on the op) when absolute address of data is <4GB
00106                 if(prefix) cache_addb(prefix);
00107                 cache_addb(op);
00108                 cache_addw(0x2504+(reg<<3));
00109                 cache_addd((Bit32u)(((Bit64u)data)&0xffffffffLL));
00110         } else {
00111                 // load 64-bit data into tmp_reg and do mov reg,[tmp_reg] (or similar, depending on the op)
00112                 HostReg tmp_reg = HOST_EAX;
00113                 if(reg == HOST_EAX) tmp_reg = HOST_ECX;
00114 
00115                 cache_addb(0x50+tmp_reg);       // push rax/rcx
00116                 gen_mov_reg_qword(tmp_reg,(Bit64u)data);
00117 
00118                 if(prefix) cache_addb(prefix);
00119                 cache_addb(op);
00120                 cache_addb(tmp_reg+(reg<<3));
00121 
00122                 cache_addb(0x58+tmp_reg);       // pop rax/rcx
00123         }
00124 }
00125 
00126 // Same as above, but with immediate addressing and a memory location
00127 static INLINE void gen_memaddr(Bit8u modreg,void* data,Bitu off,Bitu imm,Bit8u op,Bit8u prefix=0) {
00128         Bit64s diff = (Bit64s)data-((Bit64s)cache.pos+off+(prefix?7:6));
00129 //      if ((diff<0x80000000LL) && (diff>-0x80000000LL)) {
00130         if ( (diff>>63) == (diff>>31) ) {
00131                 // RIP-relative addressing is offset after the instruction 
00132                 if(prefix) cache_addb(prefix);
00133                 cache_addw(op+((modreg+1)<<8));
00134                 cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL));
00135 
00136                 switch(off) {
00137                         case 1: cache_addb(((Bit8u)imm&0xff)); break;
00138                         case 2: cache_addw(((Bit16u)imm&0xffff)); break;
00139                         case 4: cache_addd(((Bit32u)imm&0xffffffff)); break;
00140                 }
00141 
00142         } else if ((Bit64u)data<0x100000000LL) {
00143                 if(prefix) cache_addb(prefix);
00144                 cache_addw(op+(modreg<<8));
00145                 cache_addb(0x25);
00146                 cache_addd((Bit32u)(((Bit64u)data)&0xffffffffLL));
00147 
00148                 switch(off) {
00149                         case 1: cache_addb(((Bit8u)imm&0xff)); break;
00150                         case 2: cache_addw(((Bit16u)imm&0xffff)); break;
00151                         case 4: cache_addd(((Bit32u)imm&0xffffffff)); break;
00152                 }
00153 
00154         } else {
00155                 HostReg tmp_reg = HOST_EAX;
00156 
00157                 cache_addb(0x50+tmp_reg);       // push rax
00158                 gen_mov_reg_qword(tmp_reg,(Bit64u)data);
00159 
00160                 if(prefix) cache_addb(prefix);
00161                 cache_addw(op+((modreg-4+tmp_reg)<<8));
00162 
00163                 switch(off) {
00164                         case 1: cache_addb(((Bit8u)imm&0xff)); break;
00165                         case 2: cache_addw(((Bit16u)imm&0xffff)); break;
00166                         case 4: cache_addd(((Bit32u)imm&0xffffffff)); break;
00167                 }
00168 
00169                 cache_addb(0x58+tmp_reg);       // pop rax
00170         }
00171 }
00172 
00173 // move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
00174 // 16bit moves may destroy the upper 16bit of the destination register
00175 static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword,Bit8u prefix=0) {
00176         if (!dword) gen_reg_memaddr(dest_reg,data,0xb7,0x0f);   // movzx reg,[data] - zero extend data, fixes LLVM compile where the called function does not extend the parameters
00177         else gen_reg_memaddr(dest_reg,data,0x8b,prefix);        // mov reg,[data]
00178 } 
00179 
00180 // move a 16bit constant value into dest_reg
00181 // the upper 16bit of the destination register may be destroyed
00182 static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) {
00183         cache_addb(0xb8+dest_reg);                      // mov reg,imm
00184         cache_addd((Bit32u)imm);
00185 }
00186 
00187 // move a 32bit constant value into dest_reg
00188 static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
00189         cache_addb(0xb8+dest_reg);                      // mov reg,imm
00190         cache_addd(imm);
00191 }
00192 
00193 // move a 64bit constant value into a full register
00194 static void gen_mov_reg_qword(HostReg dest_reg,Bit64u imm) {
00195         if (imm==(Bit32u)imm) {
00196                 gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm);
00197                 return;
00198         }
00199         cache_addb(0x48);
00200         cache_addb(0xb8+dest_reg);                      // mov dest_reg,imm
00201         cache_addq(imm);
00202 }
00203 
00204 // move 32bit (dword==true) or 16bit (dword==false) of a register into memory
00205 static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword,Bit8u prefix=0) {
00206         gen_reg_memaddr(src_reg,dest,0x89,(dword?prefix:0x66));         // mov [data],reg
00207 }
00208 
00209 // move an 8bit value from memory into dest_reg
00210 // the upper 24bit of the destination register can be destroyed
00211 // this function does not use FC_OP1/FC_OP2 as dest_reg as these
00212 // registers might not be directly byte-accessible on some architectures
00213 static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
00214         gen_reg_memaddr(dest_reg,data,0xb6,0x0f);       // movzx reg,[data]
00215 }
00216 
00217 // move an 8bit value from memory into dest_reg
00218 // the upper 24bit of the destination register can be destroyed
00219 // this function can use FC_OP1/FC_OP2 as dest_reg which are
00220 // not directly byte-accessible on some architectures
00221 static void gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
00222         gen_reg_memaddr(dest_reg,data,0xb6,0x0f);       // movzx reg,[data]
00223 }
00224 
00225 // move an 8bit constant value into dest_reg
00226 // the upper 24bit of the destination register can be destroyed
00227 // this function does not use FC_OP1/FC_OP2 as dest_reg as these
00228 // registers might not be directly byte-accessible on some architectures
00229 static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) {
00230         cache_addb(0xb8+dest_reg);                      // mov reg,imm
00231         cache_addd((Bit32u)imm);
00232 }
00233 
00234 // move an 8bit constant value into dest_reg
00235 // the upper 24bit of the destination register can be destroyed
00236 // this function can use FC_OP1/FC_OP2 as dest_reg which are
00237 // not directly byte-accessible on some architectures
00238 static void gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
00239         cache_addb(0xb8+dest_reg);                      // mov reg,imm
00240         cache_addd((Bit32u)imm);
00241 }
00242 
00243 // move the lowest 8bit of a register into memory
00244 static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
00245         gen_reg_memaddr(src_reg,dest,0x88);     // mov byte [data],reg
00246 }
00247 
00248 
00249 
00250 // convert an 8bit word to a 32bit dword
00251 // the register is zero-extended (sign==false) or sign-extended (sign==true)
00252 static void gen_extend_byte(bool sign,HostReg reg) {
00253         cache_addw(0xb60f+(sign?0x800:0));              // movsx/movzx
00254         cache_addb(0xc0+(reg<<3)+reg);
00255 }
00256 
00257 // convert a 16bit word to a 32bit dword
00258 // the register is zero-extended (sign==false) or sign-extended (sign==true)
00259 static void gen_extend_word(bool sign,HostReg reg) {
00260         cache_addw(0xb70f+(sign?0x800:0));              // movsx/movzx
00261         cache_addb(0xc0+(reg<<3)+reg);
00262 }
00263 
00264 
00265 
00266 // add a 32bit value from memory to a full register
00267 static void gen_add(HostReg reg,void* op) {
00268         gen_reg_memaddr(reg,op,0x03);           // add reg,[data]
00269 }
00270 
00271 // add a 32bit constant value to a full register
00272 static void gen_add_imm(HostReg reg,Bit32u imm) {
00273         if (!imm) return;
00274         cache_addw(0xc081+(reg<<8));            // add reg,imm
00275         cache_addd(imm);
00276 }
00277 
00278 // and a 32bit constant value with a full register
00279 static void gen_and_imm(HostReg reg,Bit32u imm) {
00280         cache_addw(0xe081+(reg<<8));            // and reg,imm
00281         cache_addd(imm);
00282 }
00283 
00284 
00285 
00286 // move a 32bit constant value into memory
00287 static void gen_mov_direct_dword(void* dest,Bit32u imm) {
00288         gen_memaddr(0x4,dest,4,imm,0xc7);       // mov [data],imm
00289 }
00290 
00291 
00292 // move an address into memory
00293 static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
00294         gen_mov_reg_qword(HOST_EAX,imm);
00295         gen_mov_word_from_reg(HOST_EAX,dest,true,0x48);         // 0x48 prefixes full 64-bit mov
00296 }
00297 
00298 
00299 // add an 8bit constant value to a memory value
00300 static void gen_add_direct_byte(void* dest,Bit8s imm) {
00301         if (!imm) return;
00302         gen_memaddr(0x4,dest,1,imm,0x83);       // add [data],imm
00303 }
00304 
00305 // add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
00306 static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
00307         if (!imm) return;
00308         if ((imm<128) && dword) {
00309                 gen_add_direct_byte(dest,(Bit8s)imm);
00310                 return;
00311         }
00312         gen_memaddr(0x4,dest,(dword?4:2),imm,0x81,(dword?0:0x66));      // add [data],imm
00313 }
00314 
00315 // subtract an 8bit constant value from a memory value
00316 static void gen_sub_direct_byte(void* dest,Bit8s imm) {
00317         if (!imm) return;
00318         gen_memaddr(0x2c,dest,1,imm,0x83);
00319 }
00320 
00321 // subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
00322 static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
00323         if (!imm) return;
00324         if ((imm<128) && dword) {
00325                 gen_sub_direct_byte(dest,(Bit8s)imm);
00326                 return;
00327         }
00328         gen_memaddr(0x2c,dest,(dword?4:2),imm,0x81,(dword?0:0x66));     // sub [data],imm
00329 }
00330 
00331 
00332 
00333 // effective address calculation, destination is dest_reg
00334 // scale_reg is scaled by scale (scale_reg*(2^scale)) and
00335 // added to dest_reg, then the immediate value is added
00336 static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) {
00337         Bit8u rm_base;
00338         Bitu imm_size;
00339         if (!imm) {
00340                 imm_size=0;     rm_base=0x0;                    //no imm
00341         } else if ((imm>=-128 && imm<=127)) {
00342                 imm_size=1;     rm_base=0x40;                   //Signed byte imm
00343         } else {
00344                 imm_size=4;     rm_base=0x80;                   //Signed dword imm
00345         }
00346 
00347         // ea_reg := ea_reg+scale_reg*(2^scale)+imm
00348         cache_addb(0x48);
00349         cache_addb(0x8d);                       //LEA
00350         cache_addb(0x04+(dest_reg << 3)+rm_base);       //The sib indicator
00351         cache_addb((Bit8u)(dest_reg+(scale_reg<<3)+(scale<<6)));
00352 
00353         switch (imm_size) {
00354         case 0: break;
00355         case 1:cache_addb((Bit8u)imm);break;
00356         case 4:cache_addd((Bit32u)imm);break;
00357         }
00358 }
00359 
00360 // effective address calculation, destination is dest_reg
00361 // dest_reg is scaled by scale (dest_reg*(2^scale)),
00362 // then the immediate value is added
00363 static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) {
00364         // ea_reg := ea_reg*(2^scale)+imm
00365         // ea_reg :=   op2 *(2^scale)+imm
00366         cache_addb(0x48);
00367         cache_addb(0x8d);                       //LEA
00368         cache_addb(0x04+(dest_reg<<3));
00369         cache_addb((Bit8u)(0x05+(dest_reg<<3)+(scale<<6)));
00370 
00371         cache_addd((Bit32u)imm);                // always add dword immediate
00372 }
00373 
00374 
00375 
00376 // generate a call to a parameterless function
00377 template <typename T> static void INLINE gen_call_function_raw(const T func) {
00378         cache_addw(0xb848);
00379         cache_addq((Bit64u)func);
00380         cache_addw(0xd0ff);
00381 }
00382 
00383 // generate a call to a function with paramcount parameters
00384 // note: the parameters are loaded in the architecture specific way
00385 // using the gen_load_param_ functions below
00386 template <typename T> static Bit64u INLINE gen_call_function_setup(const T func,Bitu paramcount,bool fastcall=false) {
00387         (void)paramcount;
00388         (void)fastcall;
00389 
00390         Bit64u proc_addr = (Bit64u)cache.pos;
00391         gen_call_function_raw(func);
00392         return proc_addr;
00393 }
00394 
00395 
00396 // load an immediate value as param'th function parameter
00397 static void INLINE gen_load_param_imm(Bitu imm,Bitu param) {
00398         // move an immediate 32bit value into a 64bit param reg
00399         switch (param) {
00400                 case 0:                 // mov param1,imm32
00401                         gen_mov_dword_to_reg_imm(FC_OP1,(Bit32u)imm);
00402                         break;
00403                 case 1:                 // mov param2,imm32
00404                         gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)imm);
00405                         break;
00406 #if defined (_WIN64)
00407                 case 2:                 // mov r8d,imm32
00408                         cache_addw(0xb841);
00409                         cache_addd((Bit32u)imm);
00410                         break;
00411                 case 3:                 // mov r9d,imm32
00412                         cache_addw(0xb941);
00413                         cache_addd((Bit32u)imm);
00414                         break;
00415 #else
00416                 case 2:                 // mov rdx,imm32
00417                         gen_mov_dword_to_reg_imm(HOST_EDX,(Bit32u)imm);
00418                         break;
00419                 case 3:                 // mov rcx,imm32
00420                         gen_mov_dword_to_reg_imm(HOST_ECX,(Bit32u)imm);
00421                         break;
00422 #endif
00423                 default:
00424                         E_Exit("I(mm) >4 params unsupported");
00425                         break;
00426         }
00427 }
00428 
00429 // load an address as param'th function parameter
00430 static void INLINE gen_load_param_addr(DRC_PTR_SIZE_IM addr,Bitu param) {
00431         // move an immediate 64bit value into a 64bit param reg
00432         switch (param) {
00433                 case 0:                 // mov param1,addr64
00434                         gen_mov_reg_qword(FC_OP1,addr);
00435                         break;
00436                 case 1:                 // mov param2,addr64
00437                         gen_mov_reg_qword(FC_OP2,addr);
00438                         break;
00439 #if defined (_WIN64)
00440                 case 2:                 // mov r8,addr64
00441                         cache_addw(0xb849);
00442                         cache_addq(addr);
00443                         break;
00444                 case 3:                 // mov r9,addr64
00445                         cache_addw(0xb949);
00446                         cache_addq(addr);
00447                         break;
00448 #else
00449                 case 2:                 // mov rdx,addr64
00450                         gen_mov_reg_qword(HOST_EDX,addr);
00451                         break;
00452                 case 3:                 // mov rcx,addr64
00453                         gen_mov_reg_qword(HOST_ECX,addr);
00454                         break;
00455 #endif
00456                 default:
00457                         E_Exit("A(ddr) >4 params unsupported");
00458                         break;
00459         }
00460 }
00461 
00462 // load a host-register as param'th function parameter
00463 static void INLINE gen_load_param_reg(Bitu reg,Bitu param) {
00464         // move a register into a 64bit param reg, {inputregs}!={outputregs}
00465         switch (param) {
00466                 case 0:         // mov param1,reg&7
00467                         gen_mov_regs(FC_OP1,reg&7);
00468                         break;
00469                 case 1:         // mov param2,reg&7
00470                         gen_mov_regs(FC_OP2,reg&7);
00471                         break;
00472 #if defined (_WIN64)
00473                 case 2:         // mov r8,reg&7
00474                         cache_addw(0x8949);
00475                         cache_addb(0xc0 + ((reg & 7) << 3));
00476                         break;
00477                 case 3:         // mov r9,reg&7
00478                         cache_addw(0x8949);
00479                         cache_addb(0xc1 + ((reg & 7) << 3));
00480                         break;
00481 #else
00482                 case 2:         // mov rdx,reg&7
00483                         gen_mov_regs(HOST_EDX,reg&7);
00484                         break;
00485                 case 3:         // mov rcx,reg&7
00486                         gen_mov_regs(HOST_ECX,reg&7);
00487                         break;
00488 #endif
00489                 default:
00490                         E_Exit("R(eg) >4 params unsupported");
00491                         break;
00492         }
00493 }
00494 
00495 // load a value from memory as param'th function parameter
00496 static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
00497         // move memory content into a 64bit param reg
00498         switch (param) {
00499                 case 0:         // mov param1,[mem]
00500                         gen_mov_word_to_reg(FC_OP1,(void*)mem,true);
00501                         break;
00502                 case 1:         // mov param2,[mem]
00503                         gen_mov_word_to_reg(FC_OP2,(void*)mem,true);
00504                         break;
00505 #if defined (_WIN64)
00506                 case 2:         // mov r8d,[mem]
00507                         gen_mov_word_to_reg(0,(void*)mem,true,0x44);    // 0x44, use x64 rXd regs
00508                         break;
00509                 case 3:         // mov r9d,[mem]
00510                         gen_mov_word_to_reg(1,(void*)mem,true,0x44);    // 0x44, use x64 rXd regs
00511                         break;
00512 #else
00513                 case 2:         // mov edx,[mem]
00514                         gen_mov_word_to_reg(HOST_EDX,(void*)mem,true);
00515                         break;
00516                 case 3:         // mov ecx,[mem]
00517                         gen_mov_word_to_reg(HOST_ECX,(void*)mem,true);
00518                         break;
00519 #endif
00520                 default:
00521                         E_Exit("R(eg) >4 params unsupported");
00522                         break;
00523         }
00524 }
00525 
00526 
00527 
00528 // jump to an address pointed at by ptr, offset is in imm
00529 static void gen_jmp_ptr(void * ptr,Bits imm=0) {
00530         cache_addw(0xa148);             // mov rax,[data]
00531         cache_addq((Bit64u)ptr);
00532 
00533         cache_addb(0xff);               // jmp [rax+imm]
00534         if (!imm) {
00535                 cache_addb(0x20);
00536     } else if ((imm>=-128 && imm<=127)) {
00537                 cache_addb(0x60);
00538                 cache_addb((Bit8u)imm);
00539         } else {
00540                 cache_addb(0xa0);
00541                 cache_addd((Bit32u)imm);
00542         }
00543 }
00544 
00545 
00546 // short conditional jump (+-127 bytes) if register is zero
00547 // the destination is set by gen_fill_branch() later
00548 static Bit64u gen_create_branch_on_zero(HostReg reg,bool dword) {
00549         if (!dword) cache_addb(0x66);
00550         cache_addb(0x0b);                                       // or reg,reg
00551         cache_addb(0xc0+reg+(reg<<3));
00552 
00553         cache_addw(0x0074);                                     // jz addr
00554         return ((Bit64u)cache.pos-1);
00555 }
00556 
00557 // short conditional jump (+-127 bytes) if register is nonzero
00558 // the destination is set by gen_fill_branch() later
00559 static Bit64u gen_create_branch_on_nonzero(HostReg reg,bool dword) {
00560         if (!dword) cache_addb(0x66);
00561         cache_addb(0x0b);                                       // or reg,reg
00562         cache_addb(0xc0+reg+(reg<<3));
00563 
00564         cache_addw(0x0075);                                     // jnz addr
00565         return ((Bit64u)cache.pos-1);
00566 }
00567 
00568 // calculate relative offset and fill it into the location pointed to by data
00569 static void gen_fill_branch(DRC_PTR_SIZE_IM data) {
00570 #if C_DEBUG
00571         Bit64s len=(Bit64u)cache.pos-data;
00572         if (len<0) len=-len;
00573         if (len>126) LOG_MSG("Big jump %d",(int)len);
00574 #endif
00575         *(Bit8u*)data=(Bit8u)((Bit64u)cache.pos-data-1);
00576 }
00577 
00578 // conditional jump if register is nonzero
00579 // for isdword==true the 32bit of the register are tested
00580 // for isdword==false the lowest 8bit of the register are tested
00581 static Bit64u gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
00582         // isdword: cmp reg32,0
00583         // not isdword: cmp reg8,0
00584         cache_addb(0x0a+(isdword?1:0));                         // or reg,reg
00585         cache_addb(0xc0+reg+(reg<<3));
00586 
00587         cache_addw(0x850f);             // jnz
00588         cache_addd(0);
00589         return ((Bit64u)cache.pos-4);
00590 }
00591 
00592 // compare 32bit-register against zero and jump if value less/equal than zero
00593 static Bit64u gen_create_branch_long_leqzero(HostReg reg) {
00594         cache_addw(0xf883+(reg<<8));
00595         cache_addb(0x00);               // cmp reg,0
00596 
00597         cache_addw(0x8e0f);             // jle
00598         cache_addd(0);
00599         return ((Bit64u)cache.pos-4);
00600 }
00601 
00602 // calculate long relative offset and fill it into the location pointed to by data
00603 static void gen_fill_branch_long(Bit64u data) {
00604         *(Bit32u*)data=(Bit32u)((Bit64u)cache.pos-data-4);
00605 }
00606 
00607 static void gen_run_code(void) {
00608         cache_addw(0x5355);     // push rbp,rbx
00609         cache_addb(0x56);       // push rsi
00610         cache_addd(0x20EC8348); // sub rsp, 32
00611         cache_addb(0x48);cache_addw(0x2D8D);cache_addd(2); // lea rbp, [rip+2]
00612         cache_addw(0xE0FF+(FC_OP1<<8)); // jmp FC_OP1
00613         cache_addd(0x20C48348); // add rsp, 32
00614         cache_addd(0xC35D5B5E); // pop rsi,rbx,rbp;ret
00615 }
00616 
00617 // return from a function
00618 static void gen_return_function(void) {
00619         cache_addw(0xE5FF); // jmp rbp
00620 }
00621 
00622 #ifdef DRC_FLAGS_INVALIDATION
00623 // called when a call to a function can be replaced by a
00624 // call to a simpler function
00625 // check gen_call_function_raw and gen_call_function_setup
00626 // for the targeted code
00627 static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) {
00628 #ifdef DRC_FLAGS_INVALIDATION_DCODE
00629         // try to avoid function calls but rather directly fill in code
00630         switch (flags_type) {
00631                 case t_ADDb:
00632                 case t_ADDw:
00633                 case t_ADDd:
00634                         // mov eax,FC_OP1; add eax,FC_OP2
00635                         *(Bit32u*)(pos+0)=0xc001c089+(FC_OP1<<11)+(FC_OP2<<27);
00636                         *(Bit32u*)(pos+4)=0x909006eb;   // skip
00637                         *(Bit32u*)(pos+8)=0x90909090;
00638                         return;
00639                 case t_ORb:
00640                 case t_ORw:
00641                 case t_ORd:
00642                         // mov eax,FC_OP1; or eax,FC_OP2
00643                         *(Bit32u*)(pos+0)=0xc009c089+(FC_OP1<<11)+(FC_OP2<<27);
00644                         *(Bit32u*)(pos+4)=0x909006eb;   // skip
00645                         *(Bit32u*)(pos+8)=0x90909090;
00646                         return;
00647                 case t_ANDb:
00648                 case t_ANDw:
00649                 case t_ANDd:
00650                         // mov eax,FC_OP1; and eax,FC_OP2
00651                         *(Bit32u*)(pos+0)=0xc021c089+(FC_OP1<<11)+(FC_OP2<<27);
00652                         *(Bit32u*)(pos+4)=0x909006eb;   // skip
00653                         *(Bit32u*)(pos+8)=0x90909090;
00654                         return;
00655                 case t_SUBb:
00656                 case t_SUBw:
00657                 case t_SUBd:
00658                         // mov eax,FC_OP1; sub eax,FC_OP2
00659                         *(Bit32u*)(pos+0)=0xc029c089+(FC_OP1<<11)+(FC_OP2<<27);
00660                         *(Bit32u*)(pos+4)=0x909006eb;   // skip
00661                         *(Bit32u*)(pos+8)=0x90909090;
00662                         return;
00663                 case t_XORb:
00664                 case t_XORw:
00665                 case t_XORd:
00666                         // mov eax,FC_OP1; xor eax,FC_OP2
00667                         *(Bit32u*)(pos+0)=0xc031c089+(FC_OP1<<11)+(FC_OP2<<27);
00668                         *(Bit32u*)(pos+4)=0x909006eb;   // skip
00669                         *(Bit32u*)(pos+8)=0x90909090;
00670                         return;
00671                 case t_CMPb:
00672                 case t_CMPw:
00673                 case t_CMPd:
00674                 case t_TESTb:
00675                 case t_TESTw:
00676                 case t_TESTd:
00677                         *(Bit32u*)(pos+0)=0x90900aeb;   // skip
00678                         *(Bit32u*)(pos+4)=0x90909090;
00679                         *(Bit32u*)(pos+8)=0x90909090;
00680                         return;
00681                 case t_INCb:
00682                 case t_INCw:
00683                 case t_INCd:
00684                         *(Bit32u*)(pos+0)=0xc0ffc089+(FC_OP1<<11); // mov eax,ecx; inc eax
00685                         *(Bit32u*)(pos+4)=0x909006eb;   // skip
00686                         *(Bit32u*)(pos+8)=0x90909090;
00687                                 return;
00688                 case t_DECb:
00689                 case t_DECw:
00690                 case t_DECd:
00691                         *(Bit32u*)(pos+0)=0xc8ffc089+(FC_OP1<<11); // mov eax, FC_OP1; dec eax
00692                         *(Bit32u*)(pos+4)=0x909006eb;   // skip
00693                         *(Bit32u*)(pos+8)=0x90909090;
00694                         return;
00695                 case t_NEGb:
00696                 case t_NEGw:
00697                 case t_NEGd:
00698                         *(Bit32u*)(pos+0)=0xd8f7c089+(FC_OP1<<11); // mov eax, FC_OP1; neg eax
00699                         *(Bit32u*)(pos+4)=0x909006eb;   // skip
00700                         *(Bit32u*)(pos+8)=0x90909090;
00701                         return;
00702         }
00703 #endif
00704         *(Bit64u*)(pos+2)=(Bit64u)fct_ptr;              // fill function pointer
00705 }
00706 #endif
00707 
00708 static void cache_block_closing(Bit8u* block_start,Bitu block_size) {
00709         (void)block_start;
00710         (void)block_size;
00711 }
00712 
00713 static void cache_block_before_close(void) { }