fpu_etc.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*---------------------------------------------------------------------------+
  3. | fpu_etc.c |
  4. | |
  5. | Implement a few FPU instructions. |
  6. | |
  7. | Copyright (C) 1992,1993,1994,1997 |
  8. | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
  9. | Australia. E-mail billm@suburbia.net |
  10. | |
  11. | |
  12. +---------------------------------------------------------------------------*/
  13. #include "fpu_system.h"
  14. #include "exception.h"
  15. #include "fpu_emu.h"
  16. #include "status_w.h"
  17. #include "reg_constant.h"
  18. static void fchs(FPU_REG *st0_ptr, u_char st0tag)
  19. {
  20. if (st0tag ^ TAG_Empty) {
  21. signbyte(st0_ptr) ^= SIGN_NEG;
  22. clear_C1();
  23. } else
  24. FPU_stack_underflow();
  25. }
  26. static void fabs(FPU_REG *st0_ptr, u_char st0tag)
  27. {
  28. if (st0tag ^ TAG_Empty) {
  29. setpositive(st0_ptr);
  30. clear_C1();
  31. } else
  32. FPU_stack_underflow();
  33. }
  34. static void ftst_(FPU_REG *st0_ptr, u_char st0tag)
  35. {
  36. switch (st0tag) {
  37. case TAG_Zero:
  38. setcc(SW_C3);
  39. break;
  40. case TAG_Valid:
  41. if (getsign(st0_ptr) == SIGN_POS)
  42. setcc(0);
  43. else
  44. setcc(SW_C0);
  45. break;
  46. case TAG_Special:
  47. switch (FPU_Special(st0_ptr)) {
  48. case TW_Denormal:
  49. if (getsign(st0_ptr) == SIGN_POS)
  50. setcc(0);
  51. else
  52. setcc(SW_C0);
  53. if (denormal_operand() < 0) {
  54. #ifdef PECULIAR_486
  55. /* This is weird! */
  56. if (getsign(st0_ptr) == SIGN_POS)
  57. setcc(SW_C3);
  58. #endif /* PECULIAR_486 */
  59. return;
  60. }
  61. break;
  62. case TW_NaN:
  63. setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
  64. EXCEPTION(EX_Invalid);
  65. break;
  66. case TW_Infinity:
  67. if (getsign(st0_ptr) == SIGN_POS)
  68. setcc(0);
  69. else
  70. setcc(SW_C0);
  71. break;
  72. default:
  73. setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
  74. EXCEPTION(EX_INTERNAL | 0x14);
  75. break;
  76. }
  77. break;
  78. case TAG_Empty:
  79. setcc(SW_C0 | SW_C2 | SW_C3);
  80. EXCEPTION(EX_StackUnder);
  81. break;
  82. }
  83. }
  84. static void fxam(FPU_REG *st0_ptr, u_char st0tag)
  85. {
  86. int c = 0;
  87. switch (st0tag) {
  88. case TAG_Empty:
  89. c = SW_C3 | SW_C0;
  90. break;
  91. case TAG_Zero:
  92. c = SW_C3;
  93. break;
  94. case TAG_Valid:
  95. c = SW_C2;
  96. break;
  97. case TAG_Special:
  98. switch (FPU_Special(st0_ptr)) {
  99. case TW_Denormal:
  100. c = SW_C2 | SW_C3; /* Denormal */
  101. break;
  102. case TW_NaN:
  103. /* We also use NaN for unsupported types. */
  104. if ((st0_ptr->sigh & 0x80000000)
  105. && (exponent(st0_ptr) == EXP_OVER))
  106. c = SW_C0;
  107. break;
  108. case TW_Infinity:
  109. c = SW_C2 | SW_C0;
  110. break;
  111. }
  112. }
  113. if (getsign(st0_ptr) == SIGN_NEG)
  114. c |= SW_C1;
  115. setcc(c);
  116. }
  117. static FUNC_ST0 const fp_etc_table[] = {
  118. fchs, fabs, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal,
  119. ftst_, fxam, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal
  120. };
  121. void FPU_etc(void)
  122. {
  123. (fp_etc_table[FPU_rm]) (&st(0), FPU_gettag0());
  124. }