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