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