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