1 // SPDX-License-Identifier: GPL-2.0-or-later 1 2 /* 3 NetWinder Floating Point Emulator 4 (c) Rebel.COM, 1998,1999 5 (c) Philip Blundell, 1999, 2001 6 7 Direct questions, comments to Scott Bambro 8 9 */ 10 11 #include "fpa11.h" 12 #include "fpopcode.h" 13 #include "fpa11.inl" 14 #include "fpmodule.h" 15 #include "fpmodule.inl" 16 #include "softfloat.h" 17 18 unsigned int PerformFLT(const unsigned int opc 19 unsigned int PerformFIX(const unsigned int opc 20 21 static unsigned int PerformComparison(const un 22 23 unsigned int EmulateCPRT(const unsigned int op 24 { 25 26 if (opcode & 0x800000) { 27 /* This is some variant of a c 28 will sort out which one). 29 instructions are oddball ca 30 makes sense to pull this ou 31 return PerformComparison(opcod 32 } 33 34 /* Hint to GCC that we'd like a jump t 35 switch ((opcode & 0x700000) >> 20) { 36 case FLT_CODE >> 20: 37 return PerformFLT(opcode); 38 break; 39 case FIX_CODE >> 20: 40 return PerformFIX(opcode); 41 break; 42 43 case WFS_CODE >> 20: 44 writeFPSR(readRegister(getRd(o 45 break; 46 case RFS_CODE >> 20: 47 writeRegister(getRd(opcode), r 48 break; 49 50 default: 51 return 0; 52 } 53 54 return 1; 55 } 56 57 unsigned int PerformFLT(const unsigned int opc 58 { 59 FPA11 *fpa11 = GET_FPA11(); 60 struct roundingData roundData; 61 62 roundData.mode = SetRoundingMode(opcod 63 roundData.precision = SetRoundingPreci 64 roundData.exception = 0; 65 66 switch (opcode & MASK_ROUNDING_PRECISI 67 case ROUND_SINGLE: 68 { 69 fpa11->fType[getFn(opc 70 fpa11->fpreg[getFn(opc 71 } 72 break; 73 74 case ROUND_DOUBLE: 75 { 76 fpa11->fType[getFn(opc 77 fpa11->fpreg[getFn(opc 78 } 79 break; 80 81 #ifdef CONFIG_FPE_NWFPE_XP 82 case ROUND_EXTENDED: 83 { 84 fpa11->fType[getFn(opc 85 fpa11->fpreg[getFn(opc 86 } 87 break; 88 #endif 89 90 default: 91 return 0; 92 } 93 94 if (roundData.exception) 95 float_raise(roundData.exceptio 96 97 return 1; 98 } 99 100 unsigned int PerformFIX(const unsigned int opc 101 { 102 FPA11 *fpa11 = GET_FPA11(); 103 unsigned int Fn = getFm(opcode); 104 struct roundingData roundData; 105 106 roundData.mode = SetRoundingMode(opcod 107 roundData.precision = SetRoundingPreci 108 roundData.exception = 0; 109 110 switch (fpa11->fType[Fn]) { 111 case typeSingle: 112 { 113 writeRegister(getRd(op 114 } 115 break; 116 117 case typeDouble: 118 { 119 writeRegister(getRd(op 120 } 121 break; 122 123 #ifdef CONFIG_FPE_NWFPE_XP 124 case typeExtended: 125 { 126 writeRegister(getRd(op 127 } 128 break; 129 #endif 130 131 default: 132 return 0; 133 } 134 135 if (roundData.exception) 136 float_raise(roundData.exceptio 137 138 return 1; 139 } 140 141 /* This instruction sets the flags N, Z, C, V 142 static unsigned int PerformComparison(const un 143 { 144 FPA11 *fpa11 = GET_FPA11(); 145 unsigned int Fn = getFn(opcode), Fm = 146 int e_flag = opcode & 0x400000; /* 1 i 147 int n_flag = opcode & 0x200000; /* 1 i 148 unsigned int flags = 0; 149 150 #ifdef CONFIG_FPE_NWFPE_XP 151 floatx80 rFn, rFm; 152 153 /* Check for unordered condition and c 154 format. 155 ?? Might be some mileage in avoidin 156 Eg, if both operands are 32-bit, de 157 comparison (cheaper than an 80-bit 158 switch (fpa11->fType[Fn]) { 159 case typeSingle: 160 //printk("single.\n"); 161 if (float32_is_nan(fpa11->fpre 162 goto unordered; 163 rFn = float32_to_floatx80(fpa1 164 break; 165 166 case typeDouble: 167 //printk("double.\n"); 168 if (float64_is_nan(fpa11->fpre 169 goto unordered; 170 rFn = float64_to_floatx80(fpa1 171 break; 172 173 case typeExtended: 174 //printk("extended.\n"); 175 if (floatx80_is_nan(fpa11->fpr 176 goto unordered; 177 rFn = fpa11->fpreg[Fn].fExtend 178 break; 179 180 default: 181 return 0; 182 } 183 184 if (CONSTANT_FM(opcode)) { 185 //printk("Fm is a constant: #% 186 rFm = getExtendedConstant(Fm); 187 if (floatx80_is_nan(rFm)) 188 goto unordered; 189 } else { 190 //printk("Fm = r%d which conta 191 switch (fpa11->fType[Fm]) { 192 case typeSingle: 193 //printk("single.\n"); 194 if (float32_is_nan(fpa 195 goto unordered 196 rFm = float32_to_float 197 break; 198 199 case typeDouble: 200 //printk("double.\n"); 201 if (float64_is_nan(fpa 202 goto unordered 203 rFm = float64_to_float 204 break; 205 206 case typeExtended: 207 //printk("extended.\n" 208 if (floatx80_is_nan(fp 209 goto unordered 210 rFm = fpa11->fpreg[Fm] 211 break; 212 213 default: 214 return 0; 215 } 216 } 217 218 if (n_flag) 219 rFm.high ^= 0x8000; 220 221 /* test for less than condition */ 222 if (floatx80_lt(rFn, rFm)) 223 flags |= CC_NEGATIVE; 224 225 /* test for equal condition */ 226 if (floatx80_eq(rFn, rFm)) 227 flags |= CC_ZERO; 228 229 /* test for greater than or equal cond 230 if (floatx80_lt(rFm, rFn)) 231 flags |= CC_CARRY; 232 233 #else 234 if (CONSTANT_FM(opcode)) { 235 /* Fm is a constant. Do the c 236 Fn happens to be stored in. 237 if (fpa11->fType[Fn] == typeSi 238 float32 rFm = getSingl 239 float32 rFn = fpa11->f 240 241 if (float32_is_nan(rFn 242 goto unordered 243 244 if (n_flag) 245 rFm ^= 0x80000 246 247 /* test for less than 248 if (float32_lt_nocheck 249 flags |= CC_NE 250 251 /* test for equal cond 252 if (float32_eq_nocheck 253 flags |= CC_ZE 254 255 /* test for greater th 256 if (float32_lt_nocheck 257 flags |= CC_CA 258 } else { 259 float64 rFm = getDoubl 260 float64 rFn = fpa11->f 261 262 if (float64_is_nan(rFn 263 goto unordered 264 265 if (n_flag) 266 rFm ^= 0x80000 267 268 /* test for less than 269 if (float64_lt_nocheck 270 flags |= CC_NE 271 272 /* test for equal cond 273 if (float64_eq_nocheck 274 flags |= CC_ZE 275 276 /* test for greater th 277 if (float64_lt_nocheck 278 flags |= CC_CA 279 } 280 } else { 281 /* Both operands are in regist 282 if (fpa11->fType[Fn] == typeSi 283 && fpa11->fType[Fm] == typ 284 float32 rFm = fpa11->f 285 float32 rFn = fpa11->f 286 287 if (float32_is_nan(rFn 288 || float32_is_nan( 289 goto unordered 290 291 if (n_flag) 292 rFm ^= 0x80000 293 294 /* test for less than 295 if (float32_lt_nocheck 296 flags |= CC_NE 297 298 /* test for equal cond 299 if (float32_eq_nocheck 300 flags |= CC_ZE 301 302 /* test for greater th 303 if (float32_lt_nocheck 304 flags |= CC_CA 305 } else { 306 /* Promote 32-bit oper 307 float64 rFm, rFn; 308 309 rFm = (fpa11->fType[Fm 310 float32_to_float64 311 : fpa11->fpreg[Fm] 312 313 rFn = (fpa11->fType[Fn 314 float32_to_float64 315 : fpa11->fpreg[Fn] 316 317 if (float64_is_nan(rFn 318 || float64_is_nan( 319 goto unordered 320 321 if (n_flag) 322 rFm ^= 0x80000 323 324 /* test for less than 325 if (float64_lt_nocheck 326 flags |= CC_NE 327 328 /* test for equal cond 329 if (float64_eq_nocheck 330 flags |= CC_ZE 331 332 /* test for greater th 333 if (float64_lt_nocheck 334 flags |= CC_CA 335 } 336 } 337 338 #endif 339 340 writeConditionCodes(flags); 341 342 return 1; 343 344 unordered: 345 /* ?? The FPA data sheet is pretty vag 346 about whether the non-E comparisons 347 This implementation is based on a c 348 the data sheet, observation of how 349 behaves (and how programs expect it 350 flags |= CC_OVERFLOW; 351 flags &= ~(CC_ZERO | CC_NEGATIVE); 352 353 if (BIT_AC & readFPSR()) 354 flags |= CC_CARRY; 355 356 if (e_flag) 357 float_raise(float_flag_invalid 358 359 writeConditionCodes(flags); 360 return 1; 361 } 362
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.