PCem
view src/x87.c @ 154:d0d530adce12
Initial port to Linux (using Allegro).
64-bit fixes.
Some changes to aid portability.
A few other tweaks.
| author | TomW |
|---|---|
| date | Thu Sep 04 21:07:24 2014 +0100 |
| parents | eb624a751863 |
| children |
line source
1 //Quake timedemo demo1 - 8.1FPS
3 //11A00 - D_SCAlloc
4 //11C1C - D_CacheSurface
6 //36174 - SCR_CalcRefdef
8 //SCR_CalcRefdef
9 //Calls R_SetVrect and R_ViewChanged
11 #define fplog 0
13 #include <math.h>
14 #include "ibm.h"
15 #include "pic.h"
16 #include "x86.h"
17 #include "x87.h"
19 #undef readmemb
20 #undef writememb
22 #define readmemb(s,a) ((readlookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)?readmemb386l(s,a): *((uint8_t *)readlookup2[((s)+(a))>>12]+ (s) + (a)) )
23 #define writememb(s,a,v) if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememb386l(s,a,v); else *(uint8_t *)(writelookup2[((s) + (a)) >> 12] + (s) + (a)) = v
25 #define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE) writememwl(s,a,v); else *(uint16_t *)(writelookup2[((s) + (a)) >> 12] + (s) + (a)) = v
26 #define writememl(s,a,v) if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC) writememll(s,a,v); else *(uint32_t *)(writelookup2[((s) + (a)) >> 12] + (s) + (a)) = v
28 static inline uint8_t geteab()
29 {
30 if (mod==3)
31 return (rm&4)?regs[rm&3].b.h:regs[rm&3].b.l;
32 // cycles-=3;
33 if (eal_r) return *(uint8_t *)eal_r;
34 return readmemb(easeg,eaaddr);
35 }
37 static inline uint16_t geteaw()
38 {
39 if (mod==3)
40 return regs[rm].w;
41 // cycles-=3;
42 if (eal_r) return *(uint16_t *)eal_r;
43 return readmemw(easeg,eaaddr);
44 }
46 static inline uint32_t geteal()
47 {
48 if (mod==3)
49 return regs[rm].l;
50 // cycles-=3;
51 if (eal_r) return *eal_r;
52 return readmeml(easeg,eaaddr);
53 }
56 #define seteab(v) if (mod!=3) { if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,eaaddr,v); } else if (rm&4) regs[rm&3].b.h=v; else regs[rm].b.l=v
57 #define seteaw(v) if (mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,eaaddr,v); } else regs[rm].w=v
58 #define seteal(v) if (mod!=3) { if (eal_w) *eal_w=v; else writememll(easeg,eaaddr,v); } else regs[rm].l=v
62 double ST[8];
63 MMX_REG MM[8];
64 int ismmx = 0;
65 uint16_t npxs,npxc,tag;
67 int TOP;
68 #define ST(x) ST[((TOP+(x))&7)]
70 #define C0 (1<<8)
71 #define C1 (1<<9)
72 #define C2 (1<<10)
73 #define C3 (1<<14)
75 #define STATUS_ZERODIVIDE 4
77 #define x87_div(dst, src1, src2) do \
78 { \
79 if (((double)src2) == 0.0) \
80 { \
81 npxs |= STATUS_ZERODIVIDE; \
82 if (npxc & STATUS_ZERODIVIDE) \
83 dst = src1 / (double)src2; \
84 else \
85 { \
86 pclog("FPU : divide by zero\n"); \
87 picint(1 << 13); \
88 } \
89 return; \
90 } \
91 else \
92 dst = src1 / (double)src2; \
93 } while (0)
95 void x87_set_mmx()
96 {
97 TOP = 0;
98 tag = 0;
99 ismmx = 1;
100 }
102 void x87_emms()
103 {
104 tag = 0xffff;
105 ismmx = 0;
106 }
108 void x87_checkexceptions()
109 {
110 }
112 void x87_reset()
113 {
114 }
116 void x87_dumpregs()
117 {
118 if (ismmx)
119 {
120 pclog("MM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\n", MM[0].q, MM[1].q, MM[2].q, MM[3].q);
121 pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", MM[4].q, MM[5].q, MM[6].q, MM[7].q);
122 }
123 else
124 {
125 pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",ST[TOP],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]);
126 pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7]);
127 }
128 pclog("Status = %04X Control = %04X Tag = %04X\n",npxs,npxc,tag);
129 }
131 void x87_print()
132 {
133 if (ismmx)
134 {
135 pclog("\tMM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\t", MM[0].q, MM[1].q, MM[2].q, MM[3].q);
136 pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", MM[4].q, MM[5].q, MM[6].q, MM[7].q);
137 }
138 else
139 {
140 pclog("\tST(0)=%.20f\tST(1)=%.20f\tST(2)=%f\tST(3)=%f\t",ST[TOP&7],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]);
141 pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t TOP=%i CR=%04X SR=%04X TAG=%04X\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7], TOP, npxc, npxs, tag);
142 }
143 }
145 void x87_push(double i)
146 {
147 TOP=(TOP-1)&7;
148 ST[TOP]=i;
149 tag&=~(3<<((TOP&7)<<1));
150 if (i==0.0) tag|=(1<<((TOP&7)<<1));
151 }
153 double x87_pop()
154 {
155 double t=ST[TOP];
156 tag|=(3<<((TOP&7)<<1));
157 TOP=(TOP+1)&7;
158 return t;
159 }
161 int64_t x87_fround(double b)
162 {
163 switch ((npxc>>10)&3)
164 {
165 case 0: /*Nearest*/
166 return (int64_t)(b+0.5);
167 case 1: /*Down*/
168 return (int64_t)floor(b);
169 case 2: /*Up*/
170 return (int64_t)ceil(b);
171 case 3: /*Chop*/
172 return (int64_t)b;
173 }
174 }
175 #define BIAS80 16383
176 #define BIAS64 1023
178 double x87_ld80()
179 {
180 struct {
181 int16_t begin;
182 union
183 {
184 double d;
185 uint64_t ll;
186 } eind;
187 } test;
188 test.eind.ll = readmeml(easeg,eaaddr);
189 test.eind.ll |= (uint64_t)readmeml(easeg,eaaddr+4)<<32;
190 test.begin = readmemw(easeg,eaaddr+8);
192 int64_t exp64 = (((test.begin&0x7fff) - BIAS80));
193 int64_t blah = ((exp64 >0)?exp64:-exp64)&0x3ff;
194 int64_t exp64final = ((exp64 >0)?blah:-blah) +BIAS64;
196 int64_t mant64 = (test.eind.ll >> 11) & (0xfffffffffffff);
197 int64_t sign = (test.begin&0x8000)?1:0;
199 if ((test.begin & 0x7fff) == 0x7fff)
200 exp64final = 0x7ff;
201 if ((test.begin & 0x7fff) == 0)
202 exp64final = 0;
203 if (test.eind.ll & 0x400)
204 mant64++;
206 test.eind.ll = (sign <<63)|(exp64final << 52)| mant64;
208 return test.eind.d;
209 }
211 void x87_st80(double d)
212 {
213 struct {
214 int16_t begin;
215 union
216 {
217 double d;
218 uint64_t ll;
219 } eind;
220 } test;
222 test.eind.d=d;
224 int64_t sign80 = (test.eind.ll&(0x8000000000000000))?1:0;
225 int64_t exp80 = test.eind.ll&(0x7ff0000000000000);
226 int64_t exp80final = (exp80>>52);
227 int64_t mant80 = test.eind.ll&(0x000fffffffffffff);
228 int64_t mant80final = (mant80 << 11);
230 if (exp80final == 0x7ff) /*Infinity / Nan*/
231 {
232 exp80final = 0x7fff;
233 mant80final |= (0x8000000000000000);
234 }
235 else if (d != 0){ //Zero is a special case
236 // Elvira wants the 8 and tcalc doesn't
237 mant80final |= (0x8000000000000000);
238 //Ca-cyber doesn't like this when result is zero.
239 exp80final += (BIAS80 - BIAS64);
240 }
241 test.begin = (((int16_t)sign80)<<15)| (int16_t)exp80final;
242 test.eind.ll = mant80final;
244 writememl(easeg,eaaddr,test.eind.ll);
245 writememl(easeg,eaaddr+4,test.eind.ll>>32);
246 writememw(easeg,eaaddr+8,test.begin);
247 }
249 void x87_ldmmx(MMX_REG *r)
250 {
251 r->l[0] = readmeml(easeg, eaaddr);
252 r->l[1] = readmeml(easeg, eaaddr + 4);
253 r->w[4] = readmemw(easeg, eaaddr + 8);
254 }
256 void x87_stmmx(MMX_REG r)
257 {
258 writememl(easeg, eaaddr, r.l[0]);
259 writememl(easeg, eaaddr + 4, r.l[1]);
260 writememw(easeg, eaaddr + 8, 0xffff);
261 }
263 void x87_d8()
264 {
265 union
266 {
267 float s;
268 uint32_t i;
269 } ts;
270 if (mod==3)
271 {
272 switch (rmdat32&0xFF)
273 {
274 case 0xC0: case 0xC1: case 0xC2: case 0xC3: /*FADD*/
275 case 0xC4: case 0xC5: case 0xC6: case 0xC7:
276 if (fplog) pclog("FADD\n");
277 ST(0)=ST(0)+ST(rmdat32&7);
278 cycles-=8;
279 return;
280 case 0xC8: case 0xC9: case 0xCA: case 0xCB: /*FMUL*/
281 case 0xCC: case 0xCD: case 0xCE: case 0xCF:
282 if (fplog) pclog("FMUL\n");
283 ST(0)=ST(0)*ST(rmdat32&7);
284 cycles-=16;
285 return;
286 case 0xD0: case 0xD1: case 0xD2: case 0xD3: /*FCOM*/
287 case 0xD4: case 0xD5: case 0xD6: case 0xD7:
288 if (fplog) pclog("FCOM\n");
289 npxs&=~(C0|C2|C3);
290 if (ST(0)==ST(rmdat32&7)) npxs|=C3;
291 else if (ST(0)<ST(rmdat32&7)) npxs|=C0;
292 cycles-=4;
293 return;
294 case 0xD8: case 0xD9: case 0xDA: case 0xDB: /*FCOMP*/
295 case 0xDC: case 0xDD: case 0xDE: case 0xDF:
296 if (fplog) pclog("FCOMP\n");
297 npxs&=~(C0|C2|C3);
298 if (ST(0)==ST(rmdat32&7)) npxs|=C3;
299 else if (ST(0)<ST(rmdat32&7)) npxs|=C0;
300 x87_pop();
301 cycles-=4;
302 return;
303 case 0xE0: case 0xE1: case 0xE2: case 0xE3: /*FSUB*/
304 case 0xE4: case 0xE5: case 0xE6: case 0xE7:
305 if (fplog) pclog("FSUB\n");
306 ST(0)=ST(0)-ST(rmdat32&7);
307 cycles-=8;
308 return;
309 case 0xE8: case 0xE9: case 0xEA: case 0xEB: /*FSUBR*/
310 case 0xEC: case 0xED: case 0xEE: case 0xEF:
311 if (fplog) pclog("FSUBR\n");
312 ST(0)=ST(rmdat32&7)-ST(0);
313 cycles-=8;
314 return;
315 case 0xF0: case 0xF1: case 0xF2: case 0xF3: /*FDIV*/
316 case 0xF4: case 0xF5: case 0xF6: case 0xF7:
317 if (fplog) pclog("FDIV\n");
318 x87_div(ST(0), ST(0), ST(rmdat32&7));
319 cycles-=73;
320 return;
321 case 0xF8: case 0xF9: case 0xFA: case 0xFB: /*FDIVR*/
322 case 0xFC: case 0xFD: case 0xFE: case 0xFF:
323 if (fplog) pclog("FDIVR\n");
324 x87_div(ST(0), ST(rmdat32&7), ST(0));
325 cycles-=73;
326 return;
327 }
328 }
329 else
330 {
331 ts.i=geteal(); if (abrt) return;
332 switch (reg)
333 {
334 case 0: /*FADD short*/
335 if (fplog) pclog("FADDs %08X:%08X %f %f\n", easeg, eaaddr, ST(0), ts.s);
336 ST(0)+=ts.s;
337 cycles-=8;
338 return;
339 case 1: /*FMUL short*/
340 if (fplog) pclog("FMULs %08X:%08X %f %f\n", easeg, eaaddr, ST(0), ts.s);
341 ST(0)*=ts.s;
342 cycles-=11;
343 if (abrt) pclog("ABRT FMUL\n");
344 return;
345 case 2: /*FCOM short*/
346 if (fplog) pclog("FCOMs %08X:%08X %f %f\n", easeg, eaaddr, ST(0), ts.s);
347 npxs&=~(C0|C2|C3);
348 if (ST(0)==ts.s) npxs|=C3;
349 else if (ST(0)<ts.s) npxs|=C0;
350 cycles-=4;
351 return;
352 case 3: /*FCOMP short*/
353 if (fplog) pclog("FCOMPs %08X:%08X %f %f\n", easeg, eaaddr, ST(0), ts.s);
354 npxs&=~(C0|C2|C3);
355 if (ST(0)==ts.s) npxs|=C3;
356 else if (ST(0)<ts.s) npxs|=C0;
357 cycles-=4;
358 x87_pop();
359 return;
360 case 4: /*FSUB short*/
361 if (fplog) pclog("FSUBs %08X:%08X %f %f\n", easeg, eaaddr, ST(0), ts.s);
362 ST(0)-=ts.s;
363 cycles-=8;
364 return;
365 case 5: /*FSUBR short*/
366 if (fplog) pclog("FSUBRs %08X:%08X %f %f\n", easeg, eaaddr, ST(0), ts.s);
367 ST(0)=ts.s-ST(0);
368 cycles-=8;
369 return;
370 case 6: /*FDIV short*/
371 if (fplog) pclog("FDIVs %08X:%08X %f %f\n", easeg, eaaddr, ST(0), ts.s);
372 x87_div(ST(0), ST(0), ts.s);
373 cycles-=73;
374 return;
375 case 7: /*FDIVR short*/
376 if (fplog) pclog("FDIVRs %08X:%08X %f %f\n", easeg, eaaddr, ST(0), ts.s);
377 x87_div(ST(0), ts.s, ST(0));
378 cycles-=73;
379 return;
380 }
381 }
382 x86illegal();
383 // fatal("Bad x87 D8 opcode %i %02X\n",reg,rmdat32&0xFF);
384 }
385 void x87_d9()
386 {
387 union
388 {
389 float s;
390 uint32_t i;
391 } ts;
392 double td;
393 int64_t temp64;
394 uint16_t tempw;
395 int temp;
396 if (mod==3)
397 {
398 switch (rmdat32&0xFF)
399 {
400 case 0xC0: case 0xC1: case 0xC2: case 0xC3: /*FLD*/
401 case 0xC4: case 0xC5: case 0xC6: case 0xC7:
402 if (fplog) pclog("FLD %f\n", ST(rmdat32 & 7));
403 x87_push(ST(rmdat32&7));
404 cycles-=4;
405 return;
406 case 0xC8: case 0xC9: case 0xCA: case 0xCB: /*FXCH*/
407 case 0xCC: case 0xCD: case 0xCE: case 0xCF:
408 if (fplog) pclog("FXCH\n");
409 td=ST(0);
410 ST(0)=ST(rmdat32&7);
411 ST(rmdat32&7)=td;
412 cycles-=4;
413 return;
414 case 0xD0: /*FNOP*/
415 if (fplog) pclog("FNOP\n");
416 cycles-=3;
417 return;
418 case 0xD8: case 0xD9: case 0xDA: case 0xDB: /*Invalid, but apparently not illegal*/
419 case 0xDC: case 0xDD: case 0xDE: case 0xDF:
420 if (fplog) pclog("FSTP\n");
421 ST(rmdat32 & 7) = ST(0);
422 temp = (tag >> ((TOP & 7) << 1)) & 3;
423 tag &= ~(3 << (((TOP + rmdat32) & 7) << 1));
424 tag |= (temp << (((TOP + rmdat32) & 7) << 1));
425 x87_pop();
426 cycles-=3;
427 return;
428 case 0xE0: /*FCHS*/
429 if (fplog) pclog("FCHS\n");
430 ST(0)=-ST(0);
431 cycles-=6;
432 return;
433 case 0xE1: /*FABS*/
434 if (fplog) pclog("FABS %f\n", ST(0));
435 ST(0)=fabs(ST(0));
436 cycles-=3;
437 return;
438 case 0xE4: /*FTST*/
439 if (fplog) pclog("FTST\n");
440 npxs&=~(C0|C2|C3);
441 if (ST(0)==0.0) npxs|=C3;
442 else if (ST(0)<0.0) npxs|=C0;
443 cycles-=4;
444 return;
445 case 0xE5: /*FXAM*/
446 if (fplog) pclog("FXAM %i %f\n", ((tag>>((TOP&7)<<1))&3), ST(0));
447 // pclog("FXAM %f %i\n",ST(0),(tag>>((TOP&7)<<1))&3);
448 npxs&=~(C0|C2|C3);
449 if (((tag>>((TOP&7)<<1))&3)==3) npxs|=(C0|C3);
450 else if (ST(0)==0.0) npxs|=C3;
451 else npxs|=C2;
452 if (ST(0)<0.0) npxs|=C1;
453 cycles-=8;
454 return;
455 case 0xE8: /*FLD1*/
456 if (fplog) pclog("FLD1\n");
457 x87_push(1.0);
458 cycles-=4;
459 return;
460 case 0xE9: /*FLDL2T*/
461 if (fplog) pclog("FLDL2T\n");
462 x87_push(3.3219280948873623);
463 cycles-=8;
464 return;
465 case 0xEA: /*FLDL2E*/
466 if (fplog) pclog("FLDL2E\n");
467 x87_push(1.4426950408889634);
468 cycles-=8;
469 return;
470 case 0xEB: /*FLDPI*/
471 if (fplog) pclog("FLDPI\n");
472 x87_push(3.141592653589793);
473 cycles-=8;
474 return;
475 case 0xEC: /*FLDEG2*/
476 if (fplog) pclog("FLDEG2\n");
477 x87_push(0.3010299956639812);
478 cycles-=8;
479 return;
480 case 0xED: /*FLDLN2*/
481 if (fplog) pclog("FLDLN2\n");
482 x87_push(0.693147180559945);
483 cycles-=8;
484 return;
485 case 0xEE: /*FLDZ*/
486 if (fplog) pclog("FLDZ\n");
487 // pclog("FLDZ %04X:%08X\n",CS,pc);
488 x87_push(0.0);
489 tag|=(1<<((TOP&7)<<1));
490 cycles-=4;
491 return;
492 case 0xF0: /*F2XM1*/
493 if (fplog) pclog("F2XM1\n");
494 ST(0)=pow(2.0,ST(0))-1.0;
495 cycles-=200;
496 return;
497 case 0xF1: /*FYL2X*/
498 if (fplog) pclog("FYL2X\n");
499 ST(1)=ST(1)*(log(ST(0))/log(2.0));
500 x87_pop();
501 cycles-=250;
502 return;
503 case 0xF2: /*FPTAN*/
504 if (fplog) pclog("FPTAN\n");
505 // pclog("Tan of %f = ",ST(0));
506 ST(0)=tan(ST(0));
507 // pclog("%f\n",ST(0));
508 x87_push(1.0);
509 npxs&=~C2;
510 cycles-=235;
511 return;
512 case 0xF3: /*FPATAN*/
513 if (fplog) pclog("FPATAN\n");
514 /* times++;
515 if (times==50)
516 {
517 dumpregs();
518 exit(-1);
519 }*/
520 // pclog("FPATAN %08X\n",pc);
521 ST(1)=atan2(ST(1),ST(0));
522 x87_pop();
523 cycles-=250;
524 return;
525 case 0xF6: /*FDECSTP*/
526 if (fplog) pclog("FDECSTP\n");
527 TOP=(TOP-1)&7;
528 return;
529 case 0xF7: /*FINCSTP*/
530 if (fplog) pclog("FINCSTP\n");
531 TOP=(TOP+1)&7;
532 return;
533 case 0xF8: /*FPREM*/
534 if (fplog) pclog("FPREM %f %f ", ST(0), ST(1));
535 temp64=(int64_t)(ST(0)/ST(1));
536 ST(0)=ST(0)-(ST(1)*(double)temp64);
537 if (fplog) pclog("%f\n", ST(0));
538 npxs&=~(C0|C1|C2|C3);
539 if (temp64&4) npxs|=C0;
540 if (temp64&2) npxs|=C3;
541 if (temp64&1) npxs|=C1;
542 cycles-=100;
543 return;
544 case 0xFA: /*FSQRT*/
545 if (fplog) pclog("FSQRT\n");
546 ST(0)=sqrt(ST(0));
547 cycles-=83;
548 return;
549 case 0xFB: /*FSINCOS*/
550 if (fplog) pclog("FSINCOS\n");
551 td=ST(0);
552 ST(0)=sin(td);
553 x87_push(cos(td));
554 npxs&=~C2;
555 cycles-=330;
556 return;
557 case 0xFC: /*FRNDINT*/
558 if (fplog) pclog("FRNDINT %g ", ST(0));
559 // pclog("FRNDINT %f %i ",ST(0),(npxc>>10)&3);
560 ST(0)=(double)x87_fround(ST(0));
561 // pclog("%f\n",ST(0));
562 if (fplog) pclog("%g\n", ST(0));
563 cycles-=21;
564 return;
565 case 0xFD: /*FSCALE*/
566 if (fplog) pclog("FSCALE\n");
567 temp64=(int64_t)ST(1);
568 ST(0)=ST(0)*pow(2.0,(double)temp64);
569 cycles-=30;
570 return;
571 case 0xFE: /*FSIN*/
572 if (fplog) pclog("FSIN\n");
573 ST(0)=sin(ST(0));
574 npxs&=~C2;
575 cycles-=300;
576 return;
577 case 0xFF: /*FCOS*/
578 if (fplog) pclog("FCOS\n");
579 ST(0)=cos(ST(0));
580 npxs&=~C2;
581 cycles-=300;
582 return;
583 }
584 }
585 else
586 {
587 switch (reg)
588 {
589 case 0: /*FLD single-precision*/
590 if (fplog) pclog("FLDs %08X:%08X\n", easeg, eaaddr);
591 // if ((rmdat32&0xFFFF)==0xD445) { pclog("FLDS\n"); output=3; dumpregs(); exit(-1); }
592 ts.i=geteal(); if (abrt) { pclog("FLD sp abort\n"); return; }
593 if (fplog) pclog(" %f\n", ts.s);
594 x87_push((double)ts.s);
595 cycles-=3;
596 return;
597 case 2: /*FST single-precision*/
598 if (fplog) pclog("FSTs %08X:%08X\n", easeg, eaaddr);
599 ts.s=(float)ST(0);
600 seteal(ts.i);
601 if (abrt) { pclog("FST sp abort\n"); return; }
602 cycles-=7;
603 return;
604 case 3: /*FSTP single-precision*/
605 if (fplog) pclog("FSTPs %08X:%08X %f\n", easeg, eaaddr, ST(0));
606 ts.s=(float)ST(0);
607 seteal(ts.i); if (abrt) { pclog("FSTP sp abort\n"); return; }
608 // if (pc==0x3f50c) pclog("FSTP %f %f %08X\n",ST(0),ts.s,ts.i);
609 x87_pop();
610 cycles-=7;
611 return;
612 case 4: /*FLDENV*/
613 if (fplog) pclog("FLDENV %08X:%08X\n", easeg, eaaddr);
614 switch ((cr0&1)|(op32&0x100))
615 {
616 case 0x000: /*16-bit real mode*/
617 case 0x001: /*16-bit protected mode*/
618 npxc=readmemw(easeg,eaaddr);
619 npxs=readmemw(easeg,eaaddr+2);
620 tag=readmemw(easeg,eaaddr+4);
621 TOP=(npxs>>11)&7;
622 break;
623 case 0x100: /*32-bit real mode*/
624 case 0x101: /*32-bit protected mode*/
625 npxc=readmemw(easeg,eaaddr);
626 npxs=readmemw(easeg,eaaddr+4);
627 tag=readmemw(easeg,eaaddr+8);
628 TOP=(npxs>>11)&7;
629 break;
630 }
631 cycles-=(cr0&1)?34:44;
632 if (abrt) { pclog("FLDENV\n"); return; }
633 return;
634 case 5: /*FLDCW*/
635 if (fplog) pclog("FLDCW %08X:%08X\n", easeg, eaaddr);
636 tempw=geteaw();
637 if (abrt) if (abrt) { pclog("FLDCW abort\n"); return; }
638 npxc=tempw;
639 cycles-=4;
640 return;
641 case 6: /*FSTENV*/
642 if (fplog) pclog("FSTENV %08X:%08X\n", easeg, eaaddr);
643 switch ((cr0&1)|(op32&0x100))
644 {
645 case 0x000: /*16-bit real mode*/
646 writememw(easeg,eaaddr,npxc);
647 writememw(easeg,eaaddr+2,npxs);
648 writememw(easeg,eaaddr+4,tag);
649 writememw(easeg,eaaddr+6,x87_pc_off);
650 writememw(easeg,eaaddr+10,x87_op_off);
651 break;
652 case 0x001: /*16-bit protected mode*/
653 writememw(easeg,eaaddr,npxc);
654 writememw(easeg,eaaddr+2,npxs);
655 writememw(easeg,eaaddr+4,tag);
656 writememw(easeg,eaaddr+6,x87_pc_off);
657 writememw(easeg,eaaddr+8,x87_pc_seg);
658 writememw(easeg,eaaddr+10,x87_op_off);
659 writememw(easeg,eaaddr+12,x87_op_seg);
660 break;
661 case 0x100: /*32-bit real mode*/
662 writememw(easeg,eaaddr,npxc);
663 writememw(easeg,eaaddr+4,npxs);
664 writememw(easeg,eaaddr+8,tag);
665 writememw(easeg,eaaddr+12,x87_pc_off);
666 writememw(easeg,eaaddr+20,x87_op_off);
667 writememl(easeg,eaaddr+24,(x87_op_off>>16)<<12);
668 break;
669 case 0x101: /*32-bit protected mode*/
670 writememw(easeg,eaaddr,npxc);
671 writememw(easeg,eaaddr+4,npxs);
672 writememw(easeg,eaaddr+8,tag);
673 writememl(easeg,eaaddr+12,x87_pc_off);
674 writememl(easeg,eaaddr+16,x87_pc_seg);
675 writememl(easeg,eaaddr+20,x87_op_off);
676 writememl(easeg,eaaddr+24,x87_op_seg);
677 break;
678 }
679 if (abrt) { pclog("FSTENV\n"); return; }
680 cycles-=(cr0&1)?56:67;
681 return;
682 case 7: /*FSTCW*/
683 if (fplog) pclog("FSTCW %08X:%08X\n", easeg, eaaddr);
684 seteaw(npxc);
685 if (abrt) { pclog("FSTCW\n"); return; }
686 cycles-=3;
687 return;
688 }
689 }
690 // fatal("Bad x87 D9 opcode %i %02X\n",reg,rmdat32&0xFF);
691 x86illegal();
692 }
693 void x87_da()
694 {
695 int32_t templ;
696 if (mod==3)
697 {
698 switch (rmdat32&0xFF)
699 {
700 case 0xE9: /*FUCOMPP*/
701 if (fplog) pclog("FUCOMPP\n", easeg, eaaddr);
702 npxs&=~(C0|C2|C3);
703 if (ST(0)==ST(1)) npxs|=C3;
704 else if (ST(0)<ST(1)) npxs|=C0;
705 x87_pop();
706 x87_pop();
707 cycles-=5;
708 return;
709 }
710 }
711 else
712 {
713 templ=(int32_t)geteal(); if (abrt) return;
714 switch (reg)
715 {
716 case 0: /*FIADD*/
717 if (fplog) pclog("FIADDl %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
718 ST(0)=ST(0)+(double)templ;
719 cycles-=20;
720 return;
721 case 1: /*FIMUL*/
722 if (fplog) pclog("FIMULl %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
723 ST(0)=ST(0)*(double)templ;
724 cycles-=22;
725 return;
726 case 2: /*FICOM*/
727 if (fplog) pclog("FICOMl %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
728 npxs&=~(C0|C2|C3);
729 if (ST(0)==(double)templ) npxs|=C3;
730 else if (ST(0)<(double)templ) npxs|=C0;
731 cycles-=15;
732 return;
733 case 3: /*FICOMP*/
734 if (fplog) pclog("FICOMPl %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
735 npxs&=~(C0|C2|C3);
736 if (ST(0)==(double)templ) npxs|=C3;
737 else if (ST(0)<(double)templ) npxs|=C0;
738 x87_pop();
739 cycles-=15;
740 return;
741 case 4: /*FISUB*/
742 if (fplog) pclog("FISUBl %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
743 ST(0)=ST(0)-(double)templ;
744 cycles-=20;
745 return;
746 case 5: /*FISUBR*/
747 if (fplog) pclog("FISUBRl %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
748 ST(0)=(double)templ-ST(0);
749 cycles-=19;
750 return;
751 case 6: /*FIDIV*/
752 if (fplog) pclog("FIDIVl %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
753 x87_div(ST(0), ST(0), (double)templ);
754 cycles-=84;
755 return;
756 case 7: /*FIDIVR*/
757 if (fplog) pclog("FIDIVRl %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
758 x87_div(ST(0), (double)templ, ST(0));
759 cycles-=84;
760 return;
761 }
762 }
763 // fatal("Bad x87 DA opcode %i %02X\n",reg,rmdat32&0xFF);
764 x86illegal();
765 }
766 void x87_db()
767 {
768 double t;
769 int32_t templ;
770 int64_t temp64;
771 if (mod==3)
772 {
773 switch (reg)
774 {
775 case 4:
776 switch (rmdat32&0xFF)
777 {
778 case 0xE1:
779 return;
780 case 0xE2: /*FCLEX*/
781 if (fplog) pclog("FCLEX\n");
782 npxs&=0xFF00;
783 return;
784 case 0xE3: /*FINIT*/
785 if (fplog) pclog("FINIT\n");
786 npxc=0x37F;
787 npxs=0;
788 tag=0xFFFF;
789 TOP=0;
790 cycles-=17;
791 return;
792 case 0xE4:
793 return;
794 }
795 break;
796 }
797 }
798 else
799 {
800 switch (reg)
801 {
802 case 0: /*FILD short*/
803 if (fplog) pclog("FILDs %08X:%08X\n", easeg, eaaddr);
804 templ=geteal(); if (abrt) return;
805 if (fplog) pclog(" %f %08X %i\n", (double)templ, templ, templ);
806 x87_push((double)templ);
807 cycles-=9;
808 return;
809 case 2: /*FIST short*/
810 if (fplog) pclog("FISTs %08X:%08X\n", easeg, eaaddr);
811 temp64 = x87_fround(ST(0));
812 /* if (temp64 > 2147483647 || temp64 < -2147483647)
813 fatal("FISTl out of range! %i\n", temp64);*/
814 seteal((int32_t)temp64);
815 cycles-=28;
816 return;
817 case 3: /*FISTP short*/
818 if (fplog) pclog("FISTPs %08X:%08X %g ", easeg, eaaddr, ST(0));
819 temp64 = x87_fround(ST(0));
820 /* if (temp64 > 2147483647 || temp64 < -2147483647)
821 fatal("FISTPl out of range! %i\n", temp64);*/
822 if (fplog) pclog("%lli %llX\n", temp64, temp64);
823 seteal((int32_t)temp64); if (abrt) return;
824 x87_pop();
825 cycles-=28;
826 return;
827 case 5: /*FLD extended*/
828 if (fplog) pclog("FLDe %08X:%08X\n", easeg, eaaddr);
829 t=x87_ld80(); if (abrt) return;
830 if (fplog) pclog(" %f\n", t);
831 x87_push(t);
832 cycles-=6;
833 return;
834 case 7: /*FSTP extended*/
835 if (fplog) pclog("FSTPe %08X:%08X\n", easeg, eaaddr);
836 x87_st80(ST(0)); if (abrt) return;
837 x87_pop();
838 cycles-=6;
839 return;
840 }
841 }
842 // fatal("Bad x87 DB opcode %i %02X\n",reg,rmdat32&0xFF);
843 x86illegal();
844 }
845 void x87_dc()
846 {
847 union
848 {
849 double d;
850 uint64_t i;
851 } t;
852 if (mod==3)
853 {
854 switch (rmdat32&0xFF)
855 {
856 case 0xC0: case 0xC1: case 0xC2: case 0xC3: /*FADD*/
857 case 0xC4: case 0xC5: case 0xC6: case 0xC7:
858 if (fplog) pclog("FADD %f %f\n", ST(rmdat32 & 7), ST(0));
859 ST(rmdat32&7)=ST(rmdat32&7)+ST(0);
860 cycles-=8;
861 return;
862 case 0xC8: case 0xC9: case 0xCA: case 0xCB: /*FMUL*/
863 case 0xCC: case 0xCD: case 0xCE: case 0xCF:
864 if (fplog) pclog("FMUL %f %f\n", ST(rmdat32 & 7), ST(0));
865 ST(rmdat32&7)=ST(rmdat32&7)*ST(0);
866 cycles-=16;
867 return;
868 case 0xE0: case 0xE1: case 0xE2: case 0xE3: /*FSUBR*/
869 case 0xE4: case 0xE5: case 0xE6: case 0xE7:
870 if (fplog) pclog("FSUBR %f %f\n", ST(rmdat32 & 7), ST(0));
871 ST(rmdat32&7)=ST(0)-ST(rmdat32&7);
872 cycles-=8;
873 return;
874 case 0xE8: case 0xE9: case 0xEA: case 0xEB: /*FSUB*/
875 case 0xEC: case 0xED: case 0xEE: case 0xEF:
876 if (fplog) pclog("FSUB %f %f\n", ST(rmdat32 & 7), ST(0));
877 ST(rmdat32&7)=ST(rmdat32&7)-ST(0);
878 cycles-=8;
879 return;
880 case 0xF0: case 0xF1: case 0xF2: case 0xF3: /*FDIVR*/
881 case 0xF4: case 0xF5: case 0xF6: case 0xF7:
882 if (fplog) pclog("FDIVR %f %f\n", ST(rmdat32 & 7), ST(0));
883 x87_div(ST(rmdat32&7), ST(0), ST(rmdat32&7));
884 cycles-=73;
885 return;
886 case 0xF8: case 0xF9: case 0xFA: case 0xFB: /*FDIV*/
887 case 0xFC: case 0xFD: case 0xFE: case 0xFF:
888 if (fplog) pclog("FDIV %f %f\n", ST(rmdat32 & 7), ST(0));
889 x87_div(ST(rmdat32&7), ST(rmdat32&7), ST(0));
890 cycles-=73;
891 return;
892 }
893 }
894 else
895 {
896 t.i=readmeml(easeg,eaaddr);
897 t.i|=(uint64_t)readmeml(easeg,eaaddr+4)<<32;
898 if (abrt) return;
899 switch (reg)
900 {
901 case 0: /*FADD double*/
902 if (fplog) pclog("FADDd %08X:%08X %f %f\n", easeg, eaaddr, ST(0), t.d);
903 ST(0)+=t.d;
904 cycles-=8;
905 return;
906 case 1: /*FMUL double*/
907 if (fplog) pclog("FMULd %08X:%08X %f %f\n", easeg, eaaddr, ST(0), t.d);
908 ST(0)*=t.d;
909 cycles-=14;
910 return;
911 case 2: /*FCOM double*/
912 if (fplog) pclog("FCOMd %08X:%08X %f %f\n", easeg, eaaddr, ST(0), t.d);
913 npxs&=~(C0|C2|C3);
914 if (ST(0)==t.d) npxs|=C3;
915 else if (ST(0)<t.d) npxs|=C0;
916 cycles-=4;
917 return;
918 case 3: /*FCOMP double*/
919 if (fplog) pclog("FCOMPd %08X:%08X %f %f\n", easeg, eaaddr, ST(0), t.d);
920 npxs&=~(C0|C2|C3);
921 if (ST(0)==t.d) npxs|=C3;
922 else if (ST(0)<t.d) npxs|=C0;
923 cycles-=4;
924 x87_pop();
925 return;
926 case 4: /*FSUB double*/
927 if (fplog) pclog("FSUBd %08X:%08X %f %f\n", easeg, eaaddr, ST(0), t.d);
928 ST(0)-=t.d;
929 cycles-=8;
930 return;
931 case 5: /*FSUBR double*/
932 if (fplog) pclog("FSUBRd %08X:%08X %f %f\n", easeg, eaaddr, ST(0), t.d);
933 ST(0)=t.d-ST(0);
934 cycles-=8;
935 return;
936 case 6: /*FDIV double*/
937 if (fplog) pclog("FDIVd %08X:%08X %f %f\n", easeg, eaaddr, ST(0), t.d);
938 x87_div(ST(0), ST(0), t.d);
939 cycles-=73;
940 return;
941 case 7: /*FDIVR double*/
942 if (fplog) pclog("FDIVRd %08X:%08X %f %f\n", easeg, eaaddr, ST(0), t.d);
943 x87_div(ST(0), t.d, ST(0));
944 cycles-=73;
945 return;
946 }
947 }
948 // fatal("Bad x87 DC opcode %i %02X\n",reg,rmdat32&0xFF);
949 x86illegal();
950 }
951 void x87_dd()
952 {
953 union
954 {
955 double d;
956 uint64_t i;
957 } t;
958 int temp;
959 if (mod==3)
960 {
961 switch (reg)
962 {
963 case 0: /*FFREE*/
964 if (fplog) pclog("FFREE\n");
965 tag |= (3 << (((TOP + rmdat32) & 7) << 1));
966 cycles-=3;
967 return;
968 case 2: /*FST*/
969 if (fplog) pclog("FST\n");
970 ST(rmdat32 & 7) = ST(0);
971 temp = (tag >> ((TOP & 7) << 1)) & 3;
972 tag &= ~(3 << (((TOP + rmdat32) & 7) << 1));
973 tag |= (temp << (((TOP + rmdat32) & 7) << 1));
974 cycles-=3;
975 return;
976 case 3: /*FSTP*/
977 if (fplog) pclog("FSTP\n");
978 ST(rmdat32 & 7) = ST(0);
979 temp = (tag >> ((TOP & 7) << 1)) & 3;
980 tag &= ~(3 << (((TOP + rmdat32) & 7) << 1));
981 tag |= (temp << (((TOP + rmdat32) & 7) << 1));
982 x87_pop();
983 cycles-=3;
984 return;
985 case 4: /*FUCOM*/
986 if (fplog) pclog("FUCOM\n");
987 npxs&=~(C0|C2|C3);
988 if (ST(0)==ST(rmdat32&7)) npxs|=C3;
989 else if (ST(0)<ST(rmdat32&7)) npxs|=C0;
990 cycles-=4;
991 return;
992 case 5: /*FUCOMP*/
993 if (fplog) pclog("FUCOMP\n");
994 npxs&=~(C0|C2|C3);
995 if (ST(0)==ST(rmdat32&7)) npxs|=C3;
996 else if (ST(0)<ST(rmdat32&7)) npxs|=C0;
997 x87_pop();
998 cycles-=4;
999 return;
1000 }
1001 }
1002 else
1003 {
1004 switch (reg)
1005 {
1006 case 0: /*FLD double-precision*/
1007 if (fplog) pclog("FLDd %08X:%08X\n", easeg, eaaddr);
1008 t.i=readmeml(easeg,eaaddr);
1009 t.i|=(uint64_t)readmeml(easeg,eaaddr+4)<<32; if (abrt) return;
1010 if (fplog) pclog(" %f\n", t.d);
1011 x87_push(t.d);
1012 cycles-=3;
1013 return;
1014 case 2: /*FST double-precision*/
1015 if (fplog) pclog("FSTd %08X:%08X\n", easeg, eaaddr);
1016 t.d=ST(0);
1017 writememl(easeg,eaaddr,t.i);
1018 writememl(easeg,eaaddr+4,(t.i>>32));
1019 cycles-=8;
1020 return;
1021 case 3: /*FSTP double-precision*/
1022 if (fplog) pclog("FSTPd %08X:%08X\n", easeg, eaaddr);
1023 t.d=ST(0);
1024 writememl(easeg,eaaddr,t.i);
1025 writememl(easeg,eaaddr+4,(t.i>>32)); if (abrt) return;
1026 x87_pop();
1027 cycles-=8;
1028 return;
1029 case 4: /*FRSTOR*/
1030 switch ((cr0&1)|(op32&0x100))
1031 {
1032 case 0x000: /*16-bit real mode*/
1033 case 0x001: /*16-bit protected mode*/
1034 npxc=readmemw(easeg,eaaddr);
1035 npxs=readmemw(easeg,eaaddr+2);
1036 tag=readmemw(easeg,eaaddr+4);
1037 TOP=(npxs>>11)&7;
1038 eaaddr+=14;
1039 break;
1040 case 0x100: /*32-bit real mode*/
1041 case 0x101: /*32-bit protected mode*/
1042 npxc=readmemw(easeg,eaaddr);
1043 npxs=readmemw(easeg,eaaddr+4);
1044 tag=readmemw(easeg,eaaddr+8);
1045 TOP=(npxs>>11)&7;
1046 eaaddr+=28;
1047 break;
1048 }
1049 x87_ldmmx(&MM[0]); ST(0)=x87_ld80(); eaaddr += 10;
1050 x87_ldmmx(&MM[1]); ST(1)=x87_ld80(); eaaddr += 10;
1051 x87_ldmmx(&MM[2]); ST(2)=x87_ld80(); eaaddr += 10;
1052 x87_ldmmx(&MM[3]); ST(3)=x87_ld80(); eaaddr += 10;
1053 x87_ldmmx(&MM[4]); ST(4)=x87_ld80(); eaaddr += 10;
1054 x87_ldmmx(&MM[5]); ST(5)=x87_ld80(); eaaddr += 10;
1055 x87_ldmmx(&MM[6]); ST(6)=x87_ld80(); eaaddr += 10;
1056 x87_ldmmx(&MM[7]); ST(7)=x87_ld80();
1057 ismmx = 0;
1058 /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times
1059 something like this is needed*/
1060 if (MM[0].w == 0xffff && MM[1].w == 0xffff && MM[2].w == 0xffff && MM[3].w == 0xffff &&
1061 MM[4].w == 0xffff && MM[5].w == 0xffff && MM[6].w == 0xffff && MM[7].w == 0xffff &&
1062 !TOP && !tag)
1063 ismmx = 1;
1065 cycles-=(cr0&1)?34:44;
1066 if (fplog) pclog("FRSTOR %08X:%08X %i %i %04X\n", easeg, eaaddr, ismmx, TOP, tag);
1067 /* pclog("new TOP %i\n", TOP);
1068 pclog("%04X %04X %04X %f %f %f %f %f %f %f %f\n", npxc, npxs, tag, ST(0), ST(1), ST(2), ST(3), ST(4), ST(5), ST(6), ST(7));*/
1069 return;
1070 case 6: /*FSAVE*/
1071 if (fplog) pclog("FSAVE %08X:%08X %i\n", easeg, eaaddr, ismmx);
1072 npxs = (npxs & ~(7 << 11)) | (TOP << 11);
1073 /* pclog("old TOP %i %04X\n", TOP, npxs);
1074 pclog("%04X %04X %04X %f %f %f %f %f %f %f %f\n", npxc, npxs, tag, ST(0), ST(1), ST(2), ST(3), ST(4), ST(5), ST(6), ST(7));*/
1076 switch ((cr0&1)|(op32&0x100))
1077 {
1078 case 0x000: /*16-bit real mode*/
1079 writememw(easeg,eaaddr,npxc);
1080 writememw(easeg,eaaddr+2,npxs);
1081 writememw(easeg,eaaddr+4,tag);
1082 writememw(easeg,eaaddr+6,x87_pc_off);
1083 writememw(easeg,eaaddr+10,x87_op_off);
1084 eaaddr+=14;
1085 if (ismmx)
1086 {
1087 x87_stmmx(MM[0]); eaaddr+=10;
1088 x87_stmmx(MM[1]); eaaddr+=10;
1089 x87_stmmx(MM[2]); eaaddr+=10;
1090 x87_stmmx(MM[3]); eaaddr+=10;
1091 x87_stmmx(MM[4]); eaaddr+=10;
1092 x87_stmmx(MM[5]); eaaddr+=10;
1093 x87_stmmx(MM[6]); eaaddr+=10;
1094 x87_stmmx(MM[7]);
1095 }
1096 else
1097 {
1098 x87_st80(ST(0)); eaaddr+=10;
1099 x87_st80(ST(1)); eaaddr+=10;
1100 x87_st80(ST(2)); eaaddr+=10;
1101 x87_st80(ST(3)); eaaddr+=10;
1102 x87_st80(ST(4)); eaaddr+=10;
1103 x87_st80(ST(5)); eaaddr+=10;
1104 x87_st80(ST(6)); eaaddr+=10;
1105 x87_st80(ST(7));
1106 }
1107 break;
1108 case 0x001: /*16-bit protected mode*/
1109 writememw(easeg,eaaddr,npxc);
1110 writememw(easeg,eaaddr+2,npxs);
1111 writememw(easeg,eaaddr+4,tag);
1112 writememw(easeg,eaaddr+6,x87_pc_off);
1113 writememw(easeg,eaaddr+8,x87_pc_seg);
1114 writememw(easeg,eaaddr+10,x87_op_off);
1115 writememw(easeg,eaaddr+12,x87_op_seg);
1116 eaaddr+=14;
1117 if (ismmx)
1118 {
1119 x87_stmmx(MM[0]); eaaddr+=10;
1120 x87_stmmx(MM[1]); eaaddr+=10;
1121 x87_stmmx(MM[2]); eaaddr+=10;
1122 x87_stmmx(MM[3]); eaaddr+=10;
1123 x87_stmmx(MM[4]); eaaddr+=10;
1124 x87_stmmx(MM[5]); eaaddr+=10;
1125 x87_stmmx(MM[6]); eaaddr+=10;
1126 x87_stmmx(MM[7]);
1127 }
1128 else
1129 {
1130 x87_st80(ST(0)); eaaddr+=10;
1131 x87_st80(ST(1)); eaaddr+=10;
1132 x87_st80(ST(2)); eaaddr+=10;
1133 x87_st80(ST(3)); eaaddr+=10;
1134 x87_st80(ST(4)); eaaddr+=10;
1135 x87_st80(ST(5)); eaaddr+=10;
1136 x87_st80(ST(6)); eaaddr+=10;
1137 x87_st80(ST(7));
1138 }
1139 break;
1140 case 0x100: /*32-bit real mode*/
1141 writememw(easeg,eaaddr,npxc);
1142 writememw(easeg,eaaddr+4,npxs);
1143 writememw(easeg,eaaddr+8,tag);
1144 writememw(easeg,eaaddr+12,x87_pc_off);
1145 writememw(easeg,eaaddr+20,x87_op_off);
1146 writememl(easeg,eaaddr+24,(x87_op_off>>16)<<12);
1147 eaaddr+=28;
1148 if (ismmx)
1149 {
1150 x87_stmmx(MM[0]); eaaddr+=10;
1151 x87_stmmx(MM[1]); eaaddr+=10;
1152 x87_stmmx(MM[2]); eaaddr+=10;
1153 x87_stmmx(MM[3]); eaaddr+=10;
1154 x87_stmmx(MM[4]); eaaddr+=10;
1155 x87_stmmx(MM[5]); eaaddr+=10;
1156 x87_stmmx(MM[6]); eaaddr+=10;
1157 x87_stmmx(MM[7]);
1158 }
1159 else
1160 {
1161 x87_st80(ST(0)); eaaddr+=10;
1162 x87_st80(ST(1)); eaaddr+=10;
1163 x87_st80(ST(2)); eaaddr+=10;
1164 x87_st80(ST(3)); eaaddr+=10;
1165 x87_st80(ST(4)); eaaddr+=10;
1166 x87_st80(ST(5)); eaaddr+=10;
1167 x87_st80(ST(6)); eaaddr+=10;
1168 x87_st80(ST(7));
1169 }
1170 break;
1171 case 0x101: /*32-bit protected mode*/
1172 writememw(easeg,eaaddr,npxc);
1173 writememw(easeg,eaaddr+4,npxs);
1174 writememw(easeg,eaaddr+8,tag);
1175 writememl(easeg,eaaddr+12,x87_pc_off);
1176 writememl(easeg,eaaddr+16,x87_pc_seg);
1177 writememl(easeg,eaaddr+20,x87_op_off);
1178 writememl(easeg,eaaddr+24,x87_op_seg);
1179 eaaddr+=28;
1180 if (ismmx)
1181 {
1182 x87_stmmx(MM[0]); eaaddr+=10;
1183 x87_stmmx(MM[1]); eaaddr+=10;
1184 x87_stmmx(MM[2]); eaaddr+=10;
1185 x87_stmmx(MM[3]); eaaddr+=10;
1186 x87_stmmx(MM[4]); eaaddr+=10;
1187 x87_stmmx(MM[5]); eaaddr+=10;
1188 x87_stmmx(MM[6]); eaaddr+=10;
1189 x87_stmmx(MM[7]);
1190 }
1191 else
1192 {
1193 x87_st80(ST(0)); eaaddr+=10;
1194 x87_st80(ST(1)); eaaddr+=10;
1195 x87_st80(ST(2)); eaaddr+=10;
1196 x87_st80(ST(3)); eaaddr+=10;
1197 x87_st80(ST(4)); eaaddr+=10;
1198 x87_st80(ST(5)); eaaddr+=10;
1199 x87_st80(ST(6)); eaaddr+=10;
1200 x87_st80(ST(7));
1201 }
1202 break;
1203 }
1204 cycles-=(cr0&1)?56:67;
1205 return;
1206 case 7: /*FSTSW*/
1207 if (fplog) pclog("FSTSW %08X:%08X\n", easeg, eaaddr);
1208 seteaw((npxs&0xC7FF)|(TOP<<11));
1209 cycles-=3;
1210 return;
1211 }
1212 }
1213 // fatal("Bad x87 DD opcode %i %02X\n",reg,rmdat32&0xFF);
1214 x86illegal();
1215 }
1216 void x87_de()
1217 {
1218 int32_t templ;
1219 if (mod==3)
1220 {
1221 switch (rmdat32&0xFF)
1222 {
1223 case 0xC0: case 0xC1: case 0xC2: case 0xC3: /*FADDP*/
1224 case 0xC4: case 0xC5: case 0xC6: case 0xC7:
1225 if (fplog) pclog("FADDP %f %f\n", ST(rmdat32 & 7), ST(0));
1226 ST(rmdat32&7)=ST(rmdat32&7)+ST(0);
1227 x87_pop();
1228 cycles-=8;
1229 return;
1230 case 0xC8: case 0xC9: case 0xCA: case 0xCB: /*FMULP*/
1231 case 0xCC: case 0xCD: case 0xCE: case 0xCF:
1232 if (fplog) pclog("FMULP %f %f\n", ST(rmdat32 & 7), ST(0));
1233 ST(rmdat32&7)=ST(rmdat32&7)*ST(0);
1234 x87_pop();
1235 cycles-=16;
1236 return;
1237 case 0xD9: /*FCOMPP*/
1238 if (fplog) pclog("FCOMPP %f %f\n", ST(0), ST(1));
1239 npxs&=~(C0|C2|C3);
1240 if (*(uint64_t *)&ST(0) == ((uint64_t)1 << 63) && *(uint64_t *)&ST(1) == 0)
1241 npxs |= C0; /*Nasty hack to fix 80387 detection*/
1242 else if (ST(0) == ST(1))
1243 npxs |= C3;
1244 else if (ST(0) < ST(1))
1245 npxs |= C0;
1246 x87_pop();
1247 x87_pop();
1248 cycles-=5;
1249 return;
1250 case 0xE0: case 0xE1: case 0xE2: case 0xE3: /*FSUBRP*/
1251 case 0xE4: case 0xE5: case 0xE6: case 0xE7:
1252 if (fplog) pclog("FSUBRP %f %f\n", ST(rmdat32 & 7), ST(0));
1253 ST(rmdat32&7)=ST(0)-ST(rmdat32&7);
1254 x87_pop();
1255 cycles-=8;
1256 return;
1257 case 0xE8: case 0xE9: case 0xEA: case 0xEB: /*FSUBP*/
1258 case 0xEC: case 0xED: case 0xEE: case 0xEF:
1259 if (fplog) pclog("FSUBP %f %f\n", ST(rmdat32 & 7), ST(0));
1260 ST(rmdat32&7)=ST(rmdat32&7)-ST(0);
1261 x87_pop();
1262 cycles-=8;
1263 return;
1264 case 0xF0: case 0xF1: case 0xF2: case 0xF3: /*FDIVRP*/
1265 case 0xF4: case 0xF5: case 0xF6: case 0xF7:
1266 if (fplog) pclog("FDIVRP %f %f\n", ST(rmdat32 & 7), ST(0));
1267 x87_div(ST(rmdat32&7), ST(0), ST(rmdat32&7));
1268 x87_pop();
1269 cycles-=73;
1270 return;
1271 case 0xF8: case 0xF9: case 0xFA: case 0xFB: /*FDIVP*/
1272 case 0xFC: case 0xFD: case 0xFE: case 0xFF:
1273 if (fplog) pclog("FDIVP %f %f %i\n", ST(rmdat32 & 7), ST(0), rmdat32 & 7);
1274 x87_div(ST(rmdat32&7), ST(rmdat32&7), ST(0));
1275 x87_pop();
1276 cycles-=73;
1277 return;
1278 }
1279 }
1280 else
1281 {
1282 templ=(int32_t)(int16_t)geteaw(); if (abrt) return;
1283 switch (reg)
1284 {
1285 case 0: /*FIADD*/
1286 if (fplog) pclog("FIADDw %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
1287 ST(0)=ST(0)+(double)templ;
1288 cycles-=20;
1289 return;
1290 case 1: /*FIMUL*/
1291 if (fplog) pclog("FIMULw %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
1292 ST(0)=ST(0)*(double)templ;
1293 cycles-=22;
1294 return;
1295 case 2: /*FICOM*/
1296 if (fplog) pclog("FICOMw %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
1297 npxs&=~(C0|C2|C3);
1298 if (ST(0)==(double)templ) npxs|=C3;
1299 else if (ST(0)<(double)templ) npxs|=C0;
1300 cycles-=15;
1301 return;
1302 case 3: /*FICOMP*/
1303 if (fplog) pclog("FICOMPw %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
1304 npxs&=~(C0|C2|C3);
1305 if (ST(0)==(double)templ) npxs|=C3;
1306 else if (ST(0)<(double)templ) npxs|=C0;
1307 x87_pop();
1308 cycles-=15;
1309 return;
1310 case 4: /*FISUB*/
1311 if (fplog) pclog("FISUBw %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
1312 ST(0)=ST(0)-(double)templ;
1313 cycles-=20;
1314 return;
1315 case 5: /*FISUBR*/
1316 if (fplog) pclog("FISUBRw %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
1317 ST(0)=(double)templ-ST(0);
1318 cycles-=19;
1319 return;
1320 case 6: /*FIDIV*/
1321 if (fplog) pclog("FIDIVw %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
1322 x87_div(ST(0), ST(0), (double)templ);
1323 cycles-=84;
1324 return;
1325 case 7: /*FIDIVR*/
1326 if (fplog) pclog("FIDIVRw %08X:%08X %f %f\n", easeg, eaaddr, ST(0), (double)templ);
1327 x87_div(ST(0), (double)templ, ST(0));
1328 cycles-=84;
1329 return;
1330 }
1331 }
1332 // fatal("Bad x87 DE opcode %i %02X\n",reg,rmdat32&0xFF);
1333 x86illegal();
1334 }
1335 void x87_df()
1336 {
1337 int c;
1338 int64_t temp64;
1339 int16_t temp16;
1340 double tempd;
1341 uint8_t tempc;
1342 if (mod==3)
1343 {
1344 switch (reg)
1345 {
1346 case 4:
1347 switch (rmdat32&0xFF)
1348 {
1349 case 0xE0: /*FSTSW AX*/
1350 if (fplog) pclog("FSTSW\n");
1351 AX=npxs;
1352 cycles-=3;
1353 return;
1354 }
1355 break;
1356 }
1357 }
1358 else
1359 {
1360 switch (reg)
1361 {
1362 case 0: /*FILD short*/
1363 if (fplog) pclog("FILDw %08X:%08X\n", easeg, eaaddr);
1364 temp16=geteaw(); if (abrt) return;
1365 if (fplog) pclog(" %f\n", (double)temp16);
1366 x87_push((double)temp16);
1367 cycles-=13;
1368 return;
1369 case 2: /*FIST word*/
1370 if (fplog) pclog("FISTw %08X:%08X\n", easeg, eaaddr);
1371 temp64 = x87_fround(ST(0));
1372 /* if (temp64 > 32767 || temp64 < -32768)
1373 fatal("FISTw overflow %i\n", temp64);*/
1374 seteaw((int16_t)temp64);
1375 cycles-=29;
1376 return;
1377 case 3: /*FISTP word*/
1378 if (fplog) pclog("FISTPw %08X:%08X\n", easeg, eaaddr);
1379 temp64 = x87_fround(ST(0));
1380 /* if (temp64 > 32767 || temp64 < -32768)
1381 fatal("FISTw overflow %i\n", temp64);*/
1382 seteaw((int16_t)temp64); if (abrt) return;
1383 x87_pop();
1384 cycles-=29;
1385 return;
1386 case 5: /*FILD long*/
1387 if (fplog) pclog("FILDl %08X:%08X\n", easeg, eaaddr);
1388 temp64=geteal(); if (abrt) return;
1389 temp64|=(uint64_t)readmeml(easeg,eaaddr+4)<<32;
1390 if (fplog) pclog(" %f %08X %08X\n", (double)temp64, readmeml(easeg,eaaddr), readmeml(easeg,eaaddr+4));
1391 x87_push((double)temp64);
1392 cycles-=10;
1393 return;
1394 case 6: /*FBSTP*/
1395 if (fplog) pclog("FBSTP %08X:%08X\n", easeg, eaaddr);
1396 tempd=ST(0);
1397 if (tempd < 0.0)
1398 tempd = -tempd;
1399 for (c=0;c<9;c++)
1400 {
1401 tempc=(uint8_t)floor(fmod(tempd,10.0)); tempd-=floor(fmod(tempd,10.0)); tempd/=10.0;
1402 tempc|=((uint8_t)floor(fmod(tempd,10.0)))<<4; tempd-=floor(fmod(tempd,10.0)); tempd/=10.0;
1403 writememb(easeg,eaaddr+c,tempc);
1404 }
1405 tempc=(uint8_t)floor(fmod(tempd,10.0));
1406 if (ST(0)<0.0) tempc|=0x80;
1407 writememb(easeg,eaaddr+9,tempc); if (abrt) return;
1408 x87_pop();
1409 return;
1410 case 7: /*FISTP long*/
1411 if (fplog) pclog("FISTPl %08X:%08X\n", easeg, eaaddr);
1412 temp64=x87_fround(ST(0));
1413 seteal(temp64);
1414 writememl(easeg,eaaddr+4,temp64>>32); if (abrt) return;
1415 x87_pop();
1416 cycles-=29;
1417 return;
1418 }
1419 }
1420 // fatal("Bad x87 DF opcode %i %02X\n",reg,rmdat32&0xFF);
1421 x86illegal();
1422 }
