1 /* 2 NetWinder Floating Point Emulator 3 (c) Rebel.com, 1998-1999 4 (c) Philip Blundell, 1998, 2001 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 <linux/uaccess.h> 30 31 static inline void loadSingle(const unsigned int Fn, const unsigned int __user *pMem) 32 { 33 FPA11 *fpa11 = GET_FPA11(); 34 fpa11->fType[Fn] = typeSingle; 35 get_user(fpa11->fpreg[Fn].fSingle, pMem); 36 } 37 38 static inline void loadDouble(const unsigned int Fn, const unsigned int __user *pMem) 39 { 40 FPA11 *fpa11 = GET_FPA11(); 41 unsigned int *p; 42 p = (unsigned int *) &fpa11->fpreg[Fn].fDouble; 43 fpa11->fType[Fn] = typeDouble; 44 #ifdef __ARMEB__ 45 get_user(p[0], &pMem[0]); /* sign & exponent */ 46 get_user(p[1], &pMem[1]); 47 #else 48 get_user(p[0], &pMem[1]); 49 get_user(p[1], &pMem[0]); /* sign & exponent */ 50 #endif 51 } 52 53 #ifdef CONFIG_FPE_NWFPE_XP 54 static inline void loadExtended(const unsigned int Fn, const unsigned int __user *pMem) 55 { 56 FPA11 *fpa11 = GET_FPA11(); 57 unsigned int *p; 58 p = (unsigned int *) &fpa11->fpreg[Fn].fExtended; 59 fpa11->fType[Fn] = typeExtended; 60 get_user(p[0], &pMem[0]); /* sign & exponent */ 61 #ifdef __ARMEB__ 62 get_user(p[1], &pMem[1]); /* ms bits */ 63 get_user(p[2], &pMem[2]); /* ls bits */ 64 #else 65 get_user(p[1], &pMem[2]); /* ls bits */ 66 get_user(p[2], &pMem[1]); /* ms bits */ 67 #endif 68 } 69 #endif 70 71 static inline void loadMultiple(const unsigned int Fn, const unsigned int __user *pMem) 72 { 73 FPA11 *fpa11 = GET_FPA11(); 74 register unsigned int *p; 75 unsigned long x; 76 77 p = (unsigned int *) &(fpa11->fpreg[Fn]); 78 get_user(x, &pMem[0]); 79 fpa11->fType[Fn] = (x >> 14) & 0x00000003; 80 81 switch (fpa11->fType[Fn]) { 82 case typeSingle: 83 case typeDouble: 84 { 85 get_user(p[0], &pMem[2]); /* Single */ 86 get_user(p[1], &pMem[1]); /* double msw */ 87 p[2] = 0; /* empty */ 88 } 89 break; 90 91 #ifdef CONFIG_FPE_NWFPE_XP 92 case typeExtended: 93 { 94 get_user(p[1], &pMem[2]); 95 get_user(p[2], &pMem[1]); /* msw */ 96 p[0] = (x & 0x80003fff); 97 } 98 break; 99 #endif 100 } 101 } 102 103 static inline void storeSingle(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem) 104 { 105 FPA11 *fpa11 = GET_FPA11(); 106 union { 107 float32 f; 108 unsigned int i[1]; 109 } val; 110 111 switch (fpa11->fType[Fn]) { 112 case typeDouble: 113 val.f = float64_to_float32(roundData, fpa11->fpreg[Fn].fDouble); 114 break; 115 116 #ifdef CONFIG_FPE_NWFPE_XP 117 case typeExtended: 118 val.f = floatx80_to_float32(roundData, fpa11->fpreg[Fn].fExtended); 119 break; 120 #endif 121 122 default: 123 val.f = fpa11->fpreg[Fn].fSingle; 124 } 125 126 put_user(val.i[0], pMem); 127 } 128 129 static inline void storeDouble(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem) 130 { 131 FPA11 *fpa11 = GET_FPA11(); 132 union { 133 float64 f; 134 unsigned int i[2]; 135 } val; 136 137 switch (fpa11->fType[Fn]) { 138 case typeSingle: 139 val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle); 140 break; 141 142 #ifdef CONFIG_FPE_NWFPE_XP 143 case typeExtended: 144 val.f = floatx80_to_float64(roundData, fpa11->fpreg[Fn].fExtended); 145 break; 146 #endif 147 148 default: 149 val.f = fpa11->fpreg[Fn].fDouble; 150 } 151 152 #ifdef __ARMEB__ 153 put_user(val.i[0], &pMem[0]); /* msw */ 154 put_user(val.i[1], &pMem[1]); /* lsw */ 155 #else 156 put_user(val.i[1], &pMem[0]); /* msw */ 157 put_user(val.i[0], &pMem[1]); /* lsw */ 158 #endif 159 } 160 161 #ifdef CONFIG_FPE_NWFPE_XP 162 static inline void storeExtended(const unsigned int Fn, unsigned int __user *pMem) 163 { 164 FPA11 *fpa11 = GET_FPA11(); 165 union { 166 floatx80 f; 167 unsigned int i[3]; 168 } val; 169 170 switch (fpa11->fType[Fn]) { 171 case typeSingle: 172 val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); 173 break; 174 175 case typeDouble: 176 val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); 177 break; 178 179 default: 180 val.f = fpa11->fpreg[Fn].fExtended; 181 } 182 183 put_user(val.i[0], &pMem[0]); /* sign & exp */ 184 #ifdef __ARMEB__ 185 put_user(val.i[1], &pMem[1]); /* msw */ 186 put_user(val.i[2], &pMem[2]); 187 #else 188 put_user(val.i[1], &pMem[2]); 189 put_user(val.i[2], &pMem[1]); /* msw */ 190 #endif 191 } 192 #endif 193 194 static inline void storeMultiple(const unsigned int Fn, unsigned int __user *pMem) 195 { 196 FPA11 *fpa11 = GET_FPA11(); 197 register unsigned int nType, *p; 198 199 p = (unsigned int *) &(fpa11->fpreg[Fn]); 200 nType = fpa11->fType[Fn]; 201 202 switch (nType) { 203 case typeSingle: 204 case typeDouble: 205 { 206 put_user(p[0], &pMem[2]); /* single */ 207 put_user(p[1], &pMem[1]); /* double msw */ 208 put_user(nType << 14, &pMem[0]); 209 } 210 break; 211 212 #ifdef CONFIG_FPE_NWFPE_XP 213 case typeExtended: 214 { 215 put_user(p[2], &pMem[1]); /* msw */ 216 put_user(p[1], &pMem[2]); 217 put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); 218 } 219 break; 220 #endif 221 } 222 } 223 224 unsigned int PerformLDF(const unsigned int opcode) 225 { 226 unsigned int __user *pBase, *pAddress, *pFinal; 227 unsigned int nRc = 1, write_back = WRITE_BACK(opcode); 228 229 pBase = (unsigned int __user *) readRegister(getRn(opcode)); 230 if (REG_PC == getRn(opcode)) { 231 pBase += 2; 232 write_back = 0; 233 } 234 235 pFinal = pBase; 236 if (BIT_UP_SET(opcode)) 237 pFinal += getOffset(opcode); 238 else 239 pFinal -= getOffset(opcode); 240 241 if (PREINDEXED(opcode)) 242 pAddress = pFinal; 243 else 244 pAddress = pBase; 245 246 switch (opcode & MASK_TRANSFER_LENGTH) { 247 case TRANSFER_SINGLE: 248 loadSingle(getFd(opcode), pAddress); 249 break; 250 case TRANSFER_DOUBLE: 251 loadDouble(getFd(opcode), pAddress); 252 break; 253 #ifdef CONFIG_FPE_NWFPE_XP 254 case TRANSFER_EXTENDED: 255 loadExtended(getFd(opcode), pAddress); 256 break; 257 #endif 258 default: 259 nRc = 0; 260 } 261 262 if (write_back) 263 writeRegister(getRn(opcode), (unsigned long) pFinal); 264 return nRc; 265 } 266 267 unsigned int PerformSTF(const unsigned int opcode) 268 { 269 unsigned int __user *pBase, *pAddress, *pFinal; 270 unsigned int nRc = 1, write_back = WRITE_BACK(opcode); 271 struct roundingData roundData; 272 273 roundData.mode = SetRoundingMode(opcode); 274 roundData.precision = SetRoundingPrecision(opcode); 275 roundData.exception = 0; 276 277 pBase = (unsigned int __user *) readRegister(getRn(opcode)); 278 if (REG_PC == getRn(opcode)) { 279 pBase += 2; 280 write_back = 0; 281 } 282 283 pFinal = pBase; 284 if (BIT_UP_SET(opcode)) 285 pFinal += getOffset(opcode); 286 else 287 pFinal -= getOffset(opcode); 288 289 if (PREINDEXED(opcode)) 290 pAddress = pFinal; 291 else 292 pAddress = pBase; 293 294 switch (opcode & MASK_TRANSFER_LENGTH) { 295 case TRANSFER_SINGLE: 296 storeSingle(&roundData, getFd(opcode), pAddress); 297 break; 298 case TRANSFER_DOUBLE: 299 storeDouble(&roundData, getFd(opcode), pAddress); 300 break; 301 #ifdef CONFIG_FPE_NWFPE_XP 302 case TRANSFER_EXTENDED: 303 storeExtended(getFd(opcode), pAddress); 304 break; 305 #endif 306 default: 307 nRc = 0; 308 } 309 310 if (roundData.exception) 311 float_raise(roundData.exception); 312 313 if (write_back) 314 writeRegister(getRn(opcode), (unsigned long) pFinal); 315 return nRc; 316 } 317 318 unsigned int PerformLFM(const unsigned int opcode) 319 { 320 unsigned int __user *pBase, *pAddress, *pFinal; 321 unsigned int i, Fd, write_back = WRITE_BACK(opcode); 322 323 pBase = (unsigned int __user *) readRegister(getRn(opcode)); 324 if (REG_PC == getRn(opcode)) { 325 pBase += 2; 326 write_back = 0; 327 } 328 329 pFinal = pBase; 330 if (BIT_UP_SET(opcode)) 331 pFinal += getOffset(opcode); 332 else 333 pFinal -= getOffset(opcode); 334 335 if (PREINDEXED(opcode)) 336 pAddress = pFinal; 337 else 338 pAddress = pBase; 339 340 Fd = getFd(opcode); 341 for (i = getRegisterCount(opcode); i > 0; i--) { 342 loadMultiple(Fd, pAddress); 343 pAddress += 3; 344 Fd++; 345 if (Fd == 8) 346 Fd = 0; 347 } 348 349 if (write_back) 350 writeRegister(getRn(opcode), (unsigned long) pFinal); 351 return 1; 352 } 353 354 unsigned int PerformSFM(const unsigned int opcode) 355 { 356 unsigned int __user *pBase, *pAddress, *pFinal; 357 unsigned int i, Fd, write_back = WRITE_BACK(opcode); 358 359 pBase = (unsigned int __user *) readRegister(getRn(opcode)); 360 if (REG_PC == getRn(opcode)) { 361 pBase += 2; 362 write_back = 0; 363 } 364 365 pFinal = pBase; 366 if (BIT_UP_SET(opcode)) 367 pFinal += getOffset(opcode); 368 else 369 pFinal -= getOffset(opcode); 370 371 if (PREINDEXED(opcode)) 372 pAddress = pFinal; 373 else 374 pAddress = pBase; 375 376 Fd = getFd(opcode); 377 for (i = getRegisterCount(opcode); i > 0; i--) { 378 storeMultiple(Fd, pAddress); 379 pAddress += 3; 380 Fd++; 381 if (Fd == 8) 382 Fd = 0; 383 } 384 385 if (write_back) 386 writeRegister(getRn(opcode), (unsigned long) pFinal); 387 return 1; 388 } 389 390 unsigned int EmulateCPDT(const unsigned int opcode) 391 { 392 unsigned int nRc = 0; 393 394 if (LDF_OP(opcode)) { 395 nRc = PerformLDF(opcode); 396 } else if (LFM_OP(opcode)) { 397 nRc = PerformLFM(opcode); 398 } else if (STF_OP(opcode)) { 399 nRc = PerformSTF(opcode); 400 } else if (SFM_OP(opcode)) { 401 nRc = PerformSFM(opcode); 402 } else { 403 nRc = 0; 404 } 405 406 return nRc; 407 } 408