reg_compare.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  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, 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. default:
  174. #ifdef PARANOID
  175. EXCEPTION(EX_INTERNAL | 0x121);
  176. #endif /* PARANOID */
  177. f = SW_C3 | SW_C2 | SW_C0;
  178. break;
  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, 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. default:
  217. #ifdef PARANOID
  218. EXCEPTION(EX_INTERNAL | 0x122);
  219. #endif /* PARANOID */
  220. f = SW_C3 | SW_C2 | SW_C0;
  221. break;
  222. }
  223. setcc(f);
  224. if (c & COMP_Denormal) {
  225. return denormal_operand() < 0;
  226. }
  227. return 0;
  228. }
  229. static int compare_i_st_st(int nr)
  230. {
  231. int f, c;
  232. FPU_REG *st_ptr;
  233. if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
  234. FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
  235. /* Stack fault */
  236. EXCEPTION(EX_StackUnder);
  237. return !(control_word & CW_Invalid);
  238. }
  239. partial_status &= ~SW_C0;
  240. st_ptr = &st(nr);
  241. c = compare(st_ptr, FPU_gettagi(nr));
  242. if (c & COMP_NaN) {
  243. FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
  244. EXCEPTION(EX_Invalid);
  245. return !(control_word & CW_Invalid);
  246. }
  247. switch (c & 7) {
  248. case COMP_A_lt_B:
  249. f = X86_EFLAGS_CF;
  250. break;
  251. case COMP_A_eq_B:
  252. f = X86_EFLAGS_ZF;
  253. break;
  254. case COMP_A_gt_B:
  255. f = 0;
  256. break;
  257. case COMP_No_Comp:
  258. f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
  259. break;
  260. default:
  261. #ifdef PARANOID
  262. EXCEPTION(EX_INTERNAL | 0x122);
  263. #endif /* PARANOID */
  264. f = 0;
  265. break;
  266. }
  267. FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
  268. if (c & COMP_Denormal) {
  269. return denormal_operand() < 0;
  270. }
  271. return 0;
  272. }
  273. static int compare_u_st_st(int nr)
  274. {
  275. int f = 0, c;
  276. FPU_REG *st_ptr;
  277. if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
  278. setcc(SW_C3 | SW_C2 | SW_C0);
  279. /* Stack fault */
  280. EXCEPTION(EX_StackUnder);
  281. return !(control_word & CW_Invalid);
  282. }
  283. st_ptr = &st(nr);
  284. c = compare(st_ptr, FPU_gettagi(nr));
  285. if (c & COMP_NaN) {
  286. setcc(SW_C3 | SW_C2 | SW_C0);
  287. if (c & COMP_SNaN) { /* This is the only difference between
  288. un-ordered and ordinary comparisons */
  289. EXCEPTION(EX_Invalid);
  290. return !(control_word & CW_Invalid);
  291. }
  292. return 0;
  293. } else
  294. switch (c & 7) {
  295. case COMP_A_lt_B:
  296. f = SW_C0;
  297. break;
  298. case COMP_A_eq_B:
  299. f = SW_C3;
  300. break;
  301. case COMP_A_gt_B:
  302. f = 0;
  303. break;
  304. case COMP_No_Comp:
  305. f = SW_C3 | SW_C2 | SW_C0;
  306. break;
  307. #ifdef PARANOID
  308. default:
  309. EXCEPTION(EX_INTERNAL | 0x123);
  310. f = SW_C3 | SW_C2 | SW_C0;
  311. break;
  312. #endif /* PARANOID */
  313. }
  314. setcc(f);
  315. if (c & COMP_Denormal) {
  316. return denormal_operand() < 0;
  317. }
  318. return 0;
  319. }
  320. static int compare_ui_st_st(int nr)
  321. {
  322. int f = 0, c;
  323. FPU_REG *st_ptr;
  324. if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
  325. FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
  326. /* Stack fault */
  327. EXCEPTION(EX_StackUnder);
  328. return !(control_word & CW_Invalid);
  329. }
  330. partial_status &= ~SW_C0;
  331. st_ptr = &st(nr);
  332. c = compare(st_ptr, FPU_gettagi(nr));
  333. if (c & COMP_NaN) {
  334. FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
  335. if (c & COMP_SNaN) { /* This is the only difference between
  336. un-ordered and ordinary comparisons */
  337. EXCEPTION(EX_Invalid);
  338. return !(control_word & CW_Invalid);
  339. }
  340. return 0;
  341. }
  342. switch (c & 7) {
  343. case COMP_A_lt_B:
  344. f = X86_EFLAGS_CF;
  345. break;
  346. case COMP_A_eq_B:
  347. f = X86_EFLAGS_ZF;
  348. break;
  349. case COMP_A_gt_B:
  350. f = 0;
  351. break;
  352. case COMP_No_Comp:
  353. f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
  354. break;
  355. #ifdef PARANOID
  356. default:
  357. EXCEPTION(EX_INTERNAL | 0x123);
  358. f = 0;
  359. break;
  360. #endif /* PARANOID */
  361. }
  362. FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
  363. if (c & COMP_Denormal) {
  364. return denormal_operand() < 0;
  365. }
  366. return 0;
  367. }
  368. /*---------------------------------------------------------------------------*/
  369. void fcom_st(void)
  370. {
  371. /* fcom st(i) */
  372. compare_st_st(FPU_rm);
  373. }
  374. void fcompst(void)
  375. {
  376. /* fcomp st(i) */
  377. if (!compare_st_st(FPU_rm))
  378. FPU_pop();
  379. }
  380. void fcompp(void)
  381. {
  382. /* fcompp */
  383. if (FPU_rm != 1) {
  384. FPU_illegal();
  385. return;
  386. }
  387. if (!compare_st_st(1))
  388. poppop();
  389. }
  390. void fucom_(void)
  391. {
  392. /* fucom st(i) */
  393. compare_u_st_st(FPU_rm);
  394. }
  395. void fucomp(void)
  396. {
  397. /* fucomp st(i) */
  398. if (!compare_u_st_st(FPU_rm))
  399. FPU_pop();
  400. }
  401. void fucompp(void)
  402. {
  403. /* fucompp */
  404. if (FPU_rm == 1) {
  405. if (!compare_u_st_st(1))
  406. poppop();
  407. } else
  408. FPU_illegal();
  409. }
  410. /* P6+ compare-to-EFLAGS ops */
  411. void fcomi_(void)
  412. {
  413. /* fcomi st(i) */
  414. compare_i_st_st(FPU_rm);
  415. }
  416. void fcomip(void)
  417. {
  418. /* fcomip st(i) */
  419. if (!compare_i_st_st(FPU_rm))
  420. FPU_pop();
  421. }
  422. void fucomi_(void)
  423. {
  424. /* fucomi st(i) */
  425. compare_ui_st_st(FPU_rm);
  426. }
  427. void fucomip(void)
  428. {
  429. /* fucomip st(i) */
  430. if (!compare_ui_st_st(FPU_rm))
  431. FPU_pop();
  432. }