reg_compare.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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. {
  37. if ( st0_tag == TAG_Zero )
  38. {
  39. if ( tagb == TAG_Zero ) return COMP_A_eq_B;
  40. if ( tagb == TAG_Valid )
  41. return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
  42. if ( tagb == TW_Denormal )
  43. return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  44. | COMP_Denormal;
  45. }
  46. else if ( tagb == TAG_Zero )
  47. {
  48. if ( st0_tag == TAG_Valid )
  49. return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  50. if ( st0_tag == TW_Denormal )
  51. return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  52. | COMP_Denormal;
  53. }
  54. if ( st0_tag == TW_Infinity )
  55. {
  56. if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) )
  57. return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  58. else if ( tagb == TW_Denormal )
  59. return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  60. | COMP_Denormal;
  61. else if ( tagb == TW_Infinity )
  62. {
  63. /* The 80486 book says that infinities can be equal! */
  64. return (st0_sign == signb) ? COMP_A_eq_B :
  65. ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  66. }
  67. /* Fall through to the NaN code */
  68. }
  69. else if ( tagb == TW_Infinity )
  70. {
  71. if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) )
  72. return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
  73. if ( st0_tag == TW_Denormal )
  74. return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  75. | COMP_Denormal;
  76. /* Fall through to the NaN code */
  77. }
  78. /* The only possibility now should be that one of the arguments
  79. is a NaN */
  80. if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) )
  81. {
  82. int signalling = 0, unsupported = 0;
  83. if ( st0_tag == TW_NaN )
  84. {
  85. signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000;
  86. unsupported = !((exponent(st0_ptr) == EXP_OVER)
  87. && (st0_ptr->sigh & 0x80000000));
  88. }
  89. if ( tagb == TW_NaN )
  90. {
  91. signalling |= (b->sigh & 0xc0000000) == 0x80000000;
  92. unsupported |= !((exponent(b) == EXP_OVER)
  93. && (b->sigh & 0x80000000));
  94. }
  95. if ( signalling || unsupported )
  96. return COMP_No_Comp | COMP_SNaN | COMP_NaN;
  97. else
  98. /* Neither is a signaling NaN */
  99. return COMP_No_Comp | COMP_NaN;
  100. }
  101. EXCEPTION(EX_Invalid);
  102. }
  103. if (st0_sign != signb)
  104. {
  105. return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  106. | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  107. COMP_Denormal : 0);
  108. }
  109. if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
  110. {
  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. }
  118. else
  119. {
  120. exp0 = exponent(st0_ptr);
  121. expb = exponent(b);
  122. }
  123. #ifdef PARANOID
  124. if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  125. if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  126. #endif /* PARANOID */
  127. diff = exp0 - expb;
  128. if ( diff == 0 )
  129. {
  130. diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
  131. identical */
  132. if ( diff == 0 )
  133. {
  134. diff = st0_ptr->sigl > b->sigl;
  135. if ( diff == 0 )
  136. diff = -(st0_ptr->sigl < b->sigl);
  137. }
  138. }
  139. if ( diff > 0 )
  140. {
  141. return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  142. | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  143. COMP_Denormal : 0);
  144. }
  145. if ( diff < 0 )
  146. {
  147. return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  148. | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  149. COMP_Denormal : 0);
  150. }
  151. return COMP_A_eq_B
  152. | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
  153. COMP_Denormal : 0);
  154. }
  155. /* This function requires that st(0) is not empty */
  156. int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
  157. {
  158. int f = 0, c;
  159. c = compare(loaded_data, loaded_tag);
  160. if (c & COMP_NaN)
  161. {
  162. EXCEPTION(EX_Invalid);
  163. f = SW_C3 | SW_C2 | SW_C0;
  164. }
  165. else
  166. switch (c & 7)
  167. {
  168. case COMP_A_lt_B:
  169. f = SW_C0;
  170. break;
  171. case COMP_A_eq_B:
  172. f = SW_C3;
  173. break;
  174. case COMP_A_gt_B:
  175. f = 0;
  176. break;
  177. case COMP_No_Comp:
  178. f = SW_C3 | SW_C2 | SW_C0;
  179. break;
  180. #ifdef PARANOID
  181. default:
  182. EXCEPTION(EX_INTERNAL|0x121);
  183. f = SW_C3 | SW_C2 | SW_C0;
  184. break;
  185. #endif /* PARANOID */
  186. }
  187. setcc(f);
  188. if (c & COMP_Denormal)
  189. {
  190. return denormal_operand() < 0;
  191. }
  192. return 0;
  193. }
  194. static int compare_st_st(int nr)
  195. {
  196. int f = 0, c;
  197. FPU_REG *st_ptr;
  198. if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
  199. {
  200. setcc(SW_C3 | SW_C2 | SW_C0);
  201. /* Stack fault */
  202. EXCEPTION(EX_StackUnder);
  203. return !(control_word & CW_Invalid);
  204. }
  205. st_ptr = &st(nr);
  206. c = compare(st_ptr, FPU_gettagi(nr));
  207. if (c & COMP_NaN)
  208. {
  209. setcc(SW_C3 | SW_C2 | SW_C0);
  210. EXCEPTION(EX_Invalid);
  211. return !(control_word & CW_Invalid);
  212. }
  213. else
  214. switch (c & 7)
  215. {
  216. case COMP_A_lt_B:
  217. f = SW_C0;
  218. break;
  219. case COMP_A_eq_B:
  220. f = SW_C3;
  221. break;
  222. case COMP_A_gt_B:
  223. f = 0;
  224. break;
  225. case COMP_No_Comp:
  226. f = SW_C3 | SW_C2 | SW_C0;
  227. break;
  228. #ifdef PARANOID
  229. default:
  230. EXCEPTION(EX_INTERNAL|0x122);
  231. f = SW_C3 | SW_C2 | SW_C0;
  232. break;
  233. #endif /* PARANOID */
  234. }
  235. setcc(f);
  236. if (c & COMP_Denormal)
  237. {
  238. return denormal_operand() < 0;
  239. }
  240. return 0;
  241. }
  242. static int compare_u_st_st(int nr)
  243. {
  244. int f = 0, c;
  245. FPU_REG *st_ptr;
  246. if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
  247. {
  248. setcc(SW_C3 | SW_C2 | SW_C0);
  249. /* Stack fault */
  250. EXCEPTION(EX_StackUnder);
  251. return !(control_word & CW_Invalid);
  252. }
  253. st_ptr = &st(nr);
  254. c = compare(st_ptr, FPU_gettagi(nr));
  255. if (c & COMP_NaN)
  256. {
  257. setcc(SW_C3 | SW_C2 | SW_C0);
  258. if (c & COMP_SNaN) /* This is the only difference between
  259. un-ordered and ordinary comparisons */
  260. {
  261. EXCEPTION(EX_Invalid);
  262. return !(control_word & CW_Invalid);
  263. }
  264. return 0;
  265. }
  266. else
  267. switch (c & 7)
  268. {
  269. case COMP_A_lt_B:
  270. f = SW_C0;
  271. break;
  272. case COMP_A_eq_B:
  273. f = SW_C3;
  274. break;
  275. case COMP_A_gt_B:
  276. f = 0;
  277. break;
  278. case COMP_No_Comp:
  279. f = SW_C3 | SW_C2 | SW_C0;
  280. break;
  281. #ifdef PARANOID
  282. default:
  283. EXCEPTION(EX_INTERNAL|0x123);
  284. f = SW_C3 | SW_C2 | SW_C0;
  285. break;
  286. #endif /* PARANOID */
  287. }
  288. setcc(f);
  289. if (c & COMP_Denormal)
  290. {
  291. return denormal_operand() < 0;
  292. }
  293. return 0;
  294. }
  295. /*---------------------------------------------------------------------------*/
  296. void fcom_st(void)
  297. {
  298. /* fcom st(i) */
  299. compare_st_st(FPU_rm);
  300. }
  301. void fcompst(void)
  302. {
  303. /* fcomp st(i) */
  304. if ( !compare_st_st(FPU_rm) )
  305. FPU_pop();
  306. }
  307. void fcompp(void)
  308. {
  309. /* fcompp */
  310. if (FPU_rm != 1)
  311. {
  312. FPU_illegal();
  313. return;
  314. }
  315. if ( !compare_st_st(1) )
  316. poppop();
  317. }
  318. void fucom_(void)
  319. {
  320. /* fucom st(i) */
  321. compare_u_st_st(FPU_rm);
  322. }
  323. void fucomp(void)
  324. {
  325. /* fucomp st(i) */
  326. if ( !compare_u_st_st(FPU_rm) )
  327. FPU_pop();
  328. }
  329. void fucompp(void)
  330. {
  331. /* fucompp */
  332. if (FPU_rm == 1)
  333. {
  334. if ( !compare_u_st_st(1) )
  335. poppop();
  336. }
  337. else
  338. FPU_illegal();
  339. }