root/arch/x86/math-emu/fpu_aux.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fnop
  2. fclex
  3. fpstate_init_soft
  4. finit
  5. finit_
  6. fstsw_ax
  7. fstsw_
  8. fp_nop
  9. fld_i_
  10. fxch_i
  11. fcmovCC
  12. fcmovb
  13. fcmove
  14. fcmovbe
  15. fcmovu
  16. fcmovnb
  17. fcmovne
  18. fcmovnbe
  19. fcmovnu
  20. ffree_
  21. ffreep
  22. fst_i_
  23. fstp_i

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

/* [<][>][^][v][top][bottom][index][help] */