Commit 4c8c1cc5 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.10-pull-request' into staging



# gpg: Signature made Wed 21 Jun 2017 22:00:24 BST
# gpg:                using RSA key 0xF30C38BD3F2FBE3C
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>"
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>"
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>"
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier/tags/m68k-for-2.10-pull-request:
  target-m68k: add FPCR and FPSR
  target-m68k: define 96bit FP registers for gdb on 680x0
  target-m68k: use floatx80 internally
  target-m68k: initialize FPU registers
  target-m68k: move fmove CR to a function

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents e18a6391 ba624944
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -6066,7 +6066,7 @@ case "$target_name" in
  ;;
  m68k)
    bflt="yes"
    gdb_xml_files="cf-core.xml cf-fp.xml"
    gdb_xml_files="cf-core.xml cf-fp.xml m68k-fp.xml"
  ;;
  microblaze|microblazeel)
    TARGET_ARCH=microblaze

gdb-xml/m68k-fp.xml

0 → 100644
+21 −0
Original line number Diff line number Diff line
<?xml version="1.0"?>
<!-- Copyright (C) 2008 Free Software Foundation, Inc.

     Copying and distribution of this file, with or without modification,
     are permitted in any medium without royalty provided the copyright
     notice and this notice are preserved.  -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.coldfire.fp">
  <reg name="fp0" bitsize="96" type="float" group="float"/>
  <reg name="fp1" bitsize="96" type="float" group="float"/>
  <reg name="fp2" bitsize="96" type="float" group="float"/>
  <reg name="fp3" bitsize="96" type="float" group="float"/>
  <reg name="fp4" bitsize="96" type="float" group="float"/>
  <reg name="fp5" bitsize="96" type="float" group="float"/>
  <reg name="fp6" bitsize="96" type="float" group="float"/>
  <reg name="fp7" bitsize="96" type="float" group="float"/>

  <reg name="fpcontrol" bitsize="32" group="float"/>
  <reg name="fpstatus" bitsize="32" group="float"/>,
  <reg name="fpiaddr" bitsize="32" type="code_ptr" group="float"/>
</feature>
+8 −1
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ static void m68k_cpu_reset(CPUState *s)
    M68kCPU *cpu = M68K_CPU(s);
    M68kCPUClass *mcc = M68K_CPU_GET_CLASS(cpu);
    CPUM68KState *env = &cpu->env;
    floatx80 nan = floatx80_default_nan(NULL);
    int i;

    mcc->parent_reset(s);

@@ -57,7 +59,12 @@ static void m68k_cpu_reset(CPUState *s)
    env->sr = 0x2700;
#endif
    m68k_switch_sp(env);
    /* ??? FP regs should be initialized to NaN.  */
    for (i = 0; i < 8; i++) {
        env->fregs[i].d = nan;
    }
    cpu_m68k_set_fpcr(env, 0);
    env->fpsr = 0;

    cpu_m68k_set_ccr(env, 0);
    /* TODO: We should set PC from the interrupt vector.  */
    env->pc = 0;
+51 −7
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;
@@ -162,6 +171,7 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo,
                           void *puc);
uint32_t cpu_m68k_get_ccr(CPUM68KState *env);
void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t);
void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val);


/* Instead of computing the condition codes after each m68k instruction,
@@ -206,6 +216,43 @@ typedef enum {
#define M68K_SSP    0
#define M68K_USP    1

#define M68K_FPIAR_SHIFT  0
#define M68K_FPIAR        (1 << M68K_FPIAR_SHIFT)
#define M68K_FPSR_SHIFT   1
#define M68K_FPSR         (1 << M68K_FPSR_SHIFT)
#define M68K_FPCR_SHIFT   2
#define M68K_FPCR         (1 << M68K_FPCR_SHIFT)

/* Floating-Point Status Register */

/* Condition Code */
#define FPSR_CC_MASK  0x0f000000
#define FPSR_CC_A     0x01000000 /* Not-A-Number */
#define FPSR_CC_I     0x02000000 /* Infinity */
#define FPSR_CC_Z     0x04000000 /* Zero */
#define FPSR_CC_N     0x08000000 /* Negative */

/* Quotient */

#define FPSR_QT_MASK  0x00ff0000

/* Floating-Point Control Register */
/* Rounding mode */
#define FPCR_RND_MASK   0x0030
#define FPCR_RND_N      0x0000
#define FPCR_RND_Z      0x0010
#define FPCR_RND_M      0x0020
#define FPCR_RND_P      0x0030

/* Rounding precision */
#define FPCR_PREC_MASK  0x00c0
#define FPCR_PREC_X     0x0000
#define FPCR_PREC_S     0x0040
#define FPCR_PREC_D     0x0080
#define FPCR_PREC_U     0x00c0

#define FPCR_EXCP_MASK 0xff00

/* CACR fields are implementation defined, but some bits are common.  */
#define M68K_CACR_EUSP  0x10

@@ -222,8 +269,6 @@ typedef enum {
void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector);
void m68k_switch_sp(CPUM68KState *env);

#define M68K_FPCR_PREC (1 << 6)

void do_m68k_semihosting(CPUM68KState *env, int nr);

/* There are 4 ColdFire core ISA revisions: A, A+, B and C.
@@ -301,8 +346,7 @@ static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc,
{
    *pc = env->pc;
    *cs_base = 0;
    *flags = (env->fpcr & M68K_FPCR_PREC)       /* Bit  6 */
            | (env->sr & SR_S)                  /* Bit  13 */
    *flags = (env->sr & SR_S)                   /* Bit  13 */
            | ((env->macsr >> 4) & 0xf);        /* Bits 0-3 */
}

+137 −43
Original line number Diff line number Diff line
@@ -21,92 +21,186 @@
#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)
static void m68k_restore_precision_mode(CPUM68KState *env)
{
    return float64_abs(val);
    switch (env->fpcr & FPCR_PREC_MASK) {
    case FPCR_PREC_X: /* extended */
        set_floatx80_rounding_precision(80, &env->fp_status);
        break;
    case FPCR_PREC_S: /* single */
        set_floatx80_rounding_precision(32, &env->fp_status);
        break;
    case FPCR_PREC_D: /* double */
        set_floatx80_rounding_precision(64, &env->fp_status);
        break;
    case FPCR_PREC_U: /* undefined */
    default:
        break;
    }
}

static void cf_restore_precision_mode(CPUM68KState *env)
{
    if (env->fpcr & FPCR_PREC_S) { /* single */
        set_floatx80_rounding_precision(32, &env->fp_status);
    } else { /* double */
        set_floatx80_rounding_precision(64, &env->fp_status);
    }
}

static void restore_rounding_mode(CPUM68KState *env)
{
    switch (env->fpcr & FPCR_RND_MASK) {
    case FPCR_RND_N: /* round to nearest */
        set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
        break;
    case FPCR_RND_Z: /* round to zero */
        set_float_rounding_mode(float_round_to_zero, &env->fp_status);
        break;
    case FPCR_RND_M: /* round toward minus infinity */
        set_float_rounding_mode(float_round_down, &env->fp_status);
        break;
    case FPCR_RND_P: /* round toward positive infinity */
        set_float_rounding_mode(float_round_up, &env->fp_status);
        break;
    }
}

void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val)
{
    env->fpcr = val & 0xffff;

    if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
        cf_restore_precision_mode(env);
    } else {
        m68k_restore_precision_mode(env);
    }
    restore_rounding_mode(env);
}

void HELPER(fitrunc)(CPUM68KState *env, FPReg *res, FPReg *val)
{
    int rounding_mode = get_float_rounding_mode(&env->fp_status);
    set_float_rounding_mode(float_round_to_zero, &env->fp_status);
    res->d = floatx80_round_to_int(val->d, &env->fp_status);
    set_float_rounding_mode(rounding_mode, &env->fp_status);
}

void HELPER(set_fpcr)(CPUM68KState *env, uint32_t val)
{
    cpu_m68k_set_fpcr(env, val);
}

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)
{
    /* ??? 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)) {
        /* +/-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);
    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);
}

static int float_comp_to_cc(int float_compare)
{
    switch (float_compare) {
    case float_relation_equal:
        return FPSR_CC_Z;
    case float_relation_less:
        return FPSR_CC_N;
    case float_relation_unordered:
        return FPSR_CC_A;
    case float_relation_greater:
        return 0;
    default:
        g_assert_not_reached();
    }
    return res;
}

uint32_t HELPER(compare_f64)(CPUM68KState *env, float64 val)
void HELPER(fcmp)(CPUM68KState *env, FPReg *val0, FPReg *val1)
{
    return float64_compare_quiet(val, float64_zero, &env->fp_status);
    int float_compare;

    float_compare = floatx80_compare(val1->d, val0->d, &env->fp_status);
    env->fpsr = (env->fpsr & ~FPSR_CC_MASK) | float_comp_to_cc(float_compare);
}

void HELPER(ftst)(CPUM68KState *env, FPReg *val)
{
    uint32_t cc = 0;

    if (floatx80_is_neg(val->d)) {
        cc |= FPSR_CC_N;
    }

    if (floatx80_is_any_nan(val->d)) {
        cc |= FPSR_CC_A;
    } else if (floatx80_is_infinity(val->d)) {
        cc |= FPSR_CC_I;
    } else if (floatx80_is_zero(val->d)) {
        cc |= FPSR_CC_Z;
    }
    env->fpsr = (env->fpsr & ~FPSR_CC_MASK) | cc;
}
Loading