fpu fixes (Jocelyn Mayer) - soft float support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1335 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
4c2e770f37
commit
4ecc31906d
|
@ -27,6 +27,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#include "softfloat.h"
|
||||||
|
|
||||||
/* Instruction types */
|
/* Instruction types */
|
||||||
enum {
|
enum {
|
||||||
PPC_NONE = 0x0000,
|
PPC_NONE = 0x0000,
|
||||||
|
@ -94,7 +96,7 @@ typedef struct CPUPPCState {
|
||||||
/* general purpose registers */
|
/* general purpose registers */
|
||||||
uint32_t gpr[32];
|
uint32_t gpr[32];
|
||||||
/* floating point registers */
|
/* floating point registers */
|
||||||
double fpr[32];
|
float64 fpr[32];
|
||||||
/* segment registers */
|
/* segment registers */
|
||||||
uint32_t sdr1;
|
uint32_t sdr1;
|
||||||
uint32_t sr[16];
|
uint32_t sr[16];
|
||||||
|
@ -119,9 +121,11 @@ typedef struct CPUPPCState {
|
||||||
uint32_t spr[1024];
|
uint32_t spr[1024];
|
||||||
/* qemu dedicated */
|
/* qemu dedicated */
|
||||||
/* temporary float registers */
|
/* temporary float registers */
|
||||||
double ft0;
|
float64 ft0;
|
||||||
double ft1;
|
float64 ft1;
|
||||||
double ft2;
|
float64 ft2;
|
||||||
|
float_status fp_status;
|
||||||
|
|
||||||
int interrupt_request;
|
int interrupt_request;
|
||||||
jmp_buf jmp_env;
|
jmp_buf jmp_env;
|
||||||
int exception_index;
|
int exception_index;
|
||||||
|
|
|
@ -32,9 +32,6 @@ register uint32_t T2 asm(AREG3);
|
||||||
#define FT0 (env->ft0)
|
#define FT0 (env->ft0)
|
||||||
#define FT1 (env->ft1)
|
#define FT1 (env->ft1)
|
||||||
#define FT2 (env->ft2)
|
#define FT2 (env->ft2)
|
||||||
#define FTS0 ((float)env->ft0)
|
|
||||||
#define FTS1 ((float)env->ft1)
|
|
||||||
#define FTS2 ((float)env->ft2)
|
|
||||||
|
|
||||||
#if defined (DEBUG_OP)
|
#if defined (DEBUG_OP)
|
||||||
#define RETURN() __asm__ __volatile__("nop");
|
#define RETURN() __asm__ __volatile__("nop");
|
||||||
|
@ -137,17 +134,12 @@ void do_fctiw (void);
|
||||||
void do_fctiwz (void);
|
void do_fctiwz (void);
|
||||||
void do_fnmadd (void);
|
void do_fnmadd (void);
|
||||||
void do_fnmsub (void);
|
void do_fnmsub (void);
|
||||||
void do_fnmadds (void);
|
|
||||||
void do_fnmsubs (void);
|
|
||||||
void do_fsqrt (void);
|
void do_fsqrt (void);
|
||||||
void do_fsqrts (void);
|
|
||||||
void do_fres (void);
|
void do_fres (void);
|
||||||
void do_fsqrte (void);
|
void do_frsqrte (void);
|
||||||
void do_fsel (void);
|
void do_fsel (void);
|
||||||
void do_fcmpu (void);
|
void do_fcmpu (void);
|
||||||
void do_fcmpo (void);
|
void do_fcmpo (void);
|
||||||
void do_fabs (void);
|
|
||||||
void do_fnabs (void);
|
|
||||||
|
|
||||||
void do_check_reservation (void);
|
void do_check_reservation (void);
|
||||||
void do_icbi (void);
|
void do_icbi (void);
|
||||||
|
|
|
@ -809,6 +809,7 @@ void do_interrupt (CPUState *env)
|
||||||
msr |= 0x00010000;
|
msr |= 0x00010000;
|
||||||
goto store_current;
|
goto store_current;
|
||||||
case EXCP_NO_FP:
|
case EXCP_NO_FP:
|
||||||
|
msr &= ~0xFFFF0000;
|
||||||
goto store_current;
|
goto store_current;
|
||||||
case EXCP_DECR:
|
case EXCP_DECR:
|
||||||
if (msr_ee == 0) {
|
if (msr_ee == 0) {
|
||||||
|
@ -854,7 +855,6 @@ void do_interrupt (CPUState *env)
|
||||||
return;
|
return;
|
||||||
case EXCP_RFI:
|
case EXCP_RFI:
|
||||||
/* Restore user-mode state */
|
/* Restore user-mode state */
|
||||||
tb_flush(env);
|
|
||||||
#if defined (DEBUG_EXCEPTIONS)
|
#if defined (DEBUG_EXCEPTIONS)
|
||||||
if (msr_pr == 1)
|
if (msr_pr == 1)
|
||||||
printf("Return from exception => 0x%08x\n", (uint32_t)env->nip);
|
printf("Return from exception => 0x%08x\n", (uint32_t)env->nip);
|
||||||
|
@ -887,7 +887,6 @@ void do_interrupt (CPUState *env)
|
||||||
env->nip = excp << 8;
|
env->nip = excp << 8;
|
||||||
env->exception_index = EXCP_NONE;
|
env->exception_index = EXCP_NONE;
|
||||||
/* Invalidate all TLB as we may have changed translation mode */
|
/* Invalidate all TLB as we may have changed translation mode */
|
||||||
tlb_flush(env, 1);
|
|
||||||
/* ensure that no TB jump will be modified as
|
/* ensure that no TB jump will be modified as
|
||||||
the program flow was changed */
|
the program flow was changed */
|
||||||
#ifdef __sparc__
|
#ifdef __sparc__
|
||||||
|
|
|
@ -32,10 +32,6 @@
|
||||||
#define FT1 (env->ft1)
|
#define FT1 (env->ft1)
|
||||||
#define FT2 (env->ft2)
|
#define FT2 (env->ft2)
|
||||||
|
|
||||||
#define FTS0 ((float)env->ft0)
|
|
||||||
#define FTS1 ((float)env->ft1)
|
|
||||||
#define FTS2 ((float)env->ft2)
|
|
||||||
|
|
||||||
#define PPC_OP(name) void glue(op_, name)(void)
|
#define PPC_OP(name) void glue(op_, name)(void)
|
||||||
|
|
||||||
#define REG 0
|
#define REG 0
|
||||||
|
@ -1204,13 +1200,6 @@ PPC_OP(fadd)
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fadds - fadds. */
|
|
||||||
PPC_OP(fadds)
|
|
||||||
{
|
|
||||||
FT0 = FTS0 + FTS1;
|
|
||||||
RETURN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fsub - fsub. */
|
/* fsub - fsub. */
|
||||||
PPC_OP(fsub)
|
PPC_OP(fsub)
|
||||||
{
|
{
|
||||||
|
@ -1218,13 +1207,6 @@ PPC_OP(fsub)
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fsubs - fsubs. */
|
|
||||||
PPC_OP(fsubs)
|
|
||||||
{
|
|
||||||
FT0 = FTS0 - FTS1;
|
|
||||||
RETURN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fmul - fmul. */
|
/* fmul - fmul. */
|
||||||
PPC_OP(fmul)
|
PPC_OP(fmul)
|
||||||
{
|
{
|
||||||
|
@ -1232,24 +1214,11 @@ PPC_OP(fmul)
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fmuls - fmuls. */
|
|
||||||
PPC_OP(fmuls)
|
|
||||||
{
|
|
||||||
FT0 = FTS0 * FTS1;
|
|
||||||
RETURN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fdiv - fdiv. */
|
/* fdiv - fdiv. */
|
||||||
|
void do_fdiv (void);
|
||||||
PPC_OP(fdiv)
|
PPC_OP(fdiv)
|
||||||
{
|
{
|
||||||
FT0 /= FT1;
|
do_fdiv();
|
||||||
RETURN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fdivs - fdivs. */
|
|
||||||
PPC_OP(fdivs)
|
|
||||||
{
|
|
||||||
FT0 = FTS0 / FTS1;
|
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1260,13 +1229,6 @@ PPC_OP(fsqrt)
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fsqrts - fsqrts. */
|
|
||||||
PPC_OP(fsqrts)
|
|
||||||
{
|
|
||||||
do_fsqrts();
|
|
||||||
RETURN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fres - fres. */
|
/* fres - fres. */
|
||||||
PPC_OP(fres)
|
PPC_OP(fres)
|
||||||
{
|
{
|
||||||
|
@ -1277,7 +1239,7 @@ PPC_OP(fres)
|
||||||
/* frsqrte - frsqrte. */
|
/* frsqrte - frsqrte. */
|
||||||
PPC_OP(frsqrte)
|
PPC_OP(frsqrte)
|
||||||
{
|
{
|
||||||
do_fsqrte();
|
do_frsqrte();
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1296,13 +1258,6 @@ PPC_OP(fmadd)
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fmadds - fmadds. */
|
|
||||||
PPC_OP(fmadds)
|
|
||||||
{
|
|
||||||
FT0 = (FTS0 * FTS1) + FTS2;
|
|
||||||
RETURN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fmsub - fmsub. */
|
/* fmsub - fmsub. */
|
||||||
PPC_OP(fmsub)
|
PPC_OP(fmsub)
|
||||||
{
|
{
|
||||||
|
@ -1310,13 +1265,6 @@ PPC_OP(fmsub)
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fmsubs - fmsubs. */
|
|
||||||
PPC_OP(fmsubs)
|
|
||||||
{
|
|
||||||
FT0 = (FTS0 * FTS1) - FTS2;
|
|
||||||
RETURN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fnmadd - fnmadd. - fnmadds - fnmadds. */
|
/* fnmadd - fnmadd. - fnmadds - fnmadds. */
|
||||||
PPC_OP(fnmadd)
|
PPC_OP(fnmadd)
|
||||||
{
|
{
|
||||||
|
@ -1324,13 +1272,6 @@ PPC_OP(fnmadd)
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fnmadds - fnmadds. */
|
|
||||||
PPC_OP(fnmadds)
|
|
||||||
{
|
|
||||||
do_fnmadds();
|
|
||||||
RETURN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fnmsub - fnmsub. */
|
/* fnmsub - fnmsub. */
|
||||||
PPC_OP(fnmsub)
|
PPC_OP(fnmsub)
|
||||||
{
|
{
|
||||||
|
@ -1338,13 +1279,6 @@ PPC_OP(fnmsub)
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fnmsubs - fnmsubs. */
|
|
||||||
PPC_OP(fnmsubs)
|
|
||||||
{
|
|
||||||
do_fnmsubs();
|
|
||||||
RETURN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** Floating-Point round & convert ***/
|
/*** Floating-Point round & convert ***/
|
||||||
/* frsp - frsp. */
|
/* frsp - frsp. */
|
||||||
PPC_OP(frsp)
|
PPC_OP(frsp)
|
||||||
|
@ -1385,6 +1319,7 @@ PPC_OP(fcmpo)
|
||||||
|
|
||||||
/*** Floating-point move ***/
|
/*** Floating-point move ***/
|
||||||
/* fabs */
|
/* fabs */
|
||||||
|
void do_fabs (void);
|
||||||
PPC_OP(fabs)
|
PPC_OP(fabs)
|
||||||
{
|
{
|
||||||
do_fabs();
|
do_fabs();
|
||||||
|
@ -1392,6 +1327,7 @@ PPC_OP(fabs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fnabs */
|
/* fnabs */
|
||||||
|
void do_fnabs (void);
|
||||||
PPC_OP(fnabs)
|
PPC_OP(fnabs)
|
||||||
{
|
{
|
||||||
do_fnabs();
|
do_fnabs();
|
||||||
|
|
|
@ -213,7 +213,7 @@ void do_store_fpscr (uint32_t mask)
|
||||||
uint32_t u[2];
|
uint32_t u[2];
|
||||||
} s;
|
} s;
|
||||||
} u;
|
} u;
|
||||||
int i;
|
int i, rnd_type;
|
||||||
|
|
||||||
u.d = FT0;
|
u.d = FT0;
|
||||||
if (mask & 0x80)
|
if (mask & 0x80)
|
||||||
|
@ -227,21 +227,23 @@ void do_store_fpscr (uint32_t mask)
|
||||||
switch (env->fpscr[0] & 0x3) {
|
switch (env->fpscr[0] & 0x3) {
|
||||||
case 0:
|
case 0:
|
||||||
/* Best approximation (round to nearest) */
|
/* Best approximation (round to nearest) */
|
||||||
fesetround(FE_TONEAREST);
|
rnd_type = float_round_nearest_even;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* Smaller magnitude (round toward zero) */
|
/* Smaller magnitude (round toward zero) */
|
||||||
fesetround(FE_TOWARDZERO);
|
rnd_type = float_round_to_zero;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/* Round toward +infinite */
|
/* Round toward +infinite */
|
||||||
fesetround(FE_UPWARD);
|
rnd_type = float_round_up;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
case 3:
|
case 3:
|
||||||
/* Round toward -infinite */
|
/* Round toward -infinite */
|
||||||
fesetround(FE_DOWNWARD);
|
rnd_type = float_round_down;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
set_float_rounding_mode(rnd_type, &env->fp_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fctiw (void)
|
void do_fctiw (void)
|
||||||
|
@ -249,16 +251,14 @@ void do_fctiw (void)
|
||||||
union {
|
union {
|
||||||
double d;
|
double d;
|
||||||
uint64_t i;
|
uint64_t i;
|
||||||
} *p = (void *)&FT1;
|
} p;
|
||||||
|
|
||||||
if (FT0 > (double)0x7FFFFFFF)
|
/* XXX: higher bits are not supposed to be significant.
|
||||||
p->i = 0x7FFFFFFFULL << 32;
|
* to make tests easier, return the same as a real PPC 750 (aka G3)
|
||||||
else if (FT0 < -(double)0x80000000)
|
*/
|
||||||
p->i = 0x80000000ULL << 32;
|
p.i = float64_to_int32(FT0, &env->fp_status);
|
||||||
else
|
p.i |= 0xFFF80000ULL << 32;
|
||||||
p->i = 0;
|
FT0 = p.d;
|
||||||
p->i |= (uint32_t)FT0;
|
|
||||||
FT0 = p->d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fctiwz (void)
|
void do_fctiwz (void)
|
||||||
|
@ -266,39 +266,36 @@ void do_fctiwz (void)
|
||||||
union {
|
union {
|
||||||
double d;
|
double d;
|
||||||
uint64_t i;
|
uint64_t i;
|
||||||
} *p = (void *)&FT1;
|
} p;
|
||||||
int cround = fegetround();
|
|
||||||
|
|
||||||
fesetround(FE_TOWARDZERO);
|
/* XXX: higher bits are not supposed to be significant.
|
||||||
if (FT0 > (double)0x7FFFFFFF)
|
* to make tests easier, return the same as a real PPC 750 (aka G3)
|
||||||
p->i = 0x7FFFFFFFULL << 32;
|
*/
|
||||||
else if (FT0 < -(double)0x80000000)
|
p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
|
||||||
p->i = 0x80000000ULL << 32;
|
p.i |= 0xFFF80000ULL << 32;
|
||||||
else
|
FT0 = p.d;
|
||||||
p->i = 0;
|
|
||||||
p->i |= (uint32_t)FT0;
|
|
||||||
FT0 = p->d;
|
|
||||||
fesetround(cround);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fnmadd (void)
|
void do_fnmadd (void)
|
||||||
{
|
{
|
||||||
FT0 = -((FT0 * FT1) + FT2);
|
FT0 = (FT0 * FT1) + FT2;
|
||||||
|
if (!isnan(FT0))
|
||||||
|
FT0 = -FT0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fnmsub (void)
|
void do_fnmsub (void)
|
||||||
{
|
{
|
||||||
FT0 = -((FT0 * FT1) - FT2);
|
FT0 = (FT0 * FT1) - FT2;
|
||||||
|
if (!isnan(FT0))
|
||||||
|
FT0 = -FT0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fnmadds (void)
|
void do_fdiv (void)
|
||||||
{
|
{
|
||||||
FT0 = -((FTS0 * FTS1) + FTS2);
|
if (FT0 == -0.0 && FT1 == -0.0)
|
||||||
}
|
FT0 = 0.0 / 0.0;
|
||||||
|
else
|
||||||
void do_fnmsubs (void)
|
FT0 /= FT1;
|
||||||
{
|
|
||||||
FT0 = -((FTS0 * FTS1) - FTS2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fsqrt (void)
|
void do_fsqrt (void)
|
||||||
|
@ -306,27 +303,65 @@ void do_fsqrt (void)
|
||||||
FT0 = sqrt(FT0);
|
FT0 = sqrt(FT0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fsqrts (void)
|
|
||||||
{
|
|
||||||
FT0 = (float)sqrt((float)FT0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_fres (void)
|
void do_fres (void)
|
||||||
{
|
{
|
||||||
FT0 = 1.0 / FT0;
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t i;
|
||||||
|
} p;
|
||||||
|
|
||||||
|
if (isnormal(FT0)) {
|
||||||
|
FT0 = (float)(1.0 / FT0);
|
||||||
|
} else {
|
||||||
|
p.d = FT0;
|
||||||
|
if (p.i == 0x8000000000000000ULL) {
|
||||||
|
p.i = 0xFFF0000000000000ULL;
|
||||||
|
} else if (p.i == 0x0000000000000000ULL) {
|
||||||
|
p.i = 0x7FF0000000000000ULL;
|
||||||
|
} else if (isnan(FT0)) {
|
||||||
|
p.i = 0x7FF8000000000000ULL;
|
||||||
|
} else if (FT0 < 0.0) {
|
||||||
|
p.i = 0x8000000000000000ULL;
|
||||||
|
} else {
|
||||||
|
p.i = 0x0000000000000000ULL;
|
||||||
|
}
|
||||||
|
FT0 = p.d;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fsqrte (void)
|
void do_frsqrte (void)
|
||||||
{
|
{
|
||||||
FT0 = 1.0 / sqrt(FT0);
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t i;
|
||||||
|
} p;
|
||||||
|
|
||||||
|
if (isnormal(FT0) && FT0 > 0.0) {
|
||||||
|
FT0 = (float)(1.0 / sqrt(FT0));
|
||||||
|
} else {
|
||||||
|
p.d = FT0;
|
||||||
|
if (p.i == 0x8000000000000000ULL) {
|
||||||
|
p.i = 0xFFF0000000000000ULL;
|
||||||
|
} else if (p.i == 0x0000000000000000ULL) {
|
||||||
|
p.i = 0x7FF0000000000000ULL;
|
||||||
|
} else if (isnan(FT0)) {
|
||||||
|
if (!(p.i & 0x0008000000000000ULL))
|
||||||
|
p.i |= 0x000FFFFFFFFFFFFFULL;
|
||||||
|
} else if (FT0 < 0) {
|
||||||
|
p.i = 0x7FF8000000000000ULL;
|
||||||
|
} else {
|
||||||
|
p.i = 0x0000000000000000ULL;
|
||||||
|
}
|
||||||
|
FT0 = p.d;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fsel (void)
|
void do_fsel (void)
|
||||||
{
|
{
|
||||||
if (FT0 >= 0)
|
if (FT0 >= 0)
|
||||||
FT0 = FT2;
|
|
||||||
else
|
|
||||||
FT0 = FT1;
|
FT0 = FT1;
|
||||||
|
else
|
||||||
|
FT0 = FT2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fcmpu (void)
|
void do_fcmpu (void)
|
||||||
|
@ -371,12 +406,26 @@ void do_fcmpo (void)
|
||||||
|
|
||||||
void do_fabs (void)
|
void do_fabs (void)
|
||||||
{
|
{
|
||||||
FT0 = fabsl(FT0);
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t i;
|
||||||
|
} p;
|
||||||
|
|
||||||
|
p.d = FT0;
|
||||||
|
p.i &= ~0x8000000000000000ULL;
|
||||||
|
FT0 = p.d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_fnabs (void)
|
void do_fnabs (void)
|
||||||
{
|
{
|
||||||
FT0 = -fabsl(FT0);
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t i;
|
||||||
|
} p;
|
||||||
|
|
||||||
|
p.d = FT0;
|
||||||
|
p.i |= 0x8000000000000000ULL;
|
||||||
|
FT0 = p.d;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Instruction cache invalidation helper */
|
/* Instruction cache invalidation helper */
|
||||||
|
|
|
@ -740,6 +740,7 @@ __GEN_LOGICAL2(sraw, 0x18, 0x18);
|
||||||
GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
|
GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
|
||||||
{
|
{
|
||||||
gen_op_load_gpr_T0(rS(ctx->opcode));
|
gen_op_load_gpr_T0(rS(ctx->opcode));
|
||||||
|
if (SH(ctx->opcode) != 0)
|
||||||
gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
|
gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
|
||||||
if (Rc(ctx->opcode) != 0)
|
if (Rc(ctx->opcode) != 0)
|
||||||
gen_op_set_Rc0();
|
gen_op_set_Rc0();
|
||||||
|
@ -749,7 +750,7 @@ GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
|
||||||
__GEN_LOGICAL2(srw, 0x18, 0x10);
|
__GEN_LOGICAL2(srw, 0x18, 0x10);
|
||||||
|
|
||||||
/*** Floating-Point arithmetic ***/
|
/*** Floating-Point arithmetic ***/
|
||||||
#define _GEN_FLOAT_ACB(name, op1, op2) \
|
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \
|
||||||
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
|
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
|
||||||
{ \
|
{ \
|
||||||
if (!ctx->fpu_enabled) { \
|
if (!ctx->fpu_enabled) { \
|
||||||
|
@ -760,17 +761,20 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
|
||||||
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
|
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
|
||||||
gen_op_load_fpr_FT1(rC(ctx->opcode)); \
|
gen_op_load_fpr_FT1(rC(ctx->opcode)); \
|
||||||
gen_op_load_fpr_FT2(rB(ctx->opcode)); \
|
gen_op_load_fpr_FT2(rB(ctx->opcode)); \
|
||||||
gen_op_f##name(); \
|
gen_op_f##op(); \
|
||||||
|
if (isfloat) { \
|
||||||
|
gen_op_frsp(); \
|
||||||
|
} \
|
||||||
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
||||||
if (Rc(ctx->opcode)) \
|
if (Rc(ctx->opcode)) \
|
||||||
gen_op_set_Rc1(); \
|
gen_op_set_Rc1(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GEN_FLOAT_ACB(name, op2) \
|
#define GEN_FLOAT_ACB(name, op2) \
|
||||||
_GEN_FLOAT_ACB(name, 0x3F, op2); \
|
_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \
|
||||||
_GEN_FLOAT_ACB(name##s, 0x3B, op2);
|
_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
|
||||||
|
|
||||||
#define _GEN_FLOAT_AB(name, op1, op2, inval) \
|
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
|
||||||
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
|
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
|
||||||
{ \
|
{ \
|
||||||
if (!ctx->fpu_enabled) { \
|
if (!ctx->fpu_enabled) { \
|
||||||
|
@ -780,16 +784,19 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
|
||||||
gen_op_reset_scrfx(); \
|
gen_op_reset_scrfx(); \
|
||||||
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
|
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
|
||||||
gen_op_load_fpr_FT1(rB(ctx->opcode)); \
|
gen_op_load_fpr_FT1(rB(ctx->opcode)); \
|
||||||
gen_op_f##name(); \
|
gen_op_f##op(); \
|
||||||
|
if (isfloat) { \
|
||||||
|
gen_op_frsp(); \
|
||||||
|
} \
|
||||||
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
||||||
if (Rc(ctx->opcode)) \
|
if (Rc(ctx->opcode)) \
|
||||||
gen_op_set_Rc1(); \
|
gen_op_set_Rc1(); \
|
||||||
}
|
}
|
||||||
#define GEN_FLOAT_AB(name, op2, inval) \
|
#define GEN_FLOAT_AB(name, op2, inval) \
|
||||||
_GEN_FLOAT_AB(name, 0x3F, op2, inval); \
|
_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \
|
||||||
_GEN_FLOAT_AB(name##s, 0x3B, op2, inval);
|
_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
|
||||||
|
|
||||||
#define _GEN_FLOAT_AC(name, op1, op2, inval) \
|
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
|
||||||
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
|
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
|
||||||
{ \
|
{ \
|
||||||
if (!ctx->fpu_enabled) { \
|
if (!ctx->fpu_enabled) { \
|
||||||
|
@ -799,14 +806,17 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
|
||||||
gen_op_reset_scrfx(); \
|
gen_op_reset_scrfx(); \
|
||||||
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
|
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
|
||||||
gen_op_load_fpr_FT1(rC(ctx->opcode)); \
|
gen_op_load_fpr_FT1(rC(ctx->opcode)); \
|
||||||
gen_op_f##name(); \
|
gen_op_f##op(); \
|
||||||
|
if (isfloat) { \
|
||||||
|
gen_op_frsp(); \
|
||||||
|
} \
|
||||||
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
||||||
if (Rc(ctx->opcode)) \
|
if (Rc(ctx->opcode)) \
|
||||||
gen_op_set_Rc1(); \
|
gen_op_set_Rc1(); \
|
||||||
}
|
}
|
||||||
#define GEN_FLOAT_AC(name, op2, inval) \
|
#define GEN_FLOAT_AC(name, op2, inval) \
|
||||||
_GEN_FLOAT_AC(name, 0x3F, op2, inval); \
|
_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \
|
||||||
_GEN_FLOAT_AC(name##s, 0x3B, op2, inval);
|
_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
|
||||||
|
|
||||||
#define GEN_FLOAT_B(name, op2, op3) \
|
#define GEN_FLOAT_B(name, op2, op3) \
|
||||||
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
|
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
|
||||||
|
@ -823,8 +833,8 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
|
||||||
gen_op_set_Rc1(); \
|
gen_op_set_Rc1(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GEN_FLOAT_BS(name, op2) \
|
#define GEN_FLOAT_BS(name, op1, op2) \
|
||||||
GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
|
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
|
||||||
{ \
|
{ \
|
||||||
if (!ctx->fpu_enabled) { \
|
if (!ctx->fpu_enabled) { \
|
||||||
RET_EXCP(ctx, EXCP_NO_FP, 0); \
|
RET_EXCP(ctx, EXCP_NO_FP, 0); \
|
||||||
|
@ -840,24 +850,24 @@ GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
|
||||||
|
|
||||||
/* fadd - fadds */
|
/* fadd - fadds */
|
||||||
GEN_FLOAT_AB(add, 0x15, 0x000007C0);
|
GEN_FLOAT_AB(add, 0x15, 0x000007C0);
|
||||||
/* fdiv */
|
/* fdiv - fdivs */
|
||||||
GEN_FLOAT_AB(div, 0x12, 0x000007C0);
|
GEN_FLOAT_AB(div, 0x12, 0x000007C0);
|
||||||
/* fmul */
|
/* fmul - fmuls */
|
||||||
GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
|
GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
|
||||||
|
|
||||||
/* fres */
|
/* fres */
|
||||||
GEN_FLOAT_BS(res, 0x18);
|
GEN_FLOAT_BS(res, 0x3B, 0x18);
|
||||||
|
|
||||||
/* frsqrte */
|
/* frsqrte */
|
||||||
GEN_FLOAT_BS(rsqrte, 0x1A);
|
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
|
||||||
|
|
||||||
/* fsel */
|
/* fsel */
|
||||||
_GEN_FLOAT_ACB(sel, 0x3F, 0x17);
|
_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
|
||||||
/* fsub */
|
/* fsub - fsubs */
|
||||||
GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
|
GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
|
||||||
/* Optional: */
|
/* Optional: */
|
||||||
/* fsqrt */
|
/* fsqrt */
|
||||||
GEN_FLOAT_BS(sqrt, 0x16);
|
GEN_FLOAT_BS(sqrt, 0x3F, 0x16);
|
||||||
|
|
||||||
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
|
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
|
||||||
{
|
{
|
||||||
|
@ -867,20 +877,21 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
|
||||||
}
|
}
|
||||||
gen_op_reset_scrfx();
|
gen_op_reset_scrfx();
|
||||||
gen_op_load_fpr_FT0(rB(ctx->opcode));
|
gen_op_load_fpr_FT0(rB(ctx->opcode));
|
||||||
gen_op_fsqrts();
|
gen_op_fsqrt();
|
||||||
|
gen_op_frsp();
|
||||||
gen_op_store_FT0_fpr(rD(ctx->opcode));
|
gen_op_store_FT0_fpr(rD(ctx->opcode));
|
||||||
if (Rc(ctx->opcode))
|
if (Rc(ctx->opcode))
|
||||||
gen_op_set_Rc1();
|
gen_op_set_Rc1();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** Floating-Point multiply-and-add ***/
|
/*** Floating-Point multiply-and-add ***/
|
||||||
/* fmadd */
|
/* fmadd - fmadds */
|
||||||
GEN_FLOAT_ACB(madd, 0x1D);
|
GEN_FLOAT_ACB(madd, 0x1D);
|
||||||
/* fmsub */
|
/* fmsub - fmsubs */
|
||||||
GEN_FLOAT_ACB(msub, 0x1C);
|
GEN_FLOAT_ACB(msub, 0x1C);
|
||||||
/* fnmadd */
|
/* fnmadd - fnmadds */
|
||||||
GEN_FLOAT_ACB(nmadd, 0x1F);
|
GEN_FLOAT_ACB(nmadd, 0x1F);
|
||||||
/* fnmsub */
|
/* fnmsub - fnmsubs */
|
||||||
GEN_FLOAT_ACB(nmsub, 0x1E);
|
GEN_FLOAT_ACB(nmsub, 0x1E);
|
||||||
|
|
||||||
/*** Floating-Point round & convert ***/
|
/*** Floating-Point round & convert ***/
|
||||||
|
@ -1426,6 +1437,10 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
|
||||||
GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
||||||
{ \
|
{ \
|
||||||
uint32_t simm = SIMM(ctx->opcode); \
|
uint32_t simm = SIMM(ctx->opcode); \
|
||||||
|
if (!ctx->fpu_enabled) { \
|
||||||
|
RET_EXCP(ctx, EXCP_NO_FP, 0); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
if (rA(ctx->opcode) == 0) { \
|
if (rA(ctx->opcode) == 0) { \
|
||||||
gen_op_set_T0(simm); \
|
gen_op_set_T0(simm); \
|
||||||
} else { \
|
} else { \
|
||||||
|
@ -1441,6 +1456,10 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
||||||
GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
||||||
{ \
|
{ \
|
||||||
uint32_t simm = SIMM(ctx->opcode); \
|
uint32_t simm = SIMM(ctx->opcode); \
|
||||||
|
if (!ctx->fpu_enabled) { \
|
||||||
|
RET_EXCP(ctx, EXCP_NO_FP, 0); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
if (rA(ctx->opcode) == 0 || \
|
if (rA(ctx->opcode) == 0 || \
|
||||||
rA(ctx->opcode) == rD(ctx->opcode)) { \
|
rA(ctx->opcode) == rD(ctx->opcode)) { \
|
||||||
RET_INVAL(ctx); \
|
RET_INVAL(ctx); \
|
||||||
|
@ -1457,6 +1476,10 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
||||||
#define GEN_LDUXF(width, opc) \
|
#define GEN_LDUXF(width, opc) \
|
||||||
GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
|
GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
|
||||||
{ \
|
{ \
|
||||||
|
if (!ctx->fpu_enabled) { \
|
||||||
|
RET_EXCP(ctx, EXCP_NO_FP, 0); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
if (rA(ctx->opcode) == 0 || \
|
if (rA(ctx->opcode) == 0 || \
|
||||||
rA(ctx->opcode) == rD(ctx->opcode)) { \
|
rA(ctx->opcode) == rD(ctx->opcode)) { \
|
||||||
RET_INVAL(ctx); \
|
RET_INVAL(ctx); \
|
||||||
|
@ -1473,6 +1496,10 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
|
||||||
#define GEN_LDXF(width, opc2, opc3) \
|
#define GEN_LDXF(width, opc2, opc3) \
|
||||||
GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
|
GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
|
||||||
{ \
|
{ \
|
||||||
|
if (!ctx->fpu_enabled) { \
|
||||||
|
RET_EXCP(ctx, EXCP_NO_FP, 0); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
if (rA(ctx->opcode) == 0) { \
|
if (rA(ctx->opcode) == 0) { \
|
||||||
gen_op_load_gpr_T0(rB(ctx->opcode)); \
|
gen_op_load_gpr_T0(rB(ctx->opcode)); \
|
||||||
} else { \
|
} else { \
|
||||||
|
@ -1501,6 +1528,10 @@ GEN_LDFS(fs, 0x10);
|
||||||
GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
||||||
{ \
|
{ \
|
||||||
uint32_t simm = SIMM(ctx->opcode); \
|
uint32_t simm = SIMM(ctx->opcode); \
|
||||||
|
if (!ctx->fpu_enabled) { \
|
||||||
|
RET_EXCP(ctx, EXCP_NO_FP, 0); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
if (rA(ctx->opcode) == 0) { \
|
if (rA(ctx->opcode) == 0) { \
|
||||||
gen_op_set_T0(simm); \
|
gen_op_set_T0(simm); \
|
||||||
} else { \
|
} else { \
|
||||||
|
@ -1516,6 +1547,10 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
||||||
GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
||||||
{ \
|
{ \
|
||||||
uint32_t simm = SIMM(ctx->opcode); \
|
uint32_t simm = SIMM(ctx->opcode); \
|
||||||
|
if (!ctx->fpu_enabled) { \
|
||||||
|
RET_EXCP(ctx, EXCP_NO_FP, 0); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
if (rA(ctx->opcode) == 0) { \
|
if (rA(ctx->opcode) == 0) { \
|
||||||
RET_INVAL(ctx); \
|
RET_INVAL(ctx); \
|
||||||
return; \
|
return; \
|
||||||
|
@ -1531,6 +1566,10 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
|
||||||
#define GEN_STUXF(width, opc) \
|
#define GEN_STUXF(width, opc) \
|
||||||
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
|
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
|
||||||
{ \
|
{ \
|
||||||
|
if (!ctx->fpu_enabled) { \
|
||||||
|
RET_EXCP(ctx, EXCP_NO_FP, 0); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
if (rA(ctx->opcode) == 0) { \
|
if (rA(ctx->opcode) == 0) { \
|
||||||
RET_INVAL(ctx); \
|
RET_INVAL(ctx); \
|
||||||
return; \
|
return; \
|
||||||
|
@ -1546,6 +1585,10 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
|
||||||
#define GEN_STXF(width, opc2, opc3) \
|
#define GEN_STXF(width, opc2, opc3) \
|
||||||
GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
|
GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
|
||||||
{ \
|
{ \
|
||||||
|
if (!ctx->fpu_enabled) { \
|
||||||
|
RET_EXCP(ctx, EXCP_NO_FP, 0); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
if (rA(ctx->opcode) == 0) { \
|
if (rA(ctx->opcode) == 0) { \
|
||||||
gen_op_load_gpr_T0(rB(ctx->opcode)); \
|
gen_op_load_gpr_T0(rB(ctx->opcode)); \
|
||||||
} else { \
|
} else { \
|
||||||
|
|
Loading…
Reference in a new issue