Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*---------------------------------------------------------------------------+
0003  |  fpu_aux.c                                                                |
0004  |                                                                           |
0005  | Code to implement some of the FPU auxiliary instructions.                 |
0006  |                                                                           |
0007  | Copyright (C) 1992,1993,1994,1997                                         |
0008  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
0009  |                  E-mail   billm@suburbia.net                              |
0010  |                                                                           |
0011  |                                                                           |
0012  +---------------------------------------------------------------------------*/
0013 
0014 #include "fpu_system.h"
0015 #include "exception.h"
0016 #include "fpu_emu.h"
0017 #include "status_w.h"
0018 #include "control_w.h"
0019 
0020 static void fnop(void)
0021 {
0022 }
0023 
0024 static void fclex(void)
0025 {
0026     partial_status &=
0027         ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision |
0028           SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op |
0029           SW_Invalid);
0030     no_ip_update = 1;
0031 }
0032 
0033 /* Needs to be externally visible */
0034 void fpstate_init_soft(struct swregs_state *soft)
0035 {
0036     struct address *oaddr, *iaddr;
0037     memset(soft, 0, sizeof(*soft));
0038     soft->cwd = 0x037f;
0039     soft->swd = 0;
0040     soft->ftop = 0; /* We don't keep top in the status word internally. */
0041     soft->twd = 0xffff;
0042     /* The behaviour is different from that detailed in
0043        Section 15.1.6 of the Intel manual */
0044     oaddr = (struct address *)&soft->foo;
0045     oaddr->offset = 0;
0046     oaddr->selector = 0;
0047     iaddr = (struct address *)&soft->fip;
0048     iaddr->offset = 0;
0049     iaddr->selector = 0;
0050     iaddr->opcode = 0;
0051     soft->no_update = 1;
0052 }
0053 
0054 void finit(void)
0055 {
0056     fpstate_init_soft(&current->thread.fpu.fpstate->regs.soft);
0057 }
0058 
0059 /*
0060  * These are nops on the i387..
0061  */
0062 #define feni fnop
0063 #define fdisi fnop
0064 #define fsetpm fnop
0065 
0066 static FUNC const finit_table[] = {
0067     feni, fdisi, fclex, finit,
0068     fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
0069 };
0070 
0071 void finit_(void)
0072 {
0073     (finit_table[FPU_rm]) ();
0074 }
0075 
0076 static void fstsw_ax(void)
0077 {
0078     *(short *)&FPU_EAX = status_word();
0079     no_ip_update = 1;
0080 }
0081 
0082 static FUNC const fstsw_table[] = {
0083     fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
0084     FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
0085 };
0086 
0087 void fstsw_(void)
0088 {
0089     (fstsw_table[FPU_rm]) ();
0090 }
0091 
0092 static FUNC const fp_nop_table[] = {
0093     fnop, FPU_illegal, FPU_illegal, FPU_illegal,
0094     FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
0095 };
0096 
0097 void fp_nop(void)
0098 {
0099     (fp_nop_table[FPU_rm]) ();
0100 }
0101 
0102 void fld_i_(void)
0103 {
0104     FPU_REG *st_new_ptr;
0105     int i;
0106     u_char tag;
0107 
0108     if (STACK_OVERFLOW) {
0109         FPU_stack_overflow();
0110         return;
0111     }
0112 
0113     /* fld st(i) */
0114     i = FPU_rm;
0115     if (NOT_EMPTY(i)) {
0116         reg_copy(&st(i), st_new_ptr);
0117         tag = FPU_gettagi(i);
0118         push();
0119         FPU_settag0(tag);
0120     } else {
0121         if (control_word & CW_Invalid) {
0122             /* The masked response */
0123             FPU_stack_underflow();
0124         } else
0125             EXCEPTION(EX_StackUnder);
0126     }
0127 
0128 }
0129 
0130 void fxch_i(void)
0131 {
0132     /* fxch st(i) */
0133     FPU_REG t;
0134     int i = FPU_rm;
0135     FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
0136     long tag_word = fpu_tag_word;
0137     int regnr = top & 7, regnri = ((regnr + i) & 7);
0138     u_char st0_tag = (tag_word >> (regnr * 2)) & 3;
0139     u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
0140 
0141     if (st0_tag == TAG_Empty) {
0142         if (sti_tag == TAG_Empty) {
0143             FPU_stack_underflow();
0144             FPU_stack_underflow_i(i);
0145             return;
0146         }
0147         if (control_word & CW_Invalid) {
0148             /* Masked response */
0149             FPU_copy_to_reg0(sti_ptr, sti_tag);
0150         }
0151         FPU_stack_underflow_i(i);
0152         return;
0153     }
0154     if (sti_tag == TAG_Empty) {
0155         if (control_word & CW_Invalid) {
0156             /* Masked response */
0157             FPU_copy_to_regi(st0_ptr, st0_tag, i);
0158         }
0159         FPU_stack_underflow();
0160         return;
0161     }
0162     clear_C1();
0163 
0164     reg_copy(st0_ptr, &t);
0165     reg_copy(sti_ptr, st0_ptr);
0166     reg_copy(&t, sti_ptr);
0167 
0168     tag_word &= ~(3 << (regnr * 2)) & ~(3 << (regnri * 2));
0169     tag_word |= (sti_tag << (regnr * 2)) | (st0_tag << (regnri * 2));
0170     fpu_tag_word = tag_word;
0171 }
0172 
0173 static void fcmovCC(void)
0174 {
0175     /* fcmovCC st(i) */
0176     int i = FPU_rm;
0177     FPU_REG *st0_ptr = &st(0);
0178     FPU_REG *sti_ptr = &st(i);
0179     long tag_word = fpu_tag_word;
0180     int regnr = top & 7;
0181     int regnri = (top + i) & 7;
0182     u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
0183 
0184     if (sti_tag == TAG_Empty) {
0185         FPU_stack_underflow();
0186         clear_C1();
0187         return;
0188     }
0189     reg_copy(sti_ptr, st0_ptr);
0190     tag_word &= ~(3 << (regnr * 2));
0191     tag_word |= (sti_tag << (regnr * 2));
0192     fpu_tag_word = tag_word;
0193 }
0194 
0195 void fcmovb(void)
0196 {
0197     if (FPU_EFLAGS & X86_EFLAGS_CF)
0198         fcmovCC();
0199 }
0200 
0201 void fcmove(void)
0202 {
0203     if (FPU_EFLAGS & X86_EFLAGS_ZF)
0204         fcmovCC();
0205 }
0206 
0207 void fcmovbe(void)
0208 {
0209     if (FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF))
0210         fcmovCC();
0211 }
0212 
0213 void fcmovu(void)
0214 {
0215     if (FPU_EFLAGS & X86_EFLAGS_PF)
0216         fcmovCC();
0217 }
0218 
0219 void fcmovnb(void)
0220 {
0221     if (!(FPU_EFLAGS & X86_EFLAGS_CF))
0222         fcmovCC();
0223 }
0224 
0225 void fcmovne(void)
0226 {
0227     if (!(FPU_EFLAGS & X86_EFLAGS_ZF))
0228         fcmovCC();
0229 }
0230 
0231 void fcmovnbe(void)
0232 {
0233     if (!(FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF)))
0234         fcmovCC();
0235 }
0236 
0237 void fcmovnu(void)
0238 {
0239     if (!(FPU_EFLAGS & X86_EFLAGS_PF))
0240         fcmovCC();
0241 }
0242 
0243 void ffree_(void)
0244 {
0245     /* ffree st(i) */
0246     FPU_settagi(FPU_rm, TAG_Empty);
0247 }
0248 
0249 void ffreep(void)
0250 {
0251     /* ffree st(i) + pop - unofficial code */
0252     FPU_settagi(FPU_rm, TAG_Empty);
0253     FPU_pop();
0254 }
0255 
0256 void fst_i_(void)
0257 {
0258     /* fst st(i) */
0259     FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
0260 }
0261 
0262 void fstp_i(void)
0263 {
0264     /* fstp st(i) */
0265     FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
0266     FPU_pop();
0267 }