reg_compare.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*---------------------------------------------------------------------------+
  2. | reg_compare.c |
  3. | |
  4. | Compare two floating point registers |
  5. | |
  6. | Copyright (C) 1992,1993,1994,1997 |
  7. | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  8. | E-mail billm@suburbia.net |
  9. | |
  10. | |
  11. +---------------------------------------------------------------------------*/
  12. /*---------------------------------------------------------------------------+
  13. | compare() is the core FPU_REG comparison function |
  14. +---------------------------------------------------------------------------*/
  15. #include "fpu_system.h"
  16. #include "exception.h"
  17. #include "fpu_emu.h"
  18. #include "control_w.h"
  19. #include "status_w.h"
  20. static int compare(FPU_REG const *b, int tagb)
  21. {
  22. int diff, exp0, expb;
  23. u_char st0_tag;
  24. FPU_REG *st0_ptr;
  25. FPU_REG x, y;
  26. u_char st0_sign, signb = getsign(b);
  27. st0_ptr = &st(0);
  28. st0_tag = FPU_gettag0();
  29. st0_sign = getsign(st0_ptr);
  30. if (tagb == TAG_Special)
  31. tagb = FPU_Special(b);
  32. if (st0_tag == TAG_Special)
  33. st0_tag = FPU_Special(st0_ptr);
  34. if (((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
  35. || ((tagb != TAG_Valid) && (tagb != TW_Denormal))) {
  36. if (st0_tag == TAG_Zero) {
  37. if (tagb == TAG_Zero)
  38. return COMP_A_eq_B;
  39. if (tagb == TAG_Valid)
  40. return ((signb ==
  41. SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
  42. if (tagb == TW_Denormal)
  43. return ((signb ==
  44. SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  45. | COMP_Denormal;
  46. } else if (tagb == TAG_Zero) {
  47. if (st0_tag == TAG_Valid)
  48. return ((st0_sign ==
  49. SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  50. if (st0_tag == TW_Denormal)
  51. return ((st0_sign ==
  52. SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  53. | COMP_Denormal;
  54. }
  55. if (st0_tag == TW_Infinity) {
  56. if ((tagb == TAG_Valid) || (tagb == TAG_Zero))
  57. return ((st0_sign ==
  58. SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  59. else if (tagb == TW_Denormal)
  60. return ((st0_sign ==
  61. SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  62. | COMP_Denormal;
  63. else if (tagb == TW_Infinity) {
  64. /* The 80486 book says that infinities can be equal! */
  65. return (st0_sign == signb) ? COMP_A_eq_B :
  66. ((st0_sign ==
  67. SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  68. }
  69. /* Fall through to the NaN code */
  70. } else if (tagb == TW_Infinity) {
  71. if ((st0_tag == TAG_Valid) || (st0_tag == TAG_Zero))
  72. return ((signb ==
  73. SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
  74. if (st0_tag == TW_Denormal)
  75. return ((signb ==
  76. SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  77. | COMP_Denormal;
  78. /* Fall through to the NaN code */
  79. }
  80. /* The only possibility now should be that one of the arguments
  81. is a NaN */
  82. if ((st0_tag == TW_NaN) || (tagb == TW_NaN)) {
  83. int signalling = 0, unsupported = 0;
  84. if (st0_tag == TW_NaN) {
  85. signalling =
  86. (st0_ptr->sigh & 0xc0000000) == 0x80000000;
  87. unsupported = !((exponent(st0_ptr) == EXP_OVER)
  88. && (st0_ptr->
  89. sigh & 0x80000000));
  90. }
  91. if (tagb == TW_NaN) {
  92. signalling |=
  93. (b->sigh & 0xc0000000) == 0x80000000;
  94. unsupported |= !((exponent(b) == EXP_OVER)
  95. && (b->sigh & 0x80000000));
  96. }
  97. if (signalling || unsupported)
  98. return COMP_No_Comp | COMP_SNaN | COMP_NaN;
  99. else
  100. /* Neither is a signaling NaN */
  101. return COMP_No_Comp | COMP_NaN;
  102. }
  103. EXCEPTION(EX_Invalid);
  104. }
  105. if (st0_sign != signb) {
  106. return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  107. | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  108. COMP_Denormal : 0);
  109. }
  110. if ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) {
  111. FPU_to_exp16(st0_ptr, &x);
  112. FPU_to_exp16(b, &y);
  113. st0_ptr = &x;
  114. b = &y;
  115. exp0 = exponent16(st0_ptr);
  116. expb = exponent16(b);
  117. } else {
  118. exp0 = exponent(st0_ptr);
  119. expb = exponent(b);
  120. }
  121. #ifdef PARANOID
  122. if (!(st0_ptr->sigh & 0x80000000))
  123. EXCEPTION(EX_Invalid);
  124. if (!(b->sigh & 0x80000000))
  125. EXCEPTION(EX_Invalid);
  126. #endif /* PARANOID */
  127. diff = exp0 - expb;
  128. if (diff == 0) {
  129. diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
  130. identical */
  131. if (diff == 0) {
  132. diff = st0_ptr->sigl > b->sigl;
  133. if (diff == 0)
  134. diff = -(st0_ptr->sigl < b->sigl);
  135. }
  136. }
  137. if (diff > 0) {
  138. return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  139. | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  140. COMP_Denormal : 0);
  141. }
  142. if (diff < 0) {
  143. return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  144. | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  145. COMP_Denormal : 0);
  146. }
  147. return COMP_A_eq_B
  148. | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  149. COMP_Denormal : 0);
  150. }
  151. /* This function requires that st(0) is not empty */
  152. int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
  153. {
  154. int f = 0, c;
  155. c = compare(loaded_data, loaded_tag);
  156. if (c & COMP_NaN) {
  157. EXCEPTION(EX_Invalid);
  158. f = SW_C3 | SW_C2 | SW_C0;
  159. } else
  160. switch (c & 7) {
  161. case COMP_A_lt_B:
  162. f = SW_C0;
  163. break;
  164. case COMP_A_eq_B:
  165. f = SW_C3;
  166. break;
  167. case COMP_A_gt_B:
  168. f = 0;
  169. break;
  170. case COMP_No_Comp:
  171. f = SW_C3 | SW_C2 | SW_C0;
  172. break;
  173. #ifdef PARANOID
  174. default:
  175. EXCEPTION(EX_INTERNAL | 0x121);
  176. f = SW_C3 | SW_C2 | SW_C0;
  177. break;
  178. #endif /* PARANOID */
  179. }
  180. setcc(f);
  181. if (c & COMP_Denormal) {
  182. return denormal_operand() < 0;
  183. }
  184. return 0;
  185. }
  186. static int compare_st_st(int nr)
  187. {
  188. int f = 0, c;
  189. FPU_REG *st_ptr;
  190. if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
  191. setcc(SW_C3 | SW_C2 | SW_C0);
  192. /* Stack fault */
  193. EXCEPTION(EX_StackUnder);
  194. return !(control_word & CW_Invalid);
  195. }
  196. st_ptr = &st(nr);
  197. c = compare(st_ptr, FPU_gettagi(nr));
  198. if (c & COMP_NaN) {
  199. setcc(SW_C3 | SW_C2 | SW_C0);
  200. EXCEPTION(EX_Invalid);
  201. return !(control_word & CW_Invalid);
  202. } else
  203. switch (c & 7) {
  204. case COMP_A_lt_B:
  205. f = SW_C0;
  206. break;
  207. case COMP_A_eq_B:
  208. f = SW_C3;
  209. break;
  210. case COMP_A_gt_B:
  211. f = 0;
  212. break;
  213. case COMP_No_Comp:
  214. f = SW_C3 | SW_C2 | SW_C0;
  215. break;
  216. #ifdef PARANOID
  217. default:
  218. EXCEPTION(EX_INTERNAL | 0x122);
  219. f = SW_C3 | SW_C2 | SW_C0;
  220. break;
  221. #endif /* PARANOID */
  222. }
  223. setcc(f);
  224. if (c & COMP_Denormal) {
  225. return denormal_operand() < 0;
  226. }
  227. return 0;
  228. }
  229. static int compare_u_st_st(int nr)
  230. {
  231. int f = 0, c;
  232. FPU_REG *st_ptr;
  233. if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
  234. setcc(SW_C3 | SW_C2 | SW_C0);
  235. /* Stack fault */
  236. EXCEPTION(EX_StackUnder);
  237. return !(control_word & CW_Invalid);
  238. }
  239. st_ptr = &st(nr);
  240. c = compare(st_ptr, FPU_gettagi(nr));
  241. if (c & COMP_NaN) {
  242. setcc(SW_C3 | SW_C2 | SW_C0);
  243. if (c & COMP_SNaN) { /* This is the only difference between
  244. un-ordered and ordinary comparisons */
  245. EXCEPTION(EX_Invalid);
  246. return !(control_word & CW_Invalid);
  247. }
  248. return 0;
  249. } else
  250. switch (c & 7) {
  251. case COMP_A_lt_B:
  252. f = SW_C0;
  253. break;
  254. case COMP_A_eq_B:
  255. f = SW_C3;
  256. break;
  257. case COMP_A_gt_B:
  258. f = 0;
  259. break;
  260. case COMP_No_Comp:
  261. f = SW_C3 | SW_C2 | SW_C0;
  262. break;
  263. #ifdef PARANOID
  264. default:
  265. EXCEPTION(EX_INTERNAL | 0x123);
  266. f = SW_C3 | SW_C2 | SW_C0;
  267. break;
  268. #endif /* PARANOID */
  269. }
  270. setcc(f);
  271. if (c & COMP_Denormal) {
  272. return denormal_operand() < 0;
  273. }
  274. return 0;
  275. }
  276. /*---------------------------------------------------------------------------*/
  277. void fcom_st(void)
  278. {
  279. /* fcom st(i) */
  280. compare_st_st(FPU_rm);
  281. }
  282. void fcompst(void)
  283. {
  284. /* fcomp st(i) */
  285. if (!compare_st_st(FPU_rm))
  286. FPU_pop();
  287. }
  288. void fcompp(void)
  289. {
  290. /* fcompp */
  291. if (FPU_rm != 1) {
  292. FPU_illegal();
  293. return;
  294. }
  295. if (!compare_st_st(1))
  296. poppop();
  297. }
  298. void fucom_(void)
  299. {
  300. /* fucom st(i) */
  301. compare_u_st_st(FPU_rm);
  302. }
  303. void fucomp(void)
  304. {
  305. /* fucomp st(i) */
  306. if (!compare_u_st_st(FPU_rm))
  307. FPU_pop();
  308. }
  309. void fucompp(void)
  310. {
  311. /* fucompp */
  312. if (FPU_rm == 1) {
  313. if (!compare_u_st_st(1))
  314. poppop();
  315. } else
  316. FPU_illegal();
  317. }