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