Commit 00406dff19893a4fb9fb582792a249b770eb1d11
1 parent
69de927c
added arm nwfpe support (initial patch by Ulrich Hecht)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@609 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
16 changed files
with
3914 additions
and
0 deletions
Too many changes to show.
To preserve performance only 16 of 18 files are displayed.
target-arm/nwfpe/ARM-gcc.h
0 → 100644
| 1 | +/* | ||
| 2 | +------------------------------------------------------------------------------- | ||
| 3 | +The macro `BITS64' can be defined to indicate that 64-bit integer types are | ||
| 4 | +supported by the compiler. | ||
| 5 | +------------------------------------------------------------------------------- | ||
| 6 | +*/ | ||
| 7 | +#define BITS64 | ||
| 8 | + | ||
| 9 | +/* | ||
| 10 | +------------------------------------------------------------------------------- | ||
| 11 | +Each of the following `typedef's defines the most convenient type that holds | ||
| 12 | +integers of at least as many bits as specified. For example, `uint8' should | ||
| 13 | +be the most convenient type that can hold unsigned integers of as many as | ||
| 14 | +8 bits. The `flag' type must be able to hold either a 0 or 1. For most | ||
| 15 | +implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed | ||
| 16 | +to the same as `int'. | ||
| 17 | +------------------------------------------------------------------------------- | ||
| 18 | +*/ | ||
| 19 | +typedef char flag; | ||
| 20 | +typedef unsigned char uint8; | ||
| 21 | +typedef signed char int8; | ||
| 22 | +typedef int uint16; | ||
| 23 | +typedef int int16; | ||
| 24 | +typedef unsigned int uint32; | ||
| 25 | +typedef signed int int32; | ||
| 26 | +#ifdef BITS64 | ||
| 27 | +typedef unsigned long long int bits64; | ||
| 28 | +typedef signed long long int sbits64; | ||
| 29 | +#endif | ||
| 30 | + | ||
| 31 | +/* | ||
| 32 | +------------------------------------------------------------------------------- | ||
| 33 | +Each of the following `typedef's defines a type that holds integers | ||
| 34 | +of _exactly_ the number of bits specified. For instance, for most | ||
| 35 | +implementation of C, `bits16' and `sbits16' should be `typedef'ed to | ||
| 36 | +`unsigned short int' and `signed short int' (or `short int'), respectively. | ||
| 37 | +------------------------------------------------------------------------------- | ||
| 38 | +*/ | ||
| 39 | +typedef unsigned char bits8; | ||
| 40 | +typedef signed char sbits8; | ||
| 41 | +typedef unsigned short int bits16; | ||
| 42 | +typedef signed short int sbits16; | ||
| 43 | +typedef unsigned int bits32; | ||
| 44 | +typedef signed int sbits32; | ||
| 45 | +#ifdef BITS64 | ||
| 46 | +typedef unsigned long long int uint64; | ||
| 47 | +typedef signed long long int int64; | ||
| 48 | +#endif | ||
| 49 | + | ||
| 50 | +#ifdef BITS64 | ||
| 51 | +/* | ||
| 52 | +------------------------------------------------------------------------------- | ||
| 53 | +The `LIT64' macro takes as its argument a textual integer literal and if | ||
| 54 | +necessary ``marks'' the literal as having a 64-bit integer type. For | ||
| 55 | +example, the Gnu C Compiler (`gcc') requires that 64-bit literals be | ||
| 56 | +appended with the letters `LL' standing for `long long', which is `gcc's | ||
| 57 | +name for the 64-bit integer type. Some compilers may allow `LIT64' to be | ||
| 58 | +defined as the identity macro: `#define LIT64( a ) a'. | ||
| 59 | +------------------------------------------------------------------------------- | ||
| 60 | +*/ | ||
| 61 | +#define LIT64( a ) a##LL | ||
| 62 | +#endif | ||
| 63 | + | ||
| 64 | +/* | ||
| 65 | +------------------------------------------------------------------------------- | ||
| 66 | +The macro `INLINE' can be used before functions that should be inlined. If | ||
| 67 | +a compiler does not support explicit inlining, this macro should be defined | ||
| 68 | +to be `static'. | ||
| 69 | +------------------------------------------------------------------------------- | ||
| 70 | +*/ | ||
| 71 | +#define INLINE extern __inline__ | ||
| 72 | + | ||
| 73 | + | ||
| 74 | +/* For use as a GCC soft-float library we need some special function names. */ | ||
| 75 | + | ||
| 76 | +#ifdef __LIBFLOAT__ | ||
| 77 | + | ||
| 78 | +/* Some 32-bit ops can be mapped straight across by just changing the name. */ | ||
| 79 | +#define float32_add __addsf3 | ||
| 80 | +#define float32_sub __subsf3 | ||
| 81 | +#define float32_mul __mulsf3 | ||
| 82 | +#define float32_div __divsf3 | ||
| 83 | +#define int32_to_float32 __floatsisf | ||
| 84 | +#define float32_to_int32_round_to_zero __fixsfsi | ||
| 85 | +#define float32_to_uint32_round_to_zero __fixunssfsi | ||
| 86 | + | ||
| 87 | +/* These ones go through the glue code. To avoid namespace pollution | ||
| 88 | + we rename the internal functions too. */ | ||
| 89 | +#define float32_eq ___float32_eq | ||
| 90 | +#define float32_le ___float32_le | ||
| 91 | +#define float32_lt ___float32_lt | ||
| 92 | + | ||
| 93 | +/* All the 64-bit ops have to go through the glue, so we pull the same | ||
| 94 | + trick. */ | ||
| 95 | +#define float64_add ___float64_add | ||
| 96 | +#define float64_sub ___float64_sub | ||
| 97 | +#define float64_mul ___float64_mul | ||
| 98 | +#define float64_div ___float64_div | ||
| 99 | +#define int32_to_float64 ___int32_to_float64 | ||
| 100 | +#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero | ||
| 101 | +#define float64_to_uint32_round_to_zero ___float64_to_uint32_round_to_zero | ||
| 102 | +#define float64_to_float32 ___float64_to_float32 | ||
| 103 | +#define float32_to_float64 ___float32_to_float64 | ||
| 104 | +#define float64_eq ___float64_eq | ||
| 105 | +#define float64_le ___float64_le | ||
| 106 | +#define float64_lt ___float64_lt | ||
| 107 | + | ||
| 108 | +#if 0 | ||
| 109 | +#define float64_add __adddf3 | ||
| 110 | +#define float64_sub __subdf3 | ||
| 111 | +#define float64_mul __muldf3 | ||
| 112 | +#define float64_div __divdf3 | ||
| 113 | +#define int32_to_float64 __floatsidf | ||
| 114 | +#define float64_to_int32_round_to_zero __fixdfsi | ||
| 115 | +#define float64_to_uint32_round_to_zero __fixunsdfsi | ||
| 116 | +#define float64_to_float32 __truncdfsf2 | ||
| 117 | +#define float32_to_float64 __extendsfdf2 | ||
| 118 | +#endif | ||
| 119 | + | ||
| 120 | +#endif |
target-arm/nwfpe/double_cpdo.c
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.COM, 1998,1999 | ||
| 4 | + | ||
| 5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 6 | + | ||
| 7 | + This program is free software; you can redistribute it and/or modify | ||
| 8 | + it under the terms of the GNU General Public License as published by | ||
| 9 | + the Free Software Foundation; either version 2 of the License, or | ||
| 10 | + (at your option) any later version. | ||
| 11 | + | ||
| 12 | + This program is distributed in the hope that it will be useful, | ||
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | + GNU General Public License for more details. | ||
| 16 | + | ||
| 17 | + You should have received a copy of the GNU General Public License | ||
| 18 | + along with this program; if not, write to the Free Software | ||
| 19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | +*/ | ||
| 21 | + | ||
| 22 | +#include "fpa11.h" | ||
| 23 | +#include "softfloat.h" | ||
| 24 | +#include "fpopcode.h" | ||
| 25 | + | ||
| 26 | +float64 float64_exp(float64 Fm); | ||
| 27 | +float64 float64_ln(float64 Fm); | ||
| 28 | +float64 float64_sin(float64 rFm); | ||
| 29 | +float64 float64_cos(float64 rFm); | ||
| 30 | +float64 float64_arcsin(float64 rFm); | ||
| 31 | +float64 float64_arctan(float64 rFm); | ||
| 32 | +float64 float64_log(float64 rFm); | ||
| 33 | +float64 float64_tan(float64 rFm); | ||
| 34 | +float64 float64_arccos(float64 rFm); | ||
| 35 | +float64 float64_pow(float64 rFn,float64 rFm); | ||
| 36 | +float64 float64_pol(float64 rFn,float64 rFm); | ||
| 37 | + | ||
| 38 | +unsigned int DoubleCPDO(const unsigned int opcode) | ||
| 39 | +{ | ||
| 40 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 41 | + float64 rFm, rFn; | ||
| 42 | + unsigned int Fd, Fm, Fn, nRc = 1; | ||
| 43 | + | ||
| 44 | + //printk("DoubleCPDO(0x%08x)\n",opcode); | ||
| 45 | + | ||
| 46 | + Fm = getFm(opcode); | ||
| 47 | + if (CONSTANT_FM(opcode)) | ||
| 48 | + { | ||
| 49 | + rFm = getDoubleConstant(Fm); | ||
| 50 | + } | ||
| 51 | + else | ||
| 52 | + { | ||
| 53 | + switch (fpa11->fType[Fm]) | ||
| 54 | + { | ||
| 55 | + case typeSingle: | ||
| 56 | + rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle); | ||
| 57 | + break; | ||
| 58 | + | ||
| 59 | + case typeDouble: | ||
| 60 | + rFm = fpa11->fpreg[Fm].fDouble; | ||
| 61 | + break; | ||
| 62 | + | ||
| 63 | + case typeExtended: | ||
| 64 | + // !! patb | ||
| 65 | + //printk("not implemented! why not?\n"); | ||
| 66 | + //!! ScottB | ||
| 67 | + // should never get here, if extended involved | ||
| 68 | + // then other operand should be promoted then | ||
| 69 | + // ExtendedCPDO called. | ||
| 70 | + break; | ||
| 71 | + | ||
| 72 | + default: return 0; | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + if (!MONADIC_INSTRUCTION(opcode)) | ||
| 77 | + { | ||
| 78 | + Fn = getFn(opcode); | ||
| 79 | + switch (fpa11->fType[Fn]) | ||
| 80 | + { | ||
| 81 | + case typeSingle: | ||
| 82 | + rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle); | ||
| 83 | + break; | ||
| 84 | + | ||
| 85 | + case typeDouble: | ||
| 86 | + rFn = fpa11->fpreg[Fn].fDouble; | ||
| 87 | + break; | ||
| 88 | + | ||
| 89 | + default: return 0; | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + Fd = getFd(opcode); | ||
| 94 | + /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */ | ||
| 95 | + switch (opcode & MASK_ARITHMETIC_OPCODE) | ||
| 96 | + { | ||
| 97 | + /* dyadic opcodes */ | ||
| 98 | + case ADF_CODE: | ||
| 99 | + fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm); | ||
| 100 | + break; | ||
| 101 | + | ||
| 102 | + case MUF_CODE: | ||
| 103 | + case FML_CODE: | ||
| 104 | + fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm); | ||
| 105 | + break; | ||
| 106 | + | ||
| 107 | + case SUF_CODE: | ||
| 108 | + fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm); | ||
| 109 | + break; | ||
| 110 | + | ||
| 111 | + case RSF_CODE: | ||
| 112 | + fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn); | ||
| 113 | + break; | ||
| 114 | + | ||
| 115 | + case DVF_CODE: | ||
| 116 | + case FDV_CODE: | ||
| 117 | + fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm); | ||
| 118 | + break; | ||
| 119 | + | ||
| 120 | + case RDF_CODE: | ||
| 121 | + case FRD_CODE: | ||
| 122 | + fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn); | ||
| 123 | + break; | ||
| 124 | + | ||
| 125 | +#if 0 | ||
| 126 | + case POW_CODE: | ||
| 127 | + fpa11->fpreg[Fd].fDouble = float64_pow(rFn,rFm); | ||
| 128 | + break; | ||
| 129 | + | ||
| 130 | + case RPW_CODE: | ||
| 131 | + fpa11->fpreg[Fd].fDouble = float64_pow(rFm,rFn); | ||
| 132 | + break; | ||
| 133 | +#endif | ||
| 134 | + | ||
| 135 | + case RMF_CODE: | ||
| 136 | + fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm); | ||
| 137 | + break; | ||
| 138 | + | ||
| 139 | +#if 0 | ||
| 140 | + case POL_CODE: | ||
| 141 | + fpa11->fpreg[Fd].fDouble = float64_pol(rFn,rFm); | ||
| 142 | + break; | ||
| 143 | +#endif | ||
| 144 | + | ||
| 145 | + /* monadic opcodes */ | ||
| 146 | + case MVF_CODE: | ||
| 147 | + fpa11->fpreg[Fd].fDouble = rFm; | ||
| 148 | + break; | ||
| 149 | + | ||
| 150 | + case MNF_CODE: | ||
| 151 | + { | ||
| 152 | + unsigned int *p = (unsigned int*)&rFm; | ||
| 153 | + p[1] ^= 0x80000000; | ||
| 154 | + fpa11->fpreg[Fd].fDouble = rFm; | ||
| 155 | + } | ||
| 156 | + break; | ||
| 157 | + | ||
| 158 | + case ABS_CODE: | ||
| 159 | + { | ||
| 160 | + unsigned int *p = (unsigned int*)&rFm; | ||
| 161 | + p[1] &= 0x7fffffff; | ||
| 162 | + fpa11->fpreg[Fd].fDouble = rFm; | ||
| 163 | + } | ||
| 164 | + break; | ||
| 165 | + | ||
| 166 | + case RND_CODE: | ||
| 167 | + case URD_CODE: | ||
| 168 | + fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm); | ||
| 169 | + break; | ||
| 170 | + | ||
| 171 | + case SQT_CODE: | ||
| 172 | + fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm); | ||
| 173 | + break; | ||
| 174 | + | ||
| 175 | +#if 0 | ||
| 176 | + case LOG_CODE: | ||
| 177 | + fpa11->fpreg[Fd].fDouble = float64_log(rFm); | ||
| 178 | + break; | ||
| 179 | + | ||
| 180 | + case LGN_CODE: | ||
| 181 | + fpa11->fpreg[Fd].fDouble = float64_ln(rFm); | ||
| 182 | + break; | ||
| 183 | + | ||
| 184 | + case EXP_CODE: | ||
| 185 | + fpa11->fpreg[Fd].fDouble = float64_exp(rFm); | ||
| 186 | + break; | ||
| 187 | + | ||
| 188 | + case SIN_CODE: | ||
| 189 | + fpa11->fpreg[Fd].fDouble = float64_sin(rFm); | ||
| 190 | + break; | ||
| 191 | + | ||
| 192 | + case COS_CODE: | ||
| 193 | + fpa11->fpreg[Fd].fDouble = float64_cos(rFm); | ||
| 194 | + break; | ||
| 195 | + | ||
| 196 | + case TAN_CODE: | ||
| 197 | + fpa11->fpreg[Fd].fDouble = float64_tan(rFm); | ||
| 198 | + break; | ||
| 199 | + | ||
| 200 | + case ASN_CODE: | ||
| 201 | + fpa11->fpreg[Fd].fDouble = float64_arcsin(rFm); | ||
| 202 | + break; | ||
| 203 | + | ||
| 204 | + case ACS_CODE: | ||
| 205 | + fpa11->fpreg[Fd].fDouble = float64_arccos(rFm); | ||
| 206 | + break; | ||
| 207 | + | ||
| 208 | + case ATN_CODE: | ||
| 209 | + fpa11->fpreg[Fd].fDouble = float64_arctan(rFm); | ||
| 210 | + break; | ||
| 211 | +#endif | ||
| 212 | + | ||
| 213 | + case NRM_CODE: | ||
| 214 | + break; | ||
| 215 | + | ||
| 216 | + default: | ||
| 217 | + { | ||
| 218 | + nRc = 0; | ||
| 219 | + } | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | + if (0 != nRc) fpa11->fType[Fd] = typeDouble; | ||
| 223 | + return nRc; | ||
| 224 | +} | ||
| 225 | + | ||
| 226 | +#if 0 | ||
| 227 | +float64 float64_exp(float64 rFm) | ||
| 228 | +{ | ||
| 229 | + return rFm; | ||
| 230 | +//series | ||
| 231 | +} | ||
| 232 | + | ||
| 233 | +float64 float64_ln(float64 rFm) | ||
| 234 | +{ | ||
| 235 | + return rFm; | ||
| 236 | +//series | ||
| 237 | +} | ||
| 238 | + | ||
| 239 | +float64 float64_sin(float64 rFm) | ||
| 240 | +{ | ||
| 241 | + return rFm; | ||
| 242 | +//series | ||
| 243 | +} | ||
| 244 | + | ||
| 245 | +float64 float64_cos(float64 rFm) | ||
| 246 | +{ | ||
| 247 | + return rFm; | ||
| 248 | + //series | ||
| 249 | +} | ||
| 250 | + | ||
| 251 | +#if 0 | ||
| 252 | +float64 float64_arcsin(float64 rFm) | ||
| 253 | +{ | ||
| 254 | +//series | ||
| 255 | +} | ||
| 256 | + | ||
| 257 | +float64 float64_arctan(float64 rFm) | ||
| 258 | +{ | ||
| 259 | + //series | ||
| 260 | +} | ||
| 261 | +#endif | ||
| 262 | + | ||
| 263 | +float64 float64_log(float64 rFm) | ||
| 264 | +{ | ||
| 265 | + return float64_div(float64_ln(rFm),getDoubleConstant(7)); | ||
| 266 | +} | ||
| 267 | + | ||
| 268 | +float64 float64_tan(float64 rFm) | ||
| 269 | +{ | ||
| 270 | + return float64_div(float64_sin(rFm),float64_cos(rFm)); | ||
| 271 | +} | ||
| 272 | + | ||
| 273 | +float64 float64_arccos(float64 rFm) | ||
| 274 | +{ | ||
| 275 | +return rFm; | ||
| 276 | + //return float64_sub(halfPi,float64_arcsin(rFm)); | ||
| 277 | +} | ||
| 278 | + | ||
| 279 | +float64 float64_pow(float64 rFn,float64 rFm) | ||
| 280 | +{ | ||
| 281 | + return float64_exp(float64_mul(rFm,float64_ln(rFn))); | ||
| 282 | +} | ||
| 283 | + | ||
| 284 | +float64 float64_pol(float64 rFn,float64 rFm) | ||
| 285 | +{ | ||
| 286 | + return float64_arctan(float64_div(rFn,rFm)); | ||
| 287 | +} | ||
| 288 | +#endif |
target-arm/nwfpe/extended_cpdo.c
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.COM, 1998,1999 | ||
| 4 | + | ||
| 5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 6 | + | ||
| 7 | + This program is free software; you can redistribute it and/or modify | ||
| 8 | + it under the terms of the GNU General Public License as published by | ||
| 9 | + the Free Software Foundation; either version 2 of the License, or | ||
| 10 | + (at your option) any later version. | ||
| 11 | + | ||
| 12 | + This program is distributed in the hope that it will be useful, | ||
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | + GNU General Public License for more details. | ||
| 16 | + | ||
| 17 | + You should have received a copy of the GNU General Public License | ||
| 18 | + along with this program; if not, write to the Free Software | ||
| 19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | +*/ | ||
| 21 | + | ||
| 22 | +#include "fpa11.h" | ||
| 23 | +#include "softfloat.h" | ||
| 24 | +#include "fpopcode.h" | ||
| 25 | + | ||
| 26 | +floatx80 floatx80_exp(floatx80 Fm); | ||
| 27 | +floatx80 floatx80_ln(floatx80 Fm); | ||
| 28 | +floatx80 floatx80_sin(floatx80 rFm); | ||
| 29 | +floatx80 floatx80_cos(floatx80 rFm); | ||
| 30 | +floatx80 floatx80_arcsin(floatx80 rFm); | ||
| 31 | +floatx80 floatx80_arctan(floatx80 rFm); | ||
| 32 | +floatx80 floatx80_log(floatx80 rFm); | ||
| 33 | +floatx80 floatx80_tan(floatx80 rFm); | ||
| 34 | +floatx80 floatx80_arccos(floatx80 rFm); | ||
| 35 | +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm); | ||
| 36 | +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm); | ||
| 37 | + | ||
| 38 | +unsigned int ExtendedCPDO(const unsigned int opcode) | ||
| 39 | +{ | ||
| 40 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 41 | + floatx80 rFm, rFn; | ||
| 42 | + unsigned int Fd, Fm, Fn, nRc = 1; | ||
| 43 | + | ||
| 44 | + //printk("ExtendedCPDO(0x%08x)\n",opcode); | ||
| 45 | + | ||
| 46 | + Fm = getFm(opcode); | ||
| 47 | + if (CONSTANT_FM(opcode)) | ||
| 48 | + { | ||
| 49 | + rFm = getExtendedConstant(Fm); | ||
| 50 | + } | ||
| 51 | + else | ||
| 52 | + { | ||
| 53 | + switch (fpa11->fType[Fm]) | ||
| 54 | + { | ||
| 55 | + case typeSingle: | ||
| 56 | + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); | ||
| 57 | + break; | ||
| 58 | + | ||
| 59 | + case typeDouble: | ||
| 60 | + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); | ||
| 61 | + break; | ||
| 62 | + | ||
| 63 | + case typeExtended: | ||
| 64 | + rFm = fpa11->fpreg[Fm].fExtended; | ||
| 65 | + break; | ||
| 66 | + | ||
| 67 | + default: return 0; | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + if (!MONADIC_INSTRUCTION(opcode)) | ||
| 72 | + { | ||
| 73 | + Fn = getFn(opcode); | ||
| 74 | + switch (fpa11->fType[Fn]) | ||
| 75 | + { | ||
| 76 | + case typeSingle: | ||
| 77 | + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); | ||
| 78 | + break; | ||
| 79 | + | ||
| 80 | + case typeDouble: | ||
| 81 | + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); | ||
| 82 | + break; | ||
| 83 | + | ||
| 84 | + case typeExtended: | ||
| 85 | + rFn = fpa11->fpreg[Fn].fExtended; | ||
| 86 | + break; | ||
| 87 | + | ||
| 88 | + default: return 0; | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + Fd = getFd(opcode); | ||
| 93 | + switch (opcode & MASK_ARITHMETIC_OPCODE) | ||
| 94 | + { | ||
| 95 | + /* dyadic opcodes */ | ||
| 96 | + case ADF_CODE: | ||
| 97 | + fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm); | ||
| 98 | + break; | ||
| 99 | + | ||
| 100 | + case MUF_CODE: | ||
| 101 | + case FML_CODE: | ||
| 102 | + fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm); | ||
| 103 | + break; | ||
| 104 | + | ||
| 105 | + case SUF_CODE: | ||
| 106 | + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm); | ||
| 107 | + break; | ||
| 108 | + | ||
| 109 | + case RSF_CODE: | ||
| 110 | + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn); | ||
| 111 | + break; | ||
| 112 | + | ||
| 113 | + case DVF_CODE: | ||
| 114 | + case FDV_CODE: | ||
| 115 | + fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm); | ||
| 116 | + break; | ||
| 117 | + | ||
| 118 | + case RDF_CODE: | ||
| 119 | + case FRD_CODE: | ||
| 120 | + fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn); | ||
| 121 | + break; | ||
| 122 | + | ||
| 123 | +#if 0 | ||
| 124 | + case POW_CODE: | ||
| 125 | + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm); | ||
| 126 | + break; | ||
| 127 | + | ||
| 128 | + case RPW_CODE: | ||
| 129 | + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn); | ||
| 130 | + break; | ||
| 131 | +#endif | ||
| 132 | + | ||
| 133 | + case RMF_CODE: | ||
| 134 | + fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm); | ||
| 135 | + break; | ||
| 136 | + | ||
| 137 | +#if 0 | ||
| 138 | + case POL_CODE: | ||
| 139 | + fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm); | ||
| 140 | + break; | ||
| 141 | +#endif | ||
| 142 | + | ||
| 143 | + /* monadic opcodes */ | ||
| 144 | + case MVF_CODE: | ||
| 145 | + fpa11->fpreg[Fd].fExtended = rFm; | ||
| 146 | + break; | ||
| 147 | + | ||
| 148 | + case MNF_CODE: | ||
| 149 | + rFm.high ^= 0x8000; | ||
| 150 | + fpa11->fpreg[Fd].fExtended = rFm; | ||
| 151 | + break; | ||
| 152 | + | ||
| 153 | + case ABS_CODE: | ||
| 154 | + rFm.high &= 0x7fff; | ||
| 155 | + fpa11->fpreg[Fd].fExtended = rFm; | ||
| 156 | + break; | ||
| 157 | + | ||
| 158 | + case RND_CODE: | ||
| 159 | + case URD_CODE: | ||
| 160 | + fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm); | ||
| 161 | + break; | ||
| 162 | + | ||
| 163 | + case SQT_CODE: | ||
| 164 | + fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm); | ||
| 165 | + break; | ||
| 166 | + | ||
| 167 | +#if 0 | ||
| 168 | + case LOG_CODE: | ||
| 169 | + fpa11->fpreg[Fd].fExtended = floatx80_log(rFm); | ||
| 170 | + break; | ||
| 171 | + | ||
| 172 | + case LGN_CODE: | ||
| 173 | + fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm); | ||
| 174 | + break; | ||
| 175 | + | ||
| 176 | + case EXP_CODE: | ||
| 177 | + fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm); | ||
| 178 | + break; | ||
| 179 | + | ||
| 180 | + case SIN_CODE: | ||
| 181 | + fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm); | ||
| 182 | + break; | ||
| 183 | + | ||
| 184 | + case COS_CODE: | ||
| 185 | + fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm); | ||
| 186 | + break; | ||
| 187 | + | ||
| 188 | + case TAN_CODE: | ||
| 189 | + fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm); | ||
| 190 | + break; | ||
| 191 | + | ||
| 192 | + case ASN_CODE: | ||
| 193 | + fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm); | ||
| 194 | + break; | ||
| 195 | + | ||
| 196 | + case ACS_CODE: | ||
| 197 | + fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm); | ||
| 198 | + break; | ||
| 199 | + | ||
| 200 | + case ATN_CODE: | ||
| 201 | + fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm); | ||
| 202 | + break; | ||
| 203 | +#endif | ||
| 204 | + | ||
| 205 | + case NRM_CODE: | ||
| 206 | + break; | ||
| 207 | + | ||
| 208 | + default: | ||
| 209 | + { | ||
| 210 | + nRc = 0; | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + if (0 != nRc) fpa11->fType[Fd] = typeExtended; | ||
| 215 | + return nRc; | ||
| 216 | +} | ||
| 217 | + | ||
| 218 | +#if 0 | ||
| 219 | +floatx80 floatx80_exp(floatx80 Fm) | ||
| 220 | +{ | ||
| 221 | +//series | ||
| 222 | +} | ||
| 223 | + | ||
| 224 | +floatx80 floatx80_ln(floatx80 Fm) | ||
| 225 | +{ | ||
| 226 | +//series | ||
| 227 | +} | ||
| 228 | + | ||
| 229 | +floatx80 floatx80_sin(floatx80 rFm) | ||
| 230 | +{ | ||
| 231 | +//series | ||
| 232 | +} | ||
| 233 | + | ||
| 234 | +floatx80 floatx80_cos(floatx80 rFm) | ||
| 235 | +{ | ||
| 236 | +//series | ||
| 237 | +} | ||
| 238 | + | ||
| 239 | +floatx80 floatx80_arcsin(floatx80 rFm) | ||
| 240 | +{ | ||
| 241 | +//series | ||
| 242 | +} | ||
| 243 | + | ||
| 244 | +floatx80 floatx80_arctan(floatx80 rFm) | ||
| 245 | +{ | ||
| 246 | + //series | ||
| 247 | +} | ||
| 248 | + | ||
| 249 | +floatx80 floatx80_log(floatx80 rFm) | ||
| 250 | +{ | ||
| 251 | + return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7)); | ||
| 252 | +} | ||
| 253 | + | ||
| 254 | +floatx80 floatx80_tan(floatx80 rFm) | ||
| 255 | +{ | ||
| 256 | + return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm)); | ||
| 257 | +} | ||
| 258 | + | ||
| 259 | +floatx80 floatx80_arccos(floatx80 rFm) | ||
| 260 | +{ | ||
| 261 | + //return floatx80_sub(halfPi,floatx80_arcsin(rFm)); | ||
| 262 | +} | ||
| 263 | + | ||
| 264 | +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) | ||
| 265 | +{ | ||
| 266 | + return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); | ||
| 267 | +} | ||
| 268 | + | ||
| 269 | +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm) | ||
| 270 | +{ | ||
| 271 | + return floatx80_arctan(floatx80_div(rFn,rFm)); | ||
| 272 | +} | ||
| 273 | +#endif |
target-arm/nwfpe/fpa11.c
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.COM, 1998,1999 | ||
| 4 | + | ||
| 5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 6 | + | ||
| 7 | + This program is free software; you can redistribute it and/or modify | ||
| 8 | + it under the terms of the GNU General Public License as published by | ||
| 9 | + the Free Software Foundation; either version 2 of the License, or | ||
| 10 | + (at your option) any later version. | ||
| 11 | + | ||
| 12 | + This program is distributed in the hope that it will be useful, | ||
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | + GNU General Public License for more details. | ||
| 16 | + | ||
| 17 | + You should have received a copy of the GNU General Public License | ||
| 18 | + along with this program; if not, write to the Free Software | ||
| 19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | +*/ | ||
| 21 | + | ||
| 22 | +#include "fpa11.h" | ||
| 23 | + | ||
| 24 | +#include "fpopcode.h" | ||
| 25 | + | ||
| 26 | +//#include "fpmodule.h" | ||
| 27 | +//#include "fpmodule.inl" | ||
| 28 | + | ||
| 29 | +//#include <asm/system.h> | ||
| 30 | + | ||
| 31 | +#include <stdio.h> | ||
| 32 | + | ||
| 33 | +/* forward declarations */ | ||
| 34 | +unsigned int EmulateCPDO(const unsigned int); | ||
| 35 | +unsigned int EmulateCPDT(const unsigned int); | ||
| 36 | +unsigned int EmulateCPRT(const unsigned int); | ||
| 37 | + | ||
| 38 | +FPA11* qemufpa=0; | ||
| 39 | +unsigned int* user_registers=0; | ||
| 40 | + | ||
| 41 | +/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ | ||
| 42 | +void resetFPA11(void) | ||
| 43 | +{ | ||
| 44 | + int i; | ||
| 45 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 46 | + | ||
| 47 | + /* initialize the register type array */ | ||
| 48 | + for (i=0;i<=7;i++) | ||
| 49 | + { | ||
| 50 | + fpa11->fType[i] = typeNone; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ | ||
| 54 | + fpa11->fpsr = FP_EMULATOR | BIT_AC; | ||
| 55 | + | ||
| 56 | + /* FPCR: set SB, AB and DA bits, clear all others */ | ||
| 57 | +#if MAINTAIN_FPCR | ||
| 58 | + fpa11->fpcr = MASK_RESET; | ||
| 59 | +#endif | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | +void SetRoundingMode(const unsigned int opcode) | ||
| 63 | +{ | ||
| 64 | +#if MAINTAIN_FPCR | ||
| 65 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 66 | + fpa11->fpcr &= ~MASK_ROUNDING_MODE; | ||
| 67 | +#endif | ||
| 68 | + switch (opcode & MASK_ROUNDING_MODE) | ||
| 69 | + { | ||
| 70 | + default: | ||
| 71 | + case ROUND_TO_NEAREST: | ||
| 72 | + float_rounding_mode = float_round_nearest_even; | ||
| 73 | +#if MAINTAIN_FPCR | ||
| 74 | + fpa11->fpcr |= ROUND_TO_NEAREST; | ||
| 75 | +#endif | ||
| 76 | + break; | ||
| 77 | + | ||
| 78 | + case ROUND_TO_PLUS_INFINITY: | ||
| 79 | + float_rounding_mode = float_round_up; | ||
| 80 | +#if MAINTAIN_FPCR | ||
| 81 | + fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; | ||
| 82 | +#endif | ||
| 83 | + break; | ||
| 84 | + | ||
| 85 | + case ROUND_TO_MINUS_INFINITY: | ||
| 86 | + float_rounding_mode = float_round_down; | ||
| 87 | +#if MAINTAIN_FPCR | ||
| 88 | + fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; | ||
| 89 | +#endif | ||
| 90 | + break; | ||
| 91 | + | ||
| 92 | + case ROUND_TO_ZERO: | ||
| 93 | + float_rounding_mode = float_round_to_zero; | ||
| 94 | +#if MAINTAIN_FPCR | ||
| 95 | + fpa11->fpcr |= ROUND_TO_ZERO; | ||
| 96 | +#endif | ||
| 97 | + break; | ||
| 98 | + } | ||
| 99 | +} | ||
| 100 | + | ||
| 101 | +void SetRoundingPrecision(const unsigned int opcode) | ||
| 102 | +{ | ||
| 103 | +#if MAINTAIN_FPCR | ||
| 104 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 105 | + fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; | ||
| 106 | +#endif | ||
| 107 | + switch (opcode & MASK_ROUNDING_PRECISION) | ||
| 108 | + { | ||
| 109 | + case ROUND_SINGLE: | ||
| 110 | + floatx80_rounding_precision = 32; | ||
| 111 | +#if MAINTAIN_FPCR | ||
| 112 | + fpa11->fpcr |= ROUND_SINGLE; | ||
| 113 | +#endif | ||
| 114 | + break; | ||
| 115 | + | ||
| 116 | + case ROUND_DOUBLE: | ||
| 117 | + floatx80_rounding_precision = 64; | ||
| 118 | +#if MAINTAIN_FPCR | ||
| 119 | + fpa11->fpcr |= ROUND_DOUBLE; | ||
| 120 | +#endif | ||
| 121 | + break; | ||
| 122 | + | ||
| 123 | + case ROUND_EXTENDED: | ||
| 124 | + floatx80_rounding_precision = 80; | ||
| 125 | +#if MAINTAIN_FPCR | ||
| 126 | + fpa11->fpcr |= ROUND_EXTENDED; | ||
| 127 | +#endif | ||
| 128 | + break; | ||
| 129 | + | ||
| 130 | + default: floatx80_rounding_precision = 80; | ||
| 131 | + } | ||
| 132 | +} | ||
| 133 | + | ||
| 134 | +/* Emulate the instruction in the opcode. */ | ||
| 135 | +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, unsigned int* qregs) | ||
| 136 | +{ | ||
| 137 | + unsigned int nRc = 0; | ||
| 138 | +// unsigned long flags; | ||
| 139 | + FPA11 *fpa11; | ||
| 140 | +// save_flags(flags); sti(); | ||
| 141 | + | ||
| 142 | + qemufpa=qfpa; | ||
| 143 | + user_registers=qregs; | ||
| 144 | + | ||
| 145 | +#if 0 | ||
| 146 | + fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", | ||
| 147 | + opcode, qregs[REG_PC]); | ||
| 148 | +#endif | ||
| 149 | + fpa11 = GET_FPA11(); | ||
| 150 | + | ||
| 151 | + if (fpa11->initflag == 0) /* good place for __builtin_expect */ | ||
| 152 | + { | ||
| 153 | + resetFPA11(); | ||
| 154 | + SetRoundingMode(ROUND_TO_NEAREST); | ||
| 155 | + SetRoundingPrecision(ROUND_EXTENDED); | ||
| 156 | + fpa11->initflag = 1; | ||
| 157 | + } | ||
| 158 | + | ||
| 159 | + if (TEST_OPCODE(opcode,MASK_CPRT)) | ||
| 160 | + { | ||
| 161 | + //fprintf(stderr,"emulating CPRT\n"); | ||
| 162 | + /* Emulate conversion opcodes. */ | ||
| 163 | + /* Emulate register transfer opcodes. */ | ||
| 164 | + /* Emulate comparison opcodes. */ | ||
| 165 | + nRc = EmulateCPRT(opcode); | ||
| 166 | + } | ||
| 167 | + else if (TEST_OPCODE(opcode,MASK_CPDO)) | ||
| 168 | + { | ||
| 169 | + //fprintf(stderr,"emulating CPDO\n"); | ||
| 170 | + /* Emulate monadic arithmetic opcodes. */ | ||
| 171 | + /* Emulate dyadic arithmetic opcodes. */ | ||
| 172 | + nRc = EmulateCPDO(opcode); | ||
| 173 | + } | ||
| 174 | + else if (TEST_OPCODE(opcode,MASK_CPDT)) | ||
| 175 | + { | ||
| 176 | + //fprintf(stderr,"emulating CPDT\n"); | ||
| 177 | + /* Emulate load/store opcodes. */ | ||
| 178 | + /* Emulate load/store multiple opcodes. */ | ||
| 179 | + nRc = EmulateCPDT(opcode); | ||
| 180 | + } | ||
| 181 | + else | ||
| 182 | + { | ||
| 183 | + /* Invalid instruction detected. Return FALSE. */ | ||
| 184 | + nRc = 0; | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | +// restore_flags(flags); | ||
| 188 | + | ||
| 189 | + //printf("returning %d\n",nRc); | ||
| 190 | + return(nRc); | ||
| 191 | +} | ||
| 192 | + | ||
| 193 | +#if 0 | ||
| 194 | +unsigned int EmulateAll1(unsigned int opcode) | ||
| 195 | +{ | ||
| 196 | + switch ((opcode >> 24) & 0xf) | ||
| 197 | + { | ||
| 198 | + case 0xc: | ||
| 199 | + case 0xd: | ||
| 200 | + if ((opcode >> 20) & 0x1) | ||
| 201 | + { | ||
| 202 | + switch ((opcode >> 8) & 0xf) | ||
| 203 | + { | ||
| 204 | + case 0x1: return PerformLDF(opcode); break; | ||
| 205 | + case 0x2: return PerformLFM(opcode); break; | ||
| 206 | + default: return 0; | ||
| 207 | + } | ||
| 208 | + } | ||
| 209 | + else | ||
| 210 | + { | ||
| 211 | + switch ((opcode >> 8) & 0xf) | ||
| 212 | + { | ||
| 213 | + case 0x1: return PerformSTF(opcode); break; | ||
| 214 | + case 0x2: return PerformSFM(opcode); break; | ||
| 215 | + default: return 0; | ||
| 216 | + } | ||
| 217 | + } | ||
| 218 | + break; | ||
| 219 | + | ||
| 220 | + case 0xe: | ||
| 221 | + if (opcode & 0x10) | ||
| 222 | + return EmulateCPDO(opcode); | ||
| 223 | + else | ||
| 224 | + return EmulateCPRT(opcode); | ||
| 225 | + break; | ||
| 226 | + | ||
| 227 | + default: return 0; | ||
| 228 | + } | ||
| 229 | +} | ||
| 230 | +#endif | ||
| 231 | + |
target-arm/nwfpe/fpa11.h
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.com, 1998-1999 | ||
| 4 | + | ||
| 5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 6 | + | ||
| 7 | + This program is free software; you can redistribute it and/or modify | ||
| 8 | + it under the terms of the GNU General Public License as published by | ||
| 9 | + the Free Software Foundation; either version 2 of the License, or | ||
| 10 | + (at your option) any later version. | ||
| 11 | + | ||
| 12 | + This program is distributed in the hope that it will be useful, | ||
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | + GNU General Public License for more details. | ||
| 16 | + | ||
| 17 | + You should have received a copy of the GNU General Public License | ||
| 18 | + along with this program; if not, write to the Free Software | ||
| 19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | +*/ | ||
| 21 | + | ||
| 22 | +#ifndef __FPA11_H__ | ||
| 23 | +#define __FPA11_H__ | ||
| 24 | + | ||
| 25 | +#define GET_FPA11() (qemufpa) | ||
| 26 | + | ||
| 27 | +/* | ||
| 28 | + * The processes registers are always at the very top of the 8K | ||
| 29 | + * stack+task struct. Use the same method as 'current' uses to | ||
| 30 | + * reach them. | ||
| 31 | + */ | ||
| 32 | +extern unsigned int *user_registers; | ||
| 33 | + | ||
| 34 | +#define GET_USERREG() (user_registers) | ||
| 35 | + | ||
| 36 | +/* Need task_struct */ | ||
| 37 | +//#include <linux/sched.h> | ||
| 38 | + | ||
| 39 | +/* includes */ | ||
| 40 | +#include "fpsr.h" /* FP control and status register definitions */ | ||
| 41 | +#include "softfloat.h" | ||
| 42 | + | ||
| 43 | +#define typeNone 0x00 | ||
| 44 | +#define typeSingle 0x01 | ||
| 45 | +#define typeDouble 0x02 | ||
| 46 | +#define typeExtended 0x03 | ||
| 47 | + | ||
| 48 | +/* | ||
| 49 | + * This must be no more and no less than 12 bytes. | ||
| 50 | + */ | ||
| 51 | +typedef union tagFPREG { | ||
| 52 | + floatx80 fExtended; | ||
| 53 | + float64 fDouble; | ||
| 54 | + float32 fSingle; | ||
| 55 | +} FPREG; | ||
| 56 | + | ||
| 57 | +/* | ||
| 58 | + * FPA11 device model. | ||
| 59 | + * | ||
| 60 | + * This structure is exported to user space. Do not re-order. | ||
| 61 | + * Only add new stuff to the end, and do not change the size of | ||
| 62 | + * any element. Elements of this structure are used by user | ||
| 63 | + * space, and must match struct user_fp in include/asm-arm/user.h. | ||
| 64 | + * We include the byte offsets below for documentation purposes. | ||
| 65 | + * | ||
| 66 | + * The size of this structure and FPREG are checked by fpmodule.c | ||
| 67 | + * on initialisation. If the rules have been broken, NWFPE will | ||
| 68 | + * not initialise. | ||
| 69 | + */ | ||
| 70 | +typedef struct tagFPA11 { | ||
| 71 | +/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */ | ||
| 72 | +/* 96 */ FPSR fpsr; /* floating point status register */ | ||
| 73 | +/* 100 */ FPCR fpcr; /* floating point control register */ | ||
| 74 | +/* 104 */ unsigned char fType[8]; /* type of floating point value held in | ||
| 75 | + floating point registers. One of none | ||
| 76 | + single, double or extended. */ | ||
| 77 | +/* 112 */ int initflag; /* this is special. The kernel guarantees | ||
| 78 | + to set it to 0 when a thread is launched, | ||
| 79 | + so we can use it to detect whether this | ||
| 80 | + instance of the emulator needs to be | ||
| 81 | + initialised. */ | ||
| 82 | +} FPA11; | ||
| 83 | + | ||
| 84 | +extern FPA11* qemufpa; | ||
| 85 | + | ||
| 86 | +extern void resetFPA11(void); | ||
| 87 | +extern void SetRoundingMode(const unsigned int); | ||
| 88 | +extern void SetRoundingPrecision(const unsigned int); | ||
| 89 | + | ||
| 90 | +#define get_user(x,y) ((x)=*(y)) | ||
| 91 | +#define put_user(x,y) (*(y)=(x)) | ||
| 92 | +static inline unsigned int readRegister(unsigned int reg) | ||
| 93 | +{ | ||
| 94 | + return (user_registers[(reg)]); | ||
| 95 | +} | ||
| 96 | + | ||
| 97 | +static inline void writeRegister(unsigned int x, unsigned int y) | ||
| 98 | +{ | ||
| 99 | +#if 0 | ||
| 100 | + printf("writing %d to r%d\n",y,x); | ||
| 101 | +#endif | ||
| 102 | + user_registers[(x)]=(y); | ||
| 103 | +} | ||
| 104 | + | ||
| 105 | +static inline void writeConditionCodes(unsigned int x) | ||
| 106 | +{ | ||
| 107 | +#if 0 | ||
| 108 | +unsigned int y; | ||
| 109 | +unsigned int ZF; | ||
| 110 | + printf("setting flags to %x from %x\n",x,user_registers[16]); | ||
| 111 | +#endif | ||
| 112 | + user_registers[16]=(x); // cpsr | ||
| 113 | + user_registers[17]=(x>>29)&1; // cf | ||
| 114 | + user_registers[18]=(x<<3)&(1<<31); // vf | ||
| 115 | + user_registers[19]=x&(1<<31); // nzf | ||
| 116 | + if(!(x&(1<<30))) user_registers[19]++; // nzf must be non-zero for zf to be cleared | ||
| 117 | + | ||
| 118 | +#if 0 | ||
| 119 | + ZF = (user_registers[19] == 0); | ||
| 120 | + y=user_registers[16] | (user_registers[19] & 0x80000000) | (ZF << 30) | | ||
| 121 | + (user_registers[17] << 29) | ((user_registers[18] & 0x80000000) >> 3); | ||
| 122 | + if(y != x) | ||
| 123 | + printf("GODDAM SHIIIIIIIIIIIIIIIIT! %x %x nzf %x zf %x\n",x,y,user_registers[19],ZF); | ||
| 124 | +#endif | ||
| 125 | +} | ||
| 126 | + | ||
| 127 | +#define REG_PC 15 | ||
| 128 | + | ||
| 129 | +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, unsigned int* qregs); | ||
| 130 | + | ||
| 131 | +#endif |
target-arm/nwfpe/fpa11.inl
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.COM, 1998,1999 | ||
| 4 | + | ||
| 5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 6 | + | ||
| 7 | + This program is free software; you can redistribute it and/or modify | ||
| 8 | + it under the terms of the GNU General Public License as published by | ||
| 9 | + the Free Software Foundation; either version 2 of the License, or | ||
| 10 | + (at your option) any later version. | ||
| 11 | + | ||
| 12 | + This program is distributed in the hope that it will be useful, | ||
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | + GNU General Public License for more details. | ||
| 16 | + | ||
| 17 | + You should have received a copy of the GNU General Public License | ||
| 18 | + along with this program; if not, write to the Free Software | ||
| 19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | +*/ | ||
| 21 | + | ||
| 22 | +#include "fpa11.h" | ||
| 23 | + | ||
| 24 | +/* Read and write floating point status register */ | ||
| 25 | +extern __inline__ unsigned int readFPSR(void) | ||
| 26 | +{ | ||
| 27 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 28 | + return(fpa11->fpsr); | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +extern __inline__ void writeFPSR(FPSR reg) | ||
| 32 | +{ | ||
| 33 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 34 | + /* the sysid byte in the status register is readonly */ | ||
| 35 | + fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID); | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +/* Read and write floating point control register */ | ||
| 39 | +extern __inline__ FPCR readFPCR(void) | ||
| 40 | +{ | ||
| 41 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 42 | + /* clear SB, AB and DA bits before returning FPCR */ | ||
| 43 | + return(fpa11->fpcr & ~MASK_RFC); | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +extern __inline__ void writeFPCR(FPCR reg) | ||
| 47 | +{ | ||
| 48 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 49 | + fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ | ||
| 50 | + fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */ | ||
| 51 | +} |
target-arm/nwfpe/fpa11_cpdo.c
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.COM, 1998,1999 | ||
| 4 | + | ||
| 5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 6 | + | ||
| 7 | + This program is free software; you can redistribute it and/or modify | ||
| 8 | + it under the terms of the GNU General Public License as published by | ||
| 9 | + the Free Software Foundation; either version 2 of the License, or | ||
| 10 | + (at your option) any later version. | ||
| 11 | + | ||
| 12 | + This program is distributed in the hope that it will be useful, | ||
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | + GNU General Public License for more details. | ||
| 16 | + | ||
| 17 | + You should have received a copy of the GNU General Public License | ||
| 18 | + along with this program; if not, write to the Free Software | ||
| 19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | +*/ | ||
| 21 | + | ||
| 22 | +#include "fpa11.h" | ||
| 23 | +#include "fpopcode.h" | ||
| 24 | + | ||
| 25 | +unsigned int SingleCPDO(const unsigned int opcode); | ||
| 26 | +unsigned int DoubleCPDO(const unsigned int opcode); | ||
| 27 | +unsigned int ExtendedCPDO(const unsigned int opcode); | ||
| 28 | + | ||
| 29 | +unsigned int EmulateCPDO(const unsigned int opcode) | ||
| 30 | +{ | ||
| 31 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 32 | + unsigned int Fd, nType, nDest, nRc = 1; | ||
| 33 | + | ||
| 34 | + //printk("EmulateCPDO(0x%08x)\n",opcode); | ||
| 35 | + | ||
| 36 | + /* Get the destination size. If not valid let Linux perform | ||
| 37 | + an invalid instruction trap. */ | ||
| 38 | + nDest = getDestinationSize(opcode); | ||
| 39 | + if (typeNone == nDest) return 0; | ||
| 40 | + | ||
| 41 | + SetRoundingMode(opcode); | ||
| 42 | + | ||
| 43 | + /* Compare the size of the operands in Fn and Fm. | ||
| 44 | + Choose the largest size and perform operations in that size, | ||
| 45 | + in order to make use of all the precision of the operands. | ||
| 46 | + If Fm is a constant, we just grab a constant of a size | ||
| 47 | + matching the size of the operand in Fn. */ | ||
| 48 | + if (MONADIC_INSTRUCTION(opcode)) | ||
| 49 | + nType = nDest; | ||
| 50 | + else | ||
| 51 | + nType = fpa11->fType[getFn(opcode)]; | ||
| 52 | + | ||
| 53 | + if (!CONSTANT_FM(opcode)) | ||
| 54 | + { | ||
| 55 | + register unsigned int Fm = getFm(opcode); | ||
| 56 | + if (nType < fpa11->fType[Fm]) | ||
| 57 | + { | ||
| 58 | + nType = fpa11->fType[Fm]; | ||
| 59 | + } | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + switch (nType) | ||
| 63 | + { | ||
| 64 | + case typeSingle : nRc = SingleCPDO(opcode); break; | ||
| 65 | + case typeDouble : nRc = DoubleCPDO(opcode); break; | ||
| 66 | + case typeExtended : nRc = ExtendedCPDO(opcode); break; | ||
| 67 | + default : nRc = 0; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + /* If the operation succeeded, check to see if the result in the | ||
| 71 | + destination register is the correct size. If not force it | ||
| 72 | + to be. */ | ||
| 73 | + Fd = getFd(opcode); | ||
| 74 | + nType = fpa11->fType[Fd]; | ||
| 75 | + if ((0 != nRc) && (nDest != nType)) | ||
| 76 | + { | ||
| 77 | + switch (nDest) | ||
| 78 | + { | ||
| 79 | + case typeSingle: | ||
| 80 | + { | ||
| 81 | + if (typeDouble == nType) | ||
| 82 | + fpa11->fpreg[Fd].fSingle = | ||
| 83 | + float64_to_float32(fpa11->fpreg[Fd].fDouble); | ||
| 84 | + else | ||
| 85 | + fpa11->fpreg[Fd].fSingle = | ||
| 86 | + floatx80_to_float32(fpa11->fpreg[Fd].fExtended); | ||
| 87 | + } | ||
| 88 | + break; | ||
| 89 | + | ||
| 90 | + case typeDouble: | ||
| 91 | + { | ||
| 92 | + if (typeSingle == nType) | ||
| 93 | + fpa11->fpreg[Fd].fDouble = | ||
| 94 | + float32_to_float64(fpa11->fpreg[Fd].fSingle); | ||
| 95 | + else | ||
| 96 | + fpa11->fpreg[Fd].fDouble = | ||
| 97 | + floatx80_to_float64(fpa11->fpreg[Fd].fExtended); | ||
| 98 | + } | ||
| 99 | + break; | ||
| 100 | + | ||
| 101 | + case typeExtended: | ||
| 102 | + { | ||
| 103 | + if (typeSingle == nType) | ||
| 104 | + fpa11->fpreg[Fd].fExtended = | ||
| 105 | + float32_to_floatx80(fpa11->fpreg[Fd].fSingle); | ||
| 106 | + else | ||
| 107 | + fpa11->fpreg[Fd].fExtended = | ||
| 108 | + float64_to_floatx80(fpa11->fpreg[Fd].fDouble); | ||
| 109 | + } | ||
| 110 | + break; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + fpa11->fType[Fd] = nDest; | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + return nRc; | ||
| 117 | +} |
target-arm/nwfpe/fpa11_cpdt.c
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.com, 1998-1999 | ||
| 4 | + (c) Philip Blundell, 1998 | ||
| 5 | + | ||
| 6 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 7 | + | ||
| 8 | + This program is free software; you can redistribute it and/or modify | ||
| 9 | + it under the terms of the GNU General Public License as published by | ||
| 10 | + the Free Software Foundation; either version 2 of the License, or | ||
| 11 | + (at your option) any later version. | ||
| 12 | + | ||
| 13 | + This program is distributed in the hope that it will be useful, | ||
| 14 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | + GNU General Public License for more details. | ||
| 17 | + | ||
| 18 | + You should have received a copy of the GNU General Public License | ||
| 19 | + along with this program; if not, write to the Free Software | ||
| 20 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | +*/ | ||
| 22 | + | ||
| 23 | +#include "fpa11.h" | ||
| 24 | +#include "softfloat.h" | ||
| 25 | +#include "fpopcode.h" | ||
| 26 | +//#include "fpmodule.h" | ||
| 27 | +//#include "fpmodule.inl" | ||
| 28 | + | ||
| 29 | +//#include <asm/uaccess.h> | ||
| 30 | + | ||
| 31 | +static inline | ||
| 32 | +void loadSingle(const unsigned int Fn,const unsigned int *pMem) | ||
| 33 | +{ | ||
| 34 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 35 | + fpa11->fType[Fn] = typeSingle; | ||
| 36 | + get_user(fpa11->fpreg[Fn].fSingle, pMem); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +static inline | ||
| 40 | +void loadDouble(const unsigned int Fn,const unsigned int *pMem) | ||
| 41 | +{ | ||
| 42 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 43 | + unsigned int *p; | ||
| 44 | + p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; | ||
| 45 | + fpa11->fType[Fn] = typeDouble; | ||
| 46 | + get_user(p[0], &pMem[1]); | ||
| 47 | + get_user(p[1], &pMem[0]); /* sign & exponent */ | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +static inline | ||
| 51 | +void loadExtended(const unsigned int Fn,const unsigned int *pMem) | ||
| 52 | +{ | ||
| 53 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 54 | + unsigned int *p; | ||
| 55 | + p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; | ||
| 56 | + fpa11->fType[Fn] = typeExtended; | ||
| 57 | + get_user(p[0], &pMem[0]); /* sign & exponent */ | ||
| 58 | + get_user(p[1], &pMem[2]); /* ls bits */ | ||
| 59 | + get_user(p[2], &pMem[1]); /* ms bits */ | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | +static inline | ||
| 63 | +void loadMultiple(const unsigned int Fn,const unsigned int *pMem) | ||
| 64 | +{ | ||
| 65 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 66 | + register unsigned int *p; | ||
| 67 | + unsigned long x; | ||
| 68 | + | ||
| 69 | + p = (unsigned int*)&(fpa11->fpreg[Fn]); | ||
| 70 | + get_user(x, &pMem[0]); | ||
| 71 | + fpa11->fType[Fn] = (x >> 14) & 0x00000003; | ||
| 72 | + | ||
| 73 | + switch (fpa11->fType[Fn]) | ||
| 74 | + { | ||
| 75 | + case typeSingle: | ||
| 76 | + case typeDouble: | ||
| 77 | + { | ||
| 78 | + get_user(p[0], &pMem[2]); /* Single */ | ||
| 79 | + get_user(p[1], &pMem[1]); /* double msw */ | ||
| 80 | + p[2] = 0; /* empty */ | ||
| 81 | + } | ||
| 82 | + break; | ||
| 83 | + | ||
| 84 | + case typeExtended: | ||
| 85 | + { | ||
| 86 | + get_user(p[1], &pMem[2]); | ||
| 87 | + get_user(p[2], &pMem[1]); /* msw */ | ||
| 88 | + p[0] = (x & 0x80003fff); | ||
| 89 | + } | ||
| 90 | + break; | ||
| 91 | + } | ||
| 92 | +} | ||
| 93 | + | ||
| 94 | +static inline | ||
| 95 | +void storeSingle(const unsigned int Fn,unsigned int *pMem) | ||
| 96 | +{ | ||
| 97 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 98 | + float32 val; | ||
| 99 | + register unsigned int *p = (unsigned int*)&val; | ||
| 100 | + | ||
| 101 | + switch (fpa11->fType[Fn]) | ||
| 102 | + { | ||
| 103 | + case typeDouble: | ||
| 104 | + val = float64_to_float32(fpa11->fpreg[Fn].fDouble); | ||
| 105 | + break; | ||
| 106 | + | ||
| 107 | + case typeExtended: | ||
| 108 | + val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); | ||
| 109 | + break; | ||
| 110 | + | ||
| 111 | + default: val = fpa11->fpreg[Fn].fSingle; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + put_user(p[0], pMem); | ||
| 115 | +} | ||
| 116 | + | ||
| 117 | +static inline | ||
| 118 | +void storeDouble(const unsigned int Fn,unsigned int *pMem) | ||
| 119 | +{ | ||
| 120 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 121 | + float64 val; | ||
| 122 | + register unsigned int *p = (unsigned int*)&val; | ||
| 123 | + | ||
| 124 | + switch (fpa11->fType[Fn]) | ||
| 125 | + { | ||
| 126 | + case typeSingle: | ||
| 127 | + val = float32_to_float64(fpa11->fpreg[Fn].fSingle); | ||
| 128 | + break; | ||
| 129 | + | ||
| 130 | + case typeExtended: | ||
| 131 | + val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); | ||
| 132 | + break; | ||
| 133 | + | ||
| 134 | + default: val = fpa11->fpreg[Fn].fDouble; | ||
| 135 | + } | ||
| 136 | + put_user(p[1], &pMem[0]); /* msw */ | ||
| 137 | + put_user(p[0], &pMem[1]); /* lsw */ | ||
| 138 | +} | ||
| 139 | + | ||
| 140 | +static inline | ||
| 141 | +void storeExtended(const unsigned int Fn,unsigned int *pMem) | ||
| 142 | +{ | ||
| 143 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 144 | + floatx80 val; | ||
| 145 | + register unsigned int *p = (unsigned int*)&val; | ||
| 146 | + | ||
| 147 | + switch (fpa11->fType[Fn]) | ||
| 148 | + { | ||
| 149 | + case typeSingle: | ||
| 150 | + val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); | ||
| 151 | + break; | ||
| 152 | + | ||
| 153 | + case typeDouble: | ||
| 154 | + val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); | ||
| 155 | + break; | ||
| 156 | + | ||
| 157 | + default: val = fpa11->fpreg[Fn].fExtended; | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + put_user(p[0], &pMem[0]); /* sign & exp */ | ||
| 161 | + put_user(p[1], &pMem[2]); | ||
| 162 | + put_user(p[2], &pMem[1]); /* msw */ | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +static inline | ||
| 166 | +void storeMultiple(const unsigned int Fn,unsigned int *pMem) | ||
| 167 | +{ | ||
| 168 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 169 | + register unsigned int nType, *p; | ||
| 170 | + | ||
| 171 | + p = (unsigned int*)&(fpa11->fpreg[Fn]); | ||
| 172 | + nType = fpa11->fType[Fn]; | ||
| 173 | + | ||
| 174 | + switch (nType) | ||
| 175 | + { | ||
| 176 | + case typeSingle: | ||
| 177 | + case typeDouble: | ||
| 178 | + { | ||
| 179 | + put_user(p[0], &pMem[2]); /* single */ | ||
| 180 | + put_user(p[1], &pMem[1]); /* double msw */ | ||
| 181 | + put_user(nType << 14, &pMem[0]); | ||
| 182 | + } | ||
| 183 | + break; | ||
| 184 | + | ||
| 185 | + case typeExtended: | ||
| 186 | + { | ||
| 187 | + put_user(p[2], &pMem[1]); /* msw */ | ||
| 188 | + put_user(p[1], &pMem[2]); | ||
| 189 | + put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); | ||
| 190 | + } | ||
| 191 | + break; | ||
| 192 | + } | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +unsigned int PerformLDF(const unsigned int opcode) | ||
| 196 | +{ | ||
| 197 | + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, | ||
| 198 | + write_back = WRITE_BACK(opcode); | ||
| 199 | + | ||
| 200 | + //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); | ||
| 201 | + | ||
| 202 | + pBase = (unsigned int*)readRegister(getRn(opcode)); | ||
| 203 | + if (REG_PC == getRn(opcode)) | ||
| 204 | + { | ||
| 205 | + pBase += 2; | ||
| 206 | + write_back = 0; | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + pFinal = pBase; | ||
| 210 | + if (BIT_UP_SET(opcode)) | ||
| 211 | + pFinal += getOffset(opcode); | ||
| 212 | + else | ||
| 213 | + pFinal -= getOffset(opcode); | ||
| 214 | + | ||
| 215 | + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | ||
| 216 | + | ||
| 217 | + switch (opcode & MASK_TRANSFER_LENGTH) | ||
| 218 | + { | ||
| 219 | + case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; | ||
| 220 | + case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; | ||
| 221 | + case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; | ||
| 222 | + default: nRc = 0; | ||
| 223 | + } | ||
| 224 | + | ||
| 225 | + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); | ||
| 226 | + return nRc; | ||
| 227 | +} | ||
| 228 | + | ||
| 229 | +unsigned int PerformSTF(const unsigned int opcode) | ||
| 230 | +{ | ||
| 231 | + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, | ||
| 232 | + write_back = WRITE_BACK(opcode); | ||
| 233 | + | ||
| 234 | + //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); | ||
| 235 | + SetRoundingMode(ROUND_TO_NEAREST); | ||
| 236 | + | ||
| 237 | + pBase = (unsigned int*)readRegister(getRn(opcode)); | ||
| 238 | + if (REG_PC == getRn(opcode)) | ||
| 239 | + { | ||
| 240 | + pBase += 2; | ||
| 241 | + write_back = 0; | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + pFinal = pBase; | ||
| 245 | + if (BIT_UP_SET(opcode)) | ||
| 246 | + pFinal += getOffset(opcode); | ||
| 247 | + else | ||
| 248 | + pFinal -= getOffset(opcode); | ||
| 249 | + | ||
| 250 | + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | ||
| 251 | + | ||
| 252 | + switch (opcode & MASK_TRANSFER_LENGTH) | ||
| 253 | + { | ||
| 254 | + case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; | ||
| 255 | + case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; | ||
| 256 | + case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; | ||
| 257 | + default: nRc = 0; | ||
| 258 | + } | ||
| 259 | + | ||
| 260 | + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); | ||
| 261 | + return nRc; | ||
| 262 | +} | ||
| 263 | + | ||
| 264 | +unsigned int PerformLFM(const unsigned int opcode) | ||
| 265 | +{ | ||
| 266 | + unsigned int i, Fd, *pBase, *pAddress, *pFinal, | ||
| 267 | + write_back = WRITE_BACK(opcode); | ||
| 268 | + | ||
| 269 | + pBase = (unsigned int*)readRegister(getRn(opcode)); | ||
| 270 | + if (REG_PC == getRn(opcode)) | ||
| 271 | + { | ||
| 272 | + pBase += 2; | ||
| 273 | + write_back = 0; | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + pFinal = pBase; | ||
| 277 | + if (BIT_UP_SET(opcode)) | ||
| 278 | + pFinal += getOffset(opcode); | ||
| 279 | + else | ||
| 280 | + pFinal -= getOffset(opcode); | ||
| 281 | + | ||
| 282 | + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | ||
| 283 | + | ||
| 284 | + Fd = getFd(opcode); | ||
| 285 | + for (i=getRegisterCount(opcode);i>0;i--) | ||
| 286 | + { | ||
| 287 | + loadMultiple(Fd,pAddress); | ||
| 288 | + pAddress += 3; Fd++; | ||
| 289 | + if (Fd == 8) Fd = 0; | ||
| 290 | + } | ||
| 291 | + | ||
| 292 | + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); | ||
| 293 | + return 1; | ||
| 294 | +} | ||
| 295 | + | ||
| 296 | +unsigned int PerformSFM(const unsigned int opcode) | ||
| 297 | +{ | ||
| 298 | + unsigned int i, Fd, *pBase, *pAddress, *pFinal, | ||
| 299 | + write_back = WRITE_BACK(opcode); | ||
| 300 | + | ||
| 301 | + pBase = (unsigned int*)readRegister(getRn(opcode)); | ||
| 302 | + if (REG_PC == getRn(opcode)) | ||
| 303 | + { | ||
| 304 | + pBase += 2; | ||
| 305 | + write_back = 0; | ||
| 306 | + } | ||
| 307 | + | ||
| 308 | + pFinal = pBase; | ||
| 309 | + if (BIT_UP_SET(opcode)) | ||
| 310 | + pFinal += getOffset(opcode); | ||
| 311 | + else | ||
| 312 | + pFinal -= getOffset(opcode); | ||
| 313 | + | ||
| 314 | + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | ||
| 315 | + | ||
| 316 | + Fd = getFd(opcode); | ||
| 317 | + for (i=getRegisterCount(opcode);i>0;i--) | ||
| 318 | + { | ||
| 319 | + storeMultiple(Fd,pAddress); | ||
| 320 | + pAddress += 3; Fd++; | ||
| 321 | + if (Fd == 8) Fd = 0; | ||
| 322 | + } | ||
| 323 | + | ||
| 324 | + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); | ||
| 325 | + return 1; | ||
| 326 | +} | ||
| 327 | + | ||
| 328 | +#if 1 | ||
| 329 | +unsigned int EmulateCPDT(const unsigned int opcode) | ||
| 330 | +{ | ||
| 331 | + unsigned int nRc = 0; | ||
| 332 | + | ||
| 333 | + //printk("EmulateCPDT(0x%08x)\n",opcode); | ||
| 334 | + | ||
| 335 | + if (LDF_OP(opcode)) | ||
| 336 | + { | ||
| 337 | + nRc = PerformLDF(opcode); | ||
| 338 | + } | ||
| 339 | + else if (LFM_OP(opcode)) | ||
| 340 | + { | ||
| 341 | + nRc = PerformLFM(opcode); | ||
| 342 | + } | ||
| 343 | + else if (STF_OP(opcode)) | ||
| 344 | + { | ||
| 345 | + nRc = PerformSTF(opcode); | ||
| 346 | + } | ||
| 347 | + else if (SFM_OP(opcode)) | ||
| 348 | + { | ||
| 349 | + nRc = PerformSFM(opcode); | ||
| 350 | + } | ||
| 351 | + else | ||
| 352 | + { | ||
| 353 | + nRc = 0; | ||
| 354 | + } | ||
| 355 | + | ||
| 356 | + return nRc; | ||
| 357 | +} | ||
| 358 | +#endif |
target-arm/nwfpe/fpa11_cprt.c
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.COM, 1998,1999 | ||
| 4 | + (c) Philip Blundell, 1999 | ||
| 5 | + | ||
| 6 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 7 | + | ||
| 8 | + This program is free software; you can redistribute it and/or modify | ||
| 9 | + it under the terms of the GNU General Public License as published by | ||
| 10 | + the Free Software Foundation; either version 2 of the License, or | ||
| 11 | + (at your option) any later version. | ||
| 12 | + | ||
| 13 | + This program is distributed in the hope that it will be useful, | ||
| 14 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | + GNU General Public License for more details. | ||
| 17 | + | ||
| 18 | + You should have received a copy of the GNU General Public License | ||
| 19 | + along with this program; if not, write to the Free Software | ||
| 20 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | +*/ | ||
| 22 | + | ||
| 23 | +#include "fpa11.h" | ||
| 24 | +#include "milieu.h" | ||
| 25 | +#include "softfloat.h" | ||
| 26 | +#include "fpopcode.h" | ||
| 27 | +#include "fpa11.inl" | ||
| 28 | +//#include "fpmodule.h" | ||
| 29 | +//#include "fpmodule.inl" | ||
| 30 | + | ||
| 31 | +extern flag floatx80_is_nan(floatx80); | ||
| 32 | +extern flag float64_is_nan( float64); | ||
| 33 | +extern flag float32_is_nan( float32); | ||
| 34 | + | ||
| 35 | +void SetRoundingMode(const unsigned int opcode); | ||
| 36 | + | ||
| 37 | +unsigned int PerformFLT(const unsigned int opcode); | ||
| 38 | +unsigned int PerformFIX(const unsigned int opcode); | ||
| 39 | + | ||
| 40 | +static unsigned int | ||
| 41 | +PerformComparison(const unsigned int opcode); | ||
| 42 | + | ||
| 43 | +unsigned int EmulateCPRT(const unsigned int opcode) | ||
| 44 | +{ | ||
| 45 | + unsigned int nRc = 1; | ||
| 46 | + | ||
| 47 | + //printk("EmulateCPRT(0x%08x)\n",opcode); | ||
| 48 | + | ||
| 49 | + if (opcode & 0x800000) | ||
| 50 | + { | ||
| 51 | + /* This is some variant of a comparison (PerformComparison will | ||
| 52 | + sort out which one). Since most of the other CPRT | ||
| 53 | + instructions are oddball cases of some sort or other it makes | ||
| 54 | + sense to pull this out into a fast path. */ | ||
| 55 | + return PerformComparison(opcode); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ | ||
| 59 | + switch ((opcode & 0x700000) >> 20) | ||
| 60 | + { | ||
| 61 | + case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; | ||
| 62 | + case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; | ||
| 63 | + | ||
| 64 | + case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; | ||
| 65 | + case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; | ||
| 66 | + | ||
| 67 | +#if 0 /* We currently have no use for the FPCR, so there's no point | ||
| 68 | + in emulating it. */ | ||
| 69 | + case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); | ||
| 70 | + case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; | ||
| 71 | +#endif | ||
| 72 | + | ||
| 73 | + default: nRc = 0; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + return nRc; | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +unsigned int PerformFLT(const unsigned int opcode) | ||
| 80 | +{ | ||
| 81 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 82 | + | ||
| 83 | + unsigned int nRc = 1; | ||
| 84 | + SetRoundingMode(opcode); | ||
| 85 | + | ||
| 86 | + switch (opcode & MASK_ROUNDING_PRECISION) | ||
| 87 | + { | ||
| 88 | + case ROUND_SINGLE: | ||
| 89 | + { | ||
| 90 | + fpa11->fType[getFn(opcode)] = typeSingle; | ||
| 91 | + fpa11->fpreg[getFn(opcode)].fSingle = | ||
| 92 | + int32_to_float32(readRegister(getRd(opcode))); | ||
| 93 | + } | ||
| 94 | + break; | ||
| 95 | + | ||
| 96 | + case ROUND_DOUBLE: | ||
| 97 | + { | ||
| 98 | + fpa11->fType[getFn(opcode)] = typeDouble; | ||
| 99 | + fpa11->fpreg[getFn(opcode)].fDouble = | ||
| 100 | + int32_to_float64(readRegister(getRd(opcode))); | ||
| 101 | + } | ||
| 102 | + break; | ||
| 103 | + | ||
| 104 | + case ROUND_EXTENDED: | ||
| 105 | + { | ||
| 106 | + fpa11->fType[getFn(opcode)] = typeExtended; | ||
| 107 | + fpa11->fpreg[getFn(opcode)].fExtended = | ||
| 108 | + int32_to_floatx80(readRegister(getRd(opcode))); | ||
| 109 | + } | ||
| 110 | + break; | ||
| 111 | + | ||
| 112 | + default: nRc = 0; | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + return nRc; | ||
| 116 | +} | ||
| 117 | + | ||
| 118 | +unsigned int PerformFIX(const unsigned int opcode) | ||
| 119 | +{ | ||
| 120 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 121 | + unsigned int nRc = 1; | ||
| 122 | + unsigned int Fn = getFm(opcode); | ||
| 123 | + | ||
| 124 | + SetRoundingMode(opcode); | ||
| 125 | + | ||
| 126 | + switch (fpa11->fType[Fn]) | ||
| 127 | + { | ||
| 128 | + case typeSingle: | ||
| 129 | + { | ||
| 130 | + writeRegister(getRd(opcode), | ||
| 131 | + float32_to_int32(fpa11->fpreg[Fn].fSingle)); | ||
| 132 | + } | ||
| 133 | + break; | ||
| 134 | + | ||
| 135 | + case typeDouble: | ||
| 136 | + { | ||
| 137 | + //printf("F%d is 0x%llx\n",Fn,fpa11->fpreg[Fn].fDouble); | ||
| 138 | + writeRegister(getRd(opcode), | ||
| 139 | + float64_to_int32(fpa11->fpreg[Fn].fDouble)); | ||
| 140 | + } | ||
| 141 | + break; | ||
| 142 | + | ||
| 143 | + case typeExtended: | ||
| 144 | + { | ||
| 145 | + writeRegister(getRd(opcode), | ||
| 146 | + floatx80_to_int32(fpa11->fpreg[Fn].fExtended)); | ||
| 147 | + } | ||
| 148 | + break; | ||
| 149 | + | ||
| 150 | + default: nRc = 0; | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + return nRc; | ||
| 154 | +} | ||
| 155 | + | ||
| 156 | + | ||
| 157 | +static unsigned int __inline__ | ||
| 158 | +PerformComparisonOperation(floatx80 Fn, floatx80 Fm) | ||
| 159 | +{ | ||
| 160 | + unsigned int flags = 0; | ||
| 161 | + | ||
| 162 | + /* test for less than condition */ | ||
| 163 | + if (floatx80_lt(Fn,Fm)) | ||
| 164 | + { | ||
| 165 | + flags |= CC_NEGATIVE; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + /* test for equal condition */ | ||
| 169 | + if (floatx80_eq(Fn,Fm)) | ||
| 170 | + { | ||
| 171 | + flags |= CC_ZERO; | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + /* test for greater than or equal condition */ | ||
| 175 | + if (floatx80_lt(Fm,Fn)) | ||
| 176 | + { | ||
| 177 | + flags |= CC_CARRY; | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + writeConditionCodes(flags); | ||
| 181 | + return 1; | ||
| 182 | +} | ||
| 183 | + | ||
| 184 | +/* This instruction sets the flags N, Z, C, V in the FPSR. */ | ||
| 185 | + | ||
| 186 | +static unsigned int PerformComparison(const unsigned int opcode) | ||
| 187 | +{ | ||
| 188 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 189 | + unsigned int Fn, Fm; | ||
| 190 | + floatx80 rFn, rFm; | ||
| 191 | + int e_flag = opcode & 0x400000; /* 1 if CxFE */ | ||
| 192 | + int n_flag = opcode & 0x200000; /* 1 if CNxx */ | ||
| 193 | + unsigned int flags = 0; | ||
| 194 | + | ||
| 195 | + //printk("PerformComparison(0x%08x)\n",opcode); | ||
| 196 | + | ||
| 197 | + Fn = getFn(opcode); | ||
| 198 | + Fm = getFm(opcode); | ||
| 199 | + | ||
| 200 | + /* Check for unordered condition and convert all operands to 80-bit | ||
| 201 | + format. | ||
| 202 | + ?? Might be some mileage in avoiding this conversion if possible. | ||
| 203 | + Eg, if both operands are 32-bit, detect this and do a 32-bit | ||
| 204 | + comparison (cheaper than an 80-bit one). */ | ||
| 205 | + switch (fpa11->fType[Fn]) | ||
| 206 | + { | ||
| 207 | + case typeSingle: | ||
| 208 | + //printk("single.\n"); | ||
| 209 | + if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) | ||
| 210 | + goto unordered; | ||
| 211 | + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); | ||
| 212 | + break; | ||
| 213 | + | ||
| 214 | + case typeDouble: | ||
| 215 | + //printk("double.\n"); | ||
| 216 | + if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) | ||
| 217 | + goto unordered; | ||
| 218 | + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); | ||
| 219 | + break; | ||
| 220 | + | ||
| 221 | + case typeExtended: | ||
| 222 | + //printk("extended.\n"); | ||
| 223 | + if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) | ||
| 224 | + goto unordered; | ||
| 225 | + rFn = fpa11->fpreg[Fn].fExtended; | ||
| 226 | + break; | ||
| 227 | + | ||
| 228 | + default: return 0; | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + if (CONSTANT_FM(opcode)) | ||
| 232 | + { | ||
| 233 | + //printk("Fm is a constant: #%d.\n",Fm); | ||
| 234 | + rFm = getExtendedConstant(Fm); | ||
| 235 | + if (floatx80_is_nan(rFm)) | ||
| 236 | + goto unordered; | ||
| 237 | + } | ||
| 238 | + else | ||
| 239 | + { | ||
| 240 | + //printk("Fm = r%d which contains a ",Fm); | ||
| 241 | + switch (fpa11->fType[Fm]) | ||
| 242 | + { | ||
| 243 | + case typeSingle: | ||
| 244 | + //printk("single.\n"); | ||
| 245 | + if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) | ||
| 246 | + goto unordered; | ||
| 247 | + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); | ||
| 248 | + break; | ||
| 249 | + | ||
| 250 | + case typeDouble: | ||
| 251 | + //printk("double.\n"); | ||
| 252 | + if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) | ||
| 253 | + goto unordered; | ||
| 254 | + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); | ||
| 255 | + break; | ||
| 256 | + | ||
| 257 | + case typeExtended: | ||
| 258 | + //printk("extended.\n"); | ||
| 259 | + if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) | ||
| 260 | + goto unordered; | ||
| 261 | + rFm = fpa11->fpreg[Fm].fExtended; | ||
| 262 | + break; | ||
| 263 | + | ||
| 264 | + default: return 0; | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + if (n_flag) | ||
| 269 | + { | ||
| 270 | + rFm.high ^= 0x8000; | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + return PerformComparisonOperation(rFn,rFm); | ||
| 274 | + | ||
| 275 | + unordered: | ||
| 276 | + /* ?? The FPA data sheet is pretty vague about this, in particular | ||
| 277 | + about whether the non-E comparisons can ever raise exceptions. | ||
| 278 | + This implementation is based on a combination of what it says in | ||
| 279 | + the data sheet, observation of how the Acorn emulator actually | ||
| 280 | + behaves (and how programs expect it to) and guesswork. */ | ||
| 281 | + flags |= CC_OVERFLOW; | ||
| 282 | + flags &= ~(CC_ZERO | CC_NEGATIVE); | ||
| 283 | + | ||
| 284 | + if (BIT_AC & readFPSR()) flags |= CC_CARRY; | ||
| 285 | + | ||
| 286 | + if (e_flag) float_raise(float_flag_invalid); | ||
| 287 | + | ||
| 288 | + writeConditionCodes(flags); | ||
| 289 | + return 1; | ||
| 290 | +} |
target-arm/nwfpe/fpopcode.c
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.COM, 1998,1999 | ||
| 4 | + | ||
| 5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 6 | + | ||
| 7 | + This program is free software; you can redistribute it and/or modify | ||
| 8 | + it under the terms of the GNU General Public License as published by | ||
| 9 | + the Free Software Foundation; either version 2 of the License, or | ||
| 10 | + (at your option) any later version. | ||
| 11 | + | ||
| 12 | + This program is distributed in the hope that it will be useful, | ||
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | + GNU General Public License for more details. | ||
| 16 | + | ||
| 17 | + You should have received a copy of the GNU General Public License | ||
| 18 | + along with this program; if not, write to the Free Software | ||
| 19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | +*/ | ||
| 21 | + | ||
| 22 | +#include "fpa11.h" | ||
| 23 | +#include "softfloat.h" | ||
| 24 | +#include "fpopcode.h" | ||
| 25 | +#include "fpsr.h" | ||
| 26 | +//#include "fpmodule.h" | ||
| 27 | +//#include "fpmodule.inl" | ||
| 28 | + | ||
| 29 | +const floatx80 floatx80Constant[] = { | ||
| 30 | + { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ | ||
| 31 | + { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ | ||
| 32 | + { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ | ||
| 33 | + { 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ | ||
| 34 | + { 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ | ||
| 35 | + { 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ | ||
| 36 | + { 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ | ||
| 37 | + { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ | ||
| 38 | +}; | ||
| 39 | + | ||
| 40 | +const float64 float64Constant[] = { | ||
| 41 | + 0x0000000000000000ULL, /* double 0.0 */ | ||
| 42 | + 0x3ff0000000000000ULL, /* double 1.0 */ | ||
| 43 | + 0x4000000000000000ULL, /* double 2.0 */ | ||
| 44 | + 0x4008000000000000ULL, /* double 3.0 */ | ||
| 45 | + 0x4010000000000000ULL, /* double 4.0 */ | ||
| 46 | + 0x4014000000000000ULL, /* double 5.0 */ | ||
| 47 | + 0x3fe0000000000000ULL, /* double 0.5 */ | ||
| 48 | + 0x4024000000000000ULL /* double 10.0 */ | ||
| 49 | +}; | ||
| 50 | + | ||
| 51 | +const float32 float32Constant[] = { | ||
| 52 | + 0x00000000, /* single 0.0 */ | ||
| 53 | + 0x3f800000, /* single 1.0 */ | ||
| 54 | + 0x40000000, /* single 2.0 */ | ||
| 55 | + 0x40400000, /* single 3.0 */ | ||
| 56 | + 0x40800000, /* single 4.0 */ | ||
| 57 | + 0x40a00000, /* single 5.0 */ | ||
| 58 | + 0x3f000000, /* single 0.5 */ | ||
| 59 | + 0x41200000 /* single 10.0 */ | ||
| 60 | +}; | ||
| 61 | + | ||
| 62 | +unsigned int getTransferLength(const unsigned int opcode) | ||
| 63 | +{ | ||
| 64 | + unsigned int nRc; | ||
| 65 | + | ||
| 66 | + switch (opcode & MASK_TRANSFER_LENGTH) | ||
| 67 | + { | ||
| 68 | + case 0x00000000: nRc = 1; break; /* single precision */ | ||
| 69 | + case 0x00008000: nRc = 2; break; /* double precision */ | ||
| 70 | + case 0x00400000: nRc = 3; break; /* extended precision */ | ||
| 71 | + default: nRc = 0; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + return(nRc); | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +unsigned int getRegisterCount(const unsigned int opcode) | ||
| 78 | +{ | ||
| 79 | + unsigned int nRc; | ||
| 80 | + | ||
| 81 | + switch (opcode & MASK_REGISTER_COUNT) | ||
| 82 | + { | ||
| 83 | + case 0x00000000: nRc = 4; break; | ||
| 84 | + case 0x00008000: nRc = 1; break; | ||
| 85 | + case 0x00400000: nRc = 2; break; | ||
| 86 | + case 0x00408000: nRc = 3; break; | ||
| 87 | + default: nRc = 0; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + return(nRc); | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +unsigned int getRoundingPrecision(const unsigned int opcode) | ||
| 94 | +{ | ||
| 95 | + unsigned int nRc; | ||
| 96 | + | ||
| 97 | + switch (opcode & MASK_ROUNDING_PRECISION) | ||
| 98 | + { | ||
| 99 | + case 0x00000000: nRc = 1; break; | ||
| 100 | + case 0x00000080: nRc = 2; break; | ||
| 101 | + case 0x00080000: nRc = 3; break; | ||
| 102 | + default: nRc = 0; | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + return(nRc); | ||
| 106 | +} | ||
| 107 | + | ||
| 108 | +unsigned int getDestinationSize(const unsigned int opcode) | ||
| 109 | +{ | ||
| 110 | + unsigned int nRc; | ||
| 111 | + | ||
| 112 | + switch (opcode & MASK_DESTINATION_SIZE) | ||
| 113 | + { | ||
| 114 | + case 0x00000000: nRc = typeSingle; break; | ||
| 115 | + case 0x00000080: nRc = typeDouble; break; | ||
| 116 | + case 0x00080000: nRc = typeExtended; break; | ||
| 117 | + default: nRc = typeNone; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + return(nRc); | ||
| 121 | +} | ||
| 122 | + | ||
| 123 | +/* condition code lookup table | ||
| 124 | + index into the table is test code: EQ, NE, ... LT, GT, AL, NV | ||
| 125 | + bit position in short is condition code: NZCV */ | ||
| 126 | +static const unsigned short aCC[16] = { | ||
| 127 | + 0xF0F0, // EQ == Z set | ||
| 128 | + 0x0F0F, // NE | ||
| 129 | + 0xCCCC, // CS == C set | ||
| 130 | + 0x3333, // CC | ||
| 131 | + 0xFF00, // MI == N set | ||
| 132 | + 0x00FF, // PL | ||
| 133 | + 0xAAAA, // VS == V set | ||
| 134 | + 0x5555, // VC | ||
| 135 | + 0x0C0C, // HI == C set && Z clear | ||
| 136 | + 0xF3F3, // LS == C clear || Z set | ||
| 137 | + 0xAA55, // GE == (N==V) | ||
| 138 | + 0x55AA, // LT == (N!=V) | ||
| 139 | + 0x0A05, // GT == (!Z && (N==V)) | ||
| 140 | + 0xF5FA, // LE == (Z || (N!=V)) | ||
| 141 | + 0xFFFF, // AL always | ||
| 142 | + 0 // NV | ||
| 143 | +}; | ||
| 144 | + | ||
| 145 | +unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes) | ||
| 146 | +{ | ||
| 147 | + return (aCC[opcode>>28] >> (ccodes>>28)) & 1; | ||
| 148 | +} |
target-arm/nwfpe/fpopcode.h
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.COM, 1998,1999 | ||
| 4 | + | ||
| 5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 6 | + | ||
| 7 | + This program is free software; you can redistribute it and/or modify | ||
| 8 | + it under the terms of the GNU General Public License as published by | ||
| 9 | + the Free Software Foundation; either version 2 of the License, or | ||
| 10 | + (at your option) any later version. | ||
| 11 | + | ||
| 12 | + This program is distributed in the hope that it will be useful, | ||
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | + GNU General Public License for more details. | ||
| 16 | + | ||
| 17 | + You should have received a copy of the GNU General Public License | ||
| 18 | + along with this program; if not, write to the Free Software | ||
| 19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | +*/ | ||
| 21 | + | ||
| 22 | +#ifndef __FPOPCODE_H__ | ||
| 23 | +#define __FPOPCODE_H__ | ||
| 24 | + | ||
| 25 | +/* | ||
| 26 | +ARM Floating Point Instruction Classes | ||
| 27 | +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ||
| 28 | +|c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT | ||
| 29 | +|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT | ||
| 30 | +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ||
| 31 | +|c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO | ||
| 32 | +|c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT | ||
| 33 | +|c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons | ||
| 34 | +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ||
| 35 | + | ||
| 36 | +CPDT data transfer instructions | ||
| 37 | + LDF, STF, LFM, SFM | ||
| 38 | + | ||
| 39 | +CPDO dyadic arithmetic instructions | ||
| 40 | + ADF, MUF, SUF, RSF, DVF, RDF, | ||
| 41 | + POW, RPW, RMF, FML, FDV, FRD, POL | ||
| 42 | + | ||
| 43 | +CPDO monadic arithmetic instructions | ||
| 44 | + MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, | ||
| 45 | + SIN, COS, TAN, ASN, ACS, ATN, URD, NRM | ||
| 46 | + | ||
| 47 | +CPRT joint arithmetic/data transfer instructions | ||
| 48 | + FIX (arithmetic followed by load/store) | ||
| 49 | + FLT (load/store followed by arithmetic) | ||
| 50 | + CMF, CNF CMFE, CNFE (comparisons) | ||
| 51 | + WFS, RFS (write/read floating point status register) | ||
| 52 | + WFC, RFC (write/read floating point control register) | ||
| 53 | + | ||
| 54 | +cond condition codes | ||
| 55 | +P pre/post index bit: 0 = postindex, 1 = preindex | ||
| 56 | +U up/down bit: 0 = stack grows down, 1 = stack grows up | ||
| 57 | +W write back bit: 1 = update base register (Rn) | ||
| 58 | +L load/store bit: 0 = store, 1 = load | ||
| 59 | +Rn base register | ||
| 60 | +Rd destination/source register | ||
| 61 | +Fd floating point destination register | ||
| 62 | +Fn floating point source register | ||
| 63 | +Fm floating point source register or floating point constant | ||
| 64 | + | ||
| 65 | +uv transfer length (TABLE 1) | ||
| 66 | +wx register count (TABLE 2) | ||
| 67 | +abcd arithmetic opcode (TABLES 3 & 4) | ||
| 68 | +ef destination size (rounding precision) (TABLE 5) | ||
| 69 | +gh rounding mode (TABLE 6) | ||
| 70 | +j dyadic/monadic bit: 0 = dyadic, 1 = monadic | ||
| 71 | +i constant bit: 1 = constant (TABLE 6) | ||
| 72 | +*/ | ||
| 73 | + | ||
| 74 | +/* | ||
| 75 | +TABLE 1 | ||
| 76 | ++-------------------------+---+---+---------+---------+ | ||
| 77 | +| Precision | u | v | FPSR.EP | length | | ||
| 78 | ++-------------------------+---+---+---------+---------+ | ||
| 79 | +| Single | 0 ü 0 | x | 1 words | | ||
| 80 | +| Double | 1 ü 1 | x | 2 words | | ||
| 81 | +| Extended | 1 ü 1 | x | 3 words | | ||
| 82 | +| Packed decimal | 1 ü 1 | 0 | 3 words | | ||
| 83 | +| Expanded packed decimal | 1 ü 1 | 1 | 4 words | | ||
| 84 | ++-------------------------+---+---+---------+---------+ | ||
| 85 | +Note: x = don't care | ||
| 86 | +*/ | ||
| 87 | + | ||
| 88 | +/* | ||
| 89 | +TABLE 2 | ||
| 90 | ++---+---+---------------------------------+ | ||
| 91 | +| w | x | Number of registers to transfer | | ||
| 92 | ++---+---+---------------------------------+ | ||
| 93 | +| 0 ü 1 | 1 | | ||
| 94 | +| 1 ü 0 | 2 | | ||
| 95 | +| 1 ü 1 | 3 | | ||
| 96 | +| 0 ü 0 | 4 | | ||
| 97 | ++---+---+---------------------------------+ | ||
| 98 | +*/ | ||
| 99 | + | ||
| 100 | +/* | ||
| 101 | +TABLE 3: Dyadic Floating Point Opcodes | ||
| 102 | ++---+---+---+---+----------+-----------------------+-----------------------+ | ||
| 103 | +| a | b | c | d | Mnemonic | Description | Operation | | ||
| 104 | ++---+---+---+---+----------+-----------------------+-----------------------+ | ||
| 105 | +| 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | | ||
| 106 | +| 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | | ||
| 107 | +| 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | | ||
| 108 | +| 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | | ||
| 109 | +| 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | | ||
| 110 | +| 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | | ||
| 111 | +| 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | | ||
| 112 | +| 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | | ||
| 113 | +| 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | | ||
| 114 | +| 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | | ||
| 115 | +| 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | | ||
| 116 | +| 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | | ||
| 117 | +| 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | | ||
| 118 | +| 1 | 1 | 0 | 1 | | undefined instruction | trap | | ||
| 119 | +| 1 | 1 | 1 | 0 | | undefined instruction | trap | | ||
| 120 | +| 1 | 1 | 1 | 1 | | undefined instruction | trap | | ||
| 121 | ++---+---+---+---+----------+-----------------------+-----------------------+ | ||
| 122 | +Note: POW, RPW, POL are deprecated, and are available for backwards | ||
| 123 | + compatibility only. | ||
| 124 | +*/ | ||
| 125 | + | ||
| 126 | +/* | ||
| 127 | +TABLE 4: Monadic Floating Point Opcodes | ||
| 128 | ++---+---+---+---+----------+-----------------------+-----------------------+ | ||
| 129 | +| a | b | c | d | Mnemonic | Description | Operation | | ||
| 130 | ++---+---+---+---+----------+-----------------------+-----------------------+ | ||
| 131 | +| 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | | ||
| 132 | +| 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | | ||
| 133 | +| 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | | ||
| 134 | +| 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | | ||
| 135 | +| 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | | ||
| 136 | +| 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | | ||
| 137 | +| 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | | ||
| 138 | +| 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | | ||
| 139 | +| 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | | ||
| 140 | +| 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | | ||
| 141 | +| 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | | ||
| 142 | +| 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | | ||
| 143 | +| 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | | ||
| 144 | +| 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | | ||
| 145 | +| 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | | ||
| 146 | +| 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | | ||
| 147 | ++---+---+---+---+----------+-----------------------+-----------------------+ | ||
| 148 | +Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are | ||
| 149 | + available for backwards compatibility only. | ||
| 150 | +*/ | ||
| 151 | + | ||
| 152 | +/* | ||
| 153 | +TABLE 5 | ||
| 154 | ++-------------------------+---+---+ | ||
| 155 | +| Rounding Precision | e | f | | ||
| 156 | ++-------------------------+---+---+ | ||
| 157 | +| IEEE Single precision | 0 ü 0 | | ||
| 158 | +| IEEE Double precision | 0 ü 1 | | ||
| 159 | +| IEEE Extended precision | 1 ü 0 | | ||
| 160 | +| undefined (trap) | 1 ü 1 | | ||
| 161 | ++-------------------------+---+---+ | ||
| 162 | +*/ | ||
| 163 | + | ||
| 164 | +/* | ||
| 165 | +TABLE 5 | ||
| 166 | ++---------------------------------+---+---+ | ||
| 167 | +| Rounding Mode | g | h | | ||
| 168 | ++---------------------------------+---+---+ | ||
| 169 | +| Round to nearest (default) | 0 ü 0 | | ||
| 170 | +| Round toward plus infinity | 0 ü 1 | | ||
| 171 | +| Round toward negative infinity | 1 ü 0 | | ||
| 172 | +| Round toward zero | 1 ü 1 | | ||
| 173 | ++---------------------------------+---+---+ | ||
| 174 | +*/ | ||
| 175 | + | ||
| 176 | +/* | ||
| 177 | +=== | ||
| 178 | +=== Definitions for load and store instructions | ||
| 179 | +=== | ||
| 180 | +*/ | ||
| 181 | + | ||
| 182 | +/* bit masks */ | ||
| 183 | +#define BIT_PREINDEX 0x01000000 | ||
| 184 | +#define BIT_UP 0x00800000 | ||
| 185 | +#define BIT_WRITE_BACK 0x00200000 | ||
| 186 | +#define BIT_LOAD 0x00100000 | ||
| 187 | + | ||
| 188 | +/* masks for load/store */ | ||
| 189 | +#define MASK_CPDT 0x0c000000 /* data processing opcode */ | ||
| 190 | +#define MASK_OFFSET 0x000000ff | ||
| 191 | +#define MASK_TRANSFER_LENGTH 0x00408000 | ||
| 192 | +#define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH | ||
| 193 | +#define MASK_COPROCESSOR 0x00000f00 | ||
| 194 | + | ||
| 195 | +/* Tests for transfer length */ | ||
| 196 | +#define TRANSFER_SINGLE 0x00000000 | ||
| 197 | +#define TRANSFER_DOUBLE 0x00008000 | ||
| 198 | +#define TRANSFER_EXTENDED 0x00400000 | ||
| 199 | +#define TRANSFER_PACKED MASK_TRANSFER_LENGTH | ||
| 200 | + | ||
| 201 | +/* Get the coprocessor number from the opcode. */ | ||
| 202 | +#define getCoprocessorNumber(opcode) ((opcode & MASK_COPROCESSOR) >> 8) | ||
| 203 | + | ||
| 204 | +/* Get the offset from the opcode. */ | ||
| 205 | +#define getOffset(opcode) (opcode & MASK_OFFSET) | ||
| 206 | + | ||
| 207 | +/* Tests for specific data transfer load/store opcodes. */ | ||
| 208 | +#define TEST_OPCODE(opcode,mask) (((opcode) & (mask)) == (mask)) | ||
| 209 | + | ||
| 210 | +#define LOAD_OP(opcode) TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD) | ||
| 211 | +#define STORE_OP(opcode) ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT) | ||
| 212 | + | ||
| 213 | +#define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) | ||
| 214 | +#define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) | ||
| 215 | +#define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) | ||
| 216 | +#define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) | ||
| 217 | + | ||
| 218 | +#define PREINDEXED(opcode) ((opcode & BIT_PREINDEX) != 0) | ||
| 219 | +#define POSTINDEXED(opcode) ((opcode & BIT_PREINDEX) == 0) | ||
| 220 | +#define BIT_UP_SET(opcode) ((opcode & BIT_UP) != 0) | ||
| 221 | +#define BIT_UP_CLEAR(opcode) ((opcode & BIT_DOWN) == 0) | ||
| 222 | +#define WRITE_BACK(opcode) ((opcode & BIT_WRITE_BACK) != 0) | ||
| 223 | +#define LOAD(opcode) ((opcode & BIT_LOAD) != 0) | ||
| 224 | +#define STORE(opcode) ((opcode & BIT_LOAD) == 0) | ||
| 225 | + | ||
| 226 | +/* | ||
| 227 | +=== | ||
| 228 | +=== Definitions for arithmetic instructions | ||
| 229 | +=== | ||
| 230 | +*/ | ||
| 231 | +/* bit masks */ | ||
| 232 | +#define BIT_MONADIC 0x00008000 | ||
| 233 | +#define BIT_CONSTANT 0x00000008 | ||
| 234 | + | ||
| 235 | +#define CONSTANT_FM(opcode) ((opcode & BIT_CONSTANT) != 0) | ||
| 236 | +#define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0) | ||
| 237 | + | ||
| 238 | +/* instruction identification masks */ | ||
| 239 | +#define MASK_CPDO 0x0e000000 /* arithmetic opcode */ | ||
| 240 | +#define MASK_ARITHMETIC_OPCODE 0x00f08000 | ||
| 241 | +#define MASK_DESTINATION_SIZE 0x00080080 | ||
| 242 | + | ||
| 243 | +/* dyadic arithmetic opcodes. */ | ||
| 244 | +#define ADF_CODE 0x00000000 | ||
| 245 | +#define MUF_CODE 0x00100000 | ||
| 246 | +#define SUF_CODE 0x00200000 | ||
| 247 | +#define RSF_CODE 0x00300000 | ||
| 248 | +#define DVF_CODE 0x00400000 | ||
| 249 | +#define RDF_CODE 0x00500000 | ||
| 250 | +#define POW_CODE 0x00600000 | ||
| 251 | +#define RPW_CODE 0x00700000 | ||
| 252 | +#define RMF_CODE 0x00800000 | ||
| 253 | +#define FML_CODE 0x00900000 | ||
| 254 | +#define FDV_CODE 0x00a00000 | ||
| 255 | +#define FRD_CODE 0x00b00000 | ||
| 256 | +#define POL_CODE 0x00c00000 | ||
| 257 | +/* 0x00d00000 is an invalid dyadic arithmetic opcode */ | ||
| 258 | +/* 0x00e00000 is an invalid dyadic arithmetic opcode */ | ||
| 259 | +/* 0x00f00000 is an invalid dyadic arithmetic opcode */ | ||
| 260 | + | ||
| 261 | +/* monadic arithmetic opcodes. */ | ||
| 262 | +#define MVF_CODE 0x00008000 | ||
| 263 | +#define MNF_CODE 0x00108000 | ||
| 264 | +#define ABS_CODE 0x00208000 | ||
| 265 | +#define RND_CODE 0x00308000 | ||
| 266 | +#define SQT_CODE 0x00408000 | ||
| 267 | +#define LOG_CODE 0x00508000 | ||
| 268 | +#define LGN_CODE 0x00608000 | ||
| 269 | +#define EXP_CODE 0x00708000 | ||
| 270 | +#define SIN_CODE 0x00808000 | ||
| 271 | +#define COS_CODE 0x00908000 | ||
| 272 | +#define TAN_CODE 0x00a08000 | ||
| 273 | +#define ASN_CODE 0x00b08000 | ||
| 274 | +#define ACS_CODE 0x00c08000 | ||
| 275 | +#define ATN_CODE 0x00d08000 | ||
| 276 | +#define URD_CODE 0x00e08000 | ||
| 277 | +#define NRM_CODE 0x00f08000 | ||
| 278 | + | ||
| 279 | +/* | ||
| 280 | +=== | ||
| 281 | +=== Definitions for register transfer and comparison instructions | ||
| 282 | +=== | ||
| 283 | +*/ | ||
| 284 | + | ||
| 285 | +#define MASK_CPRT 0x0e000010 /* register transfer opcode */ | ||
| 286 | +#define MASK_CPRT_CODE 0x00f00000 | ||
| 287 | +#define FLT_CODE 0x00000000 | ||
| 288 | +#define FIX_CODE 0x00100000 | ||
| 289 | +#define WFS_CODE 0x00200000 | ||
| 290 | +#define RFS_CODE 0x00300000 | ||
| 291 | +#define WFC_CODE 0x00400000 | ||
| 292 | +#define RFC_CODE 0x00500000 | ||
| 293 | +#define CMF_CODE 0x00900000 | ||
| 294 | +#define CNF_CODE 0x00b00000 | ||
| 295 | +#define CMFE_CODE 0x00d00000 | ||
| 296 | +#define CNFE_CODE 0x00f00000 | ||
| 297 | + | ||
| 298 | +/* | ||
| 299 | +=== | ||
| 300 | +=== Common definitions | ||
| 301 | +=== | ||
| 302 | +*/ | ||
| 303 | + | ||
| 304 | +/* register masks */ | ||
| 305 | +#define MASK_Rd 0x0000f000 | ||
| 306 | +#define MASK_Rn 0x000f0000 | ||
| 307 | +#define MASK_Fd 0x00007000 | ||
| 308 | +#define MASK_Fm 0x00000007 | ||
| 309 | +#define MASK_Fn 0x00070000 | ||
| 310 | + | ||
| 311 | +/* condition code masks */ | ||
| 312 | +#define CC_MASK 0xf0000000 | ||
| 313 | +#define CC_NEGATIVE 0x80000000 | ||
| 314 | +#define CC_ZERO 0x40000000 | ||
| 315 | +#define CC_CARRY 0x20000000 | ||
| 316 | +#define CC_OVERFLOW 0x10000000 | ||
| 317 | +#define CC_EQ 0x00000000 | ||
| 318 | +#define CC_NE 0x10000000 | ||
| 319 | +#define CC_CS 0x20000000 | ||
| 320 | +#define CC_HS CC_CS | ||
| 321 | +#define CC_CC 0x30000000 | ||
| 322 | +#define CC_LO CC_CC | ||
| 323 | +#define CC_MI 0x40000000 | ||
| 324 | +#define CC_PL 0x50000000 | ||
| 325 | +#define CC_VS 0x60000000 | ||
| 326 | +#define CC_VC 0x70000000 | ||
| 327 | +#define CC_HI 0x80000000 | ||
| 328 | +#define CC_LS 0x90000000 | ||
| 329 | +#define CC_GE 0xa0000000 | ||
| 330 | +#define CC_LT 0xb0000000 | ||
| 331 | +#define CC_GT 0xc0000000 | ||
| 332 | +#define CC_LE 0xd0000000 | ||
| 333 | +#define CC_AL 0xe0000000 | ||
| 334 | +#define CC_NV 0xf0000000 | ||
| 335 | + | ||
| 336 | +/* rounding masks/values */ | ||
| 337 | +#define MASK_ROUNDING_MODE 0x00000060 | ||
| 338 | +#define ROUND_TO_NEAREST 0x00000000 | ||
| 339 | +#define ROUND_TO_PLUS_INFINITY 0x00000020 | ||
| 340 | +#define ROUND_TO_MINUS_INFINITY 0x00000040 | ||
| 341 | +#define ROUND_TO_ZERO 0x00000060 | ||
| 342 | + | ||
| 343 | +#define MASK_ROUNDING_PRECISION 0x00080080 | ||
| 344 | +#define ROUND_SINGLE 0x00000000 | ||
| 345 | +#define ROUND_DOUBLE 0x00000080 | ||
| 346 | +#define ROUND_EXTENDED 0x00080000 | ||
| 347 | + | ||
| 348 | +/* Get the condition code from the opcode. */ | ||
| 349 | +#define getCondition(opcode) (opcode >> 28) | ||
| 350 | + | ||
| 351 | +/* Get the source register from the opcode. */ | ||
| 352 | +#define getRn(opcode) ((opcode & MASK_Rn) >> 16) | ||
| 353 | + | ||
| 354 | +/* Get the destination floating point register from the opcode. */ | ||
| 355 | +#define getFd(opcode) ((opcode & MASK_Fd) >> 12) | ||
| 356 | + | ||
| 357 | +/* Get the first source floating point register from the opcode. */ | ||
| 358 | +#define getFn(opcode) ((opcode & MASK_Fn) >> 16) | ||
| 359 | + | ||
| 360 | +/* Get the second source floating point register from the opcode. */ | ||
| 361 | +#define getFm(opcode) (opcode & MASK_Fm) | ||
| 362 | + | ||
| 363 | +/* Get the destination register from the opcode. */ | ||
| 364 | +#define getRd(opcode) ((opcode & MASK_Rd) >> 12) | ||
| 365 | + | ||
| 366 | +/* Get the rounding mode from the opcode. */ | ||
| 367 | +#define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) | ||
| 368 | + | ||
| 369 | +static inline const floatx80 getExtendedConstant(const unsigned int nIndex) | ||
| 370 | +{ | ||
| 371 | + extern const floatx80 floatx80Constant[]; | ||
| 372 | + return floatx80Constant[nIndex]; | ||
| 373 | +} | ||
| 374 | + | ||
| 375 | +static inline const float64 getDoubleConstant(const unsigned int nIndex) | ||
| 376 | +{ | ||
| 377 | + extern const float64 float64Constant[]; | ||
| 378 | + return float64Constant[nIndex]; | ||
| 379 | +} | ||
| 380 | + | ||
| 381 | +static inline const float32 getSingleConstant(const unsigned int nIndex) | ||
| 382 | +{ | ||
| 383 | + extern const float32 float32Constant[]; | ||
| 384 | + return float32Constant[nIndex]; | ||
| 385 | +} | ||
| 386 | + | ||
| 387 | +extern unsigned int getRegisterCount(const unsigned int opcode); | ||
| 388 | +extern unsigned int getDestinationSize(const unsigned int opcode); | ||
| 389 | + | ||
| 390 | +#endif |
target-arm/nwfpe/fpsr.h
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.com, 1998-1999 | ||
| 4 | + | ||
| 5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 6 | + | ||
| 7 | + This program is free software; you can redistribute it and/or modify | ||
| 8 | + it under the terms of the GNU General Public License as published by | ||
| 9 | + the Free Software Foundation; either version 2 of the License, or | ||
| 10 | + (at your option) any later version. | ||
| 11 | + | ||
| 12 | + This program is distributed in the hope that it will be useful, | ||
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | + GNU General Public License for more details. | ||
| 16 | + | ||
| 17 | + You should have received a copy of the GNU General Public License | ||
| 18 | + along with this program; if not, write to the Free Software | ||
| 19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | +*/ | ||
| 21 | + | ||
| 22 | +#ifndef __FPSR_H__ | ||
| 23 | +#define __FPSR_H__ | ||
| 24 | + | ||
| 25 | +/* | ||
| 26 | +The FPSR is a 32 bit register consisting of 4 parts, each exactly | ||
| 27 | +one byte. | ||
| 28 | + | ||
| 29 | + SYSTEM ID | ||
| 30 | + EXCEPTION TRAP ENABLE BYTE | ||
| 31 | + SYSTEM CONTROL BYTE | ||
| 32 | + CUMULATIVE EXCEPTION FLAGS BYTE | ||
| 33 | + | ||
| 34 | +The FPCR is a 32 bit register consisting of bit flags. | ||
| 35 | +*/ | ||
| 36 | + | ||
| 37 | +/* SYSTEM ID | ||
| 38 | +------------ | ||
| 39 | +Note: the system id byte is read only */ | ||
| 40 | + | ||
| 41 | +typedef unsigned int FPSR; /* type for floating point status register */ | ||
| 42 | +typedef unsigned int FPCR; /* type for floating point control register */ | ||
| 43 | + | ||
| 44 | +#define MASK_SYSID 0xff000000 | ||
| 45 | +#define BIT_HARDWARE 0x80000000 | ||
| 46 | +#define FP_EMULATOR 0x01000000 /* System ID for emulator */ | ||
| 47 | +#define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */ | ||
| 48 | + | ||
| 49 | +/* EXCEPTION TRAP ENABLE BYTE | ||
| 50 | +----------------------------- */ | ||
| 51 | + | ||
| 52 | +#define MASK_TRAP_ENABLE 0x00ff0000 | ||
| 53 | +#define MASK_TRAP_ENABLE_STRICT 0x001f0000 | ||
| 54 | +#define BIT_IXE 0x00100000 /* inexact exception enable */ | ||
| 55 | +#define BIT_UFE 0x00080000 /* underflow exception enable */ | ||
| 56 | +#define BIT_OFE 0x00040000 /* overflow exception enable */ | ||
| 57 | +#define BIT_DZE 0x00020000 /* divide by zero exception enable */ | ||
| 58 | +#define BIT_IOE 0x00010000 /* invalid operation exception enable */ | ||
| 59 | + | ||
| 60 | +/* SYSTEM CONTROL BYTE | ||
| 61 | +---------------------- */ | ||
| 62 | + | ||
| 63 | +#define MASK_SYSTEM_CONTROL 0x0000ff00 | ||
| 64 | +#define MASK_TRAP_STRICT 0x00001f00 | ||
| 65 | + | ||
| 66 | +#define BIT_AC 0x00001000 /* use alternative C-flag definition | ||
| 67 | + for compares */ | ||
| 68 | +#define BIT_EP 0x00000800 /* use expanded packed decimal format */ | ||
| 69 | +#define BIT_SO 0x00000400 /* select synchronous operation of FPA */ | ||
| 70 | +#define BIT_NE 0x00000200 /* NaN exception bit */ | ||
| 71 | +#define BIT_ND 0x00000100 /* no denormalized numbers bit */ | ||
| 72 | + | ||
| 73 | +/* CUMULATIVE EXCEPTION FLAGS BYTE | ||
| 74 | +---------------------------------- */ | ||
| 75 | + | ||
| 76 | +#define MASK_EXCEPTION_FLAGS 0x000000ff | ||
| 77 | +#define MASK_EXCEPTION_FLAGS_STRICT 0x0000001f | ||
| 78 | + | ||
| 79 | +#define BIT_IXC 0x00000010 /* inexact exception flag */ | ||
| 80 | +#define BIT_UFC 0x00000008 /* underflow exception flag */ | ||
| 81 | +#define BIT_OFC 0x00000004 /* overfloat exception flag */ | ||
| 82 | +#define BIT_DZC 0x00000002 /* divide by zero exception flag */ | ||
| 83 | +#define BIT_IOC 0x00000001 /* invalid operation exception flag */ | ||
| 84 | + | ||
| 85 | +/* Floating Point Control Register | ||
| 86 | +----------------------------------*/ | ||
| 87 | + | ||
| 88 | +#define BIT_RU 0x80000000 /* rounded up bit */ | ||
| 89 | +#define BIT_IE 0x10000000 /* inexact bit */ | ||
| 90 | +#define BIT_MO 0x08000000 /* mantissa overflow bit */ | ||
| 91 | +#define BIT_EO 0x04000000 /* exponent overflow bit */ | ||
| 92 | +#define BIT_SB 0x00000800 /* store bounce */ | ||
| 93 | +#define BIT_AB 0x00000400 /* arithmetic bounce */ | ||
| 94 | +#define BIT_RE 0x00000200 /* rounding exception */ | ||
| 95 | +#define BIT_DA 0x00000100 /* disable FPA */ | ||
| 96 | + | ||
| 97 | +#define MASK_OP 0x00f08010 /* AU operation code */ | ||
| 98 | +#define MASK_PR 0x00080080 /* AU precision */ | ||
| 99 | +#define MASK_S1 0x00070000 /* AU source register 1 */ | ||
| 100 | +#define MASK_S2 0x00000007 /* AU source register 2 */ | ||
| 101 | +#define MASK_DS 0x00007000 /* AU destination register */ | ||
| 102 | +#define MASK_RM 0x00000060 /* AU rounding mode */ | ||
| 103 | +#define MASK_ALU 0x9cfff2ff /* only ALU can write these bits */ | ||
| 104 | +#define MASK_RESET 0x00000d00 /* bits set on reset, all others cleared */ | ||
| 105 | +#define MASK_WFC MASK_RESET | ||
| 106 | +#define MASK_RFC ~MASK_RESET | ||
| 107 | + | ||
| 108 | +#endif |
target-arm/nwfpe/milieu.h
0 → 100644
| 1 | + | ||
| 2 | +/* | ||
| 3 | +=============================================================================== | ||
| 4 | + | ||
| 5 | +This C header file is part of the SoftFloat IEC/IEEE Floating-point | ||
| 6 | +Arithmetic Package, Release 2. | ||
| 7 | + | ||
| 8 | +Written by John R. Hauser. This work was made possible in part by the | ||
| 9 | +International Computer Science Institute, located at Suite 600, 1947 Center | ||
| 10 | +Street, Berkeley, California 94704. Funding was partially provided by the | ||
| 11 | +National Science Foundation under grant MIP-9311980. The original version | ||
| 12 | +of this code was written as part of a project to build a fixed-point vector | ||
| 13 | +processor in collaboration with the University of California at Berkeley, | ||
| 14 | +overseen by Profs. Nelson Morgan and John Wawrzynek. More information | ||
| 15 | +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | ||
| 16 | +arithmetic/softfloat.html'. | ||
| 17 | + | ||
| 18 | +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | ||
| 19 | +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | ||
| 20 | +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | ||
| 21 | +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | ||
| 22 | +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | ||
| 23 | + | ||
| 24 | +Derivative works are acceptable, even for commercial purposes, so long as | ||
| 25 | +(1) they include prominent notice that the work is derivative, and (2) they | ||
| 26 | +include prominent notice akin to these three paragraphs for those parts of | ||
| 27 | +this code that are retained. | ||
| 28 | + | ||
| 29 | +=============================================================================== | ||
| 30 | +*/ | ||
| 31 | + | ||
| 32 | +/* | ||
| 33 | +------------------------------------------------------------------------------- | ||
| 34 | +Include common integer types and flags. | ||
| 35 | +------------------------------------------------------------------------------- | ||
| 36 | +*/ | ||
| 37 | +#include "ARM-gcc.h" | ||
| 38 | + | ||
| 39 | +/* | ||
| 40 | +------------------------------------------------------------------------------- | ||
| 41 | +Symbolic Boolean literals. | ||
| 42 | +------------------------------------------------------------------------------- | ||
| 43 | +*/ | ||
| 44 | +enum { | ||
| 45 | + FALSE = 0, | ||
| 46 | + TRUE = 1 | ||
| 47 | +}; | ||
| 48 | + |
target-arm/nwfpe/single_cpdo.c
0 → 100644
| 1 | +/* | ||
| 2 | + NetWinder Floating Point Emulator | ||
| 3 | + (c) Rebel.COM, 1998,1999 | ||
| 4 | + | ||
| 5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
| 6 | + | ||
| 7 | + This program is free software; you can redistribute it and/or modify | ||
| 8 | + it under the terms of the GNU General Public License as published by | ||
| 9 | + the Free Software Foundation; either version 2 of the License, or | ||
| 10 | + (at your option) any later version. | ||
| 11 | + | ||
| 12 | + This program is distributed in the hope that it will be useful, | ||
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | + GNU General Public License for more details. | ||
| 16 | + | ||
| 17 | + You should have received a copy of the GNU General Public License | ||
| 18 | + along with this program; if not, write to the Free Software | ||
| 19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | +*/ | ||
| 21 | + | ||
| 22 | +#include "fpa11.h" | ||
| 23 | +#include "softfloat.h" | ||
| 24 | +#include "fpopcode.h" | ||
| 25 | + | ||
| 26 | +float32 float32_exp(float32 Fm); | ||
| 27 | +float32 float32_ln(float32 Fm); | ||
| 28 | +float32 float32_sin(float32 rFm); | ||
| 29 | +float32 float32_cos(float32 rFm); | ||
| 30 | +float32 float32_arcsin(float32 rFm); | ||
| 31 | +float32 float32_arctan(float32 rFm); | ||
| 32 | +float32 float32_log(float32 rFm); | ||
| 33 | +float32 float32_tan(float32 rFm); | ||
| 34 | +float32 float32_arccos(float32 rFm); | ||
| 35 | +float32 float32_pow(float32 rFn,float32 rFm); | ||
| 36 | +float32 float32_pol(float32 rFn,float32 rFm); | ||
| 37 | + | ||
| 38 | +unsigned int SingleCPDO(const unsigned int opcode) | ||
| 39 | +{ | ||
| 40 | + FPA11 *fpa11 = GET_FPA11(); | ||
| 41 | + float32 rFm, rFn; | ||
| 42 | + unsigned int Fd, Fm, Fn, nRc = 1; | ||
| 43 | + | ||
| 44 | + Fm = getFm(opcode); | ||
| 45 | + if (CONSTANT_FM(opcode)) | ||
| 46 | + { | ||
| 47 | + rFm = getSingleConstant(Fm); | ||
| 48 | + } | ||
| 49 | + else | ||
| 50 | + { | ||
| 51 | + switch (fpa11->fType[Fm]) | ||
| 52 | + { | ||
| 53 | + case typeSingle: | ||
| 54 | + rFm = fpa11->fpreg[Fm].fSingle; | ||
| 55 | + break; | ||
| 56 | + | ||
| 57 | + default: return 0; | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + if (!MONADIC_INSTRUCTION(opcode)) | ||
| 62 | + { | ||
| 63 | + Fn = getFn(opcode); | ||
| 64 | + switch (fpa11->fType[Fn]) | ||
| 65 | + { | ||
| 66 | + case typeSingle: | ||
| 67 | + rFn = fpa11->fpreg[Fn].fSingle; | ||
| 68 | + break; | ||
| 69 | + | ||
| 70 | + default: return 0; | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + Fd = getFd(opcode); | ||
| 75 | + switch (opcode & MASK_ARITHMETIC_OPCODE) | ||
| 76 | + { | ||
| 77 | + /* dyadic opcodes */ | ||
| 78 | + case ADF_CODE: | ||
| 79 | + fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm); | ||
| 80 | + break; | ||
| 81 | + | ||
| 82 | + case MUF_CODE: | ||
| 83 | + case FML_CODE: | ||
| 84 | + fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm); | ||
| 85 | + break; | ||
| 86 | + | ||
| 87 | + case SUF_CODE: | ||
| 88 | + fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm); | ||
| 89 | + break; | ||
| 90 | + | ||
| 91 | + case RSF_CODE: | ||
| 92 | + fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn); | ||
| 93 | + break; | ||
| 94 | + | ||
| 95 | + case DVF_CODE: | ||
| 96 | + case FDV_CODE: | ||
| 97 | + fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm); | ||
| 98 | + break; | ||
| 99 | + | ||
| 100 | + case RDF_CODE: | ||
| 101 | + case FRD_CODE: | ||
| 102 | + fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn); | ||
| 103 | + break; | ||
| 104 | + | ||
| 105 | +#if 0 | ||
| 106 | + case POW_CODE: | ||
| 107 | + fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm); | ||
| 108 | + break; | ||
| 109 | + | ||
| 110 | + case RPW_CODE: | ||
| 111 | + fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn); | ||
| 112 | + break; | ||
| 113 | +#endif | ||
| 114 | + | ||
| 115 | + case RMF_CODE: | ||
| 116 | + fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm); | ||
| 117 | + break; | ||
| 118 | + | ||
| 119 | +#if 0 | ||
| 120 | + case POL_CODE: | ||
| 121 | + fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm); | ||
| 122 | + break; | ||
| 123 | +#endif | ||
| 124 | + | ||
| 125 | + /* monadic opcodes */ | ||
| 126 | + case MVF_CODE: | ||
| 127 | + fpa11->fpreg[Fd].fSingle = rFm; | ||
| 128 | + break; | ||
| 129 | + | ||
| 130 | + case MNF_CODE: | ||
| 131 | + rFm ^= 0x80000000; | ||
| 132 | + fpa11->fpreg[Fd].fSingle = rFm; | ||
| 133 | + break; | ||
| 134 | + | ||
| 135 | + case ABS_CODE: | ||
| 136 | + rFm &= 0x7fffffff; | ||
| 137 | + fpa11->fpreg[Fd].fSingle = rFm; | ||
| 138 | + break; | ||
| 139 | + | ||
| 140 | + case RND_CODE: | ||
| 141 | + case URD_CODE: | ||
| 142 | + fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm); | ||
| 143 | + break; | ||
| 144 | + | ||
| 145 | + case SQT_CODE: | ||
| 146 | + fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm); | ||
| 147 | + break; | ||
| 148 | + | ||
| 149 | +#if 0 | ||
| 150 | + case LOG_CODE: | ||
| 151 | + fpa11->fpreg[Fd].fSingle = float32_log(rFm); | ||
| 152 | + break; | ||
| 153 | + | ||
| 154 | + case LGN_CODE: | ||
| 155 | + fpa11->fpreg[Fd].fSingle = float32_ln(rFm); | ||
| 156 | + break; | ||
| 157 | + | ||
| 158 | + case EXP_CODE: | ||
| 159 | + fpa11->fpreg[Fd].fSingle = float32_exp(rFm); | ||
| 160 | + break; | ||
| 161 | + | ||
| 162 | + case SIN_CODE: | ||
| 163 | + fpa11->fpreg[Fd].fSingle = float32_sin(rFm); | ||
| 164 | + break; | ||
| 165 | + | ||
| 166 | + case COS_CODE: | ||
| 167 | + fpa11->fpreg[Fd].fSingle = float32_cos(rFm); | ||
| 168 | + break; | ||
| 169 | + | ||
| 170 | + case TAN_CODE: | ||
| 171 | + fpa11->fpreg[Fd].fSingle = float32_tan(rFm); | ||
| 172 | + break; | ||
| 173 | + | ||
| 174 | + case ASN_CODE: | ||
| 175 | + fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm); | ||
| 176 | + break; | ||
| 177 | + | ||
| 178 | + case ACS_CODE: | ||
| 179 | + fpa11->fpreg[Fd].fSingle = float32_arccos(rFm); | ||
| 180 | + break; | ||
| 181 | + | ||
| 182 | + case ATN_CODE: | ||
| 183 | + fpa11->fpreg[Fd].fSingle = float32_arctan(rFm); | ||
| 184 | + break; | ||
| 185 | +#endif | ||
| 186 | + | ||
| 187 | + case NRM_CODE: | ||
| 188 | + break; | ||
| 189 | + | ||
| 190 | + default: | ||
| 191 | + { | ||
| 192 | + nRc = 0; | ||
| 193 | + } | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + if (0 != nRc) fpa11->fType[Fd] = typeSingle; | ||
| 197 | + return nRc; | ||
| 198 | +} | ||
| 199 | + | ||
| 200 | +#if 0 | ||
| 201 | +float32 float32_exp(float32 Fm) | ||
| 202 | +{ | ||
| 203 | +//series | ||
| 204 | +} | ||
| 205 | + | ||
| 206 | +float32 float32_ln(float32 Fm) | ||
| 207 | +{ | ||
| 208 | +//series | ||
| 209 | +} | ||
| 210 | + | ||
| 211 | +float32 float32_sin(float32 rFm) | ||
| 212 | +{ | ||
| 213 | +//series | ||
| 214 | +} | ||
| 215 | + | ||
| 216 | +float32 float32_cos(float32 rFm) | ||
| 217 | +{ | ||
| 218 | +//series | ||
| 219 | +} | ||
| 220 | + | ||
| 221 | +float32 float32_arcsin(float32 rFm) | ||
| 222 | +{ | ||
| 223 | +//series | ||
| 224 | +} | ||
| 225 | + | ||
| 226 | +float32 float32_arctan(float32 rFm) | ||
| 227 | +{ | ||
| 228 | + //series | ||
| 229 | +} | ||
| 230 | + | ||
| 231 | +float32 float32_arccos(float32 rFm) | ||
| 232 | +{ | ||
| 233 | + //return float32_sub(halfPi,float32_arcsin(rFm)); | ||
| 234 | +} | ||
| 235 | + | ||
| 236 | +float32 float32_log(float32 rFm) | ||
| 237 | +{ | ||
| 238 | + return float32_div(float32_ln(rFm),getSingleConstant(7)); | ||
| 239 | +} | ||
| 240 | + | ||
| 241 | +float32 float32_tan(float32 rFm) | ||
| 242 | +{ | ||
| 243 | + return float32_div(float32_sin(rFm),float32_cos(rFm)); | ||
| 244 | +} | ||
| 245 | + | ||
| 246 | +float32 float32_pow(float32 rFn,float32 rFm) | ||
| 247 | +{ | ||
| 248 | + return float32_exp(float32_mul(rFm,float32_ln(rFn))); | ||
| 249 | +} | ||
| 250 | + | ||
| 251 | +float32 float32_pol(float32 rFn,float32 rFm) | ||
| 252 | +{ | ||
| 253 | + return float32_arctan(float32_div(rFn,rFm)); | ||
| 254 | +} | ||
| 255 | +#endif |
target-arm/nwfpe/softfloat-macros
0 → 100644
| 1 | + | ||
| 2 | +/* | ||
| 3 | +=============================================================================== | ||
| 4 | + | ||
| 5 | +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point | ||
| 6 | +Arithmetic Package, Release 2. | ||
| 7 | + | ||
| 8 | +Written by John R. Hauser. This work was made possible in part by the | ||
| 9 | +International Computer Science Institute, located at Suite 600, 1947 Center | ||
| 10 | +Street, Berkeley, California 94704. Funding was partially provided by the | ||
| 11 | +National Science Foundation under grant MIP-9311980. The original version | ||
| 12 | +of this code was written as part of a project to build a fixed-point vector | ||
| 13 | +processor in collaboration with the University of California at Berkeley, | ||
| 14 | +overseen by Profs. Nelson Morgan and John Wawrzynek. More information | ||
| 15 | +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | ||
| 16 | +arithmetic/softfloat.html'. | ||
| 17 | + | ||
| 18 | +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | ||
| 19 | +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | ||
| 20 | +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | ||
| 21 | +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | ||
| 22 | +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | ||
| 23 | + | ||
| 24 | +Derivative works are acceptable, even for commercial purposes, so long as | ||
| 25 | +(1) they include prominent notice that the work is derivative, and (2) they | ||
| 26 | +include prominent notice akin to these three paragraphs for those parts of | ||
| 27 | +this code that are retained. | ||
| 28 | + | ||
| 29 | +=============================================================================== | ||
| 30 | +*/ | ||
| 31 | + | ||
| 32 | +/* | ||
| 33 | +------------------------------------------------------------------------------- | ||
| 34 | +Shifts `a' right by the number of bits given in `count'. If any nonzero | ||
| 35 | +bits are shifted off, they are ``jammed'' into the least significant bit of | ||
| 36 | +the result by setting the least significant bit to 1. The value of `count' | ||
| 37 | +can be arbitrarily large; in particular, if `count' is greater than 32, the | ||
| 38 | +result will be either 0 or 1, depending on whether `a' is zero or nonzero. | ||
| 39 | +The result is stored in the location pointed to by `zPtr'. | ||
| 40 | +------------------------------------------------------------------------------- | ||
| 41 | +*/ | ||
| 42 | +INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) | ||
| 43 | +{ | ||
| 44 | + bits32 z; | ||
| 45 | + if ( count == 0 ) { | ||
| 46 | + z = a; | ||
| 47 | + } | ||
| 48 | + else if ( count < 32 ) { | ||
| 49 | + z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); | ||
| 50 | + } | ||
| 51 | + else { | ||
| 52 | + z = ( a != 0 ); | ||
| 53 | + } | ||
| 54 | + *zPtr = z; | ||
| 55 | +} | ||
| 56 | + | ||
| 57 | +/* | ||
| 58 | +------------------------------------------------------------------------------- | ||
| 59 | +Shifts `a' right by the number of bits given in `count'. If any nonzero | ||
| 60 | +bits are shifted off, they are ``jammed'' into the least significant bit of | ||
| 61 | +the result by setting the least significant bit to 1. The value of `count' | ||
| 62 | +can be arbitrarily large; in particular, if `count' is greater than 64, the | ||
| 63 | +result will be either 0 or 1, depending on whether `a' is zero or nonzero. | ||
| 64 | +The result is stored in the location pointed to by `zPtr'. | ||
| 65 | +------------------------------------------------------------------------------- | ||
| 66 | +*/ | ||
| 67 | +INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) | ||
| 68 | +{ | ||
| 69 | + bits64 z; | ||
| 70 | + | ||
| 71 | +// __asm__("@shift64RightJamming -- start"); | ||
| 72 | + if ( count == 0 ) { | ||
| 73 | + z = a; | ||
| 74 | + } | ||
| 75 | + else if ( count < 64 ) { | ||
| 76 | + z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); | ||
| 77 | + } | ||
| 78 | + else { | ||
| 79 | + z = ( a != 0 ); | ||
| 80 | + } | ||
| 81 | +// __asm__("@shift64RightJamming -- end"); | ||
| 82 | + *zPtr = z; | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +/* | ||
| 86 | +------------------------------------------------------------------------------- | ||
| 87 | +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 | ||
| 88 | +_plus_ the number of bits given in `count'. The shifted result is at most | ||
| 89 | +64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The | ||
| 90 | +bits shifted off form a second 64-bit result as follows: The _last_ bit | ||
| 91 | +shifted off is the most-significant bit of the extra result, and the other | ||
| 92 | +63 bits of the extra result are all zero if and only if _all_but_the_last_ | ||
| 93 | +bits shifted off were all zero. This extra result is stored in the location | ||
| 94 | +pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. | ||
| 95 | + (This routine makes more sense if `a0' and `a1' are considered to form a | ||
| 96 | +fixed-point value with binary point between `a0' and `a1'. This fixed-point | ||
| 97 | +value is shifted right by the number of bits given in `count', and the | ||
| 98 | +integer part of the result is returned at the location pointed to by | ||
| 99 | +`z0Ptr'. The fractional part of the result may be slightly corrupted as | ||
| 100 | +described above, and is returned at the location pointed to by `z1Ptr'.) | ||
| 101 | +------------------------------------------------------------------------------- | ||
| 102 | +*/ | ||
| 103 | +INLINE void | ||
| 104 | + shift64ExtraRightJamming( | ||
| 105 | + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) | ||
| 106 | +{ | ||
| 107 | + bits64 z0, z1; | ||
| 108 | + int8 negCount = ( - count ) & 63; | ||
| 109 | + | ||
| 110 | + if ( count == 0 ) { | ||
| 111 | + z1 = a1; | ||
| 112 | + z0 = a0; | ||
| 113 | + } | ||
| 114 | + else if ( count < 64 ) { | ||
| 115 | + z1 = ( a0<<negCount ) | ( a1 != 0 ); | ||
| 116 | + z0 = a0>>count; | ||
| 117 | + } | ||
| 118 | + else { | ||
| 119 | + if ( count == 64 ) { | ||
| 120 | + z1 = a0 | ( a1 != 0 ); | ||
| 121 | + } | ||
| 122 | + else { | ||
| 123 | + z1 = ( ( a0 | a1 ) != 0 ); | ||
| 124 | + } | ||
| 125 | + z0 = 0; | ||
| 126 | + } | ||
| 127 | + *z1Ptr = z1; | ||
| 128 | + *z0Ptr = z0; | ||
| 129 | + | ||
| 130 | +} | ||
| 131 | + | ||
| 132 | +/* | ||
| 133 | +------------------------------------------------------------------------------- | ||
| 134 | +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the | ||
| 135 | +number of bits given in `count'. Any bits shifted off are lost. The value | ||
| 136 | +of `count' can be arbitrarily large; in particular, if `count' is greater | ||
| 137 | +than 128, the result will be 0. The result is broken into two 64-bit pieces | ||
| 138 | +which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. | ||
| 139 | +------------------------------------------------------------------------------- | ||
| 140 | +*/ | ||
| 141 | +INLINE void | ||
| 142 | + shift128Right( | ||
| 143 | + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) | ||
| 144 | +{ | ||
| 145 | + bits64 z0, z1; | ||
| 146 | + int8 negCount = ( - count ) & 63; | ||
| 147 | + | ||
| 148 | + if ( count == 0 ) { | ||
| 149 | + z1 = a1; | ||
| 150 | + z0 = a0; | ||
| 151 | + } | ||
| 152 | + else if ( count < 64 ) { | ||
| 153 | + z1 = ( a0<<negCount ) | ( a1>>count ); | ||
| 154 | + z0 = a0>>count; | ||
| 155 | + } | ||
| 156 | + else { | ||
| 157 | + z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; | ||
| 158 | + z0 = 0; | ||
| 159 | + } | ||
| 160 | + *z1Ptr = z1; | ||
| 161 | + *z0Ptr = z0; | ||
| 162 | + | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +/* | ||
| 166 | +------------------------------------------------------------------------------- | ||
| 167 | +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the | ||
| 168 | +number of bits given in `count'. If any nonzero bits are shifted off, they | ||
| 169 | +are ``jammed'' into the least significant bit of the result by setting the | ||
| 170 | +least significant bit to 1. The value of `count' can be arbitrarily large; | ||
| 171 | +in particular, if `count' is greater than 128, the result will be either 0 | ||
| 172 | +or 1, depending on whether the concatenation of `a0' and `a1' is zero or | ||
| 173 | +nonzero. The result is broken into two 64-bit pieces which are stored at | ||
| 174 | +the locations pointed to by `z0Ptr' and `z1Ptr'. | ||
| 175 | +------------------------------------------------------------------------------- | ||
| 176 | +*/ | ||
| 177 | +INLINE void | ||
| 178 | + shift128RightJamming( | ||
| 179 | + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) | ||
| 180 | +{ | ||
| 181 | + bits64 z0, z1; | ||
| 182 | + int8 negCount = ( - count ) & 63; | ||
| 183 | + | ||
| 184 | + if ( count == 0 ) { | ||
| 185 | + z1 = a1; | ||
| 186 | + z0 = a0; | ||
| 187 | + } | ||
| 188 | + else if ( count < 64 ) { | ||
| 189 | + z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 ); | ||
| 190 | + z0 = a0>>count; | ||
| 191 | + } | ||
| 192 | + else { | ||
| 193 | + if ( count == 64 ) { | ||
| 194 | + z1 = a0 | ( a1 != 0 ); | ||
| 195 | + } | ||
| 196 | + else if ( count < 128 ) { | ||
| 197 | + z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 ); | ||
| 198 | + } | ||
| 199 | + else { | ||
| 200 | + z1 = ( ( a0 | a1 ) != 0 ); | ||
| 201 | + } | ||
| 202 | + z0 = 0; | ||
| 203 | + } | ||
| 204 | + *z1Ptr = z1; | ||
| 205 | + *z0Ptr = z0; | ||
| 206 | + | ||
| 207 | +} | ||
| 208 | + | ||
| 209 | +/* | ||
| 210 | +------------------------------------------------------------------------------- | ||
| 211 | +Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right | ||
| 212 | +by 64 _plus_ the number of bits given in `count'. The shifted result is | ||
| 213 | +at most 128 nonzero bits; these are broken into two 64-bit pieces which are | ||
| 214 | +stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted | ||
| 215 | +off form a third 64-bit result as follows: The _last_ bit shifted off is | ||
| 216 | +the most-significant bit of the extra result, and the other 63 bits of the | ||
| 217 | +extra result are all zero if and only if _all_but_the_last_ bits shifted off | ||
| 218 | +were all zero. This extra result is stored in the location pointed to by | ||
| 219 | +`z2Ptr'. The value of `count' can be arbitrarily large. | ||
| 220 | + (This routine makes more sense if `a0', `a1', and `a2' are considered | ||
| 221 | +to form a fixed-point value with binary point between `a1' and `a2'. This | ||
| 222 | +fixed-point value is shifted right by the number of bits given in `count', | ||
| 223 | +and the integer part of the result is returned at the locations pointed to | ||
| 224 | +by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly | ||
| 225 | +corrupted as described above, and is returned at the location pointed to by | ||
| 226 | +`z2Ptr'.) | ||
| 227 | +------------------------------------------------------------------------------- | ||
| 228 | +*/ | ||
| 229 | +INLINE void | ||
| 230 | + shift128ExtraRightJamming( | ||
| 231 | + bits64 a0, | ||
| 232 | + bits64 a1, | ||
| 233 | + bits64 a2, | ||
| 234 | + int16 count, | ||
| 235 | + bits64 *z0Ptr, | ||
| 236 | + bits64 *z1Ptr, | ||
| 237 | + bits64 *z2Ptr | ||
| 238 | + ) | ||
| 239 | +{ | ||
| 240 | + bits64 z0, z1, z2; | ||
| 241 | + int8 negCount = ( - count ) & 63; | ||
| 242 | + | ||
| 243 | + if ( count == 0 ) { | ||
| 244 | + z2 = a2; | ||
| 245 | + z1 = a1; | ||
| 246 | + z0 = a0; | ||
| 247 | + } | ||
| 248 | + else { | ||
| 249 | + if ( count < 64 ) { | ||
| 250 | + z2 = a1<<negCount; | ||
| 251 | + z1 = ( a0<<negCount ) | ( a1>>count ); | ||
| 252 | + z0 = a0>>count; | ||
| 253 | + } | ||
| 254 | + else { | ||
| 255 | + if ( count == 64 ) { | ||
| 256 | + z2 = a1; | ||
| 257 | + z1 = a0; | ||
| 258 | + } | ||
| 259 | + else { | ||
| 260 | + a2 |= a1; | ||
| 261 | + if ( count < 128 ) { | ||
| 262 | + z2 = a0<<negCount; | ||
| 263 | + z1 = a0>>( count & 63 ); | ||
| 264 | + } | ||
| 265 | + else { | ||
| 266 | + z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); | ||
| 267 | + z1 = 0; | ||
| 268 | + } | ||
| 269 | + } | ||
| 270 | + z0 = 0; | ||
| 271 | + } | ||
| 272 | + z2 |= ( a2 != 0 ); | ||
| 273 | + } | ||
| 274 | + *z2Ptr = z2; | ||
| 275 | + *z1Ptr = z1; | ||
| 276 | + *z0Ptr = z0; | ||
| 277 | + | ||
| 278 | +} | ||
| 279 | + | ||
| 280 | +/* | ||
| 281 | +------------------------------------------------------------------------------- | ||
| 282 | +Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the | ||
| 283 | +number of bits given in `count'. Any bits shifted off are lost. The value | ||
| 284 | +of `count' must be less than 64. The result is broken into two 64-bit | ||
| 285 | +pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. | ||
| 286 | +------------------------------------------------------------------------------- | ||
| 287 | +*/ | ||
| 288 | +INLINE void | ||
| 289 | + shortShift128Left( | ||
| 290 | + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) | ||
| 291 | +{ | ||
| 292 | + | ||
| 293 | + *z1Ptr = a1<<count; | ||
| 294 | + *z0Ptr = | ||
| 295 | + ( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) ); | ||
| 296 | + | ||
| 297 | +} | ||
| 298 | + | ||
| 299 | +/* | ||
| 300 | +------------------------------------------------------------------------------- | ||
| 301 | +Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left | ||
| 302 | +by the number of bits given in `count'. Any bits shifted off are lost. | ||
| 303 | +The value of `count' must be less than 64. The result is broken into three | ||
| 304 | +64-bit pieces which are stored at the locations pointed to by `z0Ptr', | ||
| 305 | +`z1Ptr', and `z2Ptr'. | ||
| 306 | +------------------------------------------------------------------------------- | ||
| 307 | +*/ | ||
| 308 | +INLINE void | ||
| 309 | + shortShift192Left( | ||
| 310 | + bits64 a0, | ||
| 311 | + bits64 a1, | ||
| 312 | + bits64 a2, | ||
| 313 | + int16 count, | ||
| 314 | + bits64 *z0Ptr, | ||
| 315 | + bits64 *z1Ptr, | ||
| 316 | + bits64 *z2Ptr | ||
| 317 | + ) | ||
| 318 | +{ | ||
| 319 | + bits64 z0, z1, z2; | ||
| 320 | + int8 negCount; | ||
| 321 | + | ||
| 322 | + z2 = a2<<count; | ||
| 323 | + z1 = a1<<count; | ||
| 324 | + z0 = a0<<count; | ||
| 325 | + if ( 0 < count ) { | ||
| 326 | + negCount = ( ( - count ) & 63 ); | ||
| 327 | + z1 |= a2>>negCount; | ||
| 328 | + z0 |= a1>>negCount; | ||
| 329 | + } | ||
| 330 | + *z2Ptr = z2; | ||
| 331 | + *z1Ptr = z1; | ||
| 332 | + *z0Ptr = z0; | ||
| 333 | + | ||
| 334 | +} | ||
| 335 | + | ||
| 336 | +/* | ||
| 337 | +------------------------------------------------------------------------------- | ||
| 338 | +Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit | ||
| 339 | +value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so | ||
| 340 | +any carry out is lost. The result is broken into two 64-bit pieces which | ||
| 341 | +are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. | ||
| 342 | +------------------------------------------------------------------------------- | ||
| 343 | +*/ | ||
| 344 | +INLINE void | ||
| 345 | + add128( | ||
| 346 | + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) | ||
| 347 | +{ | ||
| 348 | + bits64 z1; | ||
| 349 | + | ||
| 350 | + z1 = a1 + b1; | ||
| 351 | + *z1Ptr = z1; | ||
| 352 | + *z0Ptr = a0 + b0 + ( z1 < a1 ); | ||
| 353 | + | ||
| 354 | +} | ||
| 355 | + | ||
| 356 | +/* | ||
| 357 | +------------------------------------------------------------------------------- | ||
| 358 | +Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the | ||
| 359 | +192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is | ||
| 360 | +modulo 2^192, so any carry out is lost. The result is broken into three | ||
| 361 | +64-bit pieces which are stored at the locations pointed to by `z0Ptr', | ||
| 362 | +`z1Ptr', and `z2Ptr'. | ||
| 363 | +------------------------------------------------------------------------------- | ||
| 364 | +*/ | ||
| 365 | +INLINE void | ||
| 366 | + add192( | ||
| 367 | + bits64 a0, | ||
| 368 | + bits64 a1, | ||
| 369 | + bits64 a2, | ||
| 370 | + bits64 b0, | ||
| 371 | + bits64 b1, | ||
| 372 | + bits64 b2, | ||
| 373 | + bits64 *z0Ptr, | ||
| 374 | + bits64 *z1Ptr, | ||
| 375 | + bits64 *z2Ptr | ||
| 376 | + ) | ||
| 377 | +{ | ||
| 378 | + bits64 z0, z1, z2; | ||
| 379 | + int8 carry0, carry1; | ||
| 380 | + | ||
| 381 | + z2 = a2 + b2; | ||
| 382 | + carry1 = ( z2 < a2 ); | ||
| 383 | + z1 = a1 + b1; | ||
| 384 | + carry0 = ( z1 < a1 ); | ||
| 385 | + z0 = a0 + b0; | ||
| 386 | + z1 += carry1; | ||
| 387 | + z0 += ( z1 < carry1 ); | ||
| 388 | + z0 += carry0; | ||
| 389 | + *z2Ptr = z2; | ||
| 390 | + *z1Ptr = z1; | ||
| 391 | + *z0Ptr = z0; | ||
| 392 | + | ||
| 393 | +} | ||
| 394 | + | ||
| 395 | +/* | ||
| 396 | +------------------------------------------------------------------------------- | ||
| 397 | +Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the | ||
| 398 | +128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo | ||
| 399 | +2^128, so any borrow out (carry out) is lost. The result is broken into two | ||
| 400 | +64-bit pieces which are stored at the locations pointed to by `z0Ptr' and | ||
| 401 | +`z1Ptr'. | ||
| 402 | +------------------------------------------------------------------------------- | ||
| 403 | +*/ | ||
| 404 | +INLINE void | ||
| 405 | + sub128( | ||
| 406 | + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) | ||
| 407 | +{ | ||
| 408 | + | ||
| 409 | + *z1Ptr = a1 - b1; | ||
| 410 | + *z0Ptr = a0 - b0 - ( a1 < b1 ); | ||
| 411 | + | ||
| 412 | +} | ||
| 413 | + | ||
| 414 | +/* | ||
| 415 | +------------------------------------------------------------------------------- | ||
| 416 | +Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' | ||
| 417 | +from the 192-bit value formed by concatenating `a0', `a1', and `a2'. | ||
| 418 | +Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The | ||
| 419 | +result is broken into three 64-bit pieces which are stored at the locations | ||
| 420 | +pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. | ||
| 421 | +------------------------------------------------------------------------------- | ||
| 422 | +*/ | ||
| 423 | +INLINE void | ||
| 424 | + sub192( | ||
| 425 | + bits64 a0, | ||
| 426 | + bits64 a1, | ||
| 427 | + bits64 a2, | ||
| 428 | + bits64 b0, | ||
| 429 | + bits64 b1, | ||
| 430 | + bits64 b2, | ||
| 431 | + bits64 *z0Ptr, | ||
| 432 | + bits64 *z1Ptr, | ||
| 433 | + bits64 *z2Ptr | ||
| 434 | + ) | ||
| 435 | +{ | ||
| 436 | + bits64 z0, z1, z2; | ||
| 437 | + int8 borrow0, borrow1; | ||
| 438 | + | ||
| 439 | + z2 = a2 - b2; | ||
| 440 | + borrow1 = ( a2 < b2 ); | ||
| 441 | + z1 = a1 - b1; | ||
| 442 | + borrow0 = ( a1 < b1 ); | ||
| 443 | + z0 = a0 - b0; | ||
| 444 | + z0 -= ( z1 < borrow1 ); | ||
| 445 | + z1 -= borrow1; | ||
| 446 | + z0 -= borrow0; | ||
| 447 | + *z2Ptr = z2; | ||
| 448 | + *z1Ptr = z1; | ||
| 449 | + *z0Ptr = z0; | ||
| 450 | + | ||
| 451 | +} | ||
| 452 | + | ||
| 453 | +/* | ||
| 454 | +------------------------------------------------------------------------------- | ||
| 455 | +Multiplies `a' by `b' to obtain a 128-bit product. The product is broken | ||
| 456 | +into two 64-bit pieces which are stored at the locations pointed to by | ||
| 457 | +`z0Ptr' and `z1Ptr'. | ||
| 458 | +------------------------------------------------------------------------------- | ||
| 459 | +*/ | ||
| 460 | +INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) | ||
| 461 | +{ | ||
| 462 | + bits32 aHigh, aLow, bHigh, bLow; | ||
| 463 | + bits64 z0, zMiddleA, zMiddleB, z1; | ||
| 464 | + | ||
| 465 | + aLow = a; | ||
| 466 | + aHigh = a>>32; | ||
| 467 | + bLow = b; | ||
| 468 | + bHigh = b>>32; | ||
| 469 | + z1 = ( (bits64) aLow ) * bLow; | ||
| 470 | + zMiddleA = ( (bits64) aLow ) * bHigh; | ||
| 471 | + zMiddleB = ( (bits64) aHigh ) * bLow; | ||
| 472 | + z0 = ( (bits64) aHigh ) * bHigh; | ||
| 473 | + zMiddleA += zMiddleB; | ||
| 474 | + z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); | ||
| 475 | + zMiddleA <<= 32; | ||
| 476 | + z1 += zMiddleA; | ||
| 477 | + z0 += ( z1 < zMiddleA ); | ||
| 478 | + *z1Ptr = z1; | ||
| 479 | + *z0Ptr = z0; | ||
| 480 | + | ||
| 481 | +} | ||
| 482 | + | ||
| 483 | +/* | ||
| 484 | +------------------------------------------------------------------------------- | ||
| 485 | +Multiplies the 128-bit value formed by concatenating `a0' and `a1' by `b' to | ||
| 486 | +obtain a 192-bit product. The product is broken into three 64-bit pieces | ||
| 487 | +which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and | ||
| 488 | +`z2Ptr'. | ||
| 489 | +------------------------------------------------------------------------------- | ||
| 490 | +*/ | ||
| 491 | +INLINE void | ||
| 492 | + mul128By64To192( | ||
| 493 | + bits64 a0, | ||
| 494 | + bits64 a1, | ||
| 495 | + bits64 b, | ||
| 496 | + bits64 *z0Ptr, | ||
| 497 | + bits64 *z1Ptr, | ||
| 498 | + bits64 *z2Ptr | ||
| 499 | + ) | ||
| 500 | +{ | ||
| 501 | + bits64 z0, z1, z2, more1; | ||
| 502 | + | ||
| 503 | + mul64To128( a1, b, &z1, &z2 ); | ||
| 504 | + mul64To128( a0, b, &z0, &more1 ); | ||
| 505 | + add128( z0, more1, 0, z1, &z0, &z1 ); | ||
| 506 | + *z2Ptr = z2; | ||
| 507 | + *z1Ptr = z1; | ||
| 508 | + *z0Ptr = z0; | ||
| 509 | + | ||
| 510 | +} | ||
| 511 | + | ||
| 512 | +/* | ||
| 513 | +------------------------------------------------------------------------------- | ||
| 514 | +Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the | ||
| 515 | +128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit | ||
| 516 | +product. The product is broken into four 64-bit pieces which are stored at | ||
| 517 | +the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. | ||
| 518 | +------------------------------------------------------------------------------- | ||
| 519 | +*/ | ||
| 520 | +INLINE void | ||
| 521 | + mul128To256( | ||
| 522 | + bits64 a0, | ||
| 523 | + bits64 a1, | ||
| 524 | + bits64 b0, | ||
| 525 | + bits64 b1, | ||
| 526 | + bits64 *z0Ptr, | ||
| 527 | + bits64 *z1Ptr, | ||
| 528 | + bits64 *z2Ptr, | ||
| 529 | + bits64 *z3Ptr | ||
| 530 | + ) | ||
| 531 | +{ | ||
| 532 | + bits64 z0, z1, z2, z3; | ||
| 533 | + bits64 more1, more2; | ||
| 534 | + | ||
| 535 | + mul64To128( a1, b1, &z2, &z3 ); | ||
| 536 | + mul64To128( a1, b0, &z1, &more2 ); | ||
| 537 | + add128( z1, more2, 0, z2, &z1, &z2 ); | ||
| 538 | + mul64To128( a0, b0, &z0, &more1 ); | ||
| 539 | + add128( z0, more1, 0, z1, &z0, &z1 ); | ||
| 540 | + mul64To128( a0, b1, &more1, &more2 ); | ||
| 541 | + add128( more1, more2, 0, z2, &more1, &z2 ); | ||
| 542 | + add128( z0, z1, 0, more1, &z0, &z1 ); | ||
| 543 | + *z3Ptr = z3; | ||
| 544 | + *z2Ptr = z2; | ||
| 545 | + *z1Ptr = z1; | ||
| 546 | + *z0Ptr = z0; | ||
| 547 | + | ||
| 548 | +} | ||
| 549 | + | ||
| 550 | +/* | ||
| 551 | +------------------------------------------------------------------------------- | ||
| 552 | +Returns an approximation to the 64-bit integer quotient obtained by dividing | ||
| 553 | +`b' into the 128-bit value formed by concatenating `a0' and `a1'. The | ||
| 554 | +divisor `b' must be at least 2^63. If q is the exact quotient truncated | ||
| 555 | +toward zero, the approximation returned lies between q and q + 2 inclusive. | ||
| 556 | +If the exact quotient q is larger than 64 bits, the maximum positive 64-bit | ||
| 557 | +unsigned integer is returned. | ||
| 558 | +------------------------------------------------------------------------------- | ||
| 559 | +*/ | ||
| 560 | +static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) | ||
| 561 | +{ | ||
| 562 | + bits64 b0, b1; | ||
| 563 | + bits64 rem0, rem1, term0, term1; | ||
| 564 | + bits64 z; | ||
| 565 | + if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); | ||
| 566 | + b0 = b>>32; | ||
| 567 | + z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; | ||
| 568 | + mul64To128( b, z, &term0, &term1 ); | ||
| 569 | + sub128( a0, a1, term0, term1, &rem0, &rem1 ); | ||
| 570 | + while ( ( (sbits64) rem0 ) < 0 ) { | ||
| 571 | + z -= LIT64( 0x100000000 ); | ||
| 572 | + b1 = b<<32; | ||
| 573 | + add128( rem0, rem1, b0, b1, &rem0, &rem1 ); | ||
| 574 | + } | ||
| 575 | + rem0 = ( rem0<<32 ) | ( rem1>>32 ); | ||
| 576 | + z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; | ||
| 577 | + return z; | ||
| 578 | + | ||
| 579 | +} | ||
| 580 | + | ||
| 581 | +/* | ||
| 582 | +------------------------------------------------------------------------------- | ||
| 583 | +Returns an approximation to the square root of the 32-bit significand given | ||
| 584 | +by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of | ||
| 585 | +`aExp' (the least significant bit) is 1, the integer returned approximates | ||
| 586 | +2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' | ||
| 587 | +is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either | ||
| 588 | +case, the approximation returned lies strictly within +/-2 of the exact | ||
| 589 | +value. | ||
| 590 | +------------------------------------------------------------------------------- | ||
| 591 | +*/ | ||
| 592 | +static bits32 estimateSqrt32( int16 aExp, bits32 a ) | ||
| 593 | +{ | ||
| 594 | + static const bits16 sqrtOddAdjustments[] = { | ||
| 595 | + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, | ||
| 596 | + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 | ||
| 597 | + }; | ||
| 598 | + static const bits16 sqrtEvenAdjustments[] = { | ||
| 599 | + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, | ||
| 600 | + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 | ||
| 601 | + }; | ||
| 602 | + int8 index; | ||
| 603 | + bits32 z; | ||
| 604 | + | ||
| 605 | + index = ( a>>27 ) & 15; | ||
| 606 | + if ( aExp & 1 ) { | ||
| 607 | + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; | ||
| 608 | + z = ( ( a / z )<<14 ) + ( z<<15 ); | ||
| 609 | + a >>= 1; | ||
| 610 | + } | ||
| 611 | + else { | ||
| 612 | + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; | ||
| 613 | + z = a / z + z; | ||
| 614 | + z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); | ||
| 615 | + if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); | ||
| 616 | + } | ||
| 617 | + return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); | ||
| 618 | + | ||
| 619 | +} | ||
| 620 | + | ||
| 621 | +/* | ||
| 622 | +------------------------------------------------------------------------------- | ||
| 623 | +Returns the number of leading 0 bits before the most-significant 1 bit | ||
| 624 | +of `a'. If `a' is zero, 32 is returned. | ||
| 625 | +------------------------------------------------------------------------------- | ||
| 626 | +*/ | ||
| 627 | +static int8 countLeadingZeros32( bits32 a ) | ||
| 628 | +{ | ||
| 629 | + static const int8 countLeadingZerosHigh[] = { | ||
| 630 | + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, | ||
| 631 | + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | ||
| 632 | + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | ||
| 633 | + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | ||
| 634 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 635 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 636 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 637 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 638 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 639 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 640 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 641 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 642 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 643 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 644 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 645 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
| 646 | + }; | ||
| 647 | + int8 shiftCount; | ||
| 648 | + | ||
| 649 | + shiftCount = 0; | ||
| 650 | + if ( a < 0x10000 ) { | ||
| 651 | + shiftCount += 16; | ||
| 652 | + a <<= 16; | ||
| 653 | + } | ||
| 654 | + if ( a < 0x1000000 ) { | ||
| 655 | + shiftCount += 8; | ||
| 656 | + a <<= 8; | ||
| 657 | + } | ||
| 658 | + shiftCount += countLeadingZerosHigh[ a>>24 ]; | ||
| 659 | + return shiftCount; | ||
| 660 | + | ||
| 661 | +} | ||
| 662 | + | ||
| 663 | +/* | ||
| 664 | +------------------------------------------------------------------------------- | ||
| 665 | +Returns the number of leading 0 bits before the most-significant 1 bit | ||
| 666 | +of `a'. If `a' is zero, 64 is returned. | ||
| 667 | +------------------------------------------------------------------------------- | ||
| 668 | +*/ | ||
| 669 | +static int8 countLeadingZeros64( bits64 a ) | ||
| 670 | +{ | ||
| 671 | + int8 shiftCount; | ||
| 672 | + | ||
| 673 | + shiftCount = 0; | ||
| 674 | + if ( a < ( (bits64) 1 )<<32 ) { | ||
| 675 | + shiftCount += 32; | ||
| 676 | + } | ||
| 677 | + else { | ||
| 678 | + a >>= 32; | ||
| 679 | + } | ||
| 680 | + shiftCount += countLeadingZeros32( a ); | ||
| 681 | + return shiftCount; | ||
| 682 | + | ||
| 683 | +} | ||
| 684 | + | ||
| 685 | +/* | ||
| 686 | +------------------------------------------------------------------------------- | ||
| 687 | +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' | ||
| 688 | +is equal to the 128-bit value formed by concatenating `b0' and `b1'. | ||
| 689 | +Otherwise, returns 0. | ||
| 690 | +------------------------------------------------------------------------------- | ||
| 691 | +*/ | ||
| 692 | +INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | ||
| 693 | +{ | ||
| 694 | + | ||
| 695 | + return ( a0 == b0 ) && ( a1 == b1 ); | ||
| 696 | + | ||
| 697 | +} | ||
| 698 | + | ||
| 699 | +/* | ||
| 700 | +------------------------------------------------------------------------------- | ||
| 701 | +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less | ||
| 702 | +than or equal to the 128-bit value formed by concatenating `b0' and `b1'. | ||
| 703 | +Otherwise, returns 0. | ||
| 704 | +------------------------------------------------------------------------------- | ||
| 705 | +*/ | ||
| 706 | +INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | ||
| 707 | +{ | ||
| 708 | + | ||
| 709 | + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); | ||
| 710 | + | ||
| 711 | +} | ||
| 712 | + | ||
| 713 | +/* | ||
| 714 | +------------------------------------------------------------------------------- | ||
| 715 | +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less | ||
| 716 | +than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, | ||
| 717 | +returns 0. | ||
| 718 | +------------------------------------------------------------------------------- | ||
| 719 | +*/ | ||
| 720 | +INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | ||
| 721 | +{ | ||
| 722 | + | ||
| 723 | + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); | ||
| 724 | + | ||
| 725 | +} | ||
| 726 | + | ||
| 727 | +/* | ||
| 728 | +------------------------------------------------------------------------------- | ||
| 729 | +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is | ||
| 730 | +not equal to the 128-bit value formed by concatenating `b0' and `b1'. | ||
| 731 | +Otherwise, returns 0. | ||
| 732 | +------------------------------------------------------------------------------- | ||
| 733 | +*/ | ||
| 734 | +INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | ||
| 735 | +{ | ||
| 736 | + | ||
| 737 | + return ( a0 != b0 ) || ( a1 != b1 ); | ||
| 738 | + | ||
| 739 | +} | ||
| 740 | + |
target-arm/nwfpe/softfloat-specialize
0 → 100644
| 1 | + | ||
| 2 | +/* | ||
| 3 | +=============================================================================== | ||
| 4 | + | ||
| 5 | +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point | ||
| 6 | +Arithmetic Package, Release 2. | ||
| 7 | + | ||
| 8 | +Written by John R. Hauser. This work was made possible in part by the | ||
| 9 | +International Computer Science Institute, located at Suite 600, 1947 Center | ||
| 10 | +Street, Berkeley, California 94704. Funding was partially provided by the | ||
| 11 | +National Science Foundation under grant MIP-9311980. The original version | ||
| 12 | +of this code was written as part of a project to build a fixed-point vector | ||
| 13 | +processor in collaboration with the University of California at Berkeley, | ||
| 14 | +overseen by Profs. Nelson Morgan and John Wawrzynek. More information | ||
| 15 | +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | ||
| 16 | +arithmetic/softfloat.html'. | ||
| 17 | + | ||
| 18 | +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | ||
| 19 | +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | ||
| 20 | +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | ||
| 21 | +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | ||
| 22 | +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | ||
| 23 | + | ||
| 24 | +Derivative works are acceptable, even for commercial purposes, so long as | ||
| 25 | +(1) they include prominent notice that the work is derivative, and (2) they | ||
| 26 | +include prominent notice akin to these three paragraphs for those parts of | ||
| 27 | +this code that are retained. | ||
| 28 | + | ||
| 29 | +=============================================================================== | ||
| 30 | +*/ | ||
| 31 | + | ||
| 32 | +/* | ||
| 33 | +------------------------------------------------------------------------------- | ||
| 34 | +Underflow tininess-detection mode, statically initialized to default value. | ||
| 35 | +(The declaration in `softfloat.h' must match the `int8' type here.) | ||
| 36 | +------------------------------------------------------------------------------- | ||
| 37 | +*/ | ||
| 38 | +int8 float_detect_tininess = float_tininess_after_rounding; | ||
| 39 | + | ||
| 40 | +/* | ||
| 41 | +------------------------------------------------------------------------------- | ||
| 42 | +Raises the exceptions specified by `flags'. Floating-point traps can be | ||
| 43 | +defined here if desired. It is currently not possible for such a trap to | ||
| 44 | +substitute a result value. If traps are not implemented, this routine | ||
| 45 | +should be simply `float_exception_flags |= flags;'. | ||
| 46 | + | ||
| 47 | +ScottB: November 4, 1998 | ||
| 48 | +Moved this function out of softfloat-specialize into fpmodule.c. | ||
| 49 | +This effectively isolates all the changes required for integrating with the | ||
| 50 | +Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying | ||
| 51 | +fpmodule.c to integrate with the NetBSD kernel (I hope!). | ||
| 52 | +------------------------------------------------------------------------------- | ||
| 53 | +*/ | ||
| 54 | +void float_raise( int8 flags ) | ||
| 55 | +{ | ||
| 56 | + float_exception_flags |= flags; | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +/* | ||
| 60 | +------------------------------------------------------------------------------- | ||
| 61 | +Internal canonical NaN format. | ||
| 62 | +------------------------------------------------------------------------------- | ||
| 63 | +*/ | ||
| 64 | +typedef struct { | ||
| 65 | + flag sign; | ||
| 66 | + bits64 high, low; | ||
| 67 | +} commonNaNT; | ||
| 68 | + | ||
| 69 | +/* | ||
| 70 | +------------------------------------------------------------------------------- | ||
| 71 | +The pattern for a default generated single-precision NaN. | ||
| 72 | +------------------------------------------------------------------------------- | ||
| 73 | +*/ | ||
| 74 | +#define float32_default_nan 0xFFFFFFFF | ||
| 75 | + | ||
| 76 | +/* | ||
| 77 | +------------------------------------------------------------------------------- | ||
| 78 | +Returns 1 if the single-precision floating-point value `a' is a NaN; | ||
| 79 | +otherwise returns 0. | ||
| 80 | +------------------------------------------------------------------------------- | ||
| 81 | +*/ | ||
| 82 | +flag float32_is_nan( float32 a ) | ||
| 83 | +{ | ||
| 84 | + | ||
| 85 | + return ( 0xFF000000 < (bits32) ( a<<1 ) ); | ||
| 86 | + | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +/* | ||
| 90 | +------------------------------------------------------------------------------- | ||
| 91 | +Returns 1 if the single-precision floating-point value `a' is a signaling | ||
| 92 | +NaN; otherwise returns 0. | ||
| 93 | +------------------------------------------------------------------------------- | ||
| 94 | +*/ | ||
| 95 | +flag float32_is_signaling_nan( float32 a ) | ||
| 96 | +{ | ||
| 97 | + | ||
| 98 | + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); | ||
| 99 | + | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | +/* | ||
| 103 | +------------------------------------------------------------------------------- | ||
| 104 | +Returns the result of converting the single-precision floating-point NaN | ||
| 105 | +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid | ||
| 106 | +exception is raised. | ||
| 107 | +------------------------------------------------------------------------------- | ||
| 108 | +*/ | ||
| 109 | +static commonNaNT float32ToCommonNaN( float32 a ) | ||
| 110 | +{ | ||
| 111 | + commonNaNT z; | ||
| 112 | + | ||
| 113 | + if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); | ||
| 114 | + z.sign = a>>31; | ||
| 115 | + z.low = 0; | ||
| 116 | + z.high = ( (bits64) a )<<41; | ||
| 117 | + return z; | ||
| 118 | + | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +/* | ||
| 122 | +------------------------------------------------------------------------------- | ||
| 123 | +Returns the result of converting the canonical NaN `a' to the single- | ||
| 124 | +precision floating-point format. | ||
| 125 | +------------------------------------------------------------------------------- | ||
| 126 | +*/ | ||
| 127 | +static float32 commonNaNToFloat32( commonNaNT a ) | ||
| 128 | +{ | ||
| 129 | + | ||
| 130 | + return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); | ||
| 131 | + | ||
| 132 | +} | ||
| 133 | + | ||
| 134 | +/* | ||
| 135 | +------------------------------------------------------------------------------- | ||
| 136 | +Takes two single-precision floating-point values `a' and `b', one of which | ||
| 137 | +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a | ||
| 138 | +signaling NaN, the invalid exception is raised. | ||
| 139 | +------------------------------------------------------------------------------- | ||
| 140 | +*/ | ||
| 141 | +static float32 propagateFloat32NaN( float32 a, float32 b ) | ||
| 142 | +{ | ||
| 143 | + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; | ||
| 144 | + | ||
| 145 | + aIsNaN = float32_is_nan( a ); | ||
| 146 | + aIsSignalingNaN = float32_is_signaling_nan( a ); | ||
| 147 | + bIsNaN = float32_is_nan( b ); | ||
| 148 | + bIsSignalingNaN = float32_is_signaling_nan( b ); | ||
| 149 | + a |= 0x00400000; | ||
| 150 | + b |= 0x00400000; | ||
| 151 | + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); | ||
| 152 | + if ( aIsNaN ) { | ||
| 153 | + return ( aIsSignalingNaN & bIsNaN ) ? b : a; | ||
| 154 | + } | ||
| 155 | + else { | ||
| 156 | + return b; | ||
| 157 | + } | ||
| 158 | + | ||
| 159 | +} | ||
| 160 | + | ||
| 161 | +/* | ||
| 162 | +------------------------------------------------------------------------------- | ||
| 163 | +The pattern for a default generated double-precision NaN. | ||
| 164 | +------------------------------------------------------------------------------- | ||
| 165 | +*/ | ||
| 166 | +#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF ) | ||
| 167 | + | ||
| 168 | +/* | ||
| 169 | +------------------------------------------------------------------------------- | ||
| 170 | +Returns 1 if the double-precision floating-point value `a' is a NaN; | ||
| 171 | +otherwise returns 0. | ||
| 172 | +------------------------------------------------------------------------------- | ||
| 173 | +*/ | ||
| 174 | +flag float64_is_nan( float64 a ) | ||
| 175 | +{ | ||
| 176 | + | ||
| 177 | + return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); | ||
| 178 | + | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +/* | ||
| 182 | +------------------------------------------------------------------------------- | ||
| 183 | +Returns 1 if the double-precision floating-point value `a' is a signaling | ||
| 184 | +NaN; otherwise returns 0. | ||
| 185 | +------------------------------------------------------------------------------- | ||
| 186 | +*/ | ||
| 187 | +flag float64_is_signaling_nan( float64 a ) | ||
| 188 | +{ | ||
| 189 | + | ||
| 190 | + return | ||
| 191 | + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) | ||
| 192 | + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); | ||
| 193 | + | ||
| 194 | +} | ||
| 195 | + | ||
| 196 | +/* | ||
| 197 | +------------------------------------------------------------------------------- | ||
| 198 | +Returns the result of converting the double-precision floating-point NaN | ||
| 199 | +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid | ||
| 200 | +exception is raised. | ||
| 201 | +------------------------------------------------------------------------------- | ||
| 202 | +*/ | ||
| 203 | +static commonNaNT float64ToCommonNaN( float64 a ) | ||
| 204 | +{ | ||
| 205 | + commonNaNT z; | ||
| 206 | + | ||
| 207 | + if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); | ||
| 208 | + z.sign = a>>63; | ||
| 209 | + z.low = 0; | ||
| 210 | + z.high = a<<12; | ||
| 211 | + return z; | ||
| 212 | + | ||
| 213 | +} | ||
| 214 | + | ||
| 215 | +/* | ||
| 216 | +------------------------------------------------------------------------------- | ||
| 217 | +Returns the result of converting the canonical NaN `a' to the double- | ||
| 218 | +precision floating-point format. | ||
| 219 | +------------------------------------------------------------------------------- | ||
| 220 | +*/ | ||
| 221 | +static float64 commonNaNToFloat64( commonNaNT a ) | ||
| 222 | +{ | ||
| 223 | + | ||
| 224 | + return | ||
| 225 | + ( ( (bits64) a.sign )<<63 ) | ||
| 226 | + | LIT64( 0x7FF8000000000000 ) | ||
| 227 | + | ( a.high>>12 ); | ||
| 228 | + | ||
| 229 | +} | ||
| 230 | + | ||
| 231 | +/* | ||
| 232 | +------------------------------------------------------------------------------- | ||
| 233 | +Takes two double-precision floating-point values `a' and `b', one of which | ||
| 234 | +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a | ||
| 235 | +signaling NaN, the invalid exception is raised. | ||
| 236 | +------------------------------------------------------------------------------- | ||
| 237 | +*/ | ||
| 238 | +static float64 propagateFloat64NaN( float64 a, float64 b ) | ||
| 239 | +{ | ||
| 240 | + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; | ||
| 241 | + | ||
| 242 | + aIsNaN = float64_is_nan( a ); | ||
| 243 | + aIsSignalingNaN = float64_is_signaling_nan( a ); | ||
| 244 | + bIsNaN = float64_is_nan( b ); | ||
| 245 | + bIsSignalingNaN = float64_is_signaling_nan( b ); | ||
| 246 | + a |= LIT64( 0x0008000000000000 ); | ||
| 247 | + b |= LIT64( 0x0008000000000000 ); | ||
| 248 | + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); | ||
| 249 | + if ( aIsNaN ) { | ||
| 250 | + return ( aIsSignalingNaN & bIsNaN ) ? b : a; | ||
| 251 | + } | ||
| 252 | + else { | ||
| 253 | + return b; | ||
| 254 | + } | ||
| 255 | + | ||
| 256 | +} | ||
| 257 | + | ||
| 258 | +#ifdef FLOATX80 | ||
| 259 | + | ||
| 260 | +/* | ||
| 261 | +------------------------------------------------------------------------------- | ||
| 262 | +The pattern for a default generated extended double-precision NaN. The | ||
| 263 | +`high' and `low' values hold the most- and least-significant bits, | ||
| 264 | +respectively. | ||
| 265 | +------------------------------------------------------------------------------- | ||
| 266 | +*/ | ||
| 267 | +#define floatx80_default_nan_high 0xFFFF | ||
| 268 | +#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) | ||
| 269 | + | ||
| 270 | +/* | ||
| 271 | +------------------------------------------------------------------------------- | ||
| 272 | +Returns 1 if the extended double-precision floating-point value `a' is a | ||
| 273 | +NaN; otherwise returns 0. | ||
| 274 | +------------------------------------------------------------------------------- | ||
| 275 | +*/ | ||
| 276 | +flag floatx80_is_nan( floatx80 a ) | ||
| 277 | +{ | ||
| 278 | + | ||
| 279 | + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); | ||
| 280 | + | ||
| 281 | +} | ||
| 282 | + | ||
| 283 | +/* | ||
| 284 | +------------------------------------------------------------------------------- | ||
| 285 | +Returns 1 if the extended double-precision floating-point value `a' is a | ||
| 286 | +signaling NaN; otherwise returns 0. | ||
| 287 | +------------------------------------------------------------------------------- | ||
| 288 | +*/ | ||
| 289 | +flag floatx80_is_signaling_nan( floatx80 a ) | ||
| 290 | +{ | ||
| 291 | + //register int lr; | ||
| 292 | + bits64 aLow; | ||
| 293 | + | ||
| 294 | + //__asm__("mov %0, lr" : : "g" (lr)); | ||
| 295 | + //fp_printk("floatx80_is_signalling_nan() called from 0x%08x\n",lr); | ||
| 296 | + aLow = a.low & ~ LIT64( 0x4000000000000000 ); | ||
| 297 | + return | ||
| 298 | + ( ( a.high & 0x7FFF ) == 0x7FFF ) | ||
| 299 | + && (bits64) ( aLow<<1 ) | ||
| 300 | + && ( a.low == aLow ); | ||
| 301 | + | ||
| 302 | +} | ||
| 303 | + | ||
| 304 | +/* | ||
| 305 | +------------------------------------------------------------------------------- | ||
| 306 | +Returns the result of converting the extended double-precision floating- | ||
| 307 | +point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the | ||
| 308 | +invalid exception is raised. | ||
| 309 | +------------------------------------------------------------------------------- | ||
| 310 | +*/ | ||
| 311 | +static commonNaNT floatx80ToCommonNaN( floatx80 a ) | ||
| 312 | +{ | ||
| 313 | + commonNaNT z; | ||
| 314 | + | ||
| 315 | + if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); | ||
| 316 | + z.sign = a.high>>15; | ||
| 317 | + z.low = 0; | ||
| 318 | + z.high = a.low<<1; | ||
| 319 | + return z; | ||
| 320 | + | ||
| 321 | +} | ||
| 322 | + | ||
| 323 | +/* | ||
| 324 | +------------------------------------------------------------------------------- | ||
| 325 | +Returns the result of converting the canonical NaN `a' to the extended | ||
| 326 | +double-precision floating-point format. | ||
| 327 | +------------------------------------------------------------------------------- | ||
| 328 | +*/ | ||
| 329 | +static floatx80 commonNaNToFloatx80( commonNaNT a ) | ||
| 330 | +{ | ||
| 331 | + floatx80 z; | ||
| 332 | + | ||
| 333 | + z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); | ||
| 334 | + z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; | ||
| 335 | + return z; | ||
| 336 | + | ||
| 337 | +} | ||
| 338 | + | ||
| 339 | +/* | ||
| 340 | +------------------------------------------------------------------------------- | ||
| 341 | +Takes two extended double-precision floating-point values `a' and `b', one | ||
| 342 | +of which is a NaN, and returns the appropriate NaN result. If either `a' or | ||
| 343 | +`b' is a signaling NaN, the invalid exception is raised. | ||
| 344 | +------------------------------------------------------------------------------- | ||
| 345 | +*/ | ||
| 346 | +static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b ) | ||
| 347 | +{ | ||
| 348 | + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; | ||
| 349 | + | ||
| 350 | + aIsNaN = floatx80_is_nan( a ); | ||
| 351 | + aIsSignalingNaN = floatx80_is_signaling_nan( a ); | ||
| 352 | + bIsNaN = floatx80_is_nan( b ); | ||
| 353 | + bIsSignalingNaN = floatx80_is_signaling_nan( b ); | ||
| 354 | + a.low |= LIT64( 0xC000000000000000 ); | ||
| 355 | + b.low |= LIT64( 0xC000000000000000 ); | ||
| 356 | + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); | ||
| 357 | + if ( aIsNaN ) { | ||
| 358 | + return ( aIsSignalingNaN & bIsNaN ) ? b : a; | ||
| 359 | + } | ||
| 360 | + else { | ||
| 361 | + return b; | ||
| 362 | + } | ||
| 363 | + | ||
| 364 | +} | ||
| 365 | + | ||
| 366 | +#endif |