1 /*
2  *  Copyright (C) 2002-2021  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 static void gen_init(void);
20 
21 /* End of needed */
22 
23 #define X86_REGS		7
24 #define X86_REG_EAX		0x00
25 #define X86_REG_ECX		0x01
26 #define X86_REG_EDX		0x02
27 #define X86_REG_EBX		0x03
28 #define X86_REG_EBP		0x04
29 #define X86_REG_ESI		0x05
30 #define X86_REG_EDI		0x06
31 
32 #define X86_REG_MASK(_REG_) (1 << X86_REG_ ## _REG_)
33 
34 static struct {
35 	bool flagsactive;
36 	Bitu last_used;
37 	GenReg * regs[X86_REGS];
38 } x86gen;
39 
40 class GenReg {
41 public:
42 	Bit8u index = 0;
43 	DynReg  * dynreg = nullptr;
44 	Bitu last_used = 0;			//Keeps track of last assigned regs
45 	bool notusable = false;
46 
GenReg(Bit8u _index)47 	GenReg(Bit8u _index) : index(_index) {}
48 	void Load(DynReg * _dynreg,bool stale=false) {
49 		if (!_dynreg) return;
50 		if (GCC_UNLIKELY((Bitu)dynreg)) Clear();
51 		dynreg=_dynreg;
52 		last_used=x86gen.last_used;
53 		dynreg->flags&=~DYNFLG_CHANGED;
54 		dynreg->genreg=this;
55 		if ((!stale) && (dynreg->flags & (DYNFLG_LOAD|DYNFLG_ACTIVE))) {
56 			cache_addw(0x058b+(index << (8+3)));		//Mov reg,[data]
57 			cache_addd((Bit32u)dynreg->data);
58 		}
59 		dynreg->flags|=DYNFLG_ACTIVE;
60 	}
Save(void)61 	void Save(void) {
62 		if (GCC_UNLIKELY(!((Bitu)dynreg))) IllegalOption("GenReg->Save");
63 		dynreg->flags&=~DYNFLG_CHANGED;
64 		cache_addw(0x0589+(index << (8+3)));		//Mov [data],reg
65 		cache_addd((Bit32u)dynreg->data);
66 	}
Release(void)67 	void Release(void) {
68 		if (GCC_UNLIKELY(!((Bitu)dynreg))) return;
69 		if (dynreg->flags&DYNFLG_CHANGED && dynreg->flags&DYNFLG_SAVE) {
70 			Save();
71 		}
72 		dynreg->flags&=~(DYNFLG_CHANGED|DYNFLG_ACTIVE);
73 		dynreg->genreg=0;dynreg=0;
74 	}
Clear(void)75 	void Clear(void) {
76 		if (!dynreg) return;
77 		if (dynreg->flags&DYNFLG_CHANGED) {
78 			Save();
79 		}
80 		dynreg->genreg=0;dynreg=0;
81 	}
82 };
83 
gen_runcode(const Bit8u * code)84 static BlockReturn gen_runcode(const Bit8u * code) {
85 	BlockReturn retval;
86 #if defined (_MSC_VER)
87 	__asm {
88 /* Prepare the flags */
89 		mov		eax,[code]
90 		push	ebx
91 		push	ebp
92 		push	esi
93 		push	edi
94 		mov		ebx,[reg_flags]
95 		and		ebx,FMASK_TEST
96 		push	offset(return_address)
97 		push	ebx
98 		jmp		eax
99 /* Restore the flags */
100 return_address:
101 		/*	return here with flags in ecx */
102 		and		dword ptr [reg_flags],~FMASK_TEST
103 		and		ecx,FMASK_TEST
104 		or		[reg_flags],ecx
105 		pop		edi
106 		pop		esi
107 		pop		ebp
108 		pop		ebx
109 		mov		[retval],eax
110 	}
111 #elif defined (MACOSX)
112 	Bit32u tempflags = reg_flags & FMASK_TEST;
113 	__asm__ volatile (
114 		"pushl %%ebx						\n"
115 		"pushl %%ebp						\n"
116 		"pushl $(run_return_adress)			\n"
117 		"pushl  %2							\n"
118 		"jmp  *%3							\n"
119 		"run_return_adress:					\n"
120 		"popl %%ebp							\n"
121 		"popl %%ebx							\n"
122 		:"=a" (retval), "=c" (tempflags)
123 		:"r" (tempflags),"r" (code)
124 		:"%edx","%edi","%esi","cc","memory"
125 	);
126 	reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST);
127 #else
128 	Bit32u tempflags = reg_flags & FMASK_TEST;
129 	__asm__ volatile (
130 		"pushl %%ebp						\n"
131 		"pushl $(run_return_adress)			\n"
132 		"pushl  %2							\n"
133 		"jmp  *%3							\n"
134 		"run_return_adress:					\n"
135 		"popl %%ebp							\n"
136 		:"=a" (retval), "=c" (tempflags)
137 		:"r" (tempflags),"r" (code)
138 		:"%edx","%ebx","%edi","%esi","cc","memory"
139 	);
140 	reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST);
141 #endif
142 	return retval;
143 }
144 
145 static GenReg * FindDynReg(DynReg * dynreg,bool stale=false) {
146 	x86gen.last_used++;
147 	if (dynreg->genreg) {
148 		dynreg->genreg->last_used=x86gen.last_used;
149 		return dynreg->genreg;
150 	}
151 	/* Find best match for selected global reg */
152 	Bits i;
153 	Bits first_used,first_index;
154 	first_used=-1;
155 	if (dynreg->flags & DYNFLG_HAS8) {
156 		/* Has to be eax,ebx,ecx,edx */
157 		for (i=first_index=0;i<=X86_REG_EBX;i++) {
158 			GenReg * genreg=x86gen.regs[i];
159 			if (genreg->notusable) continue;
160 			if (!(genreg->dynreg)) {
161 				genreg->Load(dynreg,stale);
162 				return genreg;
163 			}
164 			if (genreg->last_used<(Bitu)first_used) {
165 				first_used=genreg->last_used;
166 				first_index=i;
167 			}
168 		}
169 	} else {
170 		for (i=first_index=X86_REGS-1;i>=0;i--) {
171 			GenReg * genreg=x86gen.regs[i];
172 			if (genreg->notusable) continue;
173 			if (!(genreg->dynreg)) {
174 				genreg->Load(dynreg,stale);
175 				return genreg;
176 			}
177 			if (genreg->last_used<(Bitu)first_used) {
178 				first_used=genreg->last_used;
179 				first_index=i;
180 			}
181 		}
182 	}
183 	/* No free register found use earliest assigned one */
184 	GenReg * newreg=x86gen.regs[first_index];
185 	newreg->Load(dynreg,stale);
186 	return newreg;
187 }
188 
ForceDynReg(GenReg * genreg,DynReg * dynreg)189 static GenReg * ForceDynReg(GenReg * genreg,DynReg * dynreg) {
190 	genreg->last_used=++x86gen.last_used;
191 	if (dynreg->genreg==genreg) return genreg;
192 	if (genreg->dynreg) genreg->Clear();
193 	if (dynreg->genreg) dynreg->genreg->Clear();
194 	genreg->Load(dynreg);
195 	return genreg;
196 }
197 
gen_preloadreg(DynReg * dynreg)198 static void gen_preloadreg(DynReg * dynreg) {
199 	FindDynReg(dynreg);
200 }
201 
gen_releasereg(DynReg * dynreg)202 static void gen_releasereg(DynReg * dynreg) {
203 	GenReg * genreg=dynreg->genreg;
204 	if (genreg) genreg->Release();
205 	else dynreg->flags&=~(DYNFLG_ACTIVE|DYNFLG_CHANGED);
206 }
207 
gen_setupreg(DynReg * dnew,DynReg * dsetup)208 static void gen_setupreg(DynReg * dnew,DynReg * dsetup) {
209 	dnew->flags=dsetup->flags;
210 	if (dnew->genreg==dsetup->genreg) return;
211 	/* Not the same genreg must be wrong */
212 	if (dnew->genreg) {
213 		/* Check if the genreg i'm changing is actually linked to me */
214 		if (dnew->genreg->dynreg==dnew) dnew->genreg->dynreg=0;
215 	}
216 	dnew->genreg=dsetup->genreg;
217 	if (dnew->genreg) dnew->genreg->dynreg=dnew;
218 }
219 
gen_synchreg(DynReg * dnew,DynReg * dsynch)220 static void gen_synchreg(DynReg * dnew,DynReg * dsynch) {
221 	/* First make sure the registers match */
222 	if (dnew->genreg!=dsynch->genreg) {
223 		if (dnew->genreg) dnew->genreg->Clear();
224 		if (dsynch->genreg) {
225 			dsynch->genreg->Load(dnew);
226 		}
227 	}
228 	/* Always use the loadonce flag from either state */
229 	dnew->flags|=(dsynch->flags & dnew->flags&DYNFLG_ACTIVE);
230 	if ((dnew->flags ^ dsynch->flags) & DYNFLG_CHANGED) {
231 		/* Ensure the changed value gets saved */
232 		if (dnew->flags & DYNFLG_CHANGED) {
233 			if (GCC_LIKELY(dnew->genreg != NULL))
234 				dnew->genreg->Save();
235 		} else dnew->flags|=DYNFLG_CHANGED;
236 	}
237 }
238 
gen_needflags(void)239 static void gen_needflags(void) {
240 	if (!x86gen.flagsactive) {
241 		x86gen.flagsactive=true;
242 		cache_addb(0x9d);		//POPFD
243 	}
244 }
245 
gen_protectflags(void)246 static void gen_protectflags(void) {
247 	if (x86gen.flagsactive) {
248 		x86gen.flagsactive=false;
249 		cache_addb(0x9c);		//PUSHFD
250 	}
251 }
252 
gen_discardflags(void)253 static void gen_discardflags(void) {
254 	if (!x86gen.flagsactive) {
255 		x86gen.flagsactive=true;
256 		cache_addw(0xc483);		//ADD ESP,4
257 		cache_addb(0x4);
258 	}
259 }
260 
gen_needcarry(void)261 static void gen_needcarry(void) {
262 	if (!x86gen.flagsactive) {
263 		x86gen.flagsactive=true;
264 		cache_addw(0x2cd1);			//SHR DWORD [ESP],1
265 		cache_addb(0x24);
266 		cache_addd(0x0424648d);		//LEA ESP,[ESP+4]
267 	}
268 }
269 
270 #if 0
271 static void gen_setzeroflag(void) {
272 	if (x86gen.flagsactive) IllegalOption("gen_setzeroflag");
273 	cache_addw(0x0c83);			//OR DWORD [ESP],0x40
274 	cache_addw(0x4024);
275 }
276 
277 static void gen_clearzeroflag(void) {
278 	if (x86gen.flagsactive) IllegalOption("gen_clearzeroflag");
279 	cache_addw(0x2483);			//AND DWORD [ESP],~0x40
280 	cache_addw(0xbf24);
281 }
282 #endif
283 
284 static bool skip_flags=false;
285 
set_skipflags(bool state)286 static void set_skipflags(bool state) {
287 	if (!state) gen_discardflags();
288 	skip_flags=state;
289 }
290 
gen_reinit(void)291 static void gen_reinit(void) {
292 	x86gen.last_used=0;
293 	x86gen.flagsactive=false;
294 	for (Bitu i=0;i<X86_REGS;i++) {
295 		x86gen.regs[i]->dynreg=0;
296 	}
297 }
298 
299 
gen_load_host(void * data,DynReg * dr1,Bitu size)300 static void gen_load_host(void * data,DynReg * dr1,Bitu size) {
301 	GenReg * gr1=FindDynReg(dr1,true);
302 	switch (size) {
303 	case 1:cache_addw(0xb60f);break;	//movzx byte
304 	case 2:cache_addw(0xb70f);break;	//movzx word
305 	case 4:cache_addb(0x8b);break;	//mov
306 	default:
307 		IllegalOption("gen_load_host");
308 	}
309 	cache_addb(0x5+(gr1->index<<3));
310 	cache_addd((Bit32u)data);
311 	dr1->flags|=DYNFLG_CHANGED;
312 }
313 
314 static void gen_mov_host(void * data,DynReg * dr1,Bitu size,Bitu di1=0) {
315 	GenReg * gr1=FindDynReg(dr1,(size==4));
316 	switch (size) {
317 	case 1:cache_addb(0x8a);break;	//mov byte
318 	case 2:cache_addb(0x66);		//mov word
319 	[[fallthrough]];
320 	case 4:cache_addb(0x8b);break;	//mov
321 	default:
322 		IllegalOption("gen_mov_host");
323 	}
324 	cache_addb(0x5+((gr1->index+di1)<<3));
325 	cache_addd((Bit32u)data);
326 	dr1->flags|=DYNFLG_CHANGED;
327 }
328 
329 
gen_dop_byte(DualOps op,DynReg * dr1,Bit8u di1,DynReg * dr2,Bit8u di2)330 static void gen_dop_byte(DualOps op,DynReg * dr1,Bit8u di1,DynReg * dr2,Bit8u di2) {
331 	GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2);
332 	Bit8u tmp = 0x00;
333 	switch (op) {
334 	case DOP_ADD:	tmp=0x02; break;
335 	case DOP_ADC:	tmp=0x12; break;
336 	case DOP_SUB:	tmp=0x2a; break;
337 	case DOP_SBB:	tmp=0x1a; break;
338 	case DOP_CMP:	tmp=0x3a; goto nochange;
339 	case DOP_XOR:	tmp=0x32; break;
340 	case DOP_AND:	tmp=0x22; if ((dr1==dr2) && (di1==di2)) goto nochange; break;
341 	case DOP_OR:	tmp=0x0a; if ((dr1==dr2) && (di1==di2)) goto nochange; break;
342 	case DOP_TEST:	tmp=0x84; goto nochange;
343 	case DOP_MOV:	if ((dr1==dr2) && (di1==di2)) return; tmp=0x8a; break;
344 	case DOP_XCHG:	if ((dr1==dr2) && (di1==di2)) return;
345 		tmp=0x86; dr2->flags|=DYNFLG_CHANGED; break;
346 	default:
347 		IllegalOption("gen_dop_byte");
348 	}
349 	dr1->flags|=DYNFLG_CHANGED;
350 nochange:
351 	cache_addw(tmp|(0xc0+((gr1->index+di1)<<3)+gr2->index+di2)<<8);
352 }
353 
gen_dop_byte_imm(DualOps op,DynReg * dr1,Bit8u di1,Bitu imm)354 static void gen_dop_byte_imm(DualOps op,DynReg * dr1,Bit8u di1,Bitu imm) {
355 	GenReg * gr1=FindDynReg(dr1);
356 	Bit16u tmp;
357 	switch (op) {
358 	case DOP_ADD:	tmp=0xc080; break;
359 	case DOP_ADC:	tmp=0xd080; break;
360 	case DOP_SUB:	tmp=0xe880; break;
361 	case DOP_SBB:	tmp=0xd880; break;
362 	case DOP_CMP:	tmp=0xf880; goto nochange;	//Doesn't change
363 	case DOP_XOR:	tmp=0xf080; break;
364 	case DOP_AND:	tmp=0xe080; break;
365 	case DOP_OR:	tmp=0xc880; break;
366 	case DOP_TEST:	tmp=0xc0f6; goto nochange;	//Doesn't change
367 	case DOP_MOV:	cache_addb(0xb0+gr1->index+di1);
368 					dr1->flags|=DYNFLG_CHANGED;
369 					goto finish;
370 	default:
371 		IllegalOption("gen_dop_byte_imm");
372 	}
373 	dr1->flags|=DYNFLG_CHANGED;
374 nochange:
375 	cache_addw(tmp+((gr1->index+di1)<<8));
376 finish:
377 	cache_addb(imm);
378 }
379 
gen_dop_byte_imm_mem(DualOps op,DynReg * dr1,Bit8u di1,void * data)380 static void gen_dop_byte_imm_mem(DualOps op,DynReg * dr1,Bit8u di1,void* data) {
381 	GenReg * gr1=FindDynReg(dr1);
382 	Bit16u tmp;
383 	switch (op) {
384 	case DOP_ADD:	tmp=0x0502; break;
385 	case DOP_ADC:	tmp=0x0512; break;
386 	case DOP_SUB:	tmp=0x052a; break;
387 	case DOP_SBB:	tmp=0x051a; break;
388 	case DOP_CMP:	tmp=0x053a; goto nochange;	//Doesn't change
389 	case DOP_XOR:	tmp=0x0532; break;
390 	case DOP_AND:	tmp=0x0522; break;
391 	case DOP_OR:	tmp=0x050a; break;
392 	case DOP_TEST:	tmp=0x0584; goto nochange;	//Doesn't change
393 	case DOP_MOV:	tmp=0x058A; break;
394 	default:
395 		IllegalOption("gen_dop_byte_imm_mem");
396 	}
397 	dr1->flags|=DYNFLG_CHANGED;
398 nochange:
399 	cache_addw(tmp+((gr1->index+di1)<<11));
400 	cache_addd((Bit32u)data);
401 }
402 
gen_sop_byte(SingleOps op,DynReg * dr1,Bit8u di1)403 static void gen_sop_byte(SingleOps op,DynReg * dr1,Bit8u di1) {
404 	GenReg * gr1=FindDynReg(dr1);
405 	Bit16u tmp;
406 	switch (op) {
407 	case SOP_INC: tmp=0xc0FE; break;
408 	case SOP_DEC: tmp=0xc8FE; break;
409 	case SOP_NOT: tmp=0xd0f6; break;
410 	case SOP_NEG: tmp=0xd8f6; break;
411 	default:
412 		IllegalOption("gen_sop_byte");
413 	}
414 	cache_addw(tmp + ((gr1->index+di1)<<8));
415 	dr1->flags|=DYNFLG_CHANGED;
416 }
417 
418 
gen_extend_word(bool sign,DynReg * ddr,DynReg * dsr)419 static void gen_extend_word(bool sign,DynReg * ddr,DynReg * dsr) {
420 	GenReg * gsr=FindDynReg(dsr);
421 	GenReg * gdr=FindDynReg(ddr,true);
422 	if (sign) cache_addw(0xbf0f);
423 	else cache_addw(0xb70f);
424 	cache_addb(0xc0+(gdr->index<<3)+(gsr->index));
425 	ddr->flags|=DYNFLG_CHANGED;
426 }
427 
gen_extend_byte(bool sign,bool dword,DynReg * ddr,DynReg * dsr,Bit8u dsi)428 static void gen_extend_byte(bool sign,bool dword,DynReg * ddr,DynReg * dsr,Bit8u dsi) {
429 	GenReg * gsr=FindDynReg(dsr);
430 	GenReg * gdr=FindDynReg(ddr,dword);
431 	if (!dword) cache_addb(0x66);
432 	if (sign) cache_addw(0xbe0f);
433 	else cache_addw(0xb60f);
434 	cache_addb(0xc0+(gdr->index<<3)+(gsr->index+dsi));
435 	ddr->flags|=DYNFLG_CHANGED;
436 }
437 
gen_lea(DynReg * ddr,DynReg * dsr1,DynReg * dsr2,Bitu scale,Bits imm)438 static void gen_lea(DynReg * ddr,DynReg * dsr1,DynReg * dsr2,Bitu scale,Bits imm) {
439 	GenReg * gdr=FindDynReg(ddr);
440 	Bitu imm_size;
441 	Bit8u rm_base=(gdr->index << 3);
442 	if (dsr1) {
443 		GenReg * gsr1=FindDynReg(dsr1);
444 		if (!imm && (gsr1->index!=0x5)) {
445 			imm_size=0;	rm_base+=0x0;			//no imm
446 		} else if ((imm>=-128 && imm<=127)) {
447 			imm_size=1;rm_base+=0x40;			//Signed byte imm
448 		} else {
449 			imm_size=4;rm_base+=0x80;			//Signed dword imm
450 		}
451 		if (dsr2) {
452 			GenReg * gsr2=FindDynReg(dsr2);
453 			cache_addb(0x8d);		//LEA
454 			cache_addb(rm_base+0x4);			//The sib indicator
455 			Bit8u sib=(gsr1->index)+(gsr2->index<<3)+(scale<<6);
456 			cache_addb(sib);
457 		} else {
458 			if ((ddr==dsr1) && !imm_size) return;
459 			cache_addb(0x8d);		//LEA
460 			cache_addb(rm_base+gsr1->index);
461 		}
462 	} else {
463 		if (dsr2) {
464 			GenReg * gsr2=FindDynReg(dsr2);
465 			cache_addb(0x8d);			//LEA
466 			cache_addb(rm_base+0x4);	//The sib indicator
467 			Bit8u sib=(5+(gsr2->index<<3)+(scale<<6));
468 			cache_addb(sib);
469 			imm_size=4;
470 		} else {
471 			cache_addb(0x8d);			//LEA
472 			cache_addb(rm_base+0x05);	//dword imm
473 			imm_size=4;
474 		}
475 	}
476 	switch (imm_size) {
477 	case 0:	break;
478 	case 1:cache_addb(imm);break;
479 	case 4:cache_addd(imm);break;
480 	}
481 	ddr->flags|=DYNFLG_CHANGED;
482 }
483 
gen_lea_imm_mem(DynReg * ddr,DynReg * dsr,void * data)484 static void gen_lea_imm_mem(DynReg * ddr,DynReg * dsr,void* data) {
485 	GenReg * gdr=FindDynReg(ddr);
486 	Bit8u rm_base=(gdr->index << 3);
487 	cache_addw(0x058b+(rm_base<<8));
488 	cache_addd((Bit32u)data);
489 	GenReg * gsr=FindDynReg(dsr);
490 	cache_addb(0x8d);		//LEA
491 	cache_addb(rm_base+0x44);
492 	cache_addb(rm_base+gsr->index);
493 	cache_addb(0x00);
494 	ddr->flags|=DYNFLG_CHANGED;
495 }
496 
gen_dop_word(DualOps op,bool dword,DynReg * dr1,DynReg * dr2)497 static void gen_dop_word(DualOps op,bool dword,DynReg * dr1,DynReg * dr2) {
498 	GenReg * gr2=FindDynReg(dr2);
499 	GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
500 	Bit8u tmp;
501 	switch (op) {
502 	case DOP_ADD:	tmp=0x03; break;
503 	case DOP_ADC:	tmp=0x13; break;
504 	case DOP_SUB:	tmp=0x2b; break;
505 	case DOP_SBB:	tmp=0x1b; break;
506 	case DOP_CMP:	tmp=0x3b; goto nochange;
507 	case DOP_XOR:	tmp=0x33; break;
508 	case DOP_AND:	tmp=0x23; if (dr1==dr2) goto nochange; break;
509 	case DOP_OR:	tmp=0x0b; if (dr1==dr2) goto nochange; break;
510 	case DOP_TEST:	tmp=0x85; goto nochange;
511 	case DOP_MOV:	if (dr1==dr2) return; tmp=0x8b; break;
512 	case DOP_XCHG:	if (dr1==dr2) return;
513 		dr2->flags|=DYNFLG_CHANGED;
514 		if (dword && !((dr1->flags&DYNFLG_HAS8) ^ (dr2->flags&DYNFLG_HAS8))) {
515 			dr1->genreg=gr2;dr1->genreg->dynreg=dr1;
516 			dr2->genreg=gr1;dr2->genreg->dynreg=dr2;
517 			dr1->flags|=DYNFLG_CHANGED;
518 			return;
519 		}
520 		tmp=0x87;
521 		break;
522 	default:
523 		IllegalOption("gen_dop_word");
524 	}
525 	dr1->flags|=DYNFLG_CHANGED;
526 nochange:
527 	if (!dword) cache_addb(0x66);
528 	cache_addw(tmp|(0xc0+(gr1->index<<3)+gr2->index)<<8);
529 }
530 
gen_dop_word_imm(DualOps op,bool dword,DynReg * dr1,Bits imm)531 static void gen_dop_word_imm(DualOps op,bool dword,DynReg * dr1,Bits imm) {
532 	GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
533 	Bit16u tmp;
534 	if (!dword) cache_addb(0x66);
535 	switch (op) {
536 	case DOP_ADD:	tmp=0xc081; break;
537 	case DOP_ADC:	tmp=0xd081; break;
538 	case DOP_SUB:	tmp=0xe881; break;
539 	case DOP_SBB:	tmp=0xd881; break;
540 	case DOP_CMP:	tmp=0xf881; goto nochange;	//Doesn't change
541 	case DOP_XOR:	tmp=0xf081; break;
542 	case DOP_AND:	tmp=0xe081; break;
543 	case DOP_OR:	tmp=0xc881; break;
544 	case DOP_TEST:	tmp=0xc0f7; goto nochange;	//Doesn't change
545 	case DOP_MOV:	cache_addb(0xb8+(gr1->index)); dr1->flags|=DYNFLG_CHANGED; goto finish;
546 	default:
547 		IllegalOption("gen_dop_word_imm");
548 	}
549 	dr1->flags|=DYNFLG_CHANGED;
550 nochange:
551 	cache_addw(tmp+(gr1->index<<8));
552 finish:
553 	if (dword) cache_addd(imm);
554 	else cache_addw(imm);
555 }
556 
gen_dop_word_imm_mem(DualOps op,bool dword,DynReg * dr1,void * data)557 static void gen_dop_word_imm_mem(DualOps op,bool dword,DynReg * dr1,void* data) {
558 	GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
559 	Bit16u tmp;
560 	switch (op) {
561 	case DOP_ADD:	tmp=0x0503; break;
562 	case DOP_ADC:	tmp=0x0513; break;
563 	case DOP_SUB:	tmp=0x052b; break;
564 	case DOP_SBB:	tmp=0x051b; break;
565 	case DOP_CMP:	tmp=0x053b; goto nochange;	//Doesn't change
566 	case DOP_XOR:	tmp=0x0533; break;
567 	case DOP_AND:	tmp=0x0523; break;
568 	case DOP_OR:	tmp=0x050b; break;
569 	case DOP_TEST:	tmp=0x0585; goto nochange;	//Doesn't change
570 	case DOP_MOV:
571 		gen_mov_host(data,dr1,dword?4:2);
572 		dr1->flags|=DYNFLG_CHANGED;
573 		return;
574 	default:
575 		IllegalOption("gen_dop_word_imm_mem");
576 	}
577 	dr1->flags|=DYNFLG_CHANGED;
578 nochange:
579 	if (!dword) cache_addb(0x66);
580 	cache_addw(tmp+(gr1->index<<11));
581 	cache_addd((Bit32u)data);
582 }
583 
gen_dop_word_var(DualOps op,bool dword,DynReg * dr1,void * drd)584 static void gen_dop_word_var(DualOps op,bool dword,DynReg * dr1,void* drd) {
585 	GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
586 	Bit8u tmp;
587 	switch (op) {
588 	case DOP_ADD:	tmp=0x03; break;
589 	case DOP_ADC:	tmp=0x13; break;
590 	case DOP_SUB:	tmp=0x2b; break;
591 	case DOP_SBB:	tmp=0x1b; break;
592 	case DOP_CMP:	tmp=0x3b; break;
593 	case DOP_XOR:	tmp=0x33; break;
594 	case DOP_AND:	tmp=0x23; break;
595 	case DOP_OR:	tmp=0x0b; break;
596 	case DOP_TEST:	tmp=0x85; break;
597 	case DOP_MOV:	tmp=0x8b; break;
598 	case DOP_XCHG:	tmp=0x87; break;
599 	default:
600 		IllegalOption("gen_dop_word_var");
601 	}
602 	if (!dword) cache_addb(0x66);
603 	cache_addw(tmp|(0x05+((gr1->index)<<3))<<8);
604 	cache_addd((Bit32u)drd);
605 }
606 
gen_imul_word(bool dword,DynReg * dr1,DynReg * dr2)607 static void gen_imul_word(bool dword,DynReg * dr1,DynReg * dr2) {
608 	GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2);
609 	dr1->flags|=DYNFLG_CHANGED;
610 	if (!dword) {
611 		cache_addd(0xaf0f66|(0xc0+(gr1->index<<3)+gr2->index)<<24);
612 	} else {
613 		cache_addw(0xaf0f);
614 		cache_addb(0xc0+(gr1->index<<3)+gr2->index);
615 	}
616 }
617 
gen_imul_word_imm(bool dword,DynReg * dr1,DynReg * dr2,Bits imm)618 static void gen_imul_word_imm(bool dword,DynReg * dr1,DynReg * dr2,Bits imm) {
619 	GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2);
620 	if (!dword) cache_addb(0x66);
621 	if ((imm>=-128 && imm<=127)) {
622 		cache_addb(0x6b);
623 		cache_addb(0xc0+(gr1->index<<3)+gr2->index);
624 		cache_addb(imm);
625 	} else {
626 		cache_addb(0x69);
627 		cache_addb(0xc0+(gr1->index<<3)+gr2->index);
628 		if (dword) cache_addd(imm);
629 		else cache_addw(imm);
630 	}
631 	dr1->flags|=DYNFLG_CHANGED;
632 }
633 
634 
gen_sop_word(SingleOps op,bool dword,DynReg * dr1)635 static void gen_sop_word(SingleOps op,bool dword,DynReg * dr1) {
636 	GenReg * gr1=FindDynReg(dr1);
637 	if (!dword) cache_addb(0x66);
638 	switch (op) {
639 	case SOP_INC:cache_addb(0x40+gr1->index);break;
640 	case SOP_DEC:cache_addb(0x48+gr1->index);break;
641 	case SOP_NOT:cache_addw(0xd0f7+(gr1->index<<8));break;
642 	case SOP_NEG:cache_addw(0xd8f7+(gr1->index<<8));break;
643 	default:
644 		IllegalOption("gen_sop_word");
645 	}
646 	dr1->flags|=DYNFLG_CHANGED;
647 }
648 
gen_shift_byte_cl(Bitu op,DynReg * dr1,Bit8u di1,DynReg * drecx)649 static void gen_shift_byte_cl(Bitu op,DynReg * dr1,Bit8u di1,DynReg * drecx) {
650 	ForceDynReg(x86gen.regs[X86_REG_ECX],drecx);
651 	GenReg * gr1=FindDynReg(dr1);
652 	cache_addw(0xc0d2+(((Bit16u)op) << 11)+ ((gr1->index+di1)<<8));
653 	dr1->flags|=DYNFLG_CHANGED;
654 }
655 
gen_shift_byte_imm(Bitu op,DynReg * dr1,Bit8u di1,Bit8u imm)656 static void gen_shift_byte_imm(Bitu op,DynReg * dr1,Bit8u di1,Bit8u imm) {
657 	GenReg * gr1=FindDynReg(dr1);
658 	cache_addw(0xc0c0+(((Bit16u)op) << 11) + ((gr1->index+di1)<<8));
659 	cache_addb(imm);
660 	dr1->flags|=DYNFLG_CHANGED;
661 }
662 
gen_shift_word_cl(Bitu op,bool dword,DynReg * dr1,DynReg * drecx)663 static void gen_shift_word_cl(Bitu op,bool dword,DynReg * dr1,DynReg * drecx) {
664 	ForceDynReg(x86gen.regs[X86_REG_ECX],drecx);
665 	GenReg * gr1=FindDynReg(dr1);
666 	if (!dword) cache_addb(0x66);
667 	cache_addw(0xc0d3+(((Bit16u)op) << 11) + ((gr1->index)<<8));
668 	dr1->flags|=DYNFLG_CHANGED;
669 }
670 
gen_shift_word_imm(Bitu op,bool dword,DynReg * dr1,Bit8u imm)671 static void gen_shift_word_imm(Bitu op,bool dword,DynReg * dr1,Bit8u imm) {
672 	GenReg * gr1=FindDynReg(dr1);
673 	dr1->flags|=DYNFLG_CHANGED;
674 	if (!dword) {
675 		cache_addd(0x66|((0xc0c1+((Bit16u)op << 11) + (gr1->index<<8))|imm<<16)<<8);
676 	} else {
677 		cache_addw(0xc0c1+((Bit16u)op << 11) + (gr1->index<<8));
678 		cache_addb(imm);
679 	}
680 }
681 
gen_cbw(bool dword,DynReg * dyn_ax)682 static void gen_cbw(bool dword,DynReg * dyn_ax) {
683 	ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
684 	if (!dword) cache_addb(0x66);
685 	cache_addb(0x98);
686 	dyn_ax->flags|=DYNFLG_CHANGED;
687 }
688 
gen_cwd(bool dword,DynReg * dyn_ax,DynReg * dyn_dx)689 static void gen_cwd(bool dword,DynReg * dyn_ax,DynReg * dyn_dx) {
690 	ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
691 	ForceDynReg(x86gen.regs[X86_REG_EDX],dyn_dx);
692 	dyn_ax->flags|=DYNFLG_CHANGED;
693 	dyn_dx->flags|=DYNFLG_CHANGED;
694 	if (!dword) cache_addw(0x9966);
695 	else cache_addb(0x99);
696 }
697 
gen_mul_byte(bool imul,DynReg * dyn_ax,DynReg * dr1,Bit8u di1)698 static void gen_mul_byte(bool imul,DynReg * dyn_ax,DynReg * dr1,Bit8u di1) {
699 	ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
700 	GenReg * gr1=FindDynReg(dr1);
701 	if (imul) cache_addw(0xe8f6+((gr1->index+di1)<<8));
702 	else cache_addw(0xe0f6+((gr1->index+di1)<<8));
703 	dyn_ax->flags|=DYNFLG_CHANGED;
704 }
705 
gen_mul_word(bool imul,DynReg * dyn_ax,DynReg * dyn_dx,bool dword,DynReg * dr1)706 static void gen_mul_word(bool imul,DynReg * dyn_ax,DynReg * dyn_dx,bool dword,DynReg * dr1) {
707 	ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
708 	ForceDynReg(x86gen.regs[X86_REG_EDX],dyn_dx);
709 	GenReg * gr1=FindDynReg(dr1);
710 	if (!dword) cache_addb(0x66);
711 	if (imul) cache_addw(0xe8f7+(gr1->index<<8));
712 	else cache_addw(0xe0f7+(gr1->index<<8));
713 	dyn_ax->flags|=DYNFLG_CHANGED;
714 	dyn_dx->flags|=DYNFLG_CHANGED;
715 }
716 
gen_dshift_imm(bool dword,bool left,DynReg * dr1,DynReg * dr2,Bitu imm)717 static void gen_dshift_imm(bool dword,bool left,DynReg * dr1,DynReg * dr2,Bitu imm) {
718 	GenReg * gr1=FindDynReg(dr1);
719 	GenReg * gr2=FindDynReg(dr2);
720 	if (!dword) cache_addb(0x66);
721 	if (left) cache_addw(0xa40f);		//SHLD IMM
722 	else  cache_addw(0xac0f);			//SHRD IMM
723 	cache_addb(0xc0+gr1->index+(gr2->index<<3));
724 	cache_addb(imm);
725 	dr1->flags|=DYNFLG_CHANGED;
726 }
727 
gen_dshift_cl(bool dword,bool left,DynReg * dr1,DynReg * dr2,DynReg * drecx)728 static void gen_dshift_cl(bool dword,bool left,DynReg * dr1,DynReg * dr2,DynReg * drecx) {
729 	ForceDynReg(x86gen.regs[X86_REG_ECX],drecx);
730 	GenReg * gr1=FindDynReg(dr1);
731 	GenReg * gr2=FindDynReg(dr2);
732 	if (!dword) cache_addb(0x66);
733 	if (left) cache_addw(0xa50f);		//SHLD CL
734 	else  cache_addw(0xad0f);			//SHRD CL
735 	cache_addb(0xc0+gr1->index+(gr2->index<<3));
736 	dr1->flags|=DYNFLG_CHANGED;
737 }
738 
gen_call_function(void * func,char const * ops,...)739 static void gen_call_function(void * func,char const* ops,...) {
740 	Bits paramcount=0;
741 	bool release_flags=false;
742 	struct ParamInfo {
743 		const char * line;
744 		Bitu value;
745 	} pinfo[32];
746 	ParamInfo * retparam=0;
747 	/* Clear the EAX Genreg for usage */
748 	x86gen.regs[X86_REG_EAX]->Clear();
749 	x86gen.regs[X86_REG_EAX]->notusable=true;
750 	/* Save the flags */
751 	if (GCC_UNLIKELY(!skip_flags)) gen_protectflags();
752 	/* Scan for the amount of params */
753 	if (ops) {
754 		va_list params;
755 		va_start(params,ops);
756 #if defined (MACOSX)
757 		Bitu stack_used=0;
758 		bool free_flags=false;
759 #endif
760 		Bits pindex=0;
761 		while (*ops) {
762 			if (*ops=='%') {
763 				pinfo[pindex].line=ops+1;
764 				pinfo[pindex].value=va_arg(params,Bitu);
765 #if defined (MACOSX)
766 				const char * scan=pinfo[pindex].line;
767 				if ((*scan=='I') || (*scan=='D')) stack_used+=4;
768 				else if (*scan=='F') free_flags=true;
769 #endif
770 				pindex++;
771 			}
772 			ops++;
773 		}
774 		va_end(params);
775 
776 #if defined (MACOSX)
777 		/* align stack */
778 		stack_used+=4;			// saving esp on stack as well
779 
780 		cache_addw(0xc48b);		// mov eax,esp
781 		cache_addb(0x2d);		// sub eax,stack_used
782 		cache_addd(stack_used);
783 		cache_addw(0xe083);		// and eax,0xfffffff0
784 		cache_addb(0xf0);
785 		cache_addb(0x05);		// sub eax,stack_used
786 		cache_addd(stack_used);
787 		cache_addb(0x94);		// xchg eax,esp
788 		if (free_flags) {
789 			cache_addw(0xc083);	// add eax,4
790 			cache_addb(0x04);
791 		}
792 		cache_addb(0x50);		// push eax (==old esp)
793 #endif
794 
795 		paramcount=0;
796 		while (pindex) {
797 			pindex--;
798 			const char * scan=pinfo[pindex].line;
799 			switch (*scan++) {
800 			case 'I':				/* immediate value */
801 				paramcount++;
802 				cache_addb(0x68);			//Push immediate
803 				cache_addd(pinfo[pindex].value);	//Push value
804 				break;
805 			case 'D':				/* Dynamic register */
806 				{
807 					bool release=false;
808 					paramcount++;
809 					DynReg * dynreg=(DynReg *)pinfo[pindex].value;
810 					GenReg * genreg=FindDynReg(dynreg);
811 					scanagain:
812 					switch (*scan++) {
813 					case 'd':
814 						cache_addb(0x50+genreg->index);		//Push reg
815 						break;
816 					case 'w':
817 						cache_addw(0xb70f);					//MOVZX EAX,reg
818 						cache_addb(0xc0+genreg->index);
819 						cache_addb(0x50);					//Push EAX
820 						break;
821 					case 'l':
822 						cache_addw(0xb60f);					//MOVZX EAX,reg[0]
823 						cache_addb(0xc0+genreg->index);
824 						cache_addb(0x50);					//Push EAX
825 						break;
826 					case 'h':
827 						cache_addw(0xb60f);					//MOVZX EAX,reg[1]
828 						cache_addb(0xc4+genreg->index);
829 						cache_addb(0x50);					//Push EAX
830 						break;
831 					case 'r':								/* release the reg afterwards */
832 						release=true;
833 						goto scanagain;
834 					default:
835 						IllegalOption("gen_call_function param:DREG");
836 					}
837 					if (release) gen_releasereg(dynreg);
838 				}
839 				break;
840 			case 'R':				/* Dynamic register to get the return value */
841 				retparam =&pinfo[pindex];
842 				pinfo[pindex].line=scan;
843 				break;
844 			case 'F':				/* Release flags from stack */
845 				release_flags=true;
846 				break;
847 			default:
848 				IllegalOption("gen_call_function unknown param");
849 			}
850 		}
851 #if defined (MACOSX)
852 		if (free_flags) release_flags=false;
853 	} else {
854 		/* align stack */
855 		Bit32u stack_used=8;	// saving esp and return address on the stack
856 
857 		cache_addw(0xc48b);		// mov eax,esp
858 		cache_addb(0x2d);		// sub eax,stack_used
859 		cache_addd(stack_used);
860 		cache_addw(0xe083);		// and eax,0xfffffff0
861 		cache_addb(0xf0);
862 		cache_addb(0x05);		// sub eax,stack_used
863 		cache_addd(stack_used);
864 		cache_addb(0x94);		// xchg eax,esp
865 		cache_addb(0x50);		// push esp (==old esp)
866 #endif
867 	}
868 
869 	/* Clear some unprotected registers */
870 	x86gen.regs[X86_REG_ECX]->Clear();
871 	x86gen.regs[X86_REG_EDX]->Clear();
872 	/* Make sure reg_esp is current */
873 	if (DynRegs[G_ESP].flags & DYNFLG_CHANGED)
874 		DynRegs[G_ESP].genreg->Save();
875 	/* Do the actual call to the procedure */
876 	cache_addb(0xe8);
877 	cache_addd((Bit32u)func - (Bit32u)cache.pos-4);
878 	/* Restore the params of the stack */
879 	if (paramcount) {
880 		cache_addw(0xc483);				//add ESP,imm byte
881 		cache_addb(paramcount*4+(release_flags?4:0));
882 	} else if (release_flags) {
883 		cache_addw(0xc483);				//add ESP,imm byte
884 		cache_addb(4);
885 	}
886 	/* Save the return value in correct register */
887 	if (retparam) {
888 		DynReg * dynreg=(DynReg *)retparam->value;
889 		GenReg * genreg=FindDynReg(dynreg);
890 		if (genreg->index)		// test for (e)ax/al
891 		switch (*retparam->line) {
892 		case 'd':
893 			cache_addw(0xc08b+(genreg->index <<(8+3)));	//mov reg,eax
894 			break;
895 		case 'w':
896 			cache_addb(0x66);
897 			cache_addw(0xc08b+(genreg->index <<(8+3)));	//mov reg,eax
898 			break;
899 		case 'l':
900 			cache_addw(0xc08a+(genreg->index <<(8+3)));	//mov reg,eax
901 			break;
902 		case 'h':
903 			cache_addw(0xc08a+((genreg->index+4) <<(8+3)));	//mov reg,eax
904 			break;
905 		}
906 		dynreg->flags|=DYNFLG_CHANGED;
907 	}
908 	/* Restore EAX registers to be used again */
909 	x86gen.regs[X86_REG_EAX]->notusable=false;
910 
911 #if defined (MACOSX)
912 	/* restore stack */
913 	cache_addb(0x5c);	// pop esp
914 #endif
915 }
916 
gen_call_write(DynReg * dr,Bit32u val,Bitu write_size)917 static void gen_call_write(DynReg * dr,Bit32u val,Bitu write_size) {
918 	/* Clear the EAX Genreg for usage */
919 	x86gen.regs[X86_REG_EAX]->Clear();
920 	x86gen.regs[X86_REG_EAX]->notusable=true;
921 	gen_protectflags();
922 
923 #if defined (MACOSX)
924 	/* align stack */
925 	Bitu stack_used=12;
926 
927 	cache_addw(0xc48b);		// mov eax,esp
928 	cache_addb(0x2d);		// sub eax,stack_used
929 	cache_addd(stack_used);
930 	cache_addw(0xe083);		// and eax,0xfffffff0
931 	cache_addb(0xf0);
932 	cache_addb(0x05);		// sub eax,stack_used
933 	cache_addd(stack_used);
934 	cache_addb(0x94);		// xchg eax,esp
935 	cache_addb(0x50);		// push eax (==old esp)
936 #endif
937 
938 	cache_addb(0x68);	//PUSH val
939 	cache_addd(val);
940 	GenReg * genreg=FindDynReg(dr);
941 	cache_addb(0x50+genreg->index);		//PUSH reg
942 
943 	/* Clear some unprotected registers */
944 	x86gen.regs[X86_REG_ECX]->Clear();
945 	x86gen.regs[X86_REG_EDX]->Clear();
946 	/* Make sure reg_esp is current */
947 	if (DynRegs[G_ESP].flags & DYNFLG_CHANGED)
948 		DynRegs[G_ESP].genreg->Save();
949 	/* Do the actual call to the procedure */
950 	cache_addb(0xe8);
951 	switch (write_size) {
952 		case 1: cache_addd((Bit32u)mem_writeb_checked - (Bit32u)cache.pos-4); break;
953 		case 2: cache_addd((Bit32u)mem_writew_checked - (Bit32u)cache.pos-4); break;
954 		case 4: cache_addd((Bit32u)mem_writed_checked - (Bit32u)cache.pos-4); break;
955 		default: IllegalOption("gen_call_write");
956 	}
957 
958 	cache_addw(0xc483);		//ADD ESP,8
959 	cache_addb(2*4);
960 	x86gen.regs[X86_REG_EAX]->notusable=false;
961 	gen_releasereg(dr);
962 
963 #if defined (MACOSX)
964 	/* restore stack */
965 	cache_addb(0x5c);	// pop esp
966 #endif
967 }
968 
gen_create_branch(BranchTypes type)969 static const Bit8u * gen_create_branch(BranchTypes type) {
970 	/* First free all registers */
971 	cache_addw(0x70+type);
972 	return (cache.pos-1);
973 }
974 
975 static void gen_fill_branch(const Bit8u * data,const Bit8u * from=cache.pos) {
976 #if C_DEBUG
977 	Bits len=from-data;
978 	if (len<0) len=-len;
979 	if (len>126) LOG_MSG("Big jump %d",len);
980 #endif
981 	cache_addb((Bit8u)(from-data-1),data);
982 }
983 
gen_create_branch_long(BranchTypes type)984 static const Bit8u * gen_create_branch_long(BranchTypes type) {
985 	cache_addw(0x800f+(type<<8));
986 	cache_addd(0);
987 	return (cache.pos-4);
988 }
989 
990 static void gen_fill_branch_long(const Bit8u * data,const Bit8u * from=cache.pos) {
991 	cache_addd((Bit32u)(from-data-4),data);
992 }
993 
994 static const Bit8u * gen_create_jump(const Bit8u * to=0) {
995 	/* First free all registers */
996 	cache_addb(0xe9);
997 	cache_addd(to-(cache.pos+4));
998 	return (cache.pos-4);
999 }
1000 
1001 static void gen_fill_jump(const Bit8u * data,const Bit8u * to=cache.pos) {
1002 	gen_fill_branch_long(data,to);
1003 }
1004 
1005 
1006 static void gen_jmp_ptr(void * ptr,Bits imm=0) {
1007 	cache_addb(0xa1);
1008 	cache_addd((Bit32u)ptr);
1009 	cache_addb(0xff);		//JMP EA
1010 	if (!imm) {			//NO EBP
1011 		cache_addb(0x20);
1012     } else if ((imm>=-128 && imm<=127)) {
1013 		cache_addb(0x60);
1014 		cache_addb(imm);
1015 	} else {
1016 		cache_addb(0xa0);
1017 		cache_addd(imm);
1018 	}
1019 }
1020 
gen_save_flags(DynReg * dynreg)1021 static void gen_save_flags(DynReg * dynreg) {
1022 	if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_save_flags");
1023 	GenReg * genreg=FindDynReg(dynreg);
1024 	cache_addb(0x8b);					//MOV REG,[esp]
1025 	cache_addw(0x2404+(genreg->index << 3));
1026 	dynreg->flags|=DYNFLG_CHANGED;
1027 }
1028 
gen_load_flags(DynReg * dynreg)1029 static void gen_load_flags(DynReg * dynreg) {
1030 	if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_load_flags");
1031 	cache_addw(0xc483);				//ADD ESP,4
1032 	cache_addb(0x4);
1033 	GenReg * genreg=FindDynReg(dynreg);
1034 	cache_addb(0x50+genreg->index);		//PUSH 32
1035 }
1036 
gen_save_host_direct(void * data,Bits imm)1037 static void gen_save_host_direct(void * data,Bits imm) {
1038 	cache_addw(0x05c7);		//MOV [],dword
1039 	cache_addd((Bit32u)data);
1040 	cache_addd(imm);
1041 }
1042 
gen_return(BlockReturn retcode)1043 static void gen_return(BlockReturn retcode) {
1044 	gen_protectflags();
1045 	cache_addb(0x59);			//POP ECX, the flags
1046 	if (retcode==0) cache_addw(0xc033);		//MOV EAX, 0
1047 	else {
1048 		cache_addb(0xb8);		//MOV EAX, retcode
1049 		cache_addd(retcode);
1050 	}
1051 	cache_addb(0xc3);			//RET
1052 }
1053 
1054 static void gen_return_fast(BlockReturn retcode,bool ret_exception=false) {
1055 	if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_return_fast");
1056 	cache_addw(0x0d8b);			//MOV ECX, the flags
1057 	cache_addd((Bit32u)&cpu_regs.flags);
1058 	if (!ret_exception) {
1059 		cache_addw(0xc483);			//ADD ESP,4
1060 		cache_addb(0x4);
1061 		if (retcode==0) cache_addw(0xc033);		//MOV EAX, 0
1062 		else {
1063 			cache_addb(0xb8);		//MOV EAX, retcode
1064 			cache_addd(retcode);
1065 		}
1066 	}
1067 	cache_addb(0xc3);			//RET
1068 }
1069 
gen_init(void)1070 static void gen_init(void) {
1071 	x86gen.regs[X86_REG_EAX]=new GenReg(0);
1072 	x86gen.regs[X86_REG_ECX]=new GenReg(1);
1073 	x86gen.regs[X86_REG_EDX]=new GenReg(2);
1074 	x86gen.regs[X86_REG_EBX]=new GenReg(3);
1075 	x86gen.regs[X86_REG_EBP]=new GenReg(5);
1076 	x86gen.regs[X86_REG_ESI]=new GenReg(6);
1077 	x86gen.regs[X86_REG_EDI]=new GenReg(7);
1078 }
1079 
1080 #if defined(X86_DYNFPU_DH_ENABLED)
gen_dh_fpu_save(void)1081 static void gen_dh_fpu_save(void)
1082 #if defined (_MSC_VER)
1083 {
1084 	__asm {
1085 	__asm	fnsave	dyn_dh_fpu.state
1086 	__asm	fldcw	dyn_dh_fpu.host_cw
1087 	}
1088 	dyn_dh_fpu.state_used=false;
1089 	dyn_dh_fpu.state.cw|=0x3f;
1090 }
1091 #else
1092 {
1093 	__asm__ volatile (
1094 		"fnsave		%0			\n"
1095 		"fldcw		%1			\n"
1096 		:	"=m" (dyn_dh_fpu.state)
1097 		:	"m" (dyn_dh_fpu.host_cw)
1098 		:	"memory"
1099 	);
1100 	dyn_dh_fpu.state_used=false;
1101 	dyn_dh_fpu.state.cw|=0x3f;
1102 }
1103 #endif
1104 #endif
1105