Commit f83311e4 authored by Laurent Vivier's avatar Laurent Vivier
Browse files

target-m68k: use floatx80 internally



Coldfire uses float64, but 680x0 use floatx80.
This patch introduces the use of floatx80 internally
and enables 680x0 80bits FPU.

Signed-off-by: default avatarLaurent Vivier <laurent@vivier.eu>
Reviewed-by: default avatarRichard Henderson <rth@twiddle.net>
Message-Id: <20170620205121.26515-4-laurent@vivier.eu>
parent f4a6ce51
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ static void m68k_cpu_reset(CPUState *s)
    M68kCPU *cpu = M68K_CPU(s);
    M68kCPUClass *mcc = M68K_CPU_GET_CLASS(cpu);
    CPUM68KState *env = &cpu->env;
    float64 nan = float64_default_nan(NULL);
    floatx80 nan = floatx80_default_nan(NULL);
    int i;

    mcc->parent_reset(s);
@@ -60,7 +60,7 @@ static void m68k_cpu_reset(CPUState *s)
#endif
    m68k_switch_sp(env);
    for (i = 0; i < 8; i++) {
        env->fregs[i] = nan;
        env->fregs[i].d = nan;
    }
    env->fpcr = 0;
    env->fpsr = 0;
+12 −3
Original line number Diff line number Diff line
@@ -55,8 +55,15 @@
#define EXCP_UNINITIALIZED  15
#define EXCP_TRAP0          32   /* User trap #0.  */
#define EXCP_TRAP15         47   /* User trap #15.  */
#define EXCP_FP_BSUN        48 /* Branch Set on Unordered */
#define EXCP_FP_INEX        49 /* Inexact result */
#define EXCP_FP_DZ          50 /* Divide by Zero */
#define EXCP_FP_UNFL        51 /* Underflow */
#define EXCP_FP_OPERR       52 /* Operand Error */
#define EXCP_FP_OVFL        53 /* Overflow */
#define EXCP_FP_SNAN        54 /* Signaling Not-A-Number */
#define EXCP_FP_UNIMP       55 /* Unimplemented Data type */
#define EXCP_UNSUPPORTED    61
#define EXCP_ICE            13

#define EXCP_RTE            0x100
#define EXCP_HALT_INSN      0x101
@@ -64,6 +71,8 @@
#define NB_MMU_MODES 2
#define TARGET_INSN_START_EXTRA_WORDS 1

typedef CPU_LDoubleU FPReg;

