DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/core_dyn_x86/risc_x86.h
00001 /*
00002  *  Copyright (C) 2002-2015  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #include "dos_inc.h"
00020 static void gen_init(void);
00021 
00022 #if defined(_MSC_VER)
00023 #pragma warning(disable:4731) /* frame pointer register 'ebp' modified by inline assembly code */
00024 #endif
00025 
00026 /* End of needed */
00027 
00028 #define X86_REGS                7
00029 #define X86_REG_EAX             0x00
00030 #define X86_REG_ECX             0x01
00031 #define X86_REG_EDX             0x02
00032 #define X86_REG_EBX             0x03
00033 #define X86_REG_EBP             0x04
00034 #define X86_REG_ESI             0x05
00035 #define X86_REG_EDI             0x06
00036 
00037 #define X86_REG_MASK(_REG_) (1 << X86_REG_ ## _REG_)
00038 
00039 static struct {
00040         bool flagsactive;
00041         Bitu last_used;
00042         GenReg * regs[X86_REGS];
00043 } x86gen;
00044 
00045 class GenReg {
00046 public:
00047         GenReg(Bit8u _index) {
00048                 index=_index;
00049                 notusable=false;dynreg=0;
00050         }
00051         DynReg  * dynreg;
00052         Bitu last_used;                 //Keeps track of last assigned regs 
00053     Bit8u index;
00054         bool notusable;
00055         void Load(DynReg * _dynreg,bool stale=false) {
00056                 if (!_dynreg) return;
00057                 if (GCC_UNLIKELY((Bitu)dynreg)) Clear();
00058                 dynreg=_dynreg;
00059                 last_used=x86gen.last_used;
00060                 dynreg->flags&=~DYNFLG_CHANGED;
00061                 dynreg->genreg=this;
00062                 if ((!stale) && (dynreg->flags & (DYNFLG_LOAD|DYNFLG_ACTIVE))) {
00063                         cache_addw(0x058b+(index << (8+3)));            //Mov reg,[data]
00064                         cache_addd((uintptr_t)dynreg->data);
00065                 }
00066                 dynreg->flags|=DYNFLG_ACTIVE;
00067         }
00068         void Save(void) {
00069                 if (GCC_UNLIKELY(!((Bitu)dynreg))) IllegalOption("GenReg->Save");
00070                 dynreg->flags&=~DYNFLG_CHANGED;
00071                 cache_addw(0x0589+(index << (8+3)));            //Mov [data],reg
00072                 cache_addd((uintptr_t)dynreg->data);
00073         }
00074         void Release(void) {
00075                 if (GCC_UNLIKELY(!((Bitu)dynreg))) return;
00076                 if (dynreg->flags&DYNFLG_CHANGED && dynreg->flags&DYNFLG_SAVE) {
00077                         Save();
00078                 }
00079                 dynreg->flags&=~(DYNFLG_CHANGED|DYNFLG_ACTIVE);
00080                 dynreg->genreg=0;dynreg=0;
00081         }
00082         void Clear(void) {
00083                 if (!dynreg) return;
00084                 if (dynreg->flags&DYNFLG_CHANGED) {
00085                         Save();
00086                 }
00087                 dynreg->genreg=0;dynreg=0;
00088         }
00089 };
00090 
00091 static BlockReturn gen_runcode(Bit8u * code) {
00092         BlockReturn retval;
00093 #if defined (_MSC_VER)
00094         __asm {
00095 /* Prepare the flags */
00096                 mov             eax,[code]
00097                 push    ebx
00098                 push    ebp
00099                 push    esi
00100                 push    edi
00101                 mov             ebx,[reg_flags]
00102                 and             ebx,FMASK_TEST
00103                 push    offset(return_address)
00104                 push    ebx
00105                 jmp             eax
00106 /* Restore the flags */
00107 return_address:
00108                 /*      return here with flags in ecx */
00109                 and             dword ptr [reg_flags],~FMASK_TEST
00110                 and             ecx,FMASK_TEST
00111                 or              [reg_flags],ecx
00112                 pop             edi
00113                 pop             esi
00114                 pop             ebp
00115                 pop             ebx
00116                 mov             [retval],eax
00117         }
00118 #elif defined (MACOSX)
00119         register Bit32u tempflags=reg_flags & FMASK_TEST;
00120         __asm__ volatile (
00121                 "pushl %%ebx                                            \n"
00122                 "pushl %%ebp                                            \n"
00123                 "pushl $(run_return_adress)                     \n"
00124                 "pushl  %2                                                      \n"
00125                 "jmp  *%3                                                       \n"
00126                 "run_return_adress:                                     \n"
00127                 "popl %%ebp                                                     \n"
00128                 "popl %%ebx                                                     \n"
00129                 :"=a" (retval), "=c" (tempflags)
00130                 :"r" (tempflags),"r" (code)
00131                 :"%edx","%edi","%esi","cc","memory"
00132         );
00133         reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST);
00134 #else
00135         register Bit32u tempflags=reg_flags & FMASK_TEST;
00136         __asm__ volatile (
00137                 "pushl %%ebp                                                    \n"
00138                 "pushl $(run_return_adress)                                     \n"
00139                 "pushl  %2                                                      \n"
00140                 "jmp  *%3                                                       \n"
00141                 "run_return_adress:                                             \n"
00142                 "popl %%ebp                                                     \n"
00143                 :"=a" (retval), "=c" (tempflags)
00144                 :"r" (tempflags),"r" (code)
00145                 :"%edx","%ebx","%edi","%esi"/*,"%ebp"*/,"cc","memory" /* NTS: GCC 7.3.0 MinGW suddenly will not allow this code to declare EBP clobbered */
00146         );
00147         reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST);
00148 #endif
00149         return retval;
00150 }
00151 
00152 static GenReg * FindDynReg(DynReg * dynreg,bool stale=false) {
00153         x86gen.last_used++;
00154         if (dynreg->genreg) {
00155                 dynreg->genreg->last_used=x86gen.last_used;
00156                 return dynreg->genreg;
00157         }
00158         /* Find best match for selected global reg */
00159         Bits i;
00160         Bits first_used,first_index;
00161         first_used=-1;
00162         if (dynreg->flags & DYNFLG_HAS8) {
00163                 /* Has to be eax,ebx,ecx,edx */
00164                 for (i=first_index=0;i<=X86_REG_EBX;i++) {
00165                         GenReg * genreg=x86gen.regs[i];
00166                         if (genreg->notusable) continue;
00167                         if (!(genreg->dynreg)) {
00168                                 genreg->Load(dynreg,stale);
00169                                 return genreg;
00170                         }
00171                         if (genreg->last_used<(Bitu)first_used) {
00172                                 first_used=genreg->last_used;
00173                                 first_index=i;
00174                         }
00175                 }
00176         } else {
00177                 for (i=first_index=X86_REGS-1;i>=0;i--) {
00178                         GenReg * genreg=x86gen.regs[i];
00179                         if (genreg->notusable) continue;
00180                         if (!(genreg->dynreg)) {
00181                                 genreg->Load(dynreg,stale);
00182                                 return genreg;
00183                         }
00184                         if (genreg->last_used<(Bitu)first_used) {
00185                                 first_used=genreg->last_used;
00186                                 first_index=i;
00187                         }
00188                 }
00189         }
00190         /* No free register found use earliest assigned one */
00191         GenReg * newreg=x86gen.regs[first_index];
00192         newreg->Load(dynreg,stale);
00193         return newreg;
00194 }
00195 
00196 static GenReg * ForceDynReg(GenReg * genreg,DynReg * dynreg) {
00197         genreg->last_used=++x86gen.last_used;
00198         if (dynreg->genreg==genreg) return genreg;
00199         if (genreg->dynreg) genreg->Clear();
00200         if (dynreg->genreg) dynreg->genreg->Clear();
00201         genreg->Load(dynreg);
00202         return genreg;
00203 }
00204 
00205 static void gen_preloadreg(DynReg * dynreg) {
00206         FindDynReg(dynreg);
00207 }
00208 
00209 static void gen_releasereg(DynReg * dynreg) {
00210         GenReg * genreg=dynreg->genreg;
00211         if (genreg) genreg->Release();
00212         else dynreg->flags&=~(DYNFLG_ACTIVE|DYNFLG_CHANGED);
00213 }
00214 
00215 static void gen_setupreg(DynReg * dnew,DynReg * dsetup) {
00216         dnew->flags=dsetup->flags;
00217         if (dnew->genreg==dsetup->genreg) return;
00218         /* Not the same genreg must be wrong */
00219         if (dnew->genreg) {
00220                 /* Check if the genreg i'm changing is actually linked to me */
00221                 if (dnew->genreg->dynreg==dnew) dnew->genreg->dynreg=0;
00222         }
00223         dnew->genreg=dsetup->genreg;
00224         if (dnew->genreg) dnew->genreg->dynreg=dnew;
00225 }
00226 
00227 static void gen_synchreg(DynReg * dnew,DynReg * dsynch) {
00228         /* First make sure the registers match */
00229         if (dnew->genreg!=dsynch->genreg) {
00230                 if (dnew->genreg) dnew->genreg->Clear();
00231                 if (dsynch->genreg) {
00232                         dsynch->genreg->Load(dnew);
00233                 }
00234         }
00235         /* Always use the loadonce flag from either state */
00236         dnew->flags|=(dsynch->flags & dnew->flags&DYNFLG_ACTIVE);
00237         if ((dnew->flags ^ dsynch->flags) & DYNFLG_CHANGED) {
00238                 /* Ensure the changed value gets saved */       
00239                 if (dnew->flags & DYNFLG_CHANGED) {
00240                         dnew->genreg->Save();
00241                 } else dnew->flags|=DYNFLG_CHANGED;
00242         }
00243 }
00244 
00245 static void gen_needflags(void) {
00246         if (!x86gen.flagsactive) {
00247                 x86gen.flagsactive=true;
00248                 cache_addb(0x9d);               //POPFD
00249         }
00250 }
00251 
00252 static void gen_protectflags(void) {
00253         if (x86gen.flagsactive) {
00254                 x86gen.flagsactive=false;
00255                 cache_addb(0x9c);               //PUSHFD
00256         }
00257 }
00258 
00259 static void gen_discardflags(void) {
00260         if (!x86gen.flagsactive) {
00261                 x86gen.flagsactive=true;
00262                 cache_addw(0xc483);             //ADD ESP,4
00263                 cache_addb(0x4);
00264         }
00265 }
00266 
00267 static void gen_needcarry(void) {
00268         if (!x86gen.flagsactive) {
00269                 x86gen.flagsactive=true;
00270                 cache_addw(0x2cd1);                     //SHR DWORD [ESP],1
00271                 cache_addb(0x24);
00272                 cache_addd(0x0424648d);         //LEA ESP,[ESP+4]
00273         }
00274 }
00275 
00276 static void gen_setzeroflag(void) {
00277         if (x86gen.flagsactive) IllegalOption("gen_setzeroflag");
00278         cache_addw(0x0c83);                     //OR DWORD [ESP],0x40
00279         cache_addw(0x4024);
00280 }
00281 
00282 static void gen_clearzeroflag(void) {
00283         if (x86gen.flagsactive) IllegalOption("gen_clearzeroflag");
00284         cache_addw(0x2483);                     //AND DWORD [ESP],~0x40
00285         cache_addw(0xbf24);
00286 }
00287 
00288 static bool skip_flags=false;
00289 
00290 static void set_skipflags(bool state) {
00291         if (!state) gen_discardflags();
00292         skip_flags=state;
00293 }
00294 
00295 static void gen_reinit(void) {
00296         x86gen.last_used=0;
00297         x86gen.flagsactive=false;
00298         for (Bitu i=0;i<X86_REGS;i++) {
00299                 x86gen.regs[i]->dynreg=0;
00300         }
00301 }
00302 
00303 
00304 static void gen_load_host(void * data,DynReg * dr1,Bitu size) {
00305         GenReg * gr1=FindDynReg(dr1,true);
00306         switch (size) {
00307         case 1:cache_addw(0xb60f);break;        //movzx byte
00308         case 2:cache_addw(0xb70f);break;        //movzx word
00309         case 4:cache_addb(0x8b);break;  //mov
00310         default:
00311                 IllegalOption("gen_load_host");
00312         }
00313         cache_addb(0x5+(gr1->index<<3));
00314         cache_addd((uintptr_t)data);
00315         dr1->flags|=DYNFLG_CHANGED;
00316 }
00317 
00318 static void gen_mov_host(void * data,DynReg * dr1,Bitu size,Bit8u di1=0) {
00319         GenReg * gr1=FindDynReg(dr1,(size==4));
00320         switch (size) {
00321         case 1:cache_addb(0x8a);break;  //mov byte
00322         case 2:cache_addb(0x66);                //mov word
00323         case 4:cache_addb(0x8b);break;  //mov
00324         default:
00325                 IllegalOption("gen_load_host");
00326         }
00327         cache_addb(0x5+((gr1->index+(di1?4:0))<<3));
00328         cache_addd((uintptr_t)data);
00329         dr1->flags|=DYNFLG_CHANGED;
00330 }
00331 
00332 
00333 static void gen_dop_byte(DualOps op,DynReg * dr1,Bit8u di1,DynReg * dr2,Bit8u di2) {
00334         GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2);
00335         Bit8u tmp;
00336         switch (op) {
00337         case DOP_ADD:   tmp=0x02; break;
00338         case DOP_ADC:   tmp=0x12; break;
00339         case DOP_SUB:   tmp=0x2a; break;
00340         case DOP_SBB:   tmp=0x1a; break;
00341         case DOP_CMP:   tmp=0x3a; goto nochange;
00342         case DOP_XOR:   tmp=0x32; break;
00343         case DOP_AND:   tmp=0x22; if ((dr1==dr2) && (di1==di2)) goto nochange; break;
00344         case DOP_OR:    tmp=0x0a; if ((dr1==dr2) && (di1==di2)) goto nochange; break;
00345         case DOP_TEST:  tmp=0x84; goto nochange;
00346         case DOP_MOV:   if ((dr1==dr2) && (di1==di2)) return; tmp=0x8a; break;
00347         case DOP_XCHG:  tmp=0x86; dr2->flags|=DYNFLG_CHANGED; break;
00348         default:
00349                 IllegalOption("gen_dop_byte");
00350         }
00351         dr1->flags|=DYNFLG_CHANGED;
00352 nochange:
00353         cache_addw(tmp|(0xc0+((gr1->index+di1)<<3)+gr2->index+di2)<<8);
00354 }
00355 
00356 static void gen_dop_byte_imm(DualOps op,DynReg * dr1,Bit8u di1,Bitu imm) {
00357         GenReg * gr1=FindDynReg(dr1);
00358         Bit16u tmp;
00359         switch (op) {
00360         case DOP_ADD:   tmp=0xc080; break;
00361         case DOP_ADC:   tmp=0xd080; break;
00362         case DOP_SUB:   tmp=0xe880; break;
00363         case DOP_SBB:   tmp=0xd880; break;
00364         case DOP_CMP:   tmp=0xf880; goto nochange;      //Doesn't change
00365         case DOP_XOR:   tmp=0xf080; break;
00366         case DOP_AND:   tmp=0xe080; break;
00367         case DOP_OR:    tmp=0xc880; break;
00368         case DOP_TEST:  tmp=0xc0f6; goto nochange;      //Doesn't change
00369         case DOP_MOV:   cache_addb(0xb0+gr1->index+di1);
00370                                         dr1->flags|=DYNFLG_CHANGED;
00371                                         goto finish;
00372         default:
00373                 IllegalOption("gen_dop_byte_imm");
00374         }
00375         dr1->flags|=DYNFLG_CHANGED;
00376 nochange:
00377         cache_addw(tmp+((gr1->index+di1)<<8));
00378 finish:
00379         cache_addb(imm);
00380 }
00381 
00382 static void gen_dop_byte_imm_mem(DualOps op,DynReg * dr1,Bit8u di1,void* data) {
00383         GenReg * gr1=FindDynReg(dr1);
00384         Bit16u tmp;
00385         switch (op) {
00386         case DOP_ADD:   tmp=0x0502; break;
00387         case DOP_ADC:   tmp=0x0512; break;
00388         case DOP_SUB:   tmp=0x052a; break;
00389         case DOP_SBB:   tmp=0x051a; break;
00390         case DOP_CMP:   tmp=0x053a; goto nochange;      //Doesn't change
00391         case DOP_XOR:   tmp=0x0532; break;
00392         case DOP_AND:   tmp=0x0522; break;
00393         case DOP_OR:    tmp=0x050a; break;
00394         case DOP_TEST:  tmp=0x0584; goto nochange;      //Doesn't change
00395         case DOP_MOV:   tmp=0x0585; break;
00396         default:
00397                 IllegalOption("gen_dop_byte_imm_mem");
00398         }
00399         dr1->flags|=DYNFLG_CHANGED;
00400 nochange:
00401         cache_addw(tmp+((gr1->index+di1)<<11));
00402         cache_addd((uintptr_t)data);
00403 }
00404 
00405 static void gen_sop_byte(SingleOps op,DynReg * dr1,Bit8u di1) {
00406         GenReg * gr1=FindDynReg(dr1);
00407         Bit16u tmp;
00408         switch (op) {
00409         case SOP_INC: tmp=0xc0FE; break;
00410         case SOP_DEC: tmp=0xc8FE; break;
00411         case SOP_NOT: tmp=0xd0f6; break;
00412         case SOP_NEG: tmp=0xd8f6; break;
00413         default:
00414                 IllegalOption("gen_sop_byte");
00415         }
00416         cache_addw(tmp + ((gr1->index+di1)<<8));
00417         dr1->flags|=DYNFLG_CHANGED;
00418 }
00419 
00420 
00421 static void gen_extend_word(bool sign,DynReg * ddr,DynReg * dsr) {
00422         GenReg * gsr=FindDynReg(dsr);
00423         GenReg * gdr=FindDynReg(ddr,true);
00424         if (sign) cache_addw(0xbf0f);
00425         else cache_addw(0xb70f);
00426         cache_addb(0xc0+(gdr->index<<3)+(gsr->index));
00427         ddr->flags|=DYNFLG_CHANGED;
00428 }
00429 
00430 static void gen_extend_byte(bool sign,bool dword,DynReg * ddr,DynReg * dsr,Bit8u dsi) {
00431         GenReg * gsr=FindDynReg(dsr);
00432         GenReg * gdr=FindDynReg(ddr,dword);
00433         if (!dword) cache_addb(0x66);
00434         if (sign) cache_addw(0xbe0f);
00435         else cache_addw(0xb60f);
00436         cache_addb(0xc0+(gdr->index<<3)+(gsr->index+dsi));
00437         ddr->flags|=DYNFLG_CHANGED;
00438 }
00439 
00440 static void gen_lea(DynReg * ddr,DynReg * dsr1,DynReg * dsr2,Bitu scale,Bits imm) {
00441         GenReg * gdr=FindDynReg(ddr);
00442         Bitu imm_size;
00443         Bit8u rm_base=(gdr->index << 3);
00444         if (dsr1) {
00445                 GenReg * gsr1=FindDynReg(dsr1);
00446                 if (!imm && (gsr1->index!=0x5)) {
00447                         imm_size=0;     rm_base+=0x0;                   //no imm
00448                 } else if ((imm>=-128 && imm<=127)) {
00449                         imm_size=1;rm_base+=0x40;                       //Signed byte imm
00450                 } else {
00451                         imm_size=4;rm_base+=0x80;                       //Signed dword imm
00452                 }
00453                 if (dsr2) {
00454                         GenReg * gsr2=FindDynReg(dsr2);
00455                         cache_addb(0x8d);               //LEA
00456                         cache_addb(rm_base+0x4);                        //The sib indicator
00457                         Bit8u sib=(gsr1->index)+(gsr2->index<<3)+(scale<<6);
00458                         cache_addb(sib);
00459                 } else {
00460                         if ((ddr==dsr1) && !imm_size) return;
00461                         cache_addb(0x8d);               //LEA
00462                         cache_addb(rm_base+gsr1->index);
00463                 }
00464         } else {
00465                 if (dsr2) {
00466                         GenReg * gsr2=FindDynReg(dsr2);
00467                         cache_addb(0x8d);                       //LEA
00468                         cache_addb(rm_base+0x4);        //The sib indicator
00469                         Bit8u sib=(5+(gsr2->index<<3)+(scale<<6));
00470                         cache_addb(sib);
00471                         imm_size=4;
00472                 } else {
00473                         cache_addb(0x8d);                       //LEA
00474                         cache_addb(rm_base+0x05);       //dword imm
00475                         imm_size=4;
00476                 }
00477         }
00478         switch (imm_size) {
00479         case 0: break;
00480         case 1:cache_addb(imm);break;
00481         case 4:cache_addd(imm);break;
00482         }
00483         ddr->flags|=DYNFLG_CHANGED;
00484 }
00485 
00486 static void gen_lea_imm_mem(DynReg * ddr,DynReg * dsr,void* data) {
00487         GenReg * gdr=FindDynReg(ddr);
00488         Bit8u rm_base=(gdr->index << 3);
00489         cache_addw(0x058b+(rm_base<<8));
00490         cache_addd((uintptr_t)data);
00491         GenReg * gsr=FindDynReg(dsr);
00492         cache_addb(0x8d);               //LEA
00493         cache_addb(rm_base+0x44);
00494         cache_addb(rm_base+gsr->index);
00495         cache_addb(0x00);
00496         ddr->flags|=DYNFLG_CHANGED;
00497 }
00498 
00499 static void gen_dop_word(DualOps op,bool dword,DynReg * dr1,DynReg * dr2) {
00500         GenReg * gr2=FindDynReg(dr2);
00501         GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
00502         Bit8u tmp;
00503         switch (op) {
00504         case DOP_ADD:   tmp=0x03; break;
00505         case DOP_ADC:   tmp=0x13; break;
00506         case DOP_SUB:   tmp=0x2b; break;
00507         case DOP_SBB:   tmp=0x1b; break;
00508         case DOP_CMP:   tmp=0x3b; goto nochange;
00509         case DOP_XOR:   tmp=0x33; break;
00510         case DOP_AND:   tmp=0x23; if (dr1==dr2) goto nochange; break;
00511         case DOP_OR:    tmp=0x0b; if (dr1==dr2) goto nochange; break;
00512         case DOP_TEST:  tmp=0x85; goto nochange;
00513         case DOP_MOV:   if (dr1==dr2) return; tmp=0x8b; break;
00514         case DOP_XCHG:
00515                 dr2->flags|=DYNFLG_CHANGED;
00516                 if (dword && !((dr1->flags&DYNFLG_HAS8) ^ (dr2->flags&DYNFLG_HAS8))) {
00517                         dr1->genreg=gr2;dr1->genreg->dynreg=dr1;
00518                         dr2->genreg=gr1;dr2->genreg->dynreg=dr2;
00519                         dr1->flags|=DYNFLG_CHANGED;
00520                         return;
00521                 }
00522                 tmp=0x87;
00523                 break;
00524         default:
00525                 IllegalOption("gen_dop_word");
00526         }
00527         dr1->flags|=DYNFLG_CHANGED;
00528 nochange:
00529         if (!dword) cache_addb(0x66);
00530         cache_addw(tmp|(0xc0+(gr1->index<<3)+gr2->index)<<8);
00531 }
00532 
00533 static void gen_dop_word_imm(DualOps op,bool dword,DynReg * dr1,Bits imm) {
00534         GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
00535         Bit16u tmp;
00536         if (!dword) cache_addb(0x66);
00537         switch (op) {
00538         case DOP_ADD:   tmp=0xc081; break; 
00539         case DOP_ADC:   tmp=0xd081; break;
00540         case DOP_SUB:   tmp=0xe881; break;
00541         case DOP_SBB:   tmp=0xd881; break;
00542         case DOP_CMP:   tmp=0xf881; goto nochange;      //Doesn't change
00543         case DOP_XOR:   tmp=0xf081; break;
00544         case DOP_AND:   tmp=0xe081; break;
00545         case DOP_OR:    tmp=0xc881; break;
00546         case DOP_TEST:  tmp=0xc0f7; goto nochange;      //Doesn't change
00547         case DOP_MOV:   cache_addb(0xb8+(gr1->index)); dr1->flags|=DYNFLG_CHANGED; goto finish;
00548         default:
00549                 IllegalOption("gen_dop_word_imm");
00550         }
00551         dr1->flags|=DYNFLG_CHANGED;
00552 nochange:
00553         cache_addw(tmp+(gr1->index<<8));
00554 finish:
00555         if (dword) cache_addd(imm);
00556         else cache_addw(imm);
00557 }
00558 
00559 static void gen_dop_word_imm_mem(DualOps op,bool dword,DynReg * dr1,void* data) {
00560         GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
00561         Bit16u tmp;
00562         switch (op) {
00563         case DOP_ADD:   tmp=0x0503; break; 
00564         case DOP_ADC:   tmp=0x0513; break;
00565         case DOP_SUB:   tmp=0x052b; break;
00566         case DOP_SBB:   tmp=0x051b; break;
00567         case DOP_CMP:   tmp=0x053b; goto nochange;      //Doesn't change
00568         case DOP_XOR:   tmp=0x0533; break;
00569         case DOP_AND:   tmp=0x0523; break;
00570         case DOP_OR:    tmp=0x050b; break;
00571         case DOP_TEST:  tmp=0x0585; goto nochange;      //Doesn't change
00572         case DOP_MOV:
00573                 gen_mov_host(data,dr1,dword?4:2);
00574                 dr1->flags|=DYNFLG_CHANGED;
00575                 return;
00576         default:
00577                 IllegalOption("gen_dop_word_imm_mem");
00578         }
00579         dr1->flags|=DYNFLG_CHANGED;
00580 nochange:
00581         if (!dword) cache_addb(0x66);
00582         cache_addw(tmp+(gr1->index<<11));
00583         cache_addd((uintptr_t)data);
00584 }
00585 
00586 static void gen_dop_word_var(DualOps op,bool dword,DynReg * dr1,void* drd) {
00587         GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
00588         Bit8u tmp;
00589         switch (op) {
00590         case DOP_ADD:   tmp=0x03; break;
00591         case DOP_ADC:   tmp=0x13; break;
00592         case DOP_SUB:   tmp=0x2b; break;
00593         case DOP_SBB:   tmp=0x1b; break;
00594         case DOP_CMP:   tmp=0x3b; break;
00595         case DOP_XOR:   tmp=0x33; break;
00596         case DOP_AND:   tmp=0x23; break;
00597         case DOP_OR:    tmp=0x0b; break;
00598         case DOP_TEST:  tmp=0x85; break;
00599         case DOP_MOV:   tmp=0x8b; break;
00600         case DOP_XCHG:  tmp=0x87; break;
00601         default:
00602                 IllegalOption("gen_dop_word_var");
00603         }
00604         if (!dword) cache_addb(0x66);
00605         cache_addw(tmp|(0x05+((gr1->index)<<3))<<8);
00606         cache_addd((uintptr_t)drd);
00607 }
00608 
00609 static void gen_imul_word(bool dword,DynReg * dr1,DynReg * dr2) {
00610         GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2);
00611         dr1->flags|=DYNFLG_CHANGED;
00612         if (!dword) {
00613                 cache_addd(0xaf0f66|(0xc0+(gr1->index<<3)+gr2->index)<<24);
00614         } else {
00615                 cache_addw(0xaf0f);
00616                 cache_addb(0xc0+(gr1->index<<3)+gr2->index);
00617         }
00618 }
00619 
00620 static void gen_imul_word_imm(bool dword,DynReg * dr1,DynReg * dr2,Bits imm) {
00621         GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2);
00622         if (!dword) cache_addb(0x66);
00623         if ((imm>=-128 && imm<=127)) {
00624                 cache_addb(0x6b);
00625                 cache_addb(0xc0+(gr1->index<<3)+gr2->index);
00626                 cache_addb(imm);
00627         } else {
00628                 cache_addb(0x69);
00629                 cache_addb(0xc0+(gr1->index<<3)+gr2->index);
00630                 if (dword) cache_addd(imm);
00631                 else cache_addw(imm);
00632         }
00633         dr1->flags|=DYNFLG_CHANGED;
00634 }
00635 
00636 
00637 static void gen_sop_word(SingleOps op,bool dword,DynReg * dr1) {
00638         GenReg * gr1=FindDynReg(dr1);
00639         if (!dword) cache_addb(0x66);
00640         switch (op) {
00641         case SOP_INC:cache_addb(0x40+gr1->index);break;
00642         case SOP_DEC:cache_addb(0x48+gr1->index);break;
00643         case SOP_NOT:cache_addw(0xd0f7+(gr1->index<<8));break;
00644         case SOP_NEG:cache_addw(0xd8f7+(gr1->index<<8));break;
00645         default:
00646                 IllegalOption("gen_sop_word");
00647         }
00648         dr1->flags|=DYNFLG_CHANGED;
00649 }
00650 
00651 static void gen_shift_byte_cl(Bitu op,DynReg * dr1,Bit8u di1,DynReg * drecx) {
00652         ForceDynReg(x86gen.regs[X86_REG_ECX],drecx);
00653         GenReg * gr1=FindDynReg(dr1);
00654         cache_addw(0xc0d2+(((Bit16u)op) << 11)+ ((gr1->index+di1)<<8));
00655         dr1->flags|=DYNFLG_CHANGED;
00656 }
00657 
00658 static void gen_shift_byte_imm(Bitu op,DynReg * dr1,Bit8u di1,Bit8u imm) {
00659         GenReg * gr1=FindDynReg(dr1);
00660         cache_addw(0xc0c0+(((Bit16u)op) << 11) + ((gr1->index+di1)<<8));
00661         cache_addb(imm);
00662         dr1->flags|=DYNFLG_CHANGED;
00663 }
00664 
00665 static void gen_shift_word_cl(Bitu op,bool dword,DynReg * dr1,DynReg * drecx) {
00666         ForceDynReg(x86gen.regs[X86_REG_ECX],drecx);
00667         GenReg * gr1=FindDynReg(dr1);
00668         if (!dword) cache_addb(0x66);
00669         cache_addw(0xc0d3+(((Bit16u)op) << 11) + ((gr1->index)<<8));
00670         dr1->flags|=DYNFLG_CHANGED;
00671 }
00672 
00673 static void gen_shift_word_imm(Bitu op,bool dword,DynReg * dr1,Bit8u imm) {
00674         GenReg * gr1=FindDynReg(dr1);
00675         dr1->flags|=DYNFLG_CHANGED;
00676         if (!dword) {
00677                 cache_addd(0x66|((0xc0c1+((Bit16u)op << 11) + (gr1->index<<8))|imm<<16)<<8);
00678         } else { 
00679                 cache_addw(0xc0c1+((Bit16u)op << 11) + (gr1->index<<8));
00680                 cache_addb(imm);
00681         }
00682 }
00683 
00684 static void gen_cbw(bool dword,DynReg * dyn_ax) {
00685         ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
00686         if (!dword) cache_addb(0x66);
00687         cache_addb(0x98);
00688         dyn_ax->flags|=DYNFLG_CHANGED;
00689 }
00690 
00691 static void gen_cwd(bool dword,DynReg * dyn_ax,DynReg * dyn_dx) {
00692         ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
00693         ForceDynReg(x86gen.regs[X86_REG_EDX],dyn_dx);
00694         dyn_ax->flags|=DYNFLG_CHANGED;
00695         dyn_dx->flags|=DYNFLG_CHANGED;
00696         if (!dword) cache_addw(0x9966);
00697         else cache_addb(0x99);
00698 }
00699 
00700 static void gen_mul_byte(bool imul,DynReg * dyn_ax,DynReg * dr1,Bit8u di1) {
00701         ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
00702         GenReg * gr1=FindDynReg(dr1);
00703         if (imul) cache_addw(0xe8f6+((gr1->index+di1)<<8));
00704         else cache_addw(0xe0f6+((gr1->index+di1)<<8));
00705         dyn_ax->flags|=DYNFLG_CHANGED;
00706 }
00707 
00708 static void gen_mul_word(bool imul,DynReg * dyn_ax,DynReg * dyn_dx,bool dword,DynReg * dr1) {
00709         ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
00710         ForceDynReg(x86gen.regs[X86_REG_EDX],dyn_dx);
00711         GenReg * gr1=FindDynReg(dr1);
00712         if (!dword) cache_addb(0x66);
00713         if (imul) cache_addw(0xe8f7+(gr1->index<<8));
00714         else cache_addw(0xe0f7+(gr1->index<<8));
00715         dyn_ax->flags|=DYNFLG_CHANGED;
00716         dyn_dx->flags|=DYNFLG_CHANGED;
00717 }
00718 
00719 static void gen_dshift_imm(bool dword,bool left,DynReg * dr1,DynReg * dr2,Bitu imm) {
00720         GenReg * gr1=FindDynReg(dr1);
00721         GenReg * gr2=FindDynReg(dr2);
00722         if (!dword) cache_addb(0x66);
00723         if (left) cache_addw(0xa40f);           //SHLD IMM
00724         else  cache_addw(0xac0f);                       //SHRD IMM
00725         cache_addb(0xc0+gr1->index+(gr2->index<<3));
00726         cache_addb(imm);
00727         dr1->flags|=DYNFLG_CHANGED;
00728 }
00729 
00730 static void gen_dshift_cl(bool dword,bool left,DynReg * dr1,DynReg * dr2,DynReg * drecx) {
00731         ForceDynReg(x86gen.regs[X86_REG_ECX],drecx);
00732         GenReg * gr1=FindDynReg(dr1);
00733         GenReg * gr2=FindDynReg(dr2);
00734         if (!dword) cache_addb(0x66);
00735         if (left) cache_addw(0xa50f);           //SHLD CL
00736         else  cache_addw(0xad0f);                       //SHRD CL
00737         cache_addb(0xc0+gr1->index+(gr2->index<<3));
00738         dr1->flags|=DYNFLG_CHANGED;
00739 }
00740 
00741 static void gen_call_function(void * func,char const* ops,...) {
00742         Bits paramcount=0;
00743         bool release_flags=false;
00744         struct ParamInfo {
00745                 const char * line;
00746                 Bitu value;
00747         } pinfo[32];
00748         ParamInfo * retparam=0;
00749         /* Clear the EAX Genreg for usage */
00750         x86gen.regs[X86_REG_EAX]->Clear();
00751         x86gen.regs[X86_REG_EAX]->notusable=true;
00752         /* Save the flags */
00753         if (GCC_UNLIKELY(!skip_flags)) gen_protectflags();
00754         /* Scan for the amount of params */
00755         if (ops) {
00756                 va_list params;
00757                 va_start(params,ops);
00758 #if defined (MACOSX)
00759                 Bitu stack_used=0;
00760                 bool free_flags=false;
00761 #endif
00762                 Bits pindex=0;
00763                 while (*ops) {
00764                         if (*ops=='%') {
00765                                 pinfo[pindex].line=ops+1;
00766                                 pinfo[pindex].value=va_arg(params,Bitu);
00767 #if defined (MACOSX)
00768                                 const char * scan=pinfo[pindex].line;
00769                                 if ((*scan=='I') || (*scan=='D')) stack_used+=4;
00770                                 else if (*scan=='F') free_flags=true;
00771 #endif
00772                                 pindex++;
00773                         }
00774                         ops++;
00775                 }
00776 
00777 #if defined (MACOSX)
00778                 /* align stack */
00779                 stack_used+=4;                  // saving esp on stack as well
00780 
00781                 cache_addw(0xc48b);             // mov eax,esp
00782                 cache_addb(0x2d);               // sub eax,stack_used
00783                 cache_addd(stack_used);
00784                 cache_addw(0xe083);             // and eax,0xfffffff0
00785                 cache_addb(0xf0);
00786                 cache_addb(0x05);               // sub eax,stack_used
00787                 cache_addd(stack_used);
00788                 cache_addb(0x94);               // xchg eax,esp
00789                 if (free_flags) {
00790                         cache_addw(0xc083);     // add eax,4
00791                         cache_addb(0x04);
00792                 }
00793                 cache_addb(0x50);               // push eax (==old esp)
00794 #endif
00795 
00796                 paramcount=0;
00797                 while (pindex) {
00798                         pindex--;
00799                         const char * scan=pinfo[pindex].line;
00800                         switch (*scan++) {
00801                         case 'I':                               /* immediate value */
00802                                 paramcount++;
00803                                 cache_addb(0x68);                       //Push immediate
00804                                 cache_addd(pinfo[pindex].value);        //Push value
00805                                 break;
00806                         case 'D':                               /* Dynamic register */
00807                                 {
00808                                         bool release=false;
00809                                         paramcount++;
00810                                         DynReg * dynreg=(DynReg *)pinfo[pindex].value;
00811                                         GenReg * genreg=FindDynReg(dynreg);
00812                                         scanagain:
00813                                         switch (*scan++) {
00814                                         case 'd':
00815                                                 cache_addb(0x50+genreg->index);         //Push reg
00816                                                 break;
00817                                         case 'w':
00818                                                 cache_addw(0xb70f);                                     //MOVZX EAX,reg
00819                                                 cache_addb(0xc0+genreg->index);
00820                                                 cache_addb(0x50);                                       //Push EAX
00821                                                 break;
00822                                         case 'l':
00823                                                 cache_addw(0xb60f);                                     //MOVZX EAX,reg[0]
00824                                                 cache_addb(0xc0+genreg->index);
00825                                                 cache_addb(0x50);                                       //Push EAX
00826                                                 break;
00827                                         case 'h':
00828                                                 cache_addw(0xb60f);                                     //MOVZX EAX,reg[1]
00829                                                 cache_addb(0xc4+genreg->index);
00830                                                 cache_addb(0x50);                                       //Push EAX
00831                                                 break;
00832                                         case 'r':                                                               /* release the reg afterwards */
00833                                                 release=true;
00834                                                 goto scanagain;
00835                                         default:
00836                                                 IllegalOption("gen_call_function param:DREG");
00837                                         }
00838                                         if (release) gen_releasereg(dynreg);
00839                                 }
00840                                 break;
00841                         case 'R':                               /* Dynamic register to get the return value */
00842                                 retparam =&pinfo[pindex];
00843                                 pinfo[pindex].line=scan;
00844                                 break;
00845                         case 'F':                               /* Release flags from stack */
00846                                 release_flags=true;
00847                                 break;
00848                         default:
00849                                 IllegalOption("gen_call_function unknown param");
00850                         }
00851                 }
00852 #if defined (MACOSX)
00853                 if (free_flags) release_flags=false;
00854         } else {
00855                 /* align stack */
00856                 Bit32u stack_used=8;    // saving esp and return address on the stack
00857 
00858                 cache_addw(0xc48b);             // mov eax,esp
00859                 cache_addb(0x2d);               // sub eax,stack_used
00860                 cache_addd(stack_used);
00861                 cache_addw(0xe083);             // and eax,0xfffffff0
00862                 cache_addb(0xf0);
00863                 cache_addb(0x05);               // sub eax,stack_used
00864                 cache_addd(stack_used);
00865                 cache_addb(0x94);               // xchg eax,esp
00866                 cache_addb(0x50);               // push esp (==old esp)
00867 #endif
00868         }
00869 
00870         /* Clear some unprotected registers */
00871         x86gen.regs[X86_REG_ECX]->Clear();
00872         x86gen.regs[X86_REG_EDX]->Clear();
00873         /* Do the actual call to the procedure */
00874         cache_addb(0xe8);
00875         cache_addd((uintptr_t)func - (uintptr_t)cache.pos - (uintptr_t)4);
00876         /* Restore the params of the stack */
00877         if (paramcount) {
00878                 cache_addw(0xc483);                             //add ESP,imm byte
00879                 cache_addb(paramcount*4+(release_flags?4:0));
00880         } else if (release_flags) {
00881                 cache_addw(0xc483);                             //add ESP,imm byte
00882                 cache_addb(4);
00883         }
00884         /* Save the return value in correct register */
00885         if (retparam) {
00886                 DynReg * dynreg=(DynReg *)retparam->value;
00887                 GenReg * genreg=FindDynReg(dynreg);
00888                 if (genreg->index)              // test for (e)ax/al
00889                 switch (*retparam->line) {
00890                 case 'd':
00891                         cache_addw(0xc08b+(genreg->index <<(8+3)));     //mov reg,eax
00892                         break;
00893                 case 'w':
00894                         cache_addb(0x66);                                                       
00895                         cache_addw(0xc08b+(genreg->index <<(8+3)));     //mov reg,eax
00896                         break;
00897                 case 'l':
00898                         cache_addw(0xc08a+(genreg->index <<(8+3)));     //mov reg,eax
00899                         break;
00900                 case 'h':
00901                         cache_addw(0xc08a+((genreg->index+4) <<(8+3))); //mov reg,eax
00902                         break;
00903                 }
00904                 dynreg->flags|=DYNFLG_CHANGED;
00905         }
00906         /* Restore EAX registers to be used again */
00907         x86gen.regs[X86_REG_EAX]->notusable=false;
00908 
00909 #if defined (MACOSX)
00910         /* restore stack */
00911         cache_addb(0x5c);       // pop esp
00912 #endif
00913 }
00914 
00915 static void gen_call_write(DynReg * dr,Bit32u val,Bitu write_size) {
00916         /* Clear the EAX Genreg for usage */
00917         x86gen.regs[X86_REG_EAX]->Clear();
00918         x86gen.regs[X86_REG_EAX]->notusable=true;
00919         gen_protectflags();
00920 
00921 #if defined (MACOSX)
00922         /* align stack */
00923         Bitu stack_used=12;
00924 
00925         cache_addw(0xc48b);             // mov eax,esp
00926         cache_addb(0x2d);               // sub eax,stack_used
00927         cache_addd(stack_used);
00928         cache_addw(0xe083);             // and eax,0xfffffff0
00929         cache_addb(0xf0);
00930         cache_addb(0x05);               // sub eax,stack_used
00931         cache_addd(stack_used);
00932         cache_addb(0x94);               // xchg eax,esp
00933         cache_addb(0x50);               // push eax (==old esp)
00934 #endif
00935 
00936         cache_addb(0x68);       //PUSH val
00937         cache_addd(val);
00938         GenReg * genreg=FindDynReg(dr);
00939         cache_addb(0x50+genreg->index);         //PUSH reg
00940 
00941         /* Clear some unprotected registers */
00942         x86gen.regs[X86_REG_ECX]->Clear();
00943         x86gen.regs[X86_REG_EDX]->Clear();
00944         /* Do the actual call to the procedure */
00945         cache_addb(0xe8);
00946         switch (write_size) {
00947                 case 1: cache_addd((uintptr_t)mem_writeb_checked - (uintptr_t)cache.pos - (uintptr_t)4); break;
00948                 case 2: cache_addd((uintptr_t)mem_writew_checked - (uintptr_t)cache.pos - (uintptr_t)4); break;
00949                 case 4: cache_addd((uintptr_t)mem_writed_checked - (uintptr_t)cache.pos - (uintptr_t)4); break;
00950                 default: IllegalOption("gen_call_write");
00951         }
00952 
00953         cache_addw(0xc483);             //ADD ESP,8
00954         cache_addb(2*4);
00955         x86gen.regs[X86_REG_EAX]->notusable=false;
00956         gen_releasereg(dr);
00957 
00958 #if defined (MACOSX)
00959         /* restore stack */
00960         cache_addb(0x5c);       // pop esp
00961 #endif
00962 }
00963 
00964 static Bit8u * gen_create_branch(BranchTypes type) {
00965         /* First free all registers */
00966         cache_addw(0x70+type);
00967         return (cache.pos-1);
00968 }
00969 
00970 static void gen_fill_branch(Bit8u * data,Bit8u * from=cache.pos) {
00971 #if C_DEBUG
00972         Bits len=from-data;
00973         if (len<0) len=-len;
00974         if (len>126) LOG_MSG("Big jump %d",len);
00975 #endif
00976         *data=(from-data-1);
00977 }
00978 
00979 static Bit8u * gen_create_branch_long(BranchTypes type) {
00980         cache_addw(0x800f+(type<<8));
00981         cache_addd(0);
00982         return (cache.pos-4);
00983 }
00984 
00985 static void gen_fill_branch_long(Bit8u * data,Bit8u * from=cache.pos) {
00986         *((Bit32u*)data) = (from-data-4);
00987 }
00988 
00989 static Bit8u * gen_create_jump(Bit8u * to=0) {
00990         /* First free all registers */
00991         cache_addb(0xe9);
00992         cache_addd(to-(cache.pos+4));
00993         return (cache.pos-4);
00994 }
00995 
00996 static void gen_fill_jump(Bit8u * data,Bit8u * to=cache.pos) {
00997         *(Bit32u*)data=(to-data-4);
00998 }
00999 
01000 
01001 static void gen_jmp_ptr(void * ptr,Bits imm=0) {
01002         cache_addb(0xa1);
01003         cache_addd((uintptr_t)ptr);
01004         cache_addb(0xff);               //JMP EA
01005         if (!imm) {                     //NO EBP
01006                 cache_addb(0x20);
01007     } else if ((imm>=-128 && imm<=127)) {
01008                 cache_addb(0x60);
01009                 cache_addb(imm);
01010         } else {
01011                 cache_addb(0xa0);
01012                 cache_addd(imm);
01013         }
01014 }
01015 
01016 static void gen_save_flags(DynReg * dynreg) {
01017         if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_save_flags");
01018         GenReg * genreg=FindDynReg(dynreg);
01019         cache_addb(0x8b);                                       //MOV REG,[esp]
01020         cache_addw(0x2404+(genreg->index << 3));
01021         dynreg->flags|=DYNFLG_CHANGED;
01022 }
01023 
01024 static void gen_load_flags(DynReg * dynreg) {
01025         if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_load_flags");
01026         cache_addw(0xc483);                             //ADD ESP,4
01027         cache_addb(0x4);
01028         GenReg * genreg=FindDynReg(dynreg);
01029         cache_addb(0x50+genreg->index);         //PUSH 32
01030 }
01031 
01032 static void gen_save_host_direct(void * data,Bits imm) {
01033         cache_addw(0x05c7);             //MOV [],dword
01034         cache_addd((uintptr_t)data);
01035         cache_addd(imm);
01036 }
01037 
01038 static void gen_return(BlockReturn retcode) {
01039         gen_protectflags();
01040         cache_addb(0x59);                       //POP ECX, the flags
01041         if (retcode==0) cache_addw(0xc033);             //MOV EAX, 0
01042         else {
01043                 cache_addb(0xb8);               //MOV EAX, retcode
01044                 cache_addd(retcode);
01045         }
01046         cache_addb(0xc3);                       //RET
01047 }
01048 
01049 static void gen_return_fast(BlockReturn retcode,bool ret_exception=false) {
01050         if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_return_fast");
01051         cache_addw(0x0d8b);                     //MOV ECX, the flags
01052         cache_addd((uintptr_t)&cpu_regs.flags);
01053         if (!ret_exception) {
01054                 cache_addw(0xc483);                     //ADD ESP,4
01055                 cache_addb(0x4);
01056                 if (retcode==0) cache_addw(0xc033);             //MOV EAX, 0
01057                 else {
01058                         cache_addb(0xb8);               //MOV EAX, retcode
01059                         cache_addd(retcode);
01060                 }
01061         }
01062         cache_addb(0xc3);                       //RET
01063 }
01064 
01065 static void gen_init(void) {
01066         x86gen.regs[X86_REG_EAX]=new GenReg(0);
01067         x86gen.regs[X86_REG_ECX]=new GenReg(1);
01068         x86gen.regs[X86_REG_EDX]=new GenReg(2);
01069         x86gen.regs[X86_REG_EBX]=new GenReg(3);
01070         x86gen.regs[X86_REG_EBP]=new GenReg(5);
01071         x86gen.regs[X86_REG_ESI]=new GenReg(6);
01072         x86gen.regs[X86_REG_EDI]=new GenReg(7);
01073 }
01074 
01075 static void gen_free(void) {
01076         if (x86gen.regs[X86_REG_EAX]) {
01077                 delete x86gen.regs[X86_REG_EAX];
01078                 x86gen.regs[X86_REG_EAX] = NULL;
01079         }
01080         if (x86gen.regs[X86_REG_ECX]) {
01081                 delete x86gen.regs[X86_REG_ECX];
01082                 x86gen.regs[X86_REG_ECX] = NULL;
01083         }
01084         if (x86gen.regs[X86_REG_EDX]) {
01085                 delete x86gen.regs[X86_REG_EDX];
01086                 x86gen.regs[X86_REG_EDX] = NULL;
01087         }
01088         if (x86gen.regs[X86_REG_EBX]) {
01089                 delete x86gen.regs[X86_REG_EBX];
01090                 x86gen.regs[X86_REG_EBX] = NULL;
01091         }
01092         if (x86gen.regs[X86_REG_EBP]) {
01093                 delete x86gen.regs[X86_REG_EBP];
01094                 x86gen.regs[X86_REG_EBP] = NULL;
01095         }
01096         if (x86gen.regs[X86_REG_ESI]) {
01097                 delete x86gen.regs[X86_REG_ESI];
01098                 x86gen.regs[X86_REG_ESI] = NULL;
01099         }
01100         if (x86gen.regs[X86_REG_EDI]) {
01101                 delete x86gen.regs[X86_REG_EDI];
01102                 x86gen.regs[X86_REG_EDI] = NULL;
01103         }
01104 }
01105