0001
0002
0003
0004
0005
0006
0007
0008
0009
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
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;
0041 soft->twd = 0xffff;
0042
0043
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(¤t->thread.fpu.fpstate->regs.soft);
0057 }
0058
0059
0060
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
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
0123 FPU_stack_underflow();
0124 } else
0125 EXCEPTION(EX_StackUnder);
0126 }
0127
0128 }
0129
0130 void fxch_i(void)
0131 {
0132
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
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
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
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
0246 FPU_settagi(FPU_rm, TAG_Empty);
0247 }
0248
0249 void ffreep(void)
0250 {
0251
0252 FPU_settagi(FPU_rm, TAG_Empty);
0253 FPU_pop();
0254 }
0255
0256 void fst_i_(void)
0257 {
0258
0259 FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
0260 }
0261
0262 void fstp_i(void)
0263 {
0264
0265 FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
0266 FPU_pop();
0267 }