fpu_etc.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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. {
  21. signbyte(st0_ptr) ^= SIGN_NEG;
  22. clear_C1();
  23. }
  24. else
  25. FPU_stack_underflow();
  26. }
  27. static void fabs(FPU_REG *st0_ptr, u_char st0tag)
  28. {
  29. if ( st0tag ^ TAG_Empty )
  30. {
  31. setpositive(st0_ptr);
  32. clear_C1();
  33. }
  34. else
  35. FPU_stack_underflow();
  36. }
  37. static void ftst_(FPU_REG *st0_ptr, u_char st0tag)
  38. {
  39. switch (st0tag)
  40. {
  41. case TAG_Zero:
  42. setcc(SW_C3);
  43. break;
  44. case TAG_Valid:
  45. if (getsign(st0_ptr) == SIGN_POS)
  46. setcc(0);
  47. else
  48. setcc(SW_C0);
  49. break;
  50. case TAG_Special:
  51. switch ( FPU_Special(st0_ptr) )
  52. {
  53. case TW_Denormal:
  54. if (getsign(st0_ptr) == SIGN_POS)
  55. setcc(0);
  56. else
  57. setcc(SW_C0);
  58. if ( denormal_operand() < 0 )
  59. {
  60. #ifdef PECULIAR_486
  61. /* This is weird! */
  62. if (getsign(st0_ptr) == SIGN_POS)
  63. setcc(SW_C3);
  64. #endif /* PECULIAR_486 */
  65. return;
  66. }
  67. break;
  68. case TW_NaN:
  69. setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
  70. EXCEPTION(EX_Invalid);
  71. break;
  72. case TW_Infinity:
  73. if (getsign(st0_ptr) == SIGN_POS)
  74. setcc(0);
  75. else
  76. setcc(SW_C0);
  77. break;
  78. default:
  79. setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
  80. EXCEPTION(EX_INTERNAL|0x14);
  81. break;
  82. }
  83. break;
  84. case TAG_Empty:
  85. setcc(SW_C0|SW_C2|SW_C3);
  86. EXCEPTION(EX_StackUnder);
  87. break;
  88. }
  89. }
  90. static void fxam(FPU_REG *st0_ptr, u_char st0tag)
  91. {
  92. int c = 0;
  93. switch (st0tag)
  94. {
  95. case TAG_Empty:
  96. c = SW_C3|SW_C0;
  97. break;
  98. case TAG_Zero:
  99. c = SW_C3;
  100. break;
  101. case TAG_Valid:
  102. c = SW_C2;
  103. break;
  104. case TAG_Special:
  105. switch ( FPU_Special(st0_ptr) )
  106. {
  107. case TW_Denormal:
  108. c = SW_C2|SW_C3; /* Denormal */
  109. break;
  110. case TW_NaN:
  111. /* We also use NaN for unsupported types. */
  112. if ( (st0_ptr->sigh & 0x80000000) && (exponent(st0_ptr) == EXP_OVER) )
  113. c = SW_C0;
  114. break;
  115. case TW_Infinity:
  116. c = SW_C2|SW_C0;
  117. break;
  118. }
  119. }
  120. if ( getsign(st0_ptr) == SIGN_NEG )
  121. c |= SW_C1;
  122. setcc(c);
  123. }
  124. static FUNC_ST0 const fp_etc_table[] = {
  125. fchs, fabs, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal,
  126. ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal
  127. };
  128. void FPU_etc(void)
  129. {
  130. (fp_etc_table[FPU_rm])(&st(0), FPU_gettag0());
  131. }