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