typedef struct CPUM68KState {
    uint32_t dregs[8];
    uint32_t aregs[8];
@@ -82,8 +91,8 @@ typedef struct CPUM68KState {
    uint32_t cc_c; /* either 0/1, unused, or computed from cc_n and cc_v */
    uint32_t cc_z; /* == 0 or unused */

    float64 fregs[8];
    float64 fp_result;
    FPReg fregs[8];
    FPReg fp_result;
    uint32_t fpcr;
    uint32_t fpsr;
    float_status fp_status;
+47 −38
Original line number Diff line number Diff line
@@ -21,92 +21,101 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"

uint32_t HELPER(f64_to_i32)(CPUM68KState *env, float64 val)
int32_t HELPER(reds32)(CPUM68KState *env, FPReg *val)
{
    return float64_to_int32(val, &env->fp_status);
    return floatx80_to_int32(val->d, &env->fp_status);
}

float32 HELPER(f64_to_f32)(CPUM68KState *env, float64 val)
float32 HELPER(redf32)(CPUM68KState *env, FPReg *val)
{
    return float64_to_float32(val, &env->fp_status);
    return floatx80_to_float32(val->d, &env->fp_status);
}

float64 HELPER(i32_to_f64)(CPUM68KState *env, uint32_t val)
void HELPER(exts32)(CPUM68KState *env, FPReg *res, int32_t val)
{
    return int32_to_float64(val, &env->fp_status);
    res->d = int32_to_floatx80(val, &env->fp_status);
}

float64 HELPER(f32_to_f64)(CPUM68KState *env, float32 val)
void HELPER(extf32)(CPUM68KState *env, FPReg *res, float32 val)
{
    return float32_to_float64(val, &env->fp_status);
    res->d = float32_to_floatx80(val, &env->fp_status);
}

float64 HELPER(iround_f64)(CPUM68KState *env, float64 val)
void HELPER(extf64)(CPUM68KState *env, FPReg *res, float64 val)
{
    return float64_round_to_int(val, &env->fp_status);
    res->d = float64_to_floatx80(val, &env->fp_status);
}

float64 HELPER(itrunc_f64)(CPUM68KState *env, float64 val)
float64 HELPER(redf64)(CPUM68KState *env, FPReg *val)
{
    return float64_trunc_to_int(val, &env->fp_status);
    return floatx80_to_float64(val->d, &env->fp_status);
}

float64 HELPER(sqrt_f64)(CPUM68KState *env, float64 val)
void HELPER(firound)(CPUM68KState *env, FPReg *res, FPReg *val)
{
    return float64_sqrt(val, &env->fp_status);
    res->d = floatx80_round_to_int(val->d, &env->fp_status);
}

float64 HELPER(abs_f64)(float64 val)
void HELPER(fitrunc)(CPUM68KState *env, FPReg *res, FPReg *val)
{
    return float64_abs(val);
    res->d = floatx80_round_to_int(val->d, &env->fp_status);
}

float64 HELPER(chs_f64)(float64 val)
void HELPER(fsqrt)(CPUM68KState *env, FPReg *res, FPReg *val)
{
    return float64_chs(val);
    res->d = floatx80_sqrt(val->d, &env->fp_status);
}

float64 HELPER(add_f64)(CPUM68KState *env, float64 a, float64 b)
void HELPER(fabs)(CPUM68KState *env, FPReg *res, FPReg *val)
{
    return float64_add(a, b, &env->fp_status);
    res->d = floatx80_abs(val->d);
}

float64 HELPER(sub_f64)(CPUM68KState *env, float64 a, float64 b)
void HELPER(fchs)(CPUM68KState *env, FPReg *res, FPReg *val)
{
    return float64_sub(a, b, &env->fp_status);
    res->d = floatx80_chs(val->d);
}

float64 HELPER(mul_f64)(CPUM68KState *env, float64 a, float64 b)
void HELPER(fadd)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
{
    return float64_mul(a, b, &env->fp_status);
    res->d = floatx80_add(val0->d, val1->d, &env->fp_status);
}

float64 HELPER(div_f64)(CPUM68KState *env, float64 a, float64 b)
void HELPER(fsub)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
{
    return float64_div(a, b, &env->fp_status);
    res->d = floatx80_sub(val1->d, val0->d, &env->fp_status);
}

float64 HELPER(sub_cmp_f64)(CPUM68KState *env, float64 a, float64 b)
void HELPER(fmul)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
{
    res->d = floatx80_mul(val0->d, val1->d, &env->fp_status);
}

void HELPER(fdiv)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
{
    res->d = floatx80_div(val1->d, val0->d, &env->fp_status);
}

void HELPER(fsub_cmp)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
{
    /* ??? This may incorrectly raise exceptions.  */
    /* ??? Should flush denormals to zero.  */
    float64 res;
    res = float64_sub(a, b, &env->fp_status);
    if (float64_is_quiet_nan(res, &env->fp_status)) {
    res->d = floatx80_sub(val0->d, val1->d, &env->fp_status);
    if (floatx80_is_quiet_nan(res->d, &env->fp_status)) {
        /* +/-inf compares equal against itself, but sub returns nan.  */
        if (!float64_is_quiet_nan(a, &env->fp_status)
            && !float64_is_quiet_nan(b, &env->fp_status)) {
            res = float64_zero;
            if (float64_lt_quiet(a, res, &env->fp_status)) {
                res = float64_chs(res);
        if (!floatx80_is_quiet_nan(val0->d, &env->fp_status)
            && !floatx80_is_quiet_nan(val1->d, &env->fp_status)) {
            res->d = floatx80_zero;
            if (floatx80_lt_quiet(val0->d, res->d, &env->fp_status)) {
                res->d = floatx80_chs(res->d);
            }
        }
    }
    return res;
}

uint32_t HELPER(compare_f64)(CPUM68KState *env, float64 val)
uint32_t HELPER(fcompare)(CPUM68KState *env, FPReg *val)
{
    return float64_compare_quiet(val, float64_zero, &env->fp_status);
    return floatx80_compare_quiet(val->d, floatx80_zero, &env->fp_status);
}
+7 −5
Original line number Diff line number Diff line
@@ -73,10 +73,11 @@ void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
    g_slist_free(list);
}

static int fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
{
    if (n < 8) {
        stfq_p(mem_buf, env->fregs[n]);
        float_status s;
        stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
        return 8;
    }
    if (n < 11) {
@@ -87,10 +88,11 @@ static int fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
    return 0;
}

static int fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
{
    if (n < 8) {
        env->fregs[n] = ldfq_p(mem_buf);
        float_status s;
        env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
        return 8;
    }
    if (n < 11) {
@@ -126,7 +128,7 @@ void m68k_cpu_init_gdb(M68kCPU *cpu)
    CPUM68KState *env = &cpu->env;

    if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
        gdb_register_coprocessor(cs, fpu_gdb_get_reg, fpu_gdb_set_reg,
        gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
                                 11, "cf-fp.xml", 18);
    }
    /* TODO: Add [E]MAC registers.  */
+22 −15
Original line number Diff line number Diff line
@@ -12,21 +12,28 @@ DEF_HELPER_3(movec, void, env, i32, i32)
DEF_HELPER_4(cas2w, void, env, i32, i32, i32)
DEF_HELPER_4(cas2l, void, env, i32, i32, i32)

DEF_HELPER_2(f64_to_i32, f32, env, f64)
DEF_HELPER_2(f64_to_f32, f32, env, f64)
DEF_HELPER_2(i32_to_f64, f64, env, i32)
DEF_HELPER_2(f32_to_f64, f64, env, f32)
DEF_HELPER_2(iround_f64, f64, env, f64)
DEF_HELPER_2(itrunc_f64, f64, env, f64)
DEF_HELPER_2(sqrt_f64, f64, env, f64)
DEF_HELPER_1(abs_f64, f64, f64)
DEF_HELPER_1(chs_f64, f64, f64)
DEF_HELPER_3(add_f64, f64, env, f64, f64)
DEF_HELPER_3(sub_f64, f64, env, f64, f64)
DEF_HELPER_3(mul_f64, f64, env, f64, f64)
DEF_HELPER_3(div_f64, f64, env, f64, f64)
DEF_HELPER_3(sub_cmp_f64, f64, env, f64, f64)
DEF_HELPER_2(compare_f64, i32, env, f64)
#define dh_alias_fp ptr
#define dh_ctype_fp FPReg *
#define dh_is_signed_fp dh_is_signed_ptr

DEF_HELPER_3(exts32, void, env, fp, s32)
DEF_HELPER_3(extf32, void, env, fp, f32)
DEF_HELPER_3(extf64, void, env, fp, f64)
DEF_HELPER_2(redf32, f32, env, fp)
DEF_HELPER_2(redf64, f64, env, fp)
DEF_HELPER_2(reds32, s32, env, fp)

DEF_HELPER_3(firound, void, env, fp, fp)
DEF_HELPER_3(fitrunc, void, env, fp, fp)
DEF_HELPER_3(fsqrt, void, env, fp, fp)
DEF_HELPER_3(fabs, void, env, fp, fp)
DEF_HELPER_3(fchs, void, env, fp, fp)
DEF_HELPER_4(fadd, void, env, fp, fp, fp)
DEF_HELPER_4(fsub, void, env, fp, fp, fp)
DEF_HELPER_4(fmul, void, env, fp, fp, fp)
DEF_HELPER_4(fdiv, void, env, fp, fp, fp)
DEF_HELPER_4(fsub_cmp, void, env, fp, fp, fp)
DEF_HELPER_2(fcompare, i32, env, fp)

DEF_HELPER_3(mac_move, void, env, i32, i32)
DEF_HELPER_3(macmulf, i64, env, i32, i32)
Loading