fpu_etc.c 3.1 KB

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