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