⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 risc_x86.h

📁 DOSBox emulates a full x86 pc with sound and dos. Its main use is to run old dosgames on platforms w
💻 H
📖 第 1 页 / 共 2 页
字号:
/* *  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 + -