📄 risc_x86.h
字号:
/* * Copyright (C) 2002-2007 The DOSBox Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */static void gen_init(void);/* End of needed */#define X86_REGS 7#define X86_REG_EAX 0x00#define X86_REG_ECX 0x01#define X86_REG_EDX 0x02#define X86_REG_EBX 0x03#define X86_REG_EBP 0x04#define X86_REG_ESI 0x05#define X86_REG_EDI 0x06#define X86_REG_MASK(_REG_) (1 << X86_REG_ ## _REG_)static struct { bool flagsactive; Bitu last_used; GenReg * regs[X86_REGS];} x86gen;class GenReg {public: GenReg(Bit8u _index) { index=_index; notusable=false;dynreg=0; } DynReg * dynreg; Bitu last_used; //Keeps track of last assigned regs Bit8u index; bool notusable; void Load(DynReg * _dynreg,bool stale=false) { if (!_dynreg) return; if (GCC_UNLIKELY((Bitu)dynreg)) Clear(); dynreg=_dynreg; last_used=x86gen.last_used; dynreg->flags&=~DYNFLG_CHANGED; dynreg->genreg=this; if ((!stale) && (dynreg->flags & (DYNFLG_LOAD|DYNFLG_ACTIVE))) { cache_addw(0x058b+(index << (8+3))); //Mov reg,[data] cache_addd((Bit32u)dynreg->data); } dynreg->flags|=DYNFLG_ACTIVE; } void Save(void) { if (GCC_UNLIKELY(!((Bitu)dynreg))) IllegalOption("GenReg->Save"); dynreg->flags&=~DYNFLG_CHANGED; cache_addw(0x0589+(index << (8+3))); //Mov [data],reg cache_addd((Bit32u)dynreg->data); } void Release(void) { if (GCC_UNLIKELY(!((Bitu)dynreg))) return; if (dynreg->flags&DYNFLG_CHANGED && dynreg->flags&DYNFLG_SAVE) { Save(); } dynreg->flags&=~(DYNFLG_CHANGED|DYNFLG_ACTIVE); dynreg->genreg=0;dynreg=0; } void Clear(void) { if (!dynreg) return; if (dynreg->flags&DYNFLG_CHANGED) { Save(); } dynreg->genreg=0;dynreg=0; }};static BlockReturn gen_runcode(Bit8u * code) { BlockReturn retval;#if defined (_MSC_VER) __asm {/* Prepare the flags */ mov eax,[code] push ebx push ebp push esi push edi mov ebx,[reg_flags] and ebx,FMASK_TEST push offset(return_address) push ebx jmp eax/* Restore the flags */return_address: /* return here with flags in ecx */ and dword ptr [reg_flags],~FMASK_TEST and ecx,FMASK_TEST or [reg_flags],ecx pop edi pop esi pop ebp pop ebx mov [retval],eax }#elif defined (MACOSX) register Bit32u tempflags=reg_flags & FMASK_TEST; __asm__ volatile ( "pushl %%ebx \n" "pushl %%ebp \n" "pushl $(run_return_adress) \n" "pushl %2 \n" "jmp *%3 \n" "run_return_adress: \n" "popl %%ebp \n" "popl %%ebx \n" :"=a" (retval), "=c" (tempflags) :"r" (tempflags),"r" (code) :"%edx","%edi","%esi","cc","memory" ); reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST);#else register Bit32u tempflags=reg_flags & FMASK_TEST; __asm__ volatile ( "pushl %%ebp \n" "pushl $(run_return_adress) \n" "pushl %2 \n" "jmp *%3 \n" "run_return_adress: \n" "popl %%ebp \n" :"=a" (retval), "=c" (tempflags) :"r" (tempflags),"r" (code) :"%edx","%ebx","%edi","%esi","cc","memory" ); reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST);#endif return retval;}static GenReg * FindDynReg(DynReg * dynreg,bool stale=false) { x86gen.last_used++; if (dynreg->genreg) { dynreg->genreg->last_used=x86gen.last_used; return dynreg->genreg; } /* Find best match for selected global reg */ Bits i; Bits first_used,first_index; first_used=-1; if (dynreg->flags & DYNFLG_HAS8) { /* Has to be eax,ebx,ecx,edx */ for (i=first_index=0;i<=X86_REG_EBX;i++) { GenReg * genreg=x86gen.regs[i]; if (genreg->notusable) continue; if (!(genreg->dynreg)) { genreg->Load(dynreg,stale); return genreg; } if (genreg->last_used<first_used) { first_used=genreg->last_used; first_index=i; } } } else { for (i=first_index=X86_REGS-1;i>=0;i--) { GenReg * genreg=x86gen.regs[i]; if (genreg->notusable) continue; if (!(genreg->dynreg)) { genreg->Load(dynreg,stale); return genreg; } if (genreg->last_used<first_used) { first_used=genreg->last_used; first_index=i; } } } /* No free register found use earliest assigned one */ GenReg * newreg=x86gen.regs[first_index]; newreg->Load(dynreg,stale); return newreg;}static GenReg * ForceDynReg(GenReg * genreg,DynReg * dynreg) { genreg->last_used=++x86gen.last_used; if (dynreg->genreg==genreg) return genreg; if (genreg->dynreg) genreg->Clear(); if (dynreg->genreg) dynreg->genreg->Clear(); genreg->Load(dynreg); return genreg;}static void gen_preloadreg(DynReg * dynreg) { FindDynReg(dynreg);}static void gen_releasereg(DynReg * dynreg) { GenReg * genreg=dynreg->genreg; if (genreg) genreg->Release(); else dynreg->flags&=~(DYNFLG_ACTIVE|DYNFLG_CHANGED);}static void gen_setupreg(DynReg * dnew,DynReg * dsetup) { dnew->flags=dsetup->flags; if (dnew->genreg==dsetup->genreg) return; /* Not the same genreg must be wrong */ if (dnew->genreg) { /* Check if the genreg i'm changing is actually linked to me */ if (dnew->genreg->dynreg==dnew) dnew->genreg->dynreg=0; } dnew->genreg=dsetup->genreg; if (dnew->genreg) dnew->genreg->dynreg=dnew;}static void gen_synchreg(DynReg * dnew,DynReg * dsynch) { /* First make sure the registers match */ if (dnew->genreg!=dsynch->genreg) { if (dnew->genreg) dnew->genreg->Clear(); if (dsynch->genreg) { dsynch->genreg->Load(dnew); } } /* Always use the loadonce flag from either state */ dnew->flags|=(dsynch->flags & dnew->flags&DYNFLG_ACTIVE); if ((dnew->flags ^ dsynch->flags) & DYNFLG_CHANGED) { /* Ensure the changed value gets saved */ if (dnew->flags & DYNFLG_CHANGED) { dnew->genreg->Save(); } else dnew->flags|=DYNFLG_CHANGED; }}static void gen_needflags(void) { if (!x86gen.flagsactive) { x86gen.flagsactive=true; cache_addb(0x9d); //POPFD }}static void gen_protectflags(void) { if (x86gen.flagsactive) { x86gen.flagsactive=false; cache_addb(0x9c); //PUSHFD }}static void gen_discardflags(void) { if (!x86gen.flagsactive) { x86gen.flagsactive=true; cache_addw(0xc483); //ADD ESP,4 cache_addb(0x4); }}static void gen_needcarry(void) { if (!x86gen.flagsactive) { x86gen.flagsactive=true; cache_addw(0x2cd1); //SHR DWORD [ESP],1 cache_addb(0x24); cache_addd(0x0424648d); //LEA ESP,[ESP+4] }}static bool skip_flags=false;static void set_skipflags(bool state) { if (!state) gen_discardflags(); skip_flags=state;}static void gen_reinit(void) { x86gen.last_used=0; x86gen.flagsactive=false; for (Bitu i=0;i<X86_REGS;i++) { x86gen.regs[i]->dynreg=0; }}static void gen_load_host(void * data,DynReg * dr1,Bitu size) { GenReg * gr1=FindDynReg(dr1,true); switch (size) { case 1:cache_addw(0xb60f);break; //movzx byte case 2:cache_addw(0xb70f);break; //movzx word case 4:cache_addb(0x8b);break; //mov default: IllegalOption("gen_load_host"); } cache_addb(0x5+(gr1->index<<3)); cache_addd((Bit32u)data); dr1->flags|=DYNFLG_CHANGED;}static void gen_mov_host(void * data,DynReg * dr1,Bitu size,Bit8u di1=0) { GenReg * gr1=FindDynReg(dr1,(size==4)); switch (size) { case 1:cache_addb(0x8a);break; //mov byte case 2:cache_addb(0x66); //mov word case 4:cache_addb(0x8b);break; //mov default: IllegalOption("gen_load_host"); } cache_addb(0x5+((gr1->index+(di1?4:0))<<3)); cache_addd((Bit32u)data); dr1->flags|=DYNFLG_CHANGED;}static void gen_dop_byte(DualOps op,DynReg * dr1,Bit8u di1,DynReg * dr2,Bit8u di2) { GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2); Bit8u tmp; switch (op) { case DOP_ADD: tmp=0x02; break; case DOP_ADC: tmp=0x12; break; case DOP_SUB: tmp=0x2a; break; case DOP_SBB: tmp=0x1a; break; case DOP_CMP: tmp=0x3a; goto nochange; case DOP_XOR: tmp=0x32; break; case DOP_AND: tmp=0x22; if ((dr1==dr2) && (di1==di2)) goto nochange; break; case DOP_OR: tmp=0x0a; if ((dr1==dr2) && (di1==di2)) goto nochange; break; case DOP_TEST: tmp=0x84; goto nochange; case DOP_MOV: if ((dr1==dr2) && (di1==di2)) return; tmp=0x8a; break; case DOP_XCHG: tmp=0x86; dr2->flags|=DYNFLG_CHANGED; break; default: IllegalOption("gen_dop_byte"); } dr1->flags|=DYNFLG_CHANGED;nochange: cache_addw(tmp|(0xc0+((gr1->index+di1)<<3)+gr2->index+di2)<<8);}static void gen_dop_byte_imm(DualOps op,DynReg * dr1,Bit8u di1,Bitu imm) { GenReg * gr1=FindDynReg(dr1); Bit16u tmp; switch (op) { case DOP_ADD: tmp=0xc080; break; case DOP_ADC: tmp=0xd080; break; case DOP_SUB: tmp=0xe880; break; case DOP_SBB: tmp=0xd880; break; case DOP_CMP: tmp=0xf880; goto nochange; //Doesn't change case DOP_XOR: tmp=0xf080; break; case DOP_AND: tmp=0xe080; break; case DOP_OR: tmp=0xc880; break; case DOP_TEST: tmp=0xc0f6; goto nochange; //Doesn't change case DOP_MOV: cache_addb(0xb0+gr1->index+di1); dr1->flags|=DYNFLG_CHANGED; goto finish; default: IllegalOption("gen_dop_byte_imm"); } dr1->flags|=DYNFLG_CHANGED;nochange: cache_addw(tmp+((gr1->index+di1)<<8));finish: cache_addb(imm);}static void gen_dop_byte_imm_mem(DualOps op,DynReg * dr1,Bit8u di1,void* data) { GenReg * gr1=FindDynReg(dr1); Bit16u tmp; switch (op) { case DOP_ADD: tmp=0x0502; break; case DOP_ADC: tmp=0x0512; break; case DOP_SUB: tmp=0x052a; break; case DOP_SBB: tmp=0x051a; break; case DOP_CMP: tmp=0x053a; goto nochange; //Doesn't change case DOP_XOR: tmp=0x0532; break; case DOP_AND: tmp=0x0522; break; case DOP_OR: tmp=0x050a; break; case DOP_TEST: tmp=0x0584; goto nochange; //Doesn't change case DOP_MOV: tmp=0x0585; break; default: IllegalOption("gen_dop_byte_imm_mem"); } dr1->flags|=DYNFLG_CHANGED;nochange: cache_addw(tmp+((gr1->index+di1)<<11)); cache_addd((Bit32u)data);}static void gen_sop_byte(SingleOps op,DynReg * dr1,Bit8u di1) { GenReg * gr1=FindDynReg(dr1); Bit16u tmp; switch (op) { case SOP_INC: tmp=0xc0FE; break; case SOP_DEC: tmp=0xc8FE; break; case SOP_NOT: tmp=0xd0f6; break; case SOP_NEG: tmp=0xd8f6; break; default: IllegalOption("gen_sop_byte"); } cache_addw(tmp + ((gr1->index+di1)<<8)); dr1->flags|=DYNFLG_CHANGED;}static void gen_extend_word(bool sign,DynReg * ddr,DynReg * dsr) { GenReg * gsr=FindDynReg(dsr); GenReg * gdr=FindDynReg(ddr,true); if (sign) cache_addw(0xbf0f); else cache_addw(0xb70f); cache_addb(0xc0+(gdr->index<<3)+(gsr->index)); ddr->flags|=DYNFLG_CHANGED;}static void gen_extend_byte(bool sign,bool dword,DynReg * ddr,DynReg * dsr,Bit8u dsi) { GenReg * gsr=FindDynReg(dsr); GenReg * gdr=FindDynReg(ddr,dword); if (!dword) cache_addb(0x66); if (sign) cache_addw(0xbe0f); else cache_addw(0xb60f); cache_addb(0xc0+(gdr->index<<3)+(gsr->index+dsi)); ddr->flags|=DYNFLG_CHANGED;}static void gen_lea(DynReg * ddr,DynReg * dsr1,DynReg * dsr2,Bitu scale,Bits imm) { GenReg * gdr=FindDynReg(ddr); Bitu imm_size; Bit8u rm_base=(gdr->index << 3); if (dsr1) { GenReg * gsr1=FindDynReg(dsr1); if (!imm && (gsr1->index!=0x5)) { imm_size=0; rm_base+=0x0; //no imm } else if ((imm>=-128 && imm<=127)) { imm_size=1;rm_base+=0x40; //Signed byte imm } else { imm_size=4;rm_base+=0x80; //Signed dword imm } if (dsr2) { GenReg * gsr2=FindDynReg(dsr2); cache_addb(0x8d); //LEA cache_addb(rm_base+0x4); //The sib indicator Bit8u sib=(gsr1->index)+(gsr2->index<<3)+(scale<<6); cache_addb(sib); } else { if ((ddr==dsr1) && !imm_size) return; cache_addb(0x8d); //LEA cache_addb(rm_base+gsr1->index); } } else { if (dsr2) { GenReg * gsr2=FindDynReg(dsr2); cache_addb(0x8d); //LEA cache_addb(rm_base+0x4); //The sib indicator Bit8u sib=(5+(gsr2->index<<3)+(scale<<6)); cache_addb(sib); imm_size=4; } else { cache_addb(0x8d); //LEA cache_addb(rm_base+0x05); //dword imm imm_size=4; } } switch (imm_size) { case 0: break; case 1:cache_addb(imm);break; case 4:cache_addd(imm);break; } ddr->flags|=DYNFLG_CHANGED;}static void gen_lea_imm_mem(DynReg * ddr,DynReg * dsr,void* data) { GenReg * gdr=FindDynReg(ddr); Bit8u rm_base=(gdr->index << 3); cache_addw(0x058b+(rm_base<<8)); cache_addd((Bit32u)data); GenReg * gsr=FindDynReg(dsr); cache_addb(0x8d); //LEA cache_addb(rm_base+0x44); cache_addb(rm_base+gsr->index); cache_addb(0x00); ddr->flags|=DYNFLG_CHANGED;}static void gen_dop_word(DualOps op,bool dword,DynReg * dr1,DynReg * dr2) { GenReg * gr2=FindDynReg(dr2); GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV); Bit8u tmp; switch (op) { case DOP_ADD: tmp=0x03; break; case DOP_ADC: tmp=0x13; break; case DOP_SUB: tmp=0x2b; break; case DOP_SBB: tmp=0x1b; break; case DOP_CMP: tmp=0x3b; goto nochange; case DOP_XOR: tmp=0x33; break; case DOP_AND: tmp=0x23; if (dr1==dr2) goto nochange; break; case DOP_OR: tmp=0x0b; if (dr1==dr2) goto nochange; break; case DOP_TEST: tmp=0x85; goto nochange; case DOP_MOV: if (dr1==dr2) return; tmp=0x8b; break; case DOP_XCHG: dr2->flags|=DYNFLG_CHANGED; if (dword && !((dr1->flags&DYNFLG_HAS8) ^ (dr2->flags&DYNFLG_HAS8))) { dr1->genreg=gr2;dr1->genreg->dynreg=dr1; dr2->genreg=gr1;dr2->genreg->dynreg=dr2; dr1->flags|=DYNFLG_CHANGED; return; } tmp=0x87; break; default: IllegalOption("gen_dop_word"); } dr1->flags|=DYNFLG_CHANGED;nochange: if (!dword) cache_addb(0x66); cache_addw(tmp|(0xc0+(gr1->index<<3)+gr2->index)<<8);}static void gen_dop_word_imm(DualOps op,bool dword,DynReg * dr1,Bits imm) { GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV); Bit16u tmp; if (!dword) cache_addb(0x66); switch (op) { case DOP_ADD: tmp=0xc081; break; case DOP_ADC: tmp=0xd081; break; case DOP_SUB: tmp=0xe881; break; case DOP_SBB: tmp=0xd881; break; case DOP_CMP: tmp=0xf881; goto nochange; //Doesn't change case DOP_XOR: tmp=0xf081; break; case DOP_AND: tmp=0xe081; break; case DOP_OR: tmp=0xc881; break; case DOP_TEST: tmp=0xc0f7; goto nochange; //Doesn't change
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -