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