diff mbox

[v3,12/16] target-m68k: add fscale, fgetman, fgetexp and fmod

Message ID 20170207005930.28327-13-laurent@vivier.eu
State New
Headers show

Commit Message

Laurent Vivier Feb. 7, 2017, 12:59 a.m. UTC
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/cpu.h        |  1 +
 target/m68k/fpu_helper.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/helper.h     |  4 ++++
 target/m68k/translate.c  | 14 ++++++++++++
 4 files changed, 75 insertions(+)

Comments

Richard Henderson Feb. 16, 2017, 1:34 a.m. UTC | #1
On 02/07/2017 11:59 AM, Laurent Vivier wrote:
> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
>  target/m68k/cpu.h        |  1 +
>  target/m68k/fpu_helper.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
>  target/m68k/helper.h     |  4 ++++
>  target/m68k/translate.c  | 14 ++++++++++++
>  4 files changed, 75 insertions(+)
>
> diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
> index 7985dc3..3042ab7 100644
> --- a/target/m68k/cpu.h
> +++ b/target/m68k/cpu.h
> @@ -253,6 +253,7 @@ typedef enum {
>  /* Quotient */
>
>  #define FPSR_QT_MASK  0x00ff0000
> +#define FPSR_QT_SHIFT 16
>
>  /* Floating-Point Control Register */
>  /* Rounding mode */
> diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
> index d8145e0..42f5b5c 100644
> --- a/target/m68k/fpu_helper.c
> +++ b/target/m68k/fpu_helper.c
> @@ -458,3 +458,59 @@ void HELPER(const_FP0)(CPUM68KState *env, uint32_t offset)
>      env->fp0l = fpu_rom[offset].low;
>      env->fp0h = fpu_rom[offset].high;
>  }
> +
> +void HELPER(getexp_FP0)(CPUM68KState *env)
> +{
> +    int32_t exp;
> +    floatx80 res;
> +
> +    res = FP0_to_floatx80(env);
> +    if (floatx80_is_zero_or_denormal(res) || floatx80_is_any_nan(res) ||
> +        floatx80_is_infinity(res)) {
> +        return;
> +    }
> +    exp = (env->fp0h & 0x7fff) - 0x3fff;
> +
> +    res = int32_to_floatx80(exp, &env->fp_status);
> +
> +    floatx80_to_FP0(env, res);

Failure to raise OPERR for infinities?

> +void HELPER(getman_FP0)(CPUM68KState *env)
> +{
> +    floatx80 res;
> +    res = int64_to_floatx80(env->fp0l, &env->fp_status);
> +    floatx80_to_FP0(env, res);
> +}

This seems completely wrong.  (1) NaN gets returned, (2) Inf raises OPERR, (3) 
Normal values return something in the range [1.0 ... 2.0).  Which means you 
should just force the exponent rather than convert the low part.

> +
> +void HELPER(scale_FP0_FP1)(CPUM68KState *env)
> +{
> +    int32_t scale;
> +    int32_t exp;
> +
> +    scale = floatx80_to_int32(FP0_to_floatx80(env), &env->fp_status);
> +
> +    exp = (env->fp1h & 0x7fff) + scale;
> +
> +    env->fp0h = (env->fp1h & 0x8000) | (exp & 0x7fff);
> +    env->fp0l = env->fp1l;
> +}

Missing handling for NaN, Inf, 0, denormal.


r~
diff mbox

Patch

diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 7985dc3..3042ab7 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -253,6 +253,7 @@  typedef enum {
 /* Quotient */
 
 #define FPSR_QT_MASK  0x00ff0000
+#define FPSR_QT_SHIFT 16
 
 /* Floating-Point Control Register */
 /* Rounding mode */
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index d8145e0..42f5b5c 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -458,3 +458,59 @@  void HELPER(const_FP0)(CPUM68KState *env, uint32_t offset)
     env->fp0l = fpu_rom[offset].low;
     env->fp0h = fpu_rom[offset].high;
 }
+
+void HELPER(getexp_FP0)(CPUM68KState *env)
+{
+    int32_t exp;
+    floatx80 res;
+
+    res = FP0_to_floatx80(env);
+    if (floatx80_is_zero_or_denormal(res) || floatx80_is_any_nan(res) ||
+        floatx80_is_infinity(res)) {
+        return;
+    }
+    exp = (env->fp0h & 0x7fff) - 0x3fff;
+
+    res = int32_to_floatx80(exp, &env->fp_status);
+
+    floatx80_to_FP0(env, res);
+}
+
+void HELPER(getman_FP0)(CPUM68KState *env)
+{
+    floatx80 res;
+    res = int64_to_floatx80(env->fp0l, &env->fp_status);
+    floatx80_to_FP0(env, res);
+}
+
+void HELPER(scale_FP0_FP1)(CPUM68KState *env)
+{
+    int32_t scale;
+    int32_t exp;
+
+    scale = floatx80_to_int32(FP0_to_floatx80(env), &env->fp_status);
+
+    exp = (env->fp1h & 0x7fff) + scale;
+
+    env->fp0h = (env->fp1h & 0x8000) | (exp & 0x7fff);
+    env->fp0l = env->fp1l;
+}
+
+static void make_quotient(CPUM68KState *env, floatx80 val)
+{
+    uint32_t quotient = floatx80_to_int32(val, &env->fp_status);
+    uint32_t sign = (quotient >> 24) & 0x80;
+    quotient = sign | (quotient & 0x7f);
+    env->fpsr = (env->fpsr & ~FPSR_QT_MASK) | (quotient << FPSR_QT_SHIFT);
+}
+
+void HELPER(mod_FP0_FP1)(CPUM68KState *env)
+{
+    floatx80 res;
+
+    res = floatx80_rem(FP1_to_floatx80(env), FP0_to_floatx80(env),
+                       &env->fp_status);
+    make_quotient(env, res);
+
+    floatx80_to_FP0(env, res);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 4927324..620e707 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -33,6 +33,10 @@  DEF_HELPER_1(tst_FP0, void, env)
 DEF_HELPER_1(update_fpstatus, void, env)
 DEF_HELPER_4(fmovem, void, env, i32, i32, i32)
 DEF_HELPER_2(const_FP0, void, env, i32)
+DEF_HELPER_1(getexp_FP0, void, env)
+DEF_HELPER_1(getman_FP0, void, env)
+DEF_HELPER_1(scale_FP0_FP1, void, env)
+DEF_HELPER_1(mod_FP0_FP1, void, env)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 23eac63..be18083 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -4629,10 +4629,20 @@  DISAS_INSN(fpu)
     case 0x1a: case 0x5a: case 0x5e: /* fneg */
         gen_helper_chs_FP0(cpu_env);
         break;
+    case 0x1e: /* fgetexp */
+        gen_helper_getexp_FP0(cpu_env);
+        break;
+    case 0x1f: /* fgetman */
+        gen_helper_getman_FP0(cpu_env);
+        break;
     case 0x20: case 0x60: case 0x64: /* fdiv */
         gen_op_load_fpr_FP1(REG(ext, 7));
         gen_helper_div_FP0_FP1(cpu_env);
         break;
+    case 0x21: /* fmod */
+        gen_op_load_fpr_FP1(REG(ext, 7));
+        gen_helper_mod_FP0_FP1(cpu_env);
+        break;
     case 0x22: case 0x62: case 0x66: /* fadd */
         gen_op_load_fpr_FP1(REG(ext, 7));
         gen_helper_add_FP0_FP1(cpu_env);
@@ -4641,6 +4651,10 @@  DISAS_INSN(fpu)
         gen_op_load_fpr_FP1(REG(ext, 7));
         gen_helper_mul_FP0_FP1(cpu_env);
         break;
+    case 0x26: /* fscale */
+        gen_op_load_fpr_FP1(REG(ext, 7));
+        gen_helper_scale_FP0_FP1(cpu_env);
+        break;
     case 0x28: case 0x68: case 0x6c: /* fsub */
         gen_op_load_fpr_FP1(REG(ext, 7));
         gen_helper_sub_FP0_FP1(cpu_env);