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 #ifndef DOSBOX_DYN_FPU_H
20 #define DOSBOX_DYN_FPU_H
21 
22 #include "dosbox.h"
23 
24 #if C_FPU
25 
26 #include <math.h>
27 #include <float.h>
28 #include "cross.h"
29 #include "mem.h"
30 #include "fpu.h"
31 #include "cpu.h"
32 
33 
FPU_FDECSTP()34 static void FPU_FDECSTP(){
35 	TOP = (TOP - 1) & 7;
36 }
37 
FPU_FINCSTP()38 static void FPU_FINCSTP(){
39 	TOP = (TOP + 1) & 7;
40 }
41 
FPU_FNSTCW(PhysPt addr)42 static void FPU_FNSTCW(PhysPt addr){
43 	mem_writew(addr,fpu.cw);
44 }
45 
FPU_FFREE(Bitu st)46 static void FPU_FFREE(Bitu st) {
47 	fpu.tags[st]=TAG_Empty;
48 }
49 
50 
51 #if C_FPU_X86
52 #include "../../fpu/fpu_instructions_x86.h"
53 #else
54 #include "../../fpu/fpu_instructions.h"
55 #endif
56 
57 
58 #define dyn_fpu_top() {				\
59 	gen_protectflags();				\
60 	gen_load_host(&TOP,DREG(EA),4); \
61 	gen_dop_word_imm(DOP_ADD,true,DREG(EA),decode.modrm.rm);	\
62 	gen_dop_word_imm(DOP_AND,true,DREG(EA),7);	\
63 	gen_load_host(&TOP,DREG(TMPB),4);			\
64 }
65 
dyn_eatree()66 static void dyn_eatree()
67 {
68 	const unsigned group = (decode.modrm.val >> 3) & 7;
69 	switch (group) {
70 	case 0x00:		/* FADD ST,STi */
71 		gen_call_function((void*)&FPU_FADD_EA,"%Drd",DREG(TMPB));
72 		break;
73 	case 0x01:		/* FMUL  ST,STi */
74 		gen_call_function((void*)&FPU_FMUL_EA,"%Drd",DREG(TMPB));
75 		break;
76 	case 0x02:		/* FCOM  STi */
77 		gen_call_function((void*)&FPU_FCOM_EA,"%Drd",DREG(TMPB));
78 		break;
79 	case 0x03:		/* FCOMP STi */
80 		gen_call_function((void*)&FPU_FCOM_EA,"%Drd",DREG(TMPB));
81 		gen_call_function((void*)&FPU_FPOP,"");
82 		break;
83 	case 0x04:		/* FSUB  ST,STi */
84 		gen_call_function((void*)&FPU_FSUB_EA,"%Drd",DREG(TMPB));
85 		break;
86 	case 0x05:		/* FSUBR ST,STi */
87 		gen_call_function((void*)&FPU_FSUBR_EA,"%Drd",DREG(TMPB));
88 		break;
89 	case 0x06:		/* FDIV  ST,STi */
90 		gen_call_function((void*)&FPU_FDIV_EA,"%Drd",DREG(TMPB));
91 		break;
92 	case 0x07:		/* FDIVR ST,STi */
93 		gen_call_function((void*)&FPU_FDIVR_EA,"%Drd",DREG(TMPB));
94 		break;
95 	default:
96 		break;
97 	}
98 }
99 
dyn_fpu_esc0()100 static void dyn_fpu_esc0()
101 {
102 	dyn_get_modrm();
103 	if (decode.modrm.val >= 0xc0) {
104 		dyn_fpu_top();
105 		const unsigned group = (decode.modrm.val >> 3) & 7;
106 		switch (group) {
107 		case 0x00:		//FADD ST,STi /
108 			gen_call_function((void*)&FPU_FADD,"%Drd%Drd",DREG(TMPB),DREG(EA));
109 			break;
110 		case 0x01:		// FMUL  ST,STi /
111 			gen_call_function((void*)&FPU_FMUL,"%Drd%Drd",DREG(TMPB),DREG(EA));
112 			break;
113 		case 0x02:		// FCOM  STi /
114 			gen_call_function((void*)&FPU_FCOM,"%Drd%Drd",DREG(TMPB),DREG(EA));
115 			break;
116 		case 0x03:		// FCOMP STi /
117 			gen_call_function((void*)&FPU_FCOM,"%Drd%Drd",DREG(TMPB),DREG(EA));
118 			gen_call_function((void*)&FPU_FPOP,"");
119 			break;
120 		case 0x04:		// FSUB  ST,STi /
121 			gen_call_function((void*)&FPU_FSUB,"%Drd%Drd",DREG(TMPB),DREG(EA));
122 			break;
123 		case 0x05:		// FSUBR ST,STi /
124 			gen_call_function((void*)&FPU_FSUBR,"%Drd%Drd",DREG(TMPB),DREG(EA));
125 			break;
126 		case 0x06:		// FDIV  ST,STi /
127 			gen_call_function((void*)&FPU_FDIV,"%Drd%Drd",DREG(TMPB),DREG(EA));
128 			break;
129 		case 0x07:		// FDIVR ST,STi /
130 			gen_call_function((void*)&FPU_FDIVR,"%Drd%Drd",DREG(TMPB),DREG(EA));
131 			break;
132 		default:
133 			break;
134 		}
135 	} else {
136 		dyn_fill_ea();
137 		gen_call_function((void*)&FPU_FLD_F32_EA,"%Drd",DREG(EA));
138 		gen_load_host(&TOP,DREG(TMPB),4);
139 		dyn_eatree();
140 	}
141 }
142 
dyn_fpu_esc1()143 static void dyn_fpu_esc1()
144 {
145 	dyn_get_modrm();
146 	const unsigned group = (decode.modrm.val >> 3) & 7;
147 	const unsigned sub = (decode.modrm.val & 7);
148 	if (decode.modrm.val >= 0xc0) {
149 		switch (group) {
150 		case 0x00: /* FLD STi */
151 			gen_protectflags();
152 			gen_load_host(&TOP,DREG(EA),4);
153 			gen_dop_word_imm(DOP_ADD,true,DREG(EA),decode.modrm.rm);
154 			gen_dop_word_imm(DOP_AND,true,DREG(EA),7);
155 			gen_call_function((void*)&FPU_PREP_PUSH,"");
156 			gen_load_host(&TOP,DREG(TMPB),4);
157 			gen_call_function((void*)&FPU_FST,"%Drd%Drd",DREG(EA),DREG(TMPB));
158 			break;
159 		case 0x01: /* FXCH STi */
160 			dyn_fpu_top();
161 			gen_call_function((void*)&FPU_FXCH,"%Drd%Drd",DREG(TMPB),DREG(EA));
162 			break;
163 		case 0x02: /* FNOP */
164 			gen_call_function((void*)&FPU_FNOP,"");
165 			break;
166 		case 0x03: /* FSTP STi */
167 			dyn_fpu_top();
168 			gen_call_function((void*)&FPU_FST,"%Drd%Drd",DREG(TMPB),DREG(EA));
169 			gen_call_function((void*)&FPU_FPOP,"");
170 			break;
171 		case 0x04:
172 			switch(sub){
173 			case 0x00:       /* FCHS */
174 				gen_call_function((void*)&FPU_FCHS,"");
175 				break;
176 			case 0x01:       /* FABS */
177 				gen_call_function((void*)&FPU_FABS,"");
178 				break;
179 			case 0x02:       /* UNKNOWN */
180 			case 0x03:       /* ILLEGAL */
181 				FPU_LOG_WARN(1,false,group,sub);
182 				break;
183 			case 0x04:       /* FTST */
184 				gen_call_function((void*)&FPU_FTST,"");
185 				break;
186 			case 0x05:       /* FXAM */
187 				gen_call_function((void*)&FPU_FXAM,"");
188 				break;
189 			case 0x06:       /* FTSTP (cyrix)*/
190 			case 0x07:       /* UNKNOWN */
191 				FPU_LOG_WARN(1,false,group,sub);
192 				break;
193 			}
194 			break;
195 		case 0x05:
196 			switch(sub){
197 			case 0x00:       /* FLD1 */
198 				gen_call_function((void*)&FPU_FLD1,"");
199 				break;
200 			case 0x01:       /* FLDL2T */
201 				gen_call_function((void*)&FPU_FLDL2T,"");
202 				break;
203 			case 0x02:       /* FLDL2E */
204 				gen_call_function((void*)&FPU_FLDL2E,"");
205 				break;
206 			case 0x03:       /* FLDPI */
207 				gen_call_function((void*)&FPU_FLDPI,"");
208 				break;
209 			case 0x04:       /* FLDLG2 */
210 				gen_call_function((void*)&FPU_FLDLG2,"");
211 				break;
212 			case 0x05:       /* FLDLN2 */
213 				gen_call_function((void*)&FPU_FLDLN2,"");
214 				break;
215 			case 0x06:       /* FLDZ*/
216 				gen_call_function((void*)&FPU_FLDZ,"");
217 				break;
218 			case 0x07:       /* ILLEGAL */
219 				FPU_LOG_WARN(1,false,group,sub);
220 				break;
221 			}
222 			break;
223 		case 0x06:
224 			switch(sub){
225 			case 0x00:	/* F2XM1 */
226 				gen_call_function((void*)&FPU_F2XM1,"");
227 				break;
228 			case 0x01:	/* FYL2X */
229 				gen_call_function((void*)&FPU_FYL2X,"");
230 				break;
231 			case 0x02:	/* FPTAN  */
232 				gen_call_function((void*)&FPU_FPTAN,"");
233 				break;
234 			case 0x03:	/* FPATAN */
235 				gen_call_function((void*)&FPU_FPATAN,"");
236 				break;
237 			case 0x04:	/* FXTRACT */
238 				gen_call_function((void*)&FPU_FXTRACT,"");
239 				break;
240 			case 0x05:	/* FPREM1 */
241 				gen_call_function((void*)&FPU_FPREM1,"");
242 				break;
243 			case 0x06:	/* FDECSTP */
244 				gen_call_function((void*)&FPU_FDECSTP,"");
245 				break;
246 			case 0x07:	/* FINCSTP */
247 				gen_call_function((void*)&FPU_FINCSTP,"");
248 				break;
249 			default:
250 				FPU_LOG_WARN(1,false,group,sub);
251 				break;
252 			}
253 			break;
254 		case 0x07:
255 			switch(sub){
256 			case 0x00:		/* FPREM */
257 				gen_call_function((void*)&FPU_FPREM,"");
258 				break;
259 			case 0x01:		/* FYL2XP1 */
260 				gen_call_function((void*)&FPU_FYL2XP1,"");
261 				break;
262 			case 0x02:		/* FSQRT */
263 				gen_call_function((void*)&FPU_FSQRT,"");
264 				break;
265 			case 0x03:		/* FSINCOS */
266 				gen_call_function((void*)&FPU_FSINCOS,"");
267 				break;
268 			case 0x04:		/* FRNDINT */
269 				gen_call_function((void*)&FPU_FRNDINT,"");
270 				break;
271 			case 0x05:		/* FSCALE */
272 				gen_call_function((void*)&FPU_FSCALE,"");
273 				break;
274 			case 0x06:		/* FSIN */
275 				gen_call_function((void*)&FPU_FSIN,"");
276 				break;
277 			case 0x07:		/* FCOS */
278 				gen_call_function((void*)&FPU_FCOS,"");
279 				break;
280 			default:
281 				FPU_LOG_WARN(1,false,group,sub);
282 				break;
283 			}
284 			break;
285 		default:
286 			FPU_LOG_WARN(1,false,group,sub);
287 			break;
288 		}
289 	} else {
290 		dyn_fill_ea();
291 		switch (group) {
292 		case 0x00: /* FLD float*/
293 			gen_protectflags();
294 			gen_call_function((void*)&FPU_PREP_PUSH,"");
295 			gen_load_host(&TOP,DREG(TMPB),4);
296 			gen_call_function((void*)&FPU_FLD_F32,"%Drd%Drd",DREG(EA),DREG(TMPB));
297 			break;
298 		case 0x01: /* UNKNOWN */
299 			FPU_LOG_WARN(1,true,group,sub);
300 			break;
301 		case 0x02: /* FST float*/
302 			gen_call_function((void*)&FPU_FST_F32,"%Drd",DREG(EA));
303 			break;
304 		case 0x03: /* FSTP float*/
305 			gen_call_function((void*)&FPU_FST_F32,"%Drd",DREG(EA));
306 			gen_call_function((void*)&FPU_FPOP,"");
307 			break;
308 		case 0x04: /* FLDENV */
309 			gen_call_function((void*)&FPU_FLDENV,"%Drd",DREG(EA));
310 			break;
311 		case 0x05: /* FLDCW */
312 			gen_call_function((void *)&FPU_FLDCW,"%Drd",DREG(EA));
313 			break;
314 		case 0x06: /* FSTENV */
315 			gen_call_function((void *)&FPU_FSTENV,"%Drd",DREG(EA));
316 			break;
317 		case 0x07:  /* FNSTCW*/
318 			gen_call_function((void *)&FPU_FNSTCW,"%Drd",DREG(EA));
319 			break;
320 		default:
321 			FPU_LOG_WARN(1,true,group,sub);
322 			break;
323 		}
324 	}
325 }
326 
dyn_fpu_esc2()327 static void dyn_fpu_esc2()
328 {
329 	dyn_get_modrm();
330 	if (decode.modrm.val >= 0xc0) {
331 		const unsigned group = (decode.modrm.val >> 3) & 7;
332 		const unsigned sub = (decode.modrm.val & 7);
333 		switch (group) {
334 		case 0x05:
335 			switch (sub) {
336 			case 0x01:		/* FUCOMPP */
337 				gen_protectflags();
338 				gen_load_host(&TOP,DREG(EA),4);
339 				gen_dop_word_imm(DOP_ADD,true,DREG(EA),1);
340 				gen_dop_word_imm(DOP_AND,true,DREG(EA),7);
341 				gen_load_host(&TOP,DREG(TMPB),4);
342 				gen_call_function((void *)&FPU_FUCOM,"%Drd%Drd",DREG(TMPB),DREG(EA));
343 				gen_call_function((void *)&FPU_FPOP,"");
344 				gen_call_function((void *)&FPU_FPOP,"");
345 				break;
346 			default:
347 				FPU_LOG_WARN(2,false,5,sub);
348 				break;
349 			}
350 			break;
351 		default:
352 			FPU_LOG_WARN(2,false,group,sub);
353 			break;
354 		}
355 	} else {
356 		dyn_fill_ea();
357 		gen_call_function((void*)&FPU_FLD_I32_EA,"%Drd",DREG(EA));
358 		gen_load_host(&TOP,DREG(TMPB),4);
359 		dyn_eatree();
360 	}
361 }
362 
dyn_fpu_esc3()363 static void dyn_fpu_esc3()
364 {
365 	dyn_get_modrm();
366 	const unsigned group = (decode.modrm.val >> 3) & 7;
367 	const unsigned sub = (decode.modrm.val & 7);
368 	if (decode.modrm.val >= 0xc0) {
369 		switch (group) {
370 		case 0x04:
371 			switch (sub) {
372 			case 0x00:				//FNENI
373 			case 0x01:				//FNDIS
374 				LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfunction: %u", sub);
375 				break;
376 			case 0x02:				//FNCLEX FCLEX
377 				gen_call_function((void*)&FPU_FCLEX,"");
378 				break;
379 			case 0x03:				//FNINIT FINIT
380 				gen_call_function((void*)&FPU_FINIT,"");
381 				break;
382 			case 0x04:				//FNSETPM
383 			case 0x05:				//FRSTPM
384 				// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done");
385 				break;
386 			default:
387 				E_Exit("ESC 3:ILLEGAL OPCODE group %u subfunction %u", group, sub);
388 			}
389 			break;
390 		default:
391 			FPU_LOG_WARN(3, false, group, sub);
392 			break;
393 		}
394 	} else {
395 		dyn_fill_ea();
396 		switch (group) {
397 		case 0x00:	/* FILD */
398 			gen_call_function((void*)&FPU_PREP_PUSH,"");
399 			gen_protectflags();
400 			gen_load_host(&TOP,DREG(TMPB),4);
401 			gen_call_function((void*)&FPU_FLD_I32,"%Drd%Drd",DREG(EA),DREG(TMPB));
402 			break;
403 		case 0x01:	/* FISTTP */
404 			FPU_LOG_WARN(3, false, 1, sub);
405 			break;
406 		case 0x02:	/* FIST */
407 			gen_call_function((void*)&FPU_FST_I32,"%Drd",DREG(EA));
408 			break;
409 		case 0x03:	/* FISTP */
410 			gen_call_function((void*)&FPU_FST_I32,"%Drd",DREG(EA));
411 			gen_call_function((void*)&FPU_FPOP,"");
412 			break;
413 		case 0x05:	/* FLD 80 Bits Real */
414 			gen_call_function((void*)&FPU_PREP_PUSH,"");
415 			gen_call_function((void*)&FPU_FLD_F80,"%Drd",DREG(EA));
416 			break;
417 		case 0x07:	/* FSTP 80 Bits Real */
418 			gen_call_function((void*)&FPU_FST_F80,"%Drd",DREG(EA));
419 			gen_call_function((void*)&FPU_FPOP,"");
420 			break;
421 		default:
422 			FPU_LOG_WARN(3, true, group, sub);
423 			break;
424 		}
425 	}
426 }
427 
dyn_fpu_esc4()428 static void dyn_fpu_esc4()
429 {
430 	dyn_get_modrm();
431 	const unsigned group = (decode.modrm.val >> 3) & 7;
432 	if (decode.modrm.val >= 0xc0) {
433 		dyn_fpu_top();
434 		switch (group) {
435 		case 0x00:	/* FADD STi,ST*/
436 			gen_call_function((void*)&FPU_FADD,"%Drd%Drd",DREG(EA),DREG(TMPB));
437 			break;
438 		case 0x01:	/* FMUL STi,ST*/
439 			gen_call_function((void*)&FPU_FMUL,"%Drd%Drd",DREG(EA),DREG(TMPB));
440 			break;
441 		case 0x02:  /* FCOM*/
442 			gen_call_function((void*)&FPU_FCOM,"%Drd%Drd",DREG(TMPB),DREG(EA));
443 			break;
444 		case 0x03:  /* FCOMP*/
445 			gen_call_function((void*)&FPU_FCOM,"%Drd%Drd",DREG(TMPB),DREG(EA));
446 			gen_call_function((void*)&FPU_FPOP,"");
447 			break;
448 		case 0x04:  /* FSUBR STi,ST*/
449 			gen_call_function((void*)&FPU_FSUBR,"%Drd%Drd",DREG(EA),DREG(TMPB));
450 			break;
451 		case 0x05:  /* FSUB  STi,ST*/
452 			gen_call_function((void*)&FPU_FSUB,"%Drd%Drd",DREG(EA),DREG(TMPB));
453 			break;
454 		case 0x06:  /* FDIVR STi,ST*/
455 			gen_call_function((void*)&FPU_FDIVR,"%Drd%Drd",DREG(EA),DREG(TMPB));
456 			break;
457 		case 0x07:  /* FDIV STi,ST*/
458 			gen_call_function((void*)&FPU_FDIV,"%Drd%Drd",DREG(EA),DREG(TMPB));
459 			break;
460 		default:
461 			break;
462 		}
463 	} else {
464 		dyn_fill_ea();
465 		gen_call_function((void*)&FPU_FLD_F64_EA,"%Drd",DREG(EA));
466 		gen_load_host(&TOP,DREG(TMPB),4);
467 		dyn_eatree();
468 	}
469 }
470 
dyn_fpu_esc5()471 static void dyn_fpu_esc5()
472 {
473 	dyn_get_modrm();
474 	const unsigned group = (decode.modrm.val >> 3) & 7;
475 	const unsigned sub = (decode.modrm.val & 7);
476 	if (decode.modrm.val >= 0xc0) {
477 		dyn_fpu_top();
478 		switch (group) {
479 		case 0x00: /* FFREE STi */
480 			gen_call_function((void*)&FPU_FFREE,"%Drd",DREG(EA));
481 			break;
482 		case 0x01: /* FXCH STi*/
483 			gen_call_function((void*)&FPU_FXCH,"%Drd%Drd",DREG(TMPB),DREG(EA));
484 			break;
485 		case 0x02: /* FST STi */
486 			gen_call_function((void*)&FPU_FST,"%Drd%Drd",DREG(TMPB),DREG(EA));
487 			break;
488 		case 0x03:  /* FSTP STi*/
489 			gen_call_function((void*)&FPU_FST,"%Drd%Drd",DREG(TMPB),DREG(EA));
490 			gen_call_function((void*)&FPU_FPOP,"");
491 			break;
492 		case 0x04:	/* FUCOM STi */
493 			gen_call_function((void*)&FPU_FUCOM,"%Drd%Drd",DREG(TMPB),DREG(EA));
494 			break;
495 		case 0x05:	/*FUCOMP STi */
496 			gen_call_function((void*)&FPU_FUCOM,"%Drd%Drd",DREG(TMPB),DREG(EA));
497 			gen_call_function((void*)&FPU_FPOP,"");
498 			break;
499 		default:
500 			FPU_LOG_WARN(5,false,group,sub);
501 			break;
502 		}
503 		gen_releasereg(DREG(EA));
504 		gen_releasereg(DREG(TMPB));
505 	} else {
506 		dyn_fill_ea();
507 		switch (group) {
508 		case 0x00:  /* FLD double real*/
509 			gen_call_function((void*)&FPU_PREP_PUSH,"");
510 			gen_protectflags();
511 			gen_load_host(&TOP,DREG(TMPB),4);
512 			gen_call_function((void*)&FPU_FLD_F64,"%Drd%Drd",DREG(EA),DREG(TMPB));
513 			break;
514 		case 0x01:  /* FISTTP longint*/
515 			FPU_LOG_WARN(5,true,1,sub);
516 			break;
517 		case 0x02:   /* FST double real*/
518 			gen_call_function((void*)&FPU_FST_F64,"%Drd",DREG(EA));
519 			break;
520 		case 0x03:	/* FSTP double real*/
521 			gen_call_function((void*)&FPU_FST_F64,"%Drd",DREG(EA));
522 			gen_call_function((void*)&FPU_FPOP,"");
523 			break;
524 		case 0x04:	/* FRSTOR */
525 			gen_call_function((void*)&FPU_FRSTOR,"%Drd",DREG(EA));
526 			break;
527 		case 0x06:	/* FSAVE */
528 			gen_call_function((void*)&FPU_FSAVE,"%Drd",DREG(EA));
529 			break;
530 		case 0x07:   /*FNSTSW */
531 			gen_protectflags();
532 			gen_load_host(&TOP,DREG(TMPB),4);
533 			gen_call_function((void*)&FPU_SET_TOP,"%Dd",DREG(TMPB));
534 			gen_load_host(&fpu.sw,DREG(TMPB),4);
535 			gen_call_function((void*)&mem_writew,"%Drd%Drd",DREG(EA),DREG(TMPB));
536 			break;
537 		default:
538 			FPU_LOG_WARN(5,true,group,sub);
539 			break;
540 		}
541 	}
542 }
543 
dyn_fpu_esc6()544 static void dyn_fpu_esc6()
545 {
546 	dyn_get_modrm();
547 	const unsigned group = (decode.modrm.val >> 3) & 7;
548 	const unsigned sub = (decode.modrm.val & 7);
549 	if (decode.modrm.val >= 0xc0) {
550 		dyn_fpu_top();
551 		switch (group) {
552 		case 0x00:	/*FADDP STi,ST*/
553 			gen_call_function((void*)&FPU_FADD,"%Drd%Drd",DREG(EA),DREG(TMPB));
554 			break;
555 		case 0x01:	/* FMULP STi,ST*/
556 			gen_call_function((void*)&FPU_FMUL,"%Drd%Drd",DREG(EA),DREG(TMPB));
557 			break;
558 		case 0x02:  /* FCOMP5*/
559 			gen_call_function((void*)&FPU_FCOM,"%Drd%Drd",DREG(TMPB),DREG(EA));
560 			break;	/* TODO IS THIS ALLRIGHT ????????? */
561 		case 0x03:  /*FCOMPP*/
562 			if(sub != 1) {
563 				FPU_LOG_WARN(6,false,3,sub);
564 				return;
565 			}
566 			gen_load_host(&TOP,DREG(EA),4);
567 			gen_dop_word_imm(DOP_ADD,true,DREG(EA),1);
568 			gen_dop_word_imm(DOP_AND,true,DREG(EA),7);
569 			gen_call_function((void*)&FPU_FCOM,"%Drd%Drd",DREG(TMPB),DREG(EA));
570 			gen_call_function((void*)&FPU_FPOP,""); /* extra pop at the bottom*/
571 			break;
572 		case 0x04:  /* FSUBRP STi,ST*/
573 			gen_call_function((void*)&FPU_FSUBR,"%Drd%Drd",DREG(EA),DREG(TMPB));
574 			break;
575 		case 0x05:  /* FSUBP  STi,ST*/
576 			gen_call_function((void*)&FPU_FSUB,"%Drd%Drd",DREG(EA),DREG(TMPB));
577 			break;
578 		case 0x06:	/* FDIVRP STi,ST*/
579 			gen_call_function((void*)&FPU_FDIVR,"%Drd%Drd",DREG(EA),DREG(TMPB));
580 			break;
581 		case 0x07:  /* FDIVP STi,ST*/
582 			gen_call_function((void*)&FPU_FDIV,"%Drd%Drd",DREG(EA),DREG(TMPB));
583 			break;
584 		default:
585 			break;
586 		}
587 		gen_call_function((void *)&FPU_FPOP, "");
588 	} else {
589 		dyn_fill_ea();
590 		gen_call_function((void*)&FPU_FLD_I16_EA,"%Drd",DREG(EA));
591 		gen_load_host(&TOP,DREG(TMPB),4);
592 		dyn_eatree();
593 	}
594 }
595 
dyn_fpu_esc7()596 static void dyn_fpu_esc7()
597 {
598 	dyn_get_modrm();
599 	const unsigned group = (decode.modrm.val >> 3) & 7;
600 	const unsigned sub = (decode.modrm.val & 7);
601 	if (decode.modrm.val >= 0xc0) {
602 		switch (group) {
603 		case 0x00: /* FFREEP STi*/
604 			dyn_fpu_top();
605 			gen_call_function((void*)&FPU_FFREE,"%Drd",DREG(EA));
606 			gen_call_function((void*)&FPU_FPOP,"");
607 			break;
608 		case 0x01: /* FXCH STi*/
609 			dyn_fpu_top();
610 			gen_call_function((void*)&FPU_FXCH,"%Drd%Drd",DREG(TMPB),DREG(EA));
611 			break;
612 		case 0x02:  /* FSTP STi*/
613 		case 0x03:  /* FSTP STi*/
614 			dyn_fpu_top();
615 			gen_call_function((void*)&FPU_FST,"%Drd%Drd",DREG(TMPB),DREG(EA));
616 			gen_call_function((void*)&FPU_FPOP,"");
617 			break;
618 		case 0x04:
619 			switch(sub){
620 				case 0x00:     /* FNSTSW AX*/
621 					gen_load_host(&TOP,DREG(TMPB),4);
622 					gen_call_function((void*)&FPU_SET_TOP,"%Drd",DREG(TMPB));
623 					gen_mov_host(&fpu.sw,DREG(EAX),2);
624 					break;
625 				default:
626 					FPU_LOG_WARN(7,false,4,sub);
627 					break;
628 			}
629 			break;
630 		default:
631 			FPU_LOG_WARN(7,false,group,sub);
632 			break;
633 		}
634 	} else {
635 		dyn_fill_ea();
636 		switch (group) {
637 		case 0x00:  /* FILD Bit16s */
638 			gen_call_function((void*)&FPU_PREP_PUSH,"");
639 			gen_load_host(&TOP,DREG(TMPB),4);
640 			gen_call_function((void*)&FPU_FLD_I16,"%Drd%Drd",DREG(EA),DREG(TMPB));
641 			break;
642 		case 0x01:
643 			FPU_LOG_WARN(7,true,group,sub);
644 			break;
645 		case 0x02:   /* FIST Bit16s */
646 			gen_call_function((void*)&FPU_FST_I16,"%Drd",DREG(EA));
647 			break;
648 		case 0x03:	/* FISTP Bit16s */
649 			gen_call_function((void*)&FPU_FST_I16,"%Drd",DREG(EA));
650 			gen_call_function((void*)&FPU_FPOP,"");
651 			break;
652 		case 0x04:   /* FBLD packed BCD */
653 			gen_call_function((void*)&FPU_PREP_PUSH,"");
654 			gen_load_host(&TOP,DREG(TMPB),4);
655 			gen_call_function((void*)&FPU_FBLD,"%Drd%Drd",DREG(EA),DREG(TMPB));
656 			break;
657 		case 0x05:  /* FILD Bit64s */
658 			gen_call_function((void*)&FPU_PREP_PUSH,"");
659 			gen_load_host(&TOP,DREG(TMPB),4);
660 			gen_call_function((void*)&FPU_FLD_I64,"%Drd%Drd",DREG(EA),DREG(TMPB));
661 			break;
662 		case 0x06:	/* FBSTP packed BCD */
663 			gen_call_function((void*)&FPU_FBST,"%Drd",DREG(EA));
664 			gen_call_function((void*)&FPU_FPOP,"");
665 			break;
666 		case 0x07:  /* FISTP Bit64s */
667 			gen_call_function((void*)&FPU_FST_I64,"%Drd",DREG(EA));
668 			gen_call_function((void*)&FPU_FPOP,"");
669 			break;
670 		default:
671 			FPU_LOG_WARN(7,true,group,sub);
672 			break;
673 		}
674 	}
675 }
676 
677 #endif // C_FPU
678 
679 #endif
680