fpu_aux.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*---------------------------------------------------------------------------+
  3. | fpu_aux.c |
  4. | |
  5. | Code to implement some of the FPU auxiliary instructions. |
  6. | |
  7. | Copyright (C) 1992,1993,1994,1997 |
  8. | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  9. | E-mail billm@suburbia.net |
  10. | |
  11. | |
  12. +---------------------------------------------------------------------------*/
  13. #include "fpu_system.h"
  14. #include "exception.h"
  15. #include "fpu_emu.h"
  16. #include "status_w.h"
  17. #include "control_w.h"
  18. static void fnop(void)
  19. {
  20. }
  21. static void fclex(void)
  22. {
  23. partial_status &=
  24. ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision |
  25. SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op |
  26. SW_Invalid);
  27. no_ip_update = 1;
  28. }
  29. /* Needs to be externally visible */
  30. void fpstate_init_soft(struct swregs_state *soft)
  31. {
  32. struct address *oaddr, *iaddr;
  33. memset(soft, 0, sizeof(*soft));
  34. soft->cwd = 0x037f;
  35. soft->swd = 0;
  36. soft->ftop = 0; /* We don't keep top in the status word internally. */
  37. soft->twd = 0xffff;
  38. /* The behaviour is different from that detailed in
  39. Section 15.1.6 of the Intel manual */
  40. oaddr = (struct address *)&soft->foo;
  41. oaddr->offset = 0;
  42. oaddr->selector = 0;
  43. iaddr = (struct address *)&soft->fip;
  44. iaddr->offset = 0;
  45. iaddr->selector = 0;
  46. iaddr->opcode = 0;
  47. soft->no_update = 1;
  48. }
  49. void finit(void)
  50. {
  51. fpstate_init_soft(&current->thread.fpu.state.soft);
  52. }
  53. /*
  54. * These are nops on the i387..
  55. */
  56. #define feni fnop
  57. #define fdisi fnop
  58. #define fsetpm fnop
  59. static FUNC const finit_table[] = {
  60. feni, fdisi, fclex, finit,
  61. fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
  62. };
  63. void finit_(void)
  64. {
  65. (finit_table[FPU_rm]) ();
  66. }
  67. static void fstsw_ax(void)
  68. {
  69. *(short *)&FPU_EAX = status_word();
  70. no_ip_update = 1;
  71. }
  72. static FUNC const fstsw_table[] = {
  73. fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
  74. FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
  75. };
  76. void fstsw_(void)
  77. {
  78. (fstsw_table[FPU_rm]) ();
  79. }
  80. static FUNC const fp_nop_table[] = {
  81. fnop, FPU_illegal, FPU_illegal, FPU_illegal,
  82. FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
  83. };
  84. void fp_nop(void)
  85. {
  86. (fp_nop_table[FPU_rm]) ();
  87. }
  88. void fld_i_(void)
  89. {
  90. FPU_REG *st_new_ptr;
  91. int i;
  92. u_char tag;
  93. if (STACK_OVERFLOW) {
  94. FPU_stack_overflow();
  95. return;
  96. }
  97. /* fld st(i) */
  98. i = FPU_rm;
  99. if (NOT_EMPTY(i)) {
  100. reg_copy(&st(i), st_new_ptr);
  101. tag = FPU_gettagi(i);
  102. push();
  103. FPU_settag0(tag);
  104. } else {
  105. if (control_word & CW_Invalid) {
  106. /* The masked response */
  107. FPU_stack_underflow();
  108. } else
  109. EXCEPTION(EX_StackUnder);
  110. }
  111. }
  112. void fxch_i(void)
  113. {
  114. /* fxch st(i) */
  115. FPU_REG t;
  116. int i = FPU_rm;
  117. FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
  118. long tag_word = fpu_tag_word;
  119. int regnr = top & 7, regnri = ((regnr + i) & 7);
  120. u_char st0_tag = (tag_word >> (regnr * 2)) & 3;
  121. u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
  122. if (st0_tag == TAG_Empty) {
  123. if (sti_tag == TAG_Empty) {
  124. FPU_stack_underflow();
  125. FPU_stack_underflow_i(i);
  126. return;
  127. }
  128. if (control_word & CW_Invalid) {
  129. /* Masked response */
  130. FPU_copy_to_reg0(sti_ptr, sti_tag);
  131. }
  132. FPU_stack_underflow_i(i);
  133. return;
  134. }
  135. if (sti_tag == TAG_Empty) {
  136. if (control_word & CW_Invalid) {
  137. /* Masked response */
  138. FPU_copy_to_regi(st0_ptr, st0_tag, i);
  139. }
  140. FPU_stack_underflow();
  141. return;
  142. }
  143. clear_C1();
  144. reg_copy(st0_ptr, &t);
  145. reg_copy(sti_ptr, st0_ptr);
  146. reg_copy(&t, sti_ptr);
  147. tag_word &= ~(3 << (regnr * 2)) & ~(3 << (regnri * 2));
  148. tag_word |= (sti_tag << (regnr * 2)) | (st0_tag << (regnri * 2));
  149. fpu_tag_word = tag_word;
  150. }
  151. static void fcmovCC(void)
  152. {
  153. /* fcmovCC st(i) */
  154. int i = FPU_rm;
  155. FPU_REG *st0_ptr = &st(0);
  156. FPU_REG *sti_ptr = &st(i);
  157. long tag_word = fpu_tag_word;
  158. int regnr = top & 7;
  159. int regnri = (top + i) & 7;
  160. u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
  161. if (sti_tag == TAG_Empty) {
  162. FPU_stack_underflow();
  163. clear_C1();
  164. return;
  165. }
  166. reg_copy(sti_ptr, st0_ptr);
  167. tag_word &= ~(3 << (regnr * 2));
  168. tag_word |= (sti_tag << (regnr * 2));
  169. fpu_tag_word = tag_word;
  170. }
  171. void fcmovb(void)
  172. {
  173. if (FPU_EFLAGS & X86_EFLAGS_CF)
  174. fcmovCC();
  175. }
  176. void fcmove(void)
  177. {
  178. if (FPU_EFLAGS & X86_EFLAGS_ZF)
  179. fcmovCC();
  180. }
  181. void fcmovbe(void)
  182. {
  183. if (FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF))
  184. fcmovCC();
  185. }
  186. void fcmovu(void)
  187. {
  188. if (FPU_EFLAGS & X86_EFLAGS_PF)
  189. fcmovCC();
  190. }
  191. void fcmovnb(void)
  192. {
  193. if (!(FPU_EFLAGS & X86_EFLAGS_CF))
  194. fcmovCC();
  195. }
  196. void fcmovne(void)
  197. {
  198. if (!(FPU_EFLAGS & X86_EFLAGS_ZF))
  199. fcmovCC();
  200. }
  201. void fcmovnbe(void)
  202. {
  203. if (!(FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF)))
  204. fcmovCC();
  205. }
  206. void fcmovnu(void)
  207. {
  208. if (!(FPU_EFLAGS & X86_EFLAGS_PF))
  209. fcmovCC();
  210. }
  211. void ffree_(void)
  212. {
  213. /* ffree st(i) */
  214. FPU_settagi(FPU_rm, TAG_Empty);
  215. }
  216. void ffreep(void)
  217. {
  218. /* ffree st(i) + pop - unofficial code */
  219. FPU_settagi(FPU_rm, TAG_Empty);
  220. FPU_pop();
  221. }
  222. void fst_i_(void)
  223. {
  224. /* fst st(i) */
  225. FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
  226. }
  227. void fstp_i(void)
  228. {
  229. /* fstp st(i) */
  230. FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
  231. FPU_pop();
  232. }