Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /*---------------------------------------------------------------------------+ |
2 | | fpu_etc.c | | |
3 | | | | |
4 | | Implement a few FPU instructions. | | |
5 | | | | |
6 | | Copyright (C) 1992,1993,1994,1997 | | |
7 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | |
8 | | Australia. E-mail billm@suburbia.net | | |
9 | | | | |
10 | | | | |
11 | +---------------------------------------------------------------------------*/ | |
12 | ||
13 | #include "fpu_system.h" | |
14 | #include "exception.h" | |
15 | #include "fpu_emu.h" | |
16 | #include "status_w.h" | |
17 | #include "reg_constant.h" | |
18 | ||
e8d591dc | 19 | static void fchs(FPU_REG *st0_ptr, u_char st0tag) |
1da177e4 | 20 | { |
3d0d14f9 IM |
21 | if (st0tag ^ TAG_Empty) { |
22 | signbyte(st0_ptr) ^= SIGN_NEG; | |
23 | clear_C1(); | |
24 | } else | |
25 | FPU_stack_underflow(); | |
1da177e4 LT |
26 | } |
27 | ||
e8d591dc | 28 | static void fabs(FPU_REG *st0_ptr, u_char st0tag) |
1da177e4 | 29 | { |
3d0d14f9 IM |
30 | if (st0tag ^ TAG_Empty) { |
31 | setpositive(st0_ptr); | |
32 | clear_C1(); | |
33 | } else | |
34 | FPU_stack_underflow(); | |
1da177e4 LT |
35 | } |
36 | ||
e8d591dc | 37 | static void ftst_(FPU_REG *st0_ptr, u_char st0tag) |
1da177e4 | 38 | { |
3d0d14f9 IM |
39 | switch (st0tag) { |
40 | case TAG_Zero: | |
1da177e4 | 41 | setcc(SW_C3); |
3d0d14f9 IM |
42 | break; |
43 | case TAG_Valid: | |
44 | if (getsign(st0_ptr) == SIGN_POS) | |
45 | setcc(0); | |
46 | else | |
47 | setcc(SW_C0); | |
48 | break; | |
49 | case TAG_Special: | |
50 | switch (FPU_Special(st0_ptr)) { | |
51 | case TW_Denormal: | |
52 | if (getsign(st0_ptr) == SIGN_POS) | |
53 | setcc(0); | |
54 | else | |
55 | setcc(SW_C0); | |
56 | if (denormal_operand() < 0) { | |
57 | #ifdef PECULIAR_486 | |
58 | /* This is weird! */ | |
59 | if (getsign(st0_ptr) == SIGN_POS) | |
60 | setcc(SW_C3); | |
1da177e4 | 61 | #endif /* PECULIAR_486 */ |
3d0d14f9 IM |
62 | return; |
63 | } | |
64 | break; | |
65 | case TW_NaN: | |
66 | setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ | |
67 | EXCEPTION(EX_Invalid); | |
68 | break; | |
69 | case TW_Infinity: | |
70 | if (getsign(st0_ptr) == SIGN_POS) | |
71 | setcc(0); | |
72 | else | |
73 | setcc(SW_C0); | |
74 | break; | |
75 | default: | |
76 | setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ | |
77 | EXCEPTION(EX_INTERNAL | 0x14); | |
78 | break; | |
79 | } | |
80 | break; | |
81 | case TAG_Empty: | |
82 | setcc(SW_C0 | SW_C2 | SW_C3); | |
83 | EXCEPTION(EX_StackUnder); | |
84 | break; | |
1da177e4 | 85 | } |
1da177e4 LT |
86 | } |
87 | ||
e8d591dc | 88 | static void fxam(FPU_REG *st0_ptr, u_char st0tag) |
1da177e4 | 89 | { |
3d0d14f9 IM |
90 | int c = 0; |
91 | switch (st0tag) { | |
92 | case TAG_Empty: | |
93 | c = SW_C3 | SW_C0; | |
94 | break; | |
95 | case TAG_Zero: | |
96 | c = SW_C3; | |
97 | break; | |
98 | case TAG_Valid: | |
99 | c = SW_C2; | |
100 | break; | |
101 | case TAG_Special: | |
102 | switch (FPU_Special(st0_ptr)) { | |
103 | case TW_Denormal: | |
104 | c = SW_C2 | SW_C3; /* Denormal */ | |
105 | break; | |
106 | case TW_NaN: | |
107 | /* We also use NaN for unsupported types. */ | |
108 | if ((st0_ptr->sigh & 0x80000000) | |
109 | && (exponent(st0_ptr) == EXP_OVER)) | |
110 | c = SW_C0; | |
111 | break; | |
112 | case TW_Infinity: | |
113 | c = SW_C2 | SW_C0; | |
114 | break; | |
115 | } | |
1da177e4 | 116 | } |
3d0d14f9 IM |
117 | if (getsign(st0_ptr) == SIGN_NEG) |
118 | c |= SW_C1; | |
119 | setcc(c); | |
1da177e4 LT |
120 | } |
121 | ||
1da177e4 | 122 | static FUNC_ST0 const fp_etc_table[] = { |
3d0d14f9 IM |
123 | fchs, fabs, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal, |
124 | ftst_, fxam, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal | |
1da177e4 LT |
125 | }; |
126 | ||
127 | void FPU_etc(void) | |
128 | { | |
3d0d14f9 | 129 | (fp_etc_table[FPU_rm]) (&st(0), FPU_gettag0()); |
1da177e4 | 130 | } |