this repo has no description
1/*
2 FPCPEMDV.h
3
4 Copyright (C) 2007 Ross Martin, Paul C. Pratt
5
6 You can redistribute this file and/or modify it under the terms
7 of version 2 of the GNU General Public License as published by
8 the Free Software Foundation. You should have received a copy
9 of the license along with this file; see the file COPYING.
10
11 This file is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 license for more details.
15*/
16
17/*
18 Floating Point CoProcessor Emulated Device
19 (included by MINEM68K.c)
20*/
21
22/*
23 ReportAbnormalID unused 0x0306 - 0x03FF
24*/
25
26
27LOCALVAR struct fpustruct
28{
29 myfpr fp[8];
30 CPTR FPIAR; /* Floating point instruction address register */
31} fpu_dat;
32
33LOCALPROC myfp_SetFPIAR(ui5r v)
34{
35 fpu_dat.FPIAR = v;
36}
37
38LOCALFUNC ui5r myfp_GetFPIAR(void)
39{
40 return fpu_dat.FPIAR;
41}
42
43LOCALFUNC blnr DecodeAddrModeRegister(ui5b sz)
44{
45 ui4r Dat = V_regs.CurDecOpY.v[0].ArgDat;
46 ui4r themode = (Dat >> 3) & 7;
47 ui4r thereg = Dat & 7;
48
49 switch (themode) {
50 case 2 :
51 case 3 :
52 case 4 :
53 case 5 :
54 case 6 :
55 return DecodeModeRegister(sz);
56 break;
57 case 7 :
58 switch (thereg) {
59 case 0 :
60 case 1 :
61 case 2 :
62 case 3 :
63 case 4 :
64 return DecodeModeRegister(sz);
65 break;
66 default :
67 return falseblnr;
68 break;
69 }
70 break;
71 default :
72 return falseblnr;
73 break;
74 }
75}
76
77LOCALPROC read_long_double(ui5r addr, myfpr *r)
78{
79 ui4r v2;
80 ui5r v1;
81 ui5r v0;
82
83 v2 = get_word(addr + 0);
84 /* ignore word at offset 2 */
85 v1 = get_long(addr + 4);
86 v0 = get_long(addr + 8);
87
88 myfp_FromExtendedFormat(r, v2, v1, v0);
89}
90
91LOCALPROC write_long_double(ui5r addr, myfpr *xx)
92{
93 ui4r v2;
94 ui5r v1;
95 ui5r v0;
96
97 myfp_ToExtendedFormat(xx, &v2, &v1, &v0);
98
99 put_word(addr + 0, v2);
100 put_word(addr + 2, 0);
101 put_long(addr + 4, v1);
102 put_long(addr + 8, v0);
103}
104
105LOCALPROC read_double(ui5r addr, myfpr *r)
106{
107 ui5r v1;
108 ui5r v0;
109
110 v1 = get_long(addr + 0);
111 v0 = get_long(addr + 4);
112
113 myfp_FromDoubleFormat(r, v1, v0);
114}
115
116LOCALPROC write_double(ui5r addr, myfpr *dd)
117{
118 ui5r v1;
119 ui5r v0;
120
121 myfp_ToDoubleFormat(dd, &v1, &v0);
122
123 put_long(addr + 0, v1);
124 put_long(addr + 4, v0);
125}
126
127#if 0
128LOCALPROC read_single(ui5r addr, myfpr *r)
129{
130 myfp_FromSingleFormat(r, get_long(addr));
131}
132
133LOCALPROC write_single(ui5r addr, myfpr *ff)
134{
135 put_long(addr, myfp_ToSingleFormat(ff));
136}
137#endif
138
139
140LOCALFUNC int CheckFPCondition(ui4b predicate)
141{
142 int condition_true = 0;
143
144 ui3r cc = myfp_GetConditionCodeByte();
145
146 int c_nan = (cc) & 1;
147 /* int c_inf = (cc >> 1) & 1; */
148 int c_zero = (cc >> 2) & 1;
149 int c_neg = (cc >> 3) & 1;
150
151 /*
152 printf(
153 "FPSR Checked: c_nan=%d, c_zero=%d, c_neg=%d,"
154 " predicate=0x%04x\n",
155 c_nan, c_zero, c_neg, predicate);
156 */
157
158 switch (predicate) {
159 case 0x11: /* SEQ */
160 case 0x01: /* EQ */
161 condition_true = c_zero;
162 break;
163 case 0x1E: /* SNE */
164 case 0x0E: /* NE */
165 condition_true = ! c_zero;
166 break;
167 case 0x02: /* OGT */
168 case 0x12: /* GT */
169 condition_true = (! c_neg) && (! c_zero) && (! c_nan);
170 break;
171 case 0x0D: /* ULE */
172 case 0x1D: /* NGT */
173 condition_true = c_neg || c_zero || c_nan;
174 break;
175 case 0x03: /* OGE */
176 case 0x13: /* GE */
177 condition_true = c_zero || ((! c_neg) && (! c_nan));
178 break;
179 case 0x0C: /* ULT */
180 case 0x1C: /* NGE */
181 condition_true = c_nan || ((! c_zero) && c_neg) ;
182 break;
183 case 0x04: /* OLT */
184 case 0x14: /* LT */
185 condition_true = c_neg && (! c_nan) && (! c_zero);
186 break;
187 case 0x0B: /* UGE */
188 case 0x1B: /* NLT */
189 condition_true = c_nan || c_zero || (! c_neg);
190 break;
191 case 0x05: /* OLE */
192 case 0x15: /* LE */
193 condition_true = ((! c_nan) && c_neg) || c_zero;
194 break;
195 case 0x0A: /* UGT */
196 case 0x1A: /* NLE */
197 condition_true = c_nan || ((! c_neg) && (! c_zero));
198 break;
199 case 0x06: /* OGL */
200 case 0x16: /* GL */
201 condition_true = (! c_nan) && (! c_zero);
202 break;
203 case 0x09: /* UEQ */
204 case 0x19: /* NGL */
205 condition_true = c_nan || c_zero;
206 break;
207 case 0x07: /* OR */
208 case 0x17: /* GLE */
209 condition_true = ! c_nan;
210 break;
211 case 0x08: /* NGLE */
212 case 0x18: /* NGLE */
213 condition_true = c_nan;
214 break;
215 case 0x00: /* SFALSE */
216 case 0x10: /* FALSE */
217 condition_true = 0;
218 break;
219 case 0x0F: /* STRUE */
220 case 0x1F: /* TRUE */
221 condition_true = 1;
222 break;
223 }
224
225 /* printf("condition_true=%d\n", condition_true); */
226
227 return condition_true;
228}
229
230LOCALIPROC DoCodeFPU_dflt(void)
231{
232 ReportAbnormalID(0x0301,
233 "unimplemented Floating Point Instruction");
234#if dbglog_HAVE
235 {
236 ui4r opcode = ((ui4r)(V_regs.CurDecOpY.v[0].AMd) << 8)
237 | V_regs.CurDecOpY.v[0].ArgDat;
238
239 dbglog_writelnNum("opcode", opcode);
240 }
241#endif
242 DoCodeFdefault();
243}
244
245LOCALIPROC DoCodeFPU_Save(void)
246{
247 ui4r opcode = ((ui4r)(V_regs.CurDecOpY.v[0].AMd) << 8)
248 | V_regs.CurDecOpY.v[0].ArgDat;
249 if ((opcode == 0xF327) || (opcode == 0xF32D)) {
250#if 0
251 DecodeModeRegister(4);
252 SetArgValueL(0); /* for now, try null state frame */
253#endif
254 /* 28 byte 68881 IDLE frame */
255
256 if (! DecodeAddrModeRegister(28)) {
257 DoCodeFPU_dflt();
258#if dbglog_HAVE
259 dbglog_writeln(
260 "DecodeAddrModeRegister fails in DoCodeFPU_Save");
261#endif
262 } else {
263 put_long(V_regs.ArgAddr.mem, 0x1f180000);
264 put_long(V_regs.ArgAddr.mem + 4, 0);
265 put_long(V_regs.ArgAddr.mem + 8, 0);
266 put_long(V_regs.ArgAddr.mem + 12, 0);
267 put_long(V_regs.ArgAddr.mem + 16, 0);
268 put_long(V_regs.ArgAddr.mem + 20, 0);
269 put_long(V_regs.ArgAddr.mem + 24, 0x70000000);
270 }
271
272 } else {
273 DoCodeFPU_dflt();
274#if dbglog_HAVE
275 dbglog_writeln("unimplemented FPU Save");
276#endif
277 }
278}
279
280LOCALIPROC DoCodeFPU_Restore(void)
281{
282 ui4r opcode = ((ui4r)(V_regs.CurDecOpY.v[0].AMd) << 8)
283 | V_regs.CurDecOpY.v[0].ArgDat;
284 ui4r themode = (opcode >> 3) & 7;
285 ui4r thereg = opcode & 7;
286 if ((opcode == 0xF35F) || (opcode == 0xF36D)) {
287 ui5r dstvalue;
288
289 if (! DecodeAddrModeRegister(4)) {
290 DoCodeFPU_dflt();
291#if dbglog_HAVE
292 dbglog_writeln(
293 "DecodeAddrModeRegister fails in DoCodeFPU_Restore");
294#endif
295 } else {
296 dstvalue = get_long(V_regs.ArgAddr.mem);
297 if (dstvalue != 0) {
298 if (0x1f180000 == dstvalue) {
299 if (3 == themode) {
300 m68k_areg(thereg) = V_regs.ArgAddr.mem + 28;
301 }
302 } else {
303 DoCodeFPU_dflt();
304#if dbglog_HAVE
305 dbglog_writeln("unknown restore");
306 /* not a null state we saved */
307#endif
308 }
309 }
310 }
311 } else {
312 DoCodeFPU_dflt();
313#if dbglog_HAVE
314 dbglog_writeln("unimplemented FPU Restore");
315#endif
316 }
317}
318
319LOCALIPROC DoCodeFPU_FBccW(void)
320{
321 /*
322 Also get here for a NOP instruction (opcode 0xF280),
323 which is simply a FBF.w with offset 0
324 */
325 ui4r Dat = V_regs.CurDecOpY.v[0].ArgDat;
326
327 if (CheckFPCondition(Dat & 0x3F)) {
328 DoCodeBraW();
329 } else {
330 SkipiWord();
331 }
332
333 /* printf("pc_p set to 0x%p in FBcc (32bit)\n", V_pc_p); */
334}
335
336LOCALIPROC DoCodeFPU_FBccL(void)
337{
338 ui4r Dat = V_regs.CurDecOpY.v[0].ArgDat;
339
340 if (CheckFPCondition(Dat & 0x3F)) {
341 DoCodeBraL();
342 } else {
343 SkipiLong();
344 }
345}
346
347LOCALIPROC DoCodeFPU_DBcc(void)
348{
349 ui4r Dat = V_regs.CurDecOpY.v[0].ArgDat;
350 ui4r thereg = Dat & 7;
351 ui4b word2 = (int)nextiword();
352
353 ui4b predicate = word2 & 0x3F;
354
355 int condition_true = CheckFPCondition(predicate);
356
357 if (! condition_true) {
358 ui5b fdb_count = ui5r_FromSWord(m68k_dreg(thereg)) - 1;
359
360 m68k_dreg(thereg) =
361 (m68k_dreg(thereg) & ~ 0xFFFF) | (fdb_count & 0xFFFF);
362 if ((si5b)fdb_count == -1) {
363 SkipiWord();
364 } else {
365 DoCodeBraW();
366 }
367 } else {
368 SkipiWord();
369 }
370}
371
372LOCALIPROC DoCodeFPU_Trapcc(void)
373{
374 ui4r Dat = V_regs.CurDecOpY.v[0].ArgDat;
375 ui4r thereg = Dat & 7;
376
377 ui4b word2 = (int)nextiword();
378
379 ui4b predicate = word2 & 0x3F;
380
381 int condition_true = CheckFPCondition(predicate);
382
383 if (thereg == 2) {
384 (void) nextiword();
385 } else if (thereg == 3) {
386 (void) nextilong();
387 } else if (thereg == 4) {
388 } else {
389 ReportAbnormalID(0x0302, "Invalid FTRAPcc (?");
390 }
391
392 if (condition_true) {
393 ReportAbnormalID(0x0303, "FTRAPcc trapping");
394 Exception(7);
395 }
396}
397
398LOCALIPROC DoCodeFPU_Scc(void)
399{
400 ui4b word2 = (int)nextiword();
401
402 if (! DecodeModeRegister(1)) {
403 DoCodeFPU_dflt();
404#if dbglog_HAVE
405 dbglog_writeln("bad mode/reg in DoCodeFPU_Scc");
406#endif
407 } else {
408 if (CheckFPCondition(word2 & 0x3F)) {
409 SetArgValueB(0xFFFF);
410 } else {
411 SetArgValueB(0x0000);
412 }
413 }
414}
415
416LOCALPROC DoCodeF_InvalidPlusWord(void)
417{
418 BackupPC();
419 DoCodeFPU_dflt();
420}
421
422LOCALFUNC int CountCSIAlist(ui4b word2)
423{
424 ui4b regselect = (word2 >> 10) & 0x7;
425 int num = 0;
426
427 if (regselect & 1) {
428 num++;
429 }
430 if (regselect & 2) {
431 num++;
432 }
433 if (regselect & 4) {
434 num++;
435 }
436
437 return num;
438}
439
440LOCALPROC DoCodeFPU_Move_EA_CSIA(ui4b word2)
441{
442 int n;
443 ui5b ea_value[3];
444 ui4b regselect = (word2 >> 10) & 0x7;
445 int num = CountCSIAlist(word2);
446
447 if (regselect == 0) {
448 DoCodeF_InvalidPlusWord();
449#if dbglog_HAVE
450 dbglog_writeln("Invalid FMOVE instruction");
451#endif
452 return;
453 }
454
455 /* FMOVEM.L <EA>, <FP CR,SR,IAR list> */
456
457 if (! DecodeModeRegister(4 * num)) {
458 DoCodeF_InvalidPlusWord();
459#if dbglog_HAVE
460 dbglog_writeln("bad mode/reg in DoCodeFPU_Move_EA_CSIA");
461#endif
462 } else {
463 ea_value[0] = GetArgValueL();
464 if (num > 1) {
465 ea_value[1] = get_long(V_regs.ArgAddr.mem + 4);
466 }
467 if (num > 2) {
468 ea_value[2] = get_long(V_regs.ArgAddr.mem + 8);
469 }
470
471 n = 0;
472 if (regselect & (1 << 2)) {
473 myfp_SetFPCR(ea_value[n++]);
474 }
475 if (regselect & (1 << 1)) {
476 myfp_SetFPSR(ea_value[n++]);
477 }
478 if (regselect & (1 << 0)) {
479 myfp_SetFPIAR(ea_value[n++]);
480 }
481 }
482}
483
484LOCALPROC DoCodeFPU_MoveM_CSIA_EA(ui4b word2)
485{
486 int n;
487 ui5b ea_value[3];
488 int num = CountCSIAlist(word2);
489
490 ui4b regselect = (word2 >> 10) & 0x7;
491
492 /* FMOVEM.L <FP CR,SR,IAR list>, <EA> */
493
494 if (0 == regselect) {
495 DoCodeF_InvalidPlusWord();
496#if dbglog_HAVE
497 dbglog_writeln("Invalid FMOVE instruction");
498#endif
499 } else
500 if (! DecodeModeRegister(4 * num)) {
501 DoCodeF_InvalidPlusWord();
502#if dbglog_HAVE
503 dbglog_writeln("bad mode/reg in DoCodeFPU_MoveM_CSIA_EA");
504#endif
505 } else
506 {
507 n = 0;
508 if (regselect & (1 << 2)) {
509 ea_value[n++] = myfp_GetFPCR();
510 }
511 if (regselect & (1 << 1)) {
512 ea_value[n++] = myfp_GetFPSR();
513 }
514 if (regselect & (1 << 0)) {
515 ea_value[n++] = myfp_GetFPIAR();
516 }
517
518 SetArgValueL(ea_value[0]);
519 if (num > 1) {
520 put_long(V_regs.ArgAddr.mem + 4, ea_value[1]);
521 }
522 if (num > 2) {
523 put_long(V_regs.ArgAddr.mem + 8, ea_value[2]);
524 }
525 }
526}
527
528LOCALPROC DoCodeFPU_MoveM_EA_list(ui4b word2)
529{
530 int i;
531 ui5r myaddr;
532 ui5r count;
533 ui4b register_list = word2;
534
535 ui4b fmove_mode = (word2 >> 11) & 0x3;
536
537 /* FMOVEM.X <ea>, <list> */
538
539 if ((fmove_mode == 0) || (fmove_mode == 1)) {
540 DoCodeF_InvalidPlusWord();
541#if dbglog_HAVE
542 dbglog_writeln("Invalid FMOVEM.X instruction");
543#endif
544 return;
545 }
546
547 if (fmove_mode == 3) {
548 /* Dynamic mode */
549 register_list = V_regs.regs[(word2 >> 4) & 7];
550 }
551
552 count = 0;
553 for (i = 0; i <= 7; i++) {
554 int j = 1 << (7 - i);
555 if (j & register_list) {
556 ++count;
557 }
558 }
559
560 if (! DecodeModeRegister(12 * count)) {
561 DoCodeF_InvalidPlusWord();
562#if dbglog_HAVE
563 dbglog_writeln(
564 "DecodeModeRegister fails DoCodeFPU_MoveM_EA_list");
565#endif
566 } else {
567 /* Postincrement mode or Control mode */
568
569 myaddr = V_regs.ArgAddr.mem;
570
571 for (i = 0; i <= 7; i++) {
572 int j = 1 << (7 - i);
573 if (j & register_list) {
574 read_long_double(myaddr, &fpu_dat.fp[i]);
575 myaddr += 12;
576 }
577 }
578 }
579}
580
581LOCALPROC DoCodeFPU_MoveM_list_EA(ui4b word2)
582{
583 /* FMOVEM.X <list>, <ea> */
584
585 int i;
586 ui5r myaddr;
587 ui5r count;
588 ui4b register_list = word2;
589 ui4r Dat = V_regs.CurDecOpY.v[0].ArgDat;
590 ui4r themode = (Dat >> 3) & 7;
591
592 ui4b fmove_mode = (word2 >> 11) & 0x3;
593
594 if ((fmove_mode == 1) || (fmove_mode == 3)) {
595 /* Dynamic mode */
596 register_list = V_regs.regs[(word2 >> 4) & 7];
597 }
598
599 count = 0;
600 for (i = 7; i >= 0; i--) {
601 int j = 1 << i;
602 if (j & register_list) {
603 ++count;
604 }
605 }
606
607 if (! DecodeModeRegister(12 * count)) {
608 DoCodeF_InvalidPlusWord();
609#if dbglog_HAVE
610 dbglog_writeln(
611 "DecodeModeRegister fails DoCodeFPU_MoveM_list_EA");
612#endif
613 } else {
614 if (themode == 4) {
615 /* Predecrement mode */
616
617 myaddr = V_regs.ArgAddr.mem + 12 * count;
618
619 for (i = 7; i >= 0; i--) {
620 int j = 1 << i;
621 if (j & register_list) {
622 myaddr -= 12;
623 write_long_double(myaddr, &fpu_dat.fp[i]);
624 }
625 }
626 } else {
627 /* Control mode */
628
629 myaddr = V_regs.ArgAddr.mem;
630
631 for (i = 0; i <= 7; i++) {
632 int j = 1 << (7 - i);
633 if (j & register_list) {
634 write_long_double(myaddr, &fpu_dat.fp[i]);
635 myaddr += 12;
636 }
637 }
638 }
639 }
640}
641
642LOCALPROC DoCodeFPU_MoveCR(ui4b word2)
643{
644 /* FMOVECR */
645 ui4r opcode = ((ui4r)(V_regs.CurDecOpY.v[0].AMd) << 8)
646 | V_regs.CurDecOpY.v[0].ArgDat;
647
648 if (opcode != 0xF200) {
649 DoCodeF_InvalidPlusWord();
650#if dbglog_HAVE
651 dbglog_writeln("bad opcode in FMOVECR");
652#endif
653 } else {
654 ui4b RomOffset = word2 & 0x7F;
655 ui4b DestReg = (word2 >> 7) & 0x7;
656
657 if (! myfp_getCR(&fpu_dat.fp[DestReg], RomOffset)) {
658 DoCodeF_InvalidPlusWord();
659#if dbglog_HAVE
660 dbglog_writeln("Invalid constant number in FMOVECR");
661#endif
662 }
663 }
664}
665
666LOCALPROC SaveResultAndFPSR(myfpr *DestReg, myfpr *result)
667{
668 *DestReg = *result;
669 myfp_SetConditionCodeByteFromResult(result);
670}
671
672LOCALPROC DoCodeFPU_GenOp(ui4b word2, myfpr *source)
673{
674 myfpr result;
675 myfpr t0;
676 myfpr *DestReg = &fpu_dat.fp[(word2 >> 7) & 0x7];
677
678 switch (word2 & 0x7F) {
679
680 case 0x00: /* FMOVE */
681 SaveResultAndFPSR(DestReg, source);
682 break;
683
684 case 0x01: /* FINT */
685 myfp_Int(&result, source);
686 SaveResultAndFPSR(DestReg, &result);
687 break;
688
689 case 0x02: /* FSINH */
690 myfp_Sinh(&result, source);
691 SaveResultAndFPSR(DestReg, &result);
692 break;
693
694 case 0x03: /* FINTRZ */
695 myfp_IntRZ(&result, source);
696 SaveResultAndFPSR(DestReg, &result);
697 break;
698
699 case 0x04: /* FSQRT */
700 myfp_Sqrt(&result, source);
701 SaveResultAndFPSR(DestReg, &result);
702 break;
703
704 case 0x06: /* FLOGNP1 */
705 myfp_LogNP1(&result, source);
706 SaveResultAndFPSR(DestReg, &result);
707 break;
708
709 case 0x08: /* FETOXM1 */
710 myfp_EToXM1(&result, source);
711 SaveResultAndFPSR(DestReg, &result);
712 break;
713
714 case 0x09: /* FTANH */
715 myfp_Tanh(&result, source);
716 SaveResultAndFPSR(DestReg, &result);
717 break;
718
719 case 0x0A: /* FATAN */
720 myfp_ATan(&result, source);
721 SaveResultAndFPSR(DestReg, &result);
722 break;
723
724 case 0x0C: /* FASIN */
725 myfp_ASin(&result, source);
726 SaveResultAndFPSR(DestReg, &result);
727 break;
728
729 case 0x0D: /* FATANH */
730 myfp_ATanh(&result, source);
731 SaveResultAndFPSR(DestReg, &result);
732 break;
733
734 case 0x0E: /* FSIN */
735 myfp_Sin(&result, source);
736 SaveResultAndFPSR(DestReg, &result);
737 break;
738
739 case 0x0F: /* FTAN */
740 myfp_Tan(&result, source);
741 SaveResultAndFPSR(DestReg, &result);
742 break;
743
744 case 0x10: /* FETOX */
745 myfp_EToX(&result, source);
746 SaveResultAndFPSR(DestReg, &result);
747 break;
748
749 case 0x11: /* FTWOTOX */
750 myfp_TwoToX(&result, source);
751 SaveResultAndFPSR(DestReg, &result);
752 break;
753
754 case 0x12: /* FTENTOX */
755 myfp_TenToX(&result, source);
756 SaveResultAndFPSR(DestReg, &result);
757 break;
758
759 case 0x14: /* FLOGN */
760 myfp_LogN(&result, source);
761 SaveResultAndFPSR(DestReg, &result);
762 break;
763
764 case 0x15: /* FLOG10 */
765 myfp_Log10(&result, source);
766 SaveResultAndFPSR(DestReg, &result);
767 break;
768
769 case 0x16: /* FLOG2 */
770 myfp_Log2(&result, source);
771 SaveResultAndFPSR(DestReg, &result);
772 break;
773
774 case 0x18: /* FABS */
775 myfp_Abs(&result, source);
776 SaveResultAndFPSR(DestReg, &result);
777 break;
778
779 case 0x19: /* FCOSH */
780 myfp_Cosh(&result, source);
781 SaveResultAndFPSR(DestReg, &result);
782 break;
783
784 case 0x1A: /* FNEG */
785 myfp_Neg(&result, source);
786 SaveResultAndFPSR(DestReg, &result);
787 break;
788
789 case 0x1C: /* FACOS */
790 myfp_ACos(&result, source);
791 SaveResultAndFPSR(DestReg, &result);
792 break;
793
794 case 0x1D: /* FCOS */
795 myfp_Cos(&result, source);
796 SaveResultAndFPSR(DestReg, &result);
797 break;
798
799 case 0x1E: /* FGETEXP */
800 myfp_GetExp(&result, source);
801 SaveResultAndFPSR(DestReg, &result);
802 break;
803
804 case 0x1F: /* FGETMAN */
805 myfp_GetMan(&result, source);
806 SaveResultAndFPSR(DestReg, &result);
807 break;
808
809 case 0x20: /* FDIV */
810 myfp_Div(&result, DestReg, source);
811 SaveResultAndFPSR(DestReg, &result);
812 break;
813
814 case 0x21: /* FMOD */ /* 0x2D in some docs, 0x21 in others ? */
815 myfp_Mod(&result, DestReg, source);
816 SaveResultAndFPSR(DestReg, &result);
817 break;
818
819 case 0x22: /* FADD */
820 myfp_Add(&result, DestReg, source);
821 SaveResultAndFPSR(DestReg, &result);
822 break;
823
824 case 0x23: /* FMUL */
825 myfp_Mul(&result, DestReg, source);
826 SaveResultAndFPSR(DestReg, &result);
827 break;
828
829 case 0x24: /* FSGLDIV */
830 myfp_Div(&t0, DestReg, source);
831 myfp_RoundToSingle(&result, &t0);
832 SaveResultAndFPSR(DestReg, &result);
833 break;
834
835 case 0x25: /* FREM */
836 myfp_Rem(&result, DestReg, source);
837 SaveResultAndFPSR(DestReg, &result);
838 break;
839
840 case 0x26: /* FSCALE */
841 myfp_Scale(&result, DestReg, source);
842 SaveResultAndFPSR(DestReg, &result);
843 break;
844
845 case 0x27: /* FSGLMUL */
846 myfp_Mul(&t0, DestReg, source);
847 myfp_RoundToSingle(&result, &t0);
848 SaveResultAndFPSR(DestReg, &result);
849 break;
850
851 case 0x28: /* FSUB */
852 myfp_Sub(&result, DestReg, source);
853 SaveResultAndFPSR(DestReg, &result);
854 break;
855
856 case 0x30:
857 case 0x31:
858 case 0x32:
859 case 0x33:
860 case 0x34:
861 case 0x35:
862 case 0x36:
863 case 0x37:
864 /* FSINCOS */
865 myfp_SinCos(&result, &fpu_dat.fp[word2 & 0x7], source);
866 SaveResultAndFPSR(DestReg, &result);
867 break;
868
869 case 0x38: /* FCMP */
870 myfp_Sub(&result, DestReg, source);
871 /* don't save result */
872 myfp_SetConditionCodeByteFromResult(&result);
873 break;
874
875 case 0x3A: /* FTST */
876 myfp_SetConditionCodeByteFromResult(source);
877 break;
878
879 /*
880 everything after here is not in 68881/68882,
881 appears first in 68040
882 */
883
884 case 0x40: /* FSMOVE */
885 myfp_RoundToSingle(&result, source);
886 SaveResultAndFPSR(DestReg, &result);
887 break;
888
889 case 0x41: /* FSSQRT */
890 myfp_Sqrt(&t0, source);
891 myfp_RoundToSingle(&result, &t0);
892 SaveResultAndFPSR(DestReg, &result);
893 break;
894
895 case 0x44: /* FDMOVE */
896 myfp_RoundToDouble(&result, source);
897 SaveResultAndFPSR(DestReg, &result);
898 break;
899
900 case 0x45: /* FDSQRT */
901 myfp_Sqrt(&t0, source);
902 myfp_RoundToDouble(&result, &t0);
903 SaveResultAndFPSR(DestReg, &result);
904 break;
905
906 case 0x58: /* FSABS */
907 myfp_Abs(&t0, source);
908 myfp_RoundToSingle(&result, &t0);
909 SaveResultAndFPSR(DestReg, &result);
910 break;
911
912 case 0x5A: /* FSNEG */
913 myfp_Neg(&t0, source);
914 myfp_RoundToSingle(&result, &t0);
915 SaveResultAndFPSR(DestReg, &result);
916 break;
917
918 case 0x5C: /* FDABS */
919 myfp_Abs(&t0, source);
920 myfp_RoundToDouble(&result, &t0);
921 SaveResultAndFPSR(DestReg, &result);
922 break;
923
924 case 0x5E: /* FDNEG */
925 myfp_Neg(&t0, source);
926 myfp_RoundToDouble(&result, &t0);
927 SaveResultAndFPSR(DestReg, &result);
928 break;
929
930 case 0x60: /* FSDIV */
931 myfp_Div(&t0, DestReg, source);
932 myfp_RoundToSingle(&result, &t0);
933 SaveResultAndFPSR(DestReg, &result);
934 break;
935
936 case 0x62: /* FSADD */
937 myfp_Add(&t0, DestReg, source);
938 myfp_RoundToSingle(&result, &t0);
939 SaveResultAndFPSR(DestReg, &result);
940 break;
941
942 case 0x63: /* FSMUL */
943 myfp_Mul(&t0, DestReg, source);
944 myfp_RoundToSingle(&result, &t0);
945 SaveResultAndFPSR(DestReg, &result);
946 break;
947
948 case 0x64: /* FDDIV */
949 myfp_Div(&t0, DestReg, source);
950 myfp_RoundToDouble(&result, &t0);
951 SaveResultAndFPSR(DestReg, &result);
952 break;
953
954 case 0x66: /* FDADD */
955 myfp_Add(&t0, DestReg, source);
956 myfp_RoundToDouble(&result, &t0);
957 SaveResultAndFPSR(DestReg, &result);
958 break;
959
960 case 0x67: /* FDMUL */
961 myfp_Mul(&t0, DestReg, source);
962 myfp_RoundToDouble(&result, &t0);
963 SaveResultAndFPSR(DestReg, &result);
964 break;
965
966 case 0x68: /* FSSUB */
967 myfp_Sub(&t0, DestReg, source);
968 myfp_RoundToSingle(&result, &t0);
969 SaveResultAndFPSR(DestReg, &result);
970 break;
971
972 case 0x6C: /* FDSUB */
973 myfp_Sub(&t0, DestReg, source);
974 myfp_RoundToDouble(&result, &t0);
975 SaveResultAndFPSR(DestReg, &result);
976 break;
977
978 default:
979 DoCodeF_InvalidPlusWord();
980#if dbglog_HAVE
981 dbglog_writeln("Invalid DoCodeFPU_GenOp");
982#endif
983 break;
984 }
985}
986
987LOCALPROC DoCodeFPU_GenOpReg(ui4b word2)
988{
989 ui4r regselect = (word2 >> 10) & 0x7;
990
991 DoCodeFPU_GenOp(word2, &fpu_dat.fp[regselect]);
992}
993
994LOCALPROC DoCodeFPU_GenOpEA(ui4b word2)
995{
996 myfpr source;
997
998 switch ((word2 >> 10) & 0x7) {
999 case 0: /* long-word integer */
1000 if (! DecodeModeRegister(4)) {
1001 DoCodeF_InvalidPlusWord();
1002#if dbglog_HAVE
1003 dbglog_writeln(
1004 "DecodeModeRegister fails GetFPSource L");
1005#endif
1006 } else {
1007 myfp_FromLong(&source, GetArgValueL());
1008 DoCodeFPU_GenOp(word2, &source);
1009 }
1010 break;
1011 case 1: /* Single-Precision real */
1012 if (! DecodeModeRegister(4)) {
1013 DoCodeF_InvalidPlusWord();
1014#if dbglog_HAVE
1015 dbglog_writeln(
1016 "DecodeModeRegister fails GetFPSource S");
1017#endif
1018 } else {
1019 myfp_FromSingleFormat(&source, GetArgValueL());
1020 DoCodeFPU_GenOp(word2, &source);
1021 }
1022 break;
1023 case 2: /* extended precision real */
1024 if (! DecodeAddrModeRegister(12)) {
1025 DoCodeF_InvalidPlusWord();
1026#if dbglog_HAVE
1027 dbglog_writeln(
1028 "DecodeAddrModeRegister fails GetFPSource X");
1029#endif
1030 } else {
1031 read_long_double(V_regs.ArgAddr.mem, &source);
1032 DoCodeFPU_GenOp(word2, &source);
1033 }
1034 break;
1035 case 3: /* packed-decimal real */
1036 if (! DecodeAddrModeRegister(16)) {
1037 DoCodeF_InvalidPlusWord();
1038#if dbglog_HAVE
1039 dbglog_writeln(
1040 "DecodeAddrModeRegister fails GetFPSource P");
1041#endif
1042 } else {
1043 ReportAbnormalID(0x0304,
1044 "Packed Decimal in GetFPSource");
1045 /* correct? just set to a constant for now */
1046 /* *r = 9123456789.0; */
1047 DoCodeFPU_GenOp(word2, &source);
1048 }
1049 break;
1050 case 4: /* Word integer */
1051 if (! DecodeModeRegister(2)) {
1052 DoCodeF_InvalidPlusWord();
1053#if dbglog_HAVE
1054 dbglog_writeln(
1055 "DecodeModeRegister fails GetFPSource W");
1056#endif
1057 } else {
1058 myfp_FromLong(&source, GetArgValueW());
1059 DoCodeFPU_GenOp(word2, &source);
1060 }
1061 break;
1062 case 5: /* Double-precision real */
1063 if (! DecodeAddrModeRegister(8)) {
1064 DoCodeF_InvalidPlusWord();
1065#if dbglog_HAVE
1066 dbglog_writeln(
1067 "DecodeAddrModeRegister fails GetFPSource D");
1068#endif
1069 } else {
1070 read_double(V_regs.ArgAddr.mem, &source);
1071 DoCodeFPU_GenOp(word2, &source);
1072 }
1073 break;
1074 case 6: /* Byte Integer */
1075 if (! DecodeModeRegister(1)) {
1076 DoCodeF_InvalidPlusWord();
1077#if dbglog_HAVE
1078 dbglog_writeln(
1079 "DecodeModeRegister fails GetFPSource B");
1080#endif
1081 } else {
1082 myfp_FromLong(&source, GetArgValueB());
1083 DoCodeFPU_GenOp(word2, &source);
1084 }
1085 break;
1086 case 7: /* Not a valid source specifier */
1087 DoCodeFPU_MoveCR(word2);
1088 break;
1089 default:
1090 /* should not be able to get here */
1091 break;
1092 }
1093}
1094
1095LOCALPROC DoCodeFPU_Move_FP_EA(ui4b word2)
1096{
1097 /* FMOVE FP?, <EA> */
1098
1099 ui4r SourceReg = (word2 >> 7) & 0x7;
1100 myfpr *source = &fpu_dat.fp[SourceReg];
1101
1102 switch ((word2 >> 10) & 0x7) {
1103 case 0: /* long-word integer */
1104 if (! DecodeModeRegister(4)) {
1105 DoCodeF_InvalidPlusWord();
1106#if dbglog_HAVE
1107 dbglog_writeln("DecodeModeRegister fails FMOVE L");
1108#endif
1109 } else {
1110 SetArgValueL(myfp_ToLong(source));
1111 }
1112 break;
1113 case 1: /* Single-Precision real */
1114 if (! DecodeModeRegister(4)) {
1115 DoCodeF_InvalidPlusWord();
1116#if dbglog_HAVE
1117 dbglog_writeln("DecodeModeRegister fails FMOVE S");
1118#endif
1119 } else {
1120 SetArgValueL(myfp_ToSingleFormat(source));
1121 }
1122 break;
1123 case 2: /* extended precision real */
1124 if (! DecodeAddrModeRegister(12)) {
1125 DoCodeF_InvalidPlusWord();
1126#if dbglog_HAVE
1127 dbglog_writeln("DecodeAddrModeRegister fails FMOVE X");
1128#endif
1129 } else {
1130 write_long_double(V_regs.ArgAddr.mem, source);
1131 }
1132 break;
1133 case 3: /* packed-decimal real */
1134 if (! DecodeAddrModeRegister(16)) {
1135 DoCodeF_InvalidPlusWord();
1136#if dbglog_HAVE
1137 dbglog_writeln("DecodeAddrModeRegister fails FMOVE P");
1138#endif
1139 } else {
1140 ReportAbnormalID(0x0305, "Packed Decimal in FMOVE");
1141 /* ? */
1142 }
1143 break;
1144 case 4: /* Word integer */
1145 if (! DecodeModeRegister(2)) {
1146 DoCodeF_InvalidPlusWord();
1147#if dbglog_HAVE
1148 dbglog_writeln("DecodeModeRegister fails FMOVE W");
1149#endif
1150 } else {
1151 SetArgValueW(myfp_ToLong(source));
1152 }
1153 break;
1154 case 5: /* Double-precision real */
1155 if (! DecodeAddrModeRegister(8)) {
1156 DoCodeF_InvalidPlusWord();
1157#if dbglog_HAVE
1158 dbglog_writeln("DecodeAddrModeRegister fails FMOVE D");
1159#endif
1160 } else {
1161 write_double(V_regs.ArgAddr.mem, source);
1162 }
1163 break;
1164 case 6: /* Byte Integer */
1165 if (! DecodeModeRegister(1)) {
1166 DoCodeF_InvalidPlusWord();
1167#if dbglog_HAVE
1168 dbglog_writeln("DecodeModeRegister fails FMOVE B");
1169#endif
1170 } else {
1171 SetArgValueB(myfp_ToLong(source));
1172 }
1173 break;
1174 default:
1175 DoCodeF_InvalidPlusWord();
1176#if dbglog_HAVE
1177 dbglog_writelnNum("Bad Source Specifier in FMOVE",
1178 (word2 >> 10) & 0x7);
1179#endif
1180 break;
1181 }
1182}
1183
1184LOCALIPROC DoCodeFPU_md60(void)
1185{
1186 ui4b word2 = (int)nextiword();
1187
1188 switch ((word2 >> 13) & 0x7) {
1189 case 0:
1190 DoCodeFPU_GenOpReg(word2);
1191 break;
1192 case 2:
1193 DoCodeFPU_GenOpEA(word2);
1194 break;
1195 case 3:
1196 DoCodeFPU_Move_FP_EA(word2);
1197 break;
1198 case 4:
1199 DoCodeFPU_Move_EA_CSIA(word2);
1200 break;
1201 case 5:
1202 DoCodeFPU_MoveM_CSIA_EA(word2);
1203 break;
1204 case 6:
1205 DoCodeFPU_MoveM_EA_list(word2);
1206 break;
1207 case 7:
1208 DoCodeFPU_MoveM_list_EA(word2);
1209 break;
1210 default:
1211 DoCodeF_InvalidPlusWord();
1212#if dbglog_HAVE
1213 dbglog_writelnNum("Invalid DoCodeFPU_md60",
1214 (word2 >> 13) & 0x7);
1215#endif
1216 break;
1217 }
1218}