Commit 4ecc31906d7535c4ad88fcc63968bef412dd67ba
1 parent
4c2e770f
fpu fixes (Jocelyn Mayer) - soft float support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1335 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
181 additions
and
158 deletions
target-ppc/cpu.h
| ... | ... | @@ -27,6 +27,8 @@ |
| 27 | 27 | #include "config.h" |
| 28 | 28 | #include <setjmp.h> |
| 29 | 29 | |
| 30 | +#include "softfloat.h" | |
| 31 | + | |
| 30 | 32 | /* Instruction types */ |
| 31 | 33 | enum { |
| 32 | 34 | PPC_NONE = 0x0000, |
| ... | ... | @@ -94,7 +96,7 @@ typedef struct CPUPPCState { |
| 94 | 96 | /* general purpose registers */ |
| 95 | 97 | uint32_t gpr[32]; |
| 96 | 98 | /* floating point registers */ |
| 97 | - double fpr[32]; | |
| 99 | + float64 fpr[32]; | |
| 98 | 100 | /* segment registers */ |
| 99 | 101 | uint32_t sdr1; |
| 100 | 102 | uint32_t sr[16]; |
| ... | ... | @@ -119,9 +121,11 @@ typedef struct CPUPPCState { |
| 119 | 121 | uint32_t spr[1024]; |
| 120 | 122 | /* qemu dedicated */ |
| 121 | 123 | /* temporary float registers */ |
| 122 | - double ft0; | |
| 123 | - double ft1; | |
| 124 | - double ft2; | |
| 124 | + float64 ft0; | |
| 125 | + float64 ft1; | |
| 126 | + float64 ft2; | |
| 127 | + float_status fp_status; | |
| 128 | + | |
| 125 | 129 | int interrupt_request; |
| 126 | 130 | jmp_buf jmp_env; |
| 127 | 131 | int exception_index; | ... | ... |
target-ppc/exec.h
| ... | ... | @@ -32,9 +32,6 @@ register uint32_t T2 asm(AREG3); |
| 32 | 32 | #define FT0 (env->ft0) |
| 33 | 33 | #define FT1 (env->ft1) |
| 34 | 34 | #define FT2 (env->ft2) |
| 35 | -#define FTS0 ((float)env->ft0) | |
| 36 | -#define FTS1 ((float)env->ft1) | |
| 37 | -#define FTS2 ((float)env->ft2) | |
| 38 | 35 | |
| 39 | 36 | #if defined (DEBUG_OP) |
| 40 | 37 | #define RETURN() __asm__ __volatile__("nop"); |
| ... | ... | @@ -137,17 +134,12 @@ void do_fctiw (void); |
| 137 | 134 | void do_fctiwz (void); |
| 138 | 135 | void do_fnmadd (void); |
| 139 | 136 | void do_fnmsub (void); |
| 140 | -void do_fnmadds (void); | |
| 141 | -void do_fnmsubs (void); | |
| 142 | 137 | void do_fsqrt (void); |
| 143 | -void do_fsqrts (void); | |
| 144 | 138 | void do_fres (void); |
| 145 | -void do_fsqrte (void); | |
| 139 | +void do_frsqrte (void); | |
| 146 | 140 | void do_fsel (void); |
| 147 | 141 | void do_fcmpu (void); |
| 148 | 142 | void do_fcmpo (void); |
| 149 | -void do_fabs (void); | |
| 150 | -void do_fnabs (void); | |
| 151 | 143 | |
| 152 | 144 | void do_check_reservation (void); |
| 153 | 145 | void do_icbi (void); | ... | ... |
target-ppc/helper.c
| ... | ... | @@ -809,6 +809,7 @@ void do_interrupt (CPUState *env) |
| 809 | 809 | msr |= 0x00010000; |
| 810 | 810 | goto store_current; |
| 811 | 811 | case EXCP_NO_FP: |
| 812 | + msr &= ~0xFFFF0000; | |
| 812 | 813 | goto store_current; |
| 813 | 814 | case EXCP_DECR: |
| 814 | 815 | if (msr_ee == 0) { |
| ... | ... | @@ -854,7 +855,6 @@ void do_interrupt (CPUState *env) |
| 854 | 855 | return; |
| 855 | 856 | case EXCP_RFI: |
| 856 | 857 | /* Restore user-mode state */ |
| 857 | - tb_flush(env); | |
| 858 | 858 | #if defined (DEBUG_EXCEPTIONS) |
| 859 | 859 | if (msr_pr == 1) |
| 860 | 860 | printf("Return from exception => 0x%08x\n", (uint32_t)env->nip); |
| ... | ... | @@ -887,7 +887,6 @@ void do_interrupt (CPUState *env) |
| 887 | 887 | env->nip = excp << 8; |
| 888 | 888 | env->exception_index = EXCP_NONE; |
| 889 | 889 | /* Invalidate all TLB as we may have changed translation mode */ |
| 890 | - tlb_flush(env, 1); | |
| 891 | 890 | /* ensure that no TB jump will be modified as |
| 892 | 891 | the program flow was changed */ |
| 893 | 892 | #ifdef __sparc__ | ... | ... |
target-ppc/op.c
| ... | ... | @@ -32,10 +32,6 @@ |
| 32 | 32 | #define FT1 (env->ft1) |
| 33 | 33 | #define FT2 (env->ft2) |
| 34 | 34 | |
| 35 | -#define FTS0 ((float)env->ft0) | |
| 36 | -#define FTS1 ((float)env->ft1) | |
| 37 | -#define FTS2 ((float)env->ft2) | |
| 38 | - | |
| 39 | 35 | #define PPC_OP(name) void glue(op_, name)(void) |
| 40 | 36 | |
| 41 | 37 | #define REG 0 |
| ... | ... | @@ -1204,13 +1200,6 @@ PPC_OP(fadd) |
| 1204 | 1200 | RETURN(); |
| 1205 | 1201 | } |
| 1206 | 1202 | |
| 1207 | -/* fadds - fadds. */ | |
| 1208 | -PPC_OP(fadds) | |
| 1209 | -{ | |
| 1210 | - FT0 = FTS0 + FTS1; | |
| 1211 | - RETURN(); | |
| 1212 | -} | |
| 1213 | - | |
| 1214 | 1203 | /* fsub - fsub. */ |
| 1215 | 1204 | PPC_OP(fsub) |
| 1216 | 1205 | { |
| ... | ... | @@ -1218,13 +1207,6 @@ PPC_OP(fsub) |
| 1218 | 1207 | RETURN(); |
| 1219 | 1208 | } |
| 1220 | 1209 | |
| 1221 | -/* fsubs - fsubs. */ | |
| 1222 | -PPC_OP(fsubs) | |
| 1223 | -{ | |
| 1224 | - FT0 = FTS0 - FTS1; | |
| 1225 | - RETURN(); | |
| 1226 | -} | |
| 1227 | - | |
| 1228 | 1210 | /* fmul - fmul. */ |
| 1229 | 1211 | PPC_OP(fmul) |
| 1230 | 1212 | { |
| ... | ... | @@ -1232,24 +1214,11 @@ PPC_OP(fmul) |
| 1232 | 1214 | RETURN(); |
| 1233 | 1215 | } |
| 1234 | 1216 | |
| 1235 | -/* fmuls - fmuls. */ | |
| 1236 | -PPC_OP(fmuls) | |
| 1237 | -{ | |
| 1238 | - FT0 = FTS0 * FTS1; | |
| 1239 | - RETURN(); | |
| 1240 | -} | |
| 1241 | - | |
| 1242 | 1217 | /* fdiv - fdiv. */ |
| 1218 | +void do_fdiv (void); | |
| 1243 | 1219 | PPC_OP(fdiv) |
| 1244 | 1220 | { |
| 1245 | - FT0 /= FT1; | |
| 1246 | - RETURN(); | |
| 1247 | -} | |
| 1248 | - | |
| 1249 | -/* fdivs - fdivs. */ | |
| 1250 | -PPC_OP(fdivs) | |
| 1251 | -{ | |
| 1252 | - FT0 = FTS0 / FTS1; | |
| 1221 | + do_fdiv(); | |
| 1253 | 1222 | RETURN(); |
| 1254 | 1223 | } |
| 1255 | 1224 | |
| ... | ... | @@ -1260,13 +1229,6 @@ PPC_OP(fsqrt) |
| 1260 | 1229 | RETURN(); |
| 1261 | 1230 | } |
| 1262 | 1231 | |
| 1263 | -/* fsqrts - fsqrts. */ | |
| 1264 | -PPC_OP(fsqrts) | |
| 1265 | -{ | |
| 1266 | - do_fsqrts(); | |
| 1267 | - RETURN(); | |
| 1268 | -} | |
| 1269 | - | |
| 1270 | 1232 | /* fres - fres. */ |
| 1271 | 1233 | PPC_OP(fres) |
| 1272 | 1234 | { |
| ... | ... | @@ -1277,7 +1239,7 @@ PPC_OP(fres) |
| 1277 | 1239 | /* frsqrte - frsqrte. */ |
| 1278 | 1240 | PPC_OP(frsqrte) |
| 1279 | 1241 | { |
| 1280 | - do_fsqrte(); | |
| 1242 | + do_frsqrte(); | |
| 1281 | 1243 | RETURN(); |
| 1282 | 1244 | } |
| 1283 | 1245 | |
| ... | ... | @@ -1296,13 +1258,6 @@ PPC_OP(fmadd) |
| 1296 | 1258 | RETURN(); |
| 1297 | 1259 | } |
| 1298 | 1260 | |
| 1299 | -/* fmadds - fmadds. */ | |
| 1300 | -PPC_OP(fmadds) | |
| 1301 | -{ | |
| 1302 | - FT0 = (FTS0 * FTS1) + FTS2; | |
| 1303 | - RETURN(); | |
| 1304 | -} | |
| 1305 | - | |
| 1306 | 1261 | /* fmsub - fmsub. */ |
| 1307 | 1262 | PPC_OP(fmsub) |
| 1308 | 1263 | { |
| ... | ... | @@ -1310,13 +1265,6 @@ PPC_OP(fmsub) |
| 1310 | 1265 | RETURN(); |
| 1311 | 1266 | } |
| 1312 | 1267 | |
| 1313 | -/* fmsubs - fmsubs. */ | |
| 1314 | -PPC_OP(fmsubs) | |
| 1315 | -{ | |
| 1316 | - FT0 = (FTS0 * FTS1) - FTS2; | |
| 1317 | - RETURN(); | |
| 1318 | -} | |
| 1319 | - | |
| 1320 | 1268 | /* fnmadd - fnmadd. - fnmadds - fnmadds. */ |
| 1321 | 1269 | PPC_OP(fnmadd) |
| 1322 | 1270 | { |
| ... | ... | @@ -1324,13 +1272,6 @@ PPC_OP(fnmadd) |
| 1324 | 1272 | RETURN(); |
| 1325 | 1273 | } |
| 1326 | 1274 | |
| 1327 | -/* fnmadds - fnmadds. */ | |
| 1328 | -PPC_OP(fnmadds) | |
| 1329 | -{ | |
| 1330 | - do_fnmadds(); | |
| 1331 | - RETURN(); | |
| 1332 | -} | |
| 1333 | - | |
| 1334 | 1275 | /* fnmsub - fnmsub. */ |
| 1335 | 1276 | PPC_OP(fnmsub) |
| 1336 | 1277 | { |
| ... | ... | @@ -1338,13 +1279,6 @@ PPC_OP(fnmsub) |
| 1338 | 1279 | RETURN(); |
| 1339 | 1280 | } |
| 1340 | 1281 | |
| 1341 | -/* fnmsubs - fnmsubs. */ | |
| 1342 | -PPC_OP(fnmsubs) | |
| 1343 | -{ | |
| 1344 | - do_fnmsubs(); | |
| 1345 | - RETURN(); | |
| 1346 | -} | |
| 1347 | - | |
| 1348 | 1282 | /*** Floating-Point round & convert ***/ |
| 1349 | 1283 | /* frsp - frsp. */ |
| 1350 | 1284 | PPC_OP(frsp) |
| ... | ... | @@ -1385,6 +1319,7 @@ PPC_OP(fcmpo) |
| 1385 | 1319 | |
| 1386 | 1320 | /*** Floating-point move ***/ |
| 1387 | 1321 | /* fabs */ |
| 1322 | +void do_fabs (void); | |
| 1388 | 1323 | PPC_OP(fabs) |
| 1389 | 1324 | { |
| 1390 | 1325 | do_fabs(); |
| ... | ... | @@ -1392,6 +1327,7 @@ PPC_OP(fabs) |
| 1392 | 1327 | } |
| 1393 | 1328 | |
| 1394 | 1329 | /* fnabs */ |
| 1330 | +void do_fnabs (void); | |
| 1395 | 1331 | PPC_OP(fnabs) |
| 1396 | 1332 | { |
| 1397 | 1333 | do_fnabs(); | ... | ... |
target-ppc/op_helper.c
| ... | ... | @@ -213,7 +213,7 @@ void do_store_fpscr (uint32_t mask) |
| 213 | 213 | uint32_t u[2]; |
| 214 | 214 | } s; |
| 215 | 215 | } u; |
| 216 | - int i; | |
| 216 | + int i, rnd_type; | |
| 217 | 217 | |
| 218 | 218 | u.d = FT0; |
| 219 | 219 | if (mask & 0x80) |
| ... | ... | @@ -227,21 +227,23 @@ void do_store_fpscr (uint32_t mask) |
| 227 | 227 | switch (env->fpscr[0] & 0x3) { |
| 228 | 228 | case 0: |
| 229 | 229 | /* Best approximation (round to nearest) */ |
| 230 | - fesetround(FE_TONEAREST); | |
| 230 | + rnd_type = float_round_nearest_even; | |
| 231 | 231 | break; |
| 232 | 232 | case 1: |
| 233 | 233 | /* Smaller magnitude (round toward zero) */ |
| 234 | - fesetround(FE_TOWARDZERO); | |
| 234 | + rnd_type = float_round_to_zero; | |
| 235 | 235 | break; |
| 236 | 236 | case 2: |
| 237 | 237 | /* Round toward +infinite */ |
| 238 | - fesetround(FE_UPWARD); | |
| 238 | + rnd_type = float_round_up; | |
| 239 | 239 | break; |
| 240 | + default: | |
| 240 | 241 | case 3: |
| 241 | 242 | /* Round toward -infinite */ |
| 242 | - fesetround(FE_DOWNWARD); | |
| 243 | + rnd_type = float_round_down; | |
| 243 | 244 | break; |
| 244 | 245 | } |
| 246 | + set_float_rounding_mode(rnd_type, &env->fp_status); | |
| 245 | 247 | } |
| 246 | 248 | |
| 247 | 249 | void do_fctiw (void) |
| ... | ... | @@ -249,16 +251,14 @@ void do_fctiw (void) |
| 249 | 251 | union { |
| 250 | 252 | double d; |
| 251 | 253 | uint64_t i; |
| 252 | - } *p = (void *)&FT1; | |
| 254 | + } p; | |
| 253 | 255 | |
| 254 | - if (FT0 > (double)0x7FFFFFFF) | |
| 255 | - p->i = 0x7FFFFFFFULL << 32; | |
| 256 | - else if (FT0 < -(double)0x80000000) | |
| 257 | - p->i = 0x80000000ULL << 32; | |
| 258 | - else | |
| 259 | - p->i = 0; | |
| 260 | - p->i |= (uint32_t)FT0; | |
| 261 | - FT0 = p->d; | |
| 256 | + /* XXX: higher bits are not supposed to be significant. | |
| 257 | + * to make tests easier, return the same as a real PPC 750 (aka G3) | |
| 258 | + */ | |
| 259 | + p.i = float64_to_int32(FT0, &env->fp_status); | |
| 260 | + p.i |= 0xFFF80000ULL << 32; | |
| 261 | + FT0 = p.d; | |
| 262 | 262 | } |
| 263 | 263 | |
| 264 | 264 | void do_fctiwz (void) |
| ... | ... | @@ -266,39 +266,36 @@ void do_fctiwz (void) |
| 266 | 266 | union { |
| 267 | 267 | double d; |
| 268 | 268 | uint64_t i; |
| 269 | - } *p = (void *)&FT1; | |
| 270 | - int cround = fegetround(); | |
| 271 | - | |
| 272 | - fesetround(FE_TOWARDZERO); | |
| 273 | - if (FT0 > (double)0x7FFFFFFF) | |
| 274 | - p->i = 0x7FFFFFFFULL << 32; | |
| 275 | - else if (FT0 < -(double)0x80000000) | |
| 276 | - p->i = 0x80000000ULL << 32; | |
| 277 | - else | |
| 278 | - p->i = 0; | |
| 279 | - p->i |= (uint32_t)FT0; | |
| 280 | - FT0 = p->d; | |
| 281 | - fesetround(cround); | |
| 269 | + } p; | |
| 270 | + | |
| 271 | + /* XXX: higher bits are not supposed to be significant. | |
| 272 | + * to make tests easier, return the same as a real PPC 750 (aka G3) | |
| 273 | + */ | |
| 274 | + p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); | |
| 275 | + p.i |= 0xFFF80000ULL << 32; | |
| 276 | + FT0 = p.d; | |
| 282 | 277 | } |
| 283 | 278 | |
| 284 | 279 | void do_fnmadd (void) |
| 285 | 280 | { |
| 286 | - FT0 = -((FT0 * FT1) + FT2); | |
| 281 | + FT0 = (FT0 * FT1) + FT2; | |
| 282 | + if (!isnan(FT0)) | |
| 283 | + FT0 = -FT0; | |
| 287 | 284 | } |
| 288 | 285 | |
| 289 | 286 | void do_fnmsub (void) |
| 290 | 287 | { |
| 291 | - FT0 = -((FT0 * FT1) - FT2); | |
| 288 | + FT0 = (FT0 * FT1) - FT2; | |
| 289 | + if (!isnan(FT0)) | |
| 290 | + FT0 = -FT0; | |
| 292 | 291 | } |
| 293 | 292 | |
| 294 | -void do_fnmadds (void) | |
| 293 | +void do_fdiv (void) | |
| 295 | 294 | { |
| 296 | - FT0 = -((FTS0 * FTS1) + FTS2); | |
| 297 | -} | |
| 298 | - | |
| 299 | -void do_fnmsubs (void) | |
| 300 | -{ | |
| 301 | - FT0 = -((FTS0 * FTS1) - FTS2); | |
| 295 | + if (FT0 == -0.0 && FT1 == -0.0) | |
| 296 | + FT0 = 0.0 / 0.0; | |
| 297 | + else | |
| 298 | + FT0 /= FT1; | |
| 302 | 299 | } |
| 303 | 300 | |
| 304 | 301 | void do_fsqrt (void) |
| ... | ... | @@ -306,27 +303,65 @@ void do_fsqrt (void) |
| 306 | 303 | FT0 = sqrt(FT0); |
| 307 | 304 | } |
| 308 | 305 | |
| 309 | -void do_fsqrts (void) | |
| 310 | -{ | |
| 311 | - FT0 = (float)sqrt((float)FT0); | |
| 312 | -} | |
| 313 | - | |
| 314 | 306 | void do_fres (void) |
| 315 | 307 | { |
| 316 | - FT0 = 1.0 / FT0; | |
| 308 | + union { | |
| 309 | + double d; | |
| 310 | + uint64_t i; | |
| 311 | + } p; | |
| 312 | + | |
| 313 | + if (isnormal(FT0)) { | |
| 314 | + FT0 = (float)(1.0 / FT0); | |
| 315 | + } else { | |
| 316 | + p.d = FT0; | |
| 317 | + if (p.i == 0x8000000000000000ULL) { | |
| 318 | + p.i = 0xFFF0000000000000ULL; | |
| 319 | + } else if (p.i == 0x0000000000000000ULL) { | |
| 320 | + p.i = 0x7FF0000000000000ULL; | |
| 321 | + } else if (isnan(FT0)) { | |
| 322 | + p.i = 0x7FF8000000000000ULL; | |
| 323 | + } else if (FT0 < 0.0) { | |
| 324 | + p.i = 0x8000000000000000ULL; | |
| 325 | + } else { | |
| 326 | + p.i = 0x0000000000000000ULL; | |
| 327 | + } | |
| 328 | + FT0 = p.d; | |
| 329 | + } | |
| 317 | 330 | } |
| 318 | 331 | |
| 319 | -void do_fsqrte (void) | |
| 332 | +void do_frsqrte (void) | |
| 320 | 333 | { |
| 321 | - FT0 = 1.0 / sqrt(FT0); | |
| 334 | + union { | |
| 335 | + double d; | |
| 336 | + uint64_t i; | |
| 337 | + } p; | |
| 338 | + | |
| 339 | + if (isnormal(FT0) && FT0 > 0.0) { | |
| 340 | + FT0 = (float)(1.0 / sqrt(FT0)); | |
| 341 | + } else { | |
| 342 | + p.d = FT0; | |
| 343 | + if (p.i == 0x8000000000000000ULL) { | |
| 344 | + p.i = 0xFFF0000000000000ULL; | |
| 345 | + } else if (p.i == 0x0000000000000000ULL) { | |
| 346 | + p.i = 0x7FF0000000000000ULL; | |
| 347 | + } else if (isnan(FT0)) { | |
| 348 | + if (!(p.i & 0x0008000000000000ULL)) | |
| 349 | + p.i |= 0x000FFFFFFFFFFFFFULL; | |
| 350 | + } else if (FT0 < 0) { | |
| 351 | + p.i = 0x7FF8000000000000ULL; | |
| 352 | + } else { | |
| 353 | + p.i = 0x0000000000000000ULL; | |
| 354 | + } | |
| 355 | + FT0 = p.d; | |
| 356 | + } | |
| 322 | 357 | } |
| 323 | 358 | |
| 324 | 359 | void do_fsel (void) |
| 325 | 360 | { |
| 326 | 361 | if (FT0 >= 0) |
| 327 | - FT0 = FT2; | |
| 328 | - else | |
| 329 | 362 | FT0 = FT1; |
| 363 | + else | |
| 364 | + FT0 = FT2; | |
| 330 | 365 | } |
| 331 | 366 | |
| 332 | 367 | void do_fcmpu (void) |
| ... | ... | @@ -371,12 +406,26 @@ void do_fcmpo (void) |
| 371 | 406 | |
| 372 | 407 | void do_fabs (void) |
| 373 | 408 | { |
| 374 | - FT0 = fabsl(FT0); | |
| 409 | + union { | |
| 410 | + double d; | |
| 411 | + uint64_t i; | |
| 412 | + } p; | |
| 413 | + | |
| 414 | + p.d = FT0; | |
| 415 | + p.i &= ~0x8000000000000000ULL; | |
| 416 | + FT0 = p.d; | |
| 375 | 417 | } |
| 376 | 418 | |
| 377 | 419 | void do_fnabs (void) |
| 378 | 420 | { |
| 379 | - FT0 = -fabsl(FT0); | |
| 421 | + union { | |
| 422 | + double d; | |
| 423 | + uint64_t i; | |
| 424 | + } p; | |
| 425 | + | |
| 426 | + p.d = FT0; | |
| 427 | + p.i |= 0x8000000000000000ULL; | |
| 428 | + FT0 = p.d; | |
| 380 | 429 | } |
| 381 | 430 | |
| 382 | 431 | /* Instruction cache invalidation helper */ | ... | ... |
target-ppc/translate.c
| ... | ... | @@ -740,6 +740,7 @@ __GEN_LOGICAL2(sraw, 0x18, 0x18); |
| 740 | 740 | GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER) |
| 741 | 741 | { |
| 742 | 742 | gen_op_load_gpr_T0(rS(ctx->opcode)); |
| 743 | + if (SH(ctx->opcode) != 0) | |
| 743 | 744 | gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31)); |
| 744 | 745 | if (Rc(ctx->opcode) != 0) |
| 745 | 746 | gen_op_set_Rc0(); |
| ... | ... | @@ -749,7 +750,7 @@ GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER) |
| 749 | 750 | __GEN_LOGICAL2(srw, 0x18, 0x10); |
| 750 | 751 | |
| 751 | 752 | /*** Floating-Point arithmetic ***/ |
| 752 | -#define _GEN_FLOAT_ACB(name, op1, op2) \ | |
| 753 | +#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \ | |
| 753 | 754 | GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ |
| 754 | 755 | { \ |
| 755 | 756 | if (!ctx->fpu_enabled) { \ |
| ... | ... | @@ -760,17 +761,20 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ |
| 760 | 761 | gen_op_load_fpr_FT0(rA(ctx->opcode)); \ |
| 761 | 762 | gen_op_load_fpr_FT1(rC(ctx->opcode)); \ |
| 762 | 763 | gen_op_load_fpr_FT2(rB(ctx->opcode)); \ |
| 763 | - gen_op_f##name(); \ | |
| 764 | + gen_op_f##op(); \ | |
| 765 | + if (isfloat) { \ | |
| 766 | + gen_op_frsp(); \ | |
| 767 | + } \ | |
| 764 | 768 | gen_op_store_FT0_fpr(rD(ctx->opcode)); \ |
| 765 | 769 | if (Rc(ctx->opcode)) \ |
| 766 | 770 | gen_op_set_Rc1(); \ |
| 767 | 771 | } |
| 768 | 772 | |
| 769 | 773 | #define GEN_FLOAT_ACB(name, op2) \ |
| 770 | -_GEN_FLOAT_ACB(name, 0x3F, op2); \ | |
| 771 | -_GEN_FLOAT_ACB(name##s, 0x3B, op2); | |
| 774 | +_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \ | |
| 775 | +_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1); | |
| 772 | 776 | |
| 773 | -#define _GEN_FLOAT_AB(name, op1, op2, inval) \ | |
| 777 | +#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \ | |
| 774 | 778 | GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ |
| 775 | 779 | { \ |
| 776 | 780 | if (!ctx->fpu_enabled) { \ |
| ... | ... | @@ -780,16 +784,19 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ |
| 780 | 784 | gen_op_reset_scrfx(); \ |
| 781 | 785 | gen_op_load_fpr_FT0(rA(ctx->opcode)); \ |
| 782 | 786 | gen_op_load_fpr_FT1(rB(ctx->opcode)); \ |
| 783 | - gen_op_f##name(); \ | |
| 787 | + gen_op_f##op(); \ | |
| 788 | + if (isfloat) { \ | |
| 789 | + gen_op_frsp(); \ | |
| 790 | + } \ | |
| 784 | 791 | gen_op_store_FT0_fpr(rD(ctx->opcode)); \ |
| 785 | 792 | if (Rc(ctx->opcode)) \ |
| 786 | 793 | gen_op_set_Rc1(); \ |
| 787 | 794 | } |
| 788 | 795 | #define GEN_FLOAT_AB(name, op2, inval) \ |
| 789 | -_GEN_FLOAT_AB(name, 0x3F, op2, inval); \ | |
| 790 | -_GEN_FLOAT_AB(name##s, 0x3B, op2, inval); | |
| 796 | +_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \ | |
| 797 | +_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1); | |
| 791 | 798 | |
| 792 | -#define _GEN_FLOAT_AC(name, op1, op2, inval) \ | |
| 799 | +#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \ | |
| 793 | 800 | GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ |
| 794 | 801 | { \ |
| 795 | 802 | if (!ctx->fpu_enabled) { \ |
| ... | ... | @@ -799,14 +806,17 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ |
| 799 | 806 | gen_op_reset_scrfx(); \ |
| 800 | 807 | gen_op_load_fpr_FT0(rA(ctx->opcode)); \ |
| 801 | 808 | gen_op_load_fpr_FT1(rC(ctx->opcode)); \ |
| 802 | - gen_op_f##name(); \ | |
| 809 | + gen_op_f##op(); \ | |
| 810 | + if (isfloat) { \ | |
| 811 | + gen_op_frsp(); \ | |
| 812 | + } \ | |
| 803 | 813 | gen_op_store_FT0_fpr(rD(ctx->opcode)); \ |
| 804 | 814 | if (Rc(ctx->opcode)) \ |
| 805 | 815 | gen_op_set_Rc1(); \ |
| 806 | 816 | } |
| 807 | 817 | #define GEN_FLOAT_AC(name, op2, inval) \ |
| 808 | -_GEN_FLOAT_AC(name, 0x3F, op2, inval); \ | |
| 809 | -_GEN_FLOAT_AC(name##s, 0x3B, op2, inval); | |
| 818 | +_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \ | |
| 819 | +_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1); | |
| 810 | 820 | |
| 811 | 821 | #define GEN_FLOAT_B(name, op2, op3) \ |
| 812 | 822 | GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ |
| ... | ... | @@ -823,8 +833,8 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ |
| 823 | 833 | gen_op_set_Rc1(); \ |
| 824 | 834 | } |
| 825 | 835 | |
| 826 | -#define GEN_FLOAT_BS(name, op2) \ | |
| 827 | -GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ | |
| 836 | +#define GEN_FLOAT_BS(name, op1, op2) \ | |
| 837 | +GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ | |
| 828 | 838 | { \ |
| 829 | 839 | if (!ctx->fpu_enabled) { \ |
| 830 | 840 | RET_EXCP(ctx, EXCP_NO_FP, 0); \ |
| ... | ... | @@ -840,24 +850,24 @@ GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ |
| 840 | 850 | |
| 841 | 851 | /* fadd - fadds */ |
| 842 | 852 | GEN_FLOAT_AB(add, 0x15, 0x000007C0); |
| 843 | -/* fdiv */ | |
| 853 | +/* fdiv - fdivs */ | |
| 844 | 854 | GEN_FLOAT_AB(div, 0x12, 0x000007C0); |
| 845 | -/* fmul */ | |
| 855 | +/* fmul - fmuls */ | |
| 846 | 856 | GEN_FLOAT_AC(mul, 0x19, 0x0000F800); |
| 847 | 857 | |
| 848 | 858 | /* fres */ |
| 849 | -GEN_FLOAT_BS(res, 0x18); | |
| 859 | +GEN_FLOAT_BS(res, 0x3B, 0x18); | |
| 850 | 860 | |
| 851 | 861 | /* frsqrte */ |
| 852 | -GEN_FLOAT_BS(rsqrte, 0x1A); | |
| 862 | +GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A); | |
| 853 | 863 | |
| 854 | 864 | /* fsel */ |
| 855 | -_GEN_FLOAT_ACB(sel, 0x3F, 0x17); | |
| 856 | -/* fsub */ | |
| 865 | +_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0); | |
| 866 | +/* fsub - fsubs */ | |
| 857 | 867 | GEN_FLOAT_AB(sub, 0x14, 0x000007C0); |
| 858 | 868 | /* Optional: */ |
| 859 | 869 | /* fsqrt */ |
| 860 | -GEN_FLOAT_BS(sqrt, 0x16); | |
| 870 | +GEN_FLOAT_BS(sqrt, 0x3F, 0x16); | |
| 861 | 871 | |
| 862 | 872 | GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) |
| 863 | 873 | { |
| ... | ... | @@ -867,20 +877,21 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) |
| 867 | 877 | } |
| 868 | 878 | gen_op_reset_scrfx(); |
| 869 | 879 | gen_op_load_fpr_FT0(rB(ctx->opcode)); |
| 870 | - gen_op_fsqrts(); | |
| 880 | + gen_op_fsqrt(); | |
| 881 | + gen_op_frsp(); | |
| 871 | 882 | gen_op_store_FT0_fpr(rD(ctx->opcode)); |
| 872 | 883 | if (Rc(ctx->opcode)) |
| 873 | 884 | gen_op_set_Rc1(); |
| 874 | 885 | } |
| 875 | 886 | |
| 876 | 887 | /*** Floating-Point multiply-and-add ***/ |
| 877 | -/* fmadd */ | |
| 888 | +/* fmadd - fmadds */ | |
| 878 | 889 | GEN_FLOAT_ACB(madd, 0x1D); |
| 879 | -/* fmsub */ | |
| 890 | +/* fmsub - fmsubs */ | |
| 880 | 891 | GEN_FLOAT_ACB(msub, 0x1C); |
| 881 | -/* fnmadd */ | |
| 892 | +/* fnmadd - fnmadds */ | |
| 882 | 893 | GEN_FLOAT_ACB(nmadd, 0x1F); |
| 883 | -/* fnmsub */ | |
| 894 | +/* fnmsub - fnmsubs */ | |
| 884 | 895 | GEN_FLOAT_ACB(nmsub, 0x1E); |
| 885 | 896 | |
| 886 | 897 | /*** Floating-Point round & convert ***/ |
| ... | ... | @@ -1426,6 +1437,10 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM) |
| 1426 | 1437 | GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1427 | 1438 | { \ |
| 1428 | 1439 | uint32_t simm = SIMM(ctx->opcode); \ |
| 1440 | + if (!ctx->fpu_enabled) { \ | |
| 1441 | + RET_EXCP(ctx, EXCP_NO_FP, 0); \ | |
| 1442 | + return; \ | |
| 1443 | + } \ | |
| 1429 | 1444 | if (rA(ctx->opcode) == 0) { \ |
| 1430 | 1445 | gen_op_set_T0(simm); \ |
| 1431 | 1446 | } else { \ |
| ... | ... | @@ -1441,6 +1456,10 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1441 | 1456 | GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1442 | 1457 | { \ |
| 1443 | 1458 | uint32_t simm = SIMM(ctx->opcode); \ |
| 1459 | + if (!ctx->fpu_enabled) { \ | |
| 1460 | + RET_EXCP(ctx, EXCP_NO_FP, 0); \ | |
| 1461 | + return; \ | |
| 1462 | + } \ | |
| 1444 | 1463 | if (rA(ctx->opcode) == 0 || \ |
| 1445 | 1464 | rA(ctx->opcode) == rD(ctx->opcode)) { \ |
| 1446 | 1465 | RET_INVAL(ctx); \ |
| ... | ... | @@ -1457,6 +1476,10 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1457 | 1476 | #define GEN_LDUXF(width, opc) \ |
| 1458 | 1477 | GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ |
| 1459 | 1478 | { \ |
| 1479 | + if (!ctx->fpu_enabled) { \ | |
| 1480 | + RET_EXCP(ctx, EXCP_NO_FP, 0); \ | |
| 1481 | + return; \ | |
| 1482 | + } \ | |
| 1460 | 1483 | if (rA(ctx->opcode) == 0 || \ |
| 1461 | 1484 | rA(ctx->opcode) == rD(ctx->opcode)) { \ |
| 1462 | 1485 | RET_INVAL(ctx); \ |
| ... | ... | @@ -1473,6 +1496,10 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ |
| 1473 | 1496 | #define GEN_LDXF(width, opc2, opc3) \ |
| 1474 | 1497 | GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ |
| 1475 | 1498 | { \ |
| 1499 | + if (!ctx->fpu_enabled) { \ | |
| 1500 | + RET_EXCP(ctx, EXCP_NO_FP, 0); \ | |
| 1501 | + return; \ | |
| 1502 | + } \ | |
| 1476 | 1503 | if (rA(ctx->opcode) == 0) { \ |
| 1477 | 1504 | gen_op_load_gpr_T0(rB(ctx->opcode)); \ |
| 1478 | 1505 | } else { \ |
| ... | ... | @@ -1501,6 +1528,10 @@ GEN_LDFS(fs, 0x10); |
| 1501 | 1528 | GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1502 | 1529 | { \ |
| 1503 | 1530 | uint32_t simm = SIMM(ctx->opcode); \ |
| 1531 | + if (!ctx->fpu_enabled) { \ | |
| 1532 | + RET_EXCP(ctx, EXCP_NO_FP, 0); \ | |
| 1533 | + return; \ | |
| 1534 | + } \ | |
| 1504 | 1535 | if (rA(ctx->opcode) == 0) { \ |
| 1505 | 1536 | gen_op_set_T0(simm); \ |
| 1506 | 1537 | } else { \ |
| ... | ... | @@ -1516,6 +1547,10 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1516 | 1547 | GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1517 | 1548 | { \ |
| 1518 | 1549 | uint32_t simm = SIMM(ctx->opcode); \ |
| 1550 | + if (!ctx->fpu_enabled) { \ | |
| 1551 | + RET_EXCP(ctx, EXCP_NO_FP, 0); \ | |
| 1552 | + return; \ | |
| 1553 | + } \ | |
| 1519 | 1554 | if (rA(ctx->opcode) == 0) { \ |
| 1520 | 1555 | RET_INVAL(ctx); \ |
| 1521 | 1556 | return; \ |
| ... | ... | @@ -1531,6 +1566,10 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1531 | 1566 | #define GEN_STUXF(width, opc) \ |
| 1532 | 1567 | GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ |
| 1533 | 1568 | { \ |
| 1569 | + if (!ctx->fpu_enabled) { \ | |
| 1570 | + RET_EXCP(ctx, EXCP_NO_FP, 0); \ | |
| 1571 | + return; \ | |
| 1572 | + } \ | |
| 1534 | 1573 | if (rA(ctx->opcode) == 0) { \ |
| 1535 | 1574 | RET_INVAL(ctx); \ |
| 1536 | 1575 | return; \ |
| ... | ... | @@ -1546,6 +1585,10 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ |
| 1546 | 1585 | #define GEN_STXF(width, opc2, opc3) \ |
| 1547 | 1586 | GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ |
| 1548 | 1587 | { \ |
| 1588 | + if (!ctx->fpu_enabled) { \ | |
| 1589 | + RET_EXCP(ctx, EXCP_NO_FP, 0); \ | |
| 1590 | + return; \ | |
| 1591 | + } \ | |
| 1549 | 1592 | if (rA(ctx->opcode) == 0) { \ |
| 1550 | 1593 | gen_op_load_gpr_T0(rB(ctx->opcode)); \ |
| 1551 | 1594 | } else { \ | ... | ... |