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