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 { \ | ... | ... |