Message ID | 20170703162328.24474-5-laurent@vivier.eu |
---|---|
State | New |
Headers | show |
On 07/03/2017 09:23 AM, Laurent Vivier wrote: > +void HELPER(fgetman)(CPUM68KState *env, FPReg *res, FPReg *val) > +{ > + if (floatx80_is_infinity(val->d)) { > + res->d = floatx80_default_nan(NULL); > + /* FIXME: set the OPERR bit int he FPSR */ > + return; > + } > + if (floatx80_is_zero(val->d) || > + floatx80_is_any_nan(val->d)) { > + *res = *val; > + return; > + } > + > + res->l.upper = (val->l.upper & 0x8000) | 0x3fff; > + if (floatx80_is_zero_or_denormal(val->d)) { > + res->l.lower = val->l.lower << 1; Surely you have to do more than this for denormals? There may be more than one leading zero bit in the mant. Do you actually need to re-normalize? Or does real hardware produce a so-called "unnormal" in this situation? r~
Le 03/07/2017 à 21:26, Richard Henderson a écrit : > On 07/03/2017 09:23 AM, Laurent Vivier wrote: >> +void HELPER(fgetman)(CPUM68KState *env, FPReg *res, FPReg *val) >> +{ >> + if (floatx80_is_infinity(val->d)) { >> + res->d = floatx80_default_nan(NULL); >> + /* FIXME: set the OPERR bit int he FPSR */ >> + return; >> + } >> + if (floatx80_is_zero(val->d) || >> + floatx80_is_any_nan(val->d)) { >> + *res = *val; >> + return; >> + } >> + >> + res->l.upper = (val->l.upper & 0x8000) | 0x3fff; >> + if (floatx80_is_zero_or_denormal(val->d)) { >> + res->l.lower = val->l.lower << 1; > > Surely you have to do more than this for denormals? There may be more > than one leading zero bit in the mant. Do you actually need to > re-normalize? Or does real hardware produce a so-called "unnormal" in > this situation? I don't know. Do you have test values I can try on real hardware to know? I've tried: fmove.x #0x000056789ABCDEF12345,%fp0 fgetman.x %fp0,%fp6 fp0 1.135643728339893804160017756766172e-4932 (raw 0x0000000056789abcdef12345) fp6 1.3511111111108837373479679699883604 (raw 0x3fff0000acf13579bde2468a) fmove.x #0x000086789ABCDEF12345,%fp0 fgetman.x %fp0,%fp6 fp0 1.7660380676734113365842698475140006e-4932 (raw 0x0000000086789abcdef12345) fp6 1.0505555555554418686739839849941802 (raw 0x3fff000086789abcdef12345) fmove.x #0x000000000ABCDEF12345,%fp0 fgetman.x %fp0,%fp6 fp0 2.1518178707571747286191852003521627e-4938 (raw 0x0000000000000abcdef12345) fp6 1.342222103012886691431049257516861 (raw 0x3fff0000abcdef1234500000) So I guess the mantissa must be shifted to left until we have a 1 in the explicit integer part bit? Thanks, Laurent
On 07/03/2017 12:50 PM, Laurent Vivier wrote: > fmove.x #0x000000000ABCDEF12345,%fp0 > fgetman.x %fp0,%fp6 > fp0 2.1518178707571747286191852003521627e-4938 (raw > 0x0000000000000abcdef12345) > fp6 1.342222103012886691431049257516861 (raw > 0x3fff0000abcdef1234500000) This one shows exactly what I was thinking about. > So I guess the mantissa must be shifted to left until we have a 1 in the > explicit integer part bit? Yes. Please try fgetexp on this same input. I suspect the answer is -16384 - clz64(val->l.lower). Otherwise the behaviour of fgetman above doesn't make sense. r~
Le 03/07/2017 à 22:31, Richard Henderson a écrit : > On 07/03/2017 12:50 PM, Laurent Vivier wrote: >> fmove.x #0x000000000ABCDEF12345,%fp0 >> fgetman.x %fp0,%fp6 >> fp0 2.1518178707571747286191852003521627e-4938 (raw >> 0x0000000000000abcdef12345) >> fp6 1.342222103012886691431049257516861 (raw >> 0x3fff0000abcdef1234500000) > > This one shows exactly what I was thinking about. > >> So I guess the mantissa must be shifted to left until we have a 1 in the >> explicit integer part bit? > > Yes. > > Please try fgetexp on this same input. fmove.x #0x000000000ABCDEF12345,%fp0 fgetexp.x %fp0,%fp6 fp0 (raw 0x0000000000000abcdef12345) fp6 -16403 > I suspect the answer is -16384 - clz64(val->l.lower). It looks like -16383 - clz64(val->l.lower) fmove.x #0x000056789ABCDEF12345,%fp0 fgetexp.x %fp0,%fp6 fp0 (raw 0x0000000056789abcdef12345) fp6 -16384 fmove.x #0x000086789ABCDEF12345,%fp0 fgetexp.x %fp0,%fp6 fp0 (raw 0x0000000086789abcdef12345) fp6 -16383 Thanks, Laurent
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 715b9be..88957fa 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -771,3 +771,109 @@ void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) make_quotient(env, dst, sign); res->d = ldouble_to_floatx80(dst, &env->fp_status); } + +void HELPER(fgetexp)(CPUM68KState *env, FPReg *res, FPReg *val) +{ + int32_t exp; + + if (floatx80_is_infinity(val->d)) { + res->d = floatx80_default_nan(NULL); + /* FIXME: set the OPERR bit int he FPSR */ + return; + } + if (floatx80_is_zero(val->d)) { + *res = *val; + return; + } + if (floatx80_is_zero_or_denormal(val->d)) { + res->d = int32_to_floatx80(-16384, &env->fp_status); + return; + } + + if (floatx80_is_any_nan(val->d)) { + res->d = floatx80_default_nan(NULL); + return; + } + + exp = (val->l.upper & 0x7fff) - 0x3fff; + + res->d = int32_to_floatx80(exp, &env->fp_status); +} + +void HELPER(fgetman)(CPUM68KState *env, FPReg *res, FPReg *val) +{ + if (floatx80_is_infinity(val->d)) { + res->d = floatx80_default_nan(NULL); + /* FIXME: set the OPERR bit int he FPSR */ + return; + } + if (floatx80_is_zero(val->d) || + floatx80_is_any_nan(val->d)) { + *res = *val; + return; + } + + res->l.upper = (val->l.upper & 0x8000) | 0x3fff; + if (floatx80_is_zero_or_denormal(val->d)) { + res->l.lower = val->l.lower << 1; + } else { + res->l.lower = val->l.lower; + } +} + +void HELPER(fscale)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) +{ + int rounding_mode; + int32_t scale; + int32_t exp; + + if (floatx80_is_infinity(val0->d)) { + res->d = floatx80_default_nan(NULL); + /* FIXME: set the OPERR bit in the FPSR */ + return; + } + if (floatx80_is_any_nan(val0->d)) { + res->d = floatx80_default_nan(NULL); + return; + } + if (floatx80_is_infinity(val1->d) || + floatx80_is_zero_or_denormal(val1->d)) { + *res = *val1; + return; + } + if (floatx80_is_zero(val0->d)) { + res->d = floatx80_round(val1->d, &env->fp_status); + return; + } + + rounding_mode = get_float_rounding_mode(&env->fp_status); + set_float_rounding_mode(float_round_to_zero, &env->fp_status); + scale = floatx80_to_int32(val0->d, &env->fp_status); + set_float_rounding_mode(rounding_mode, &env->fp_status); + + if (scale >= 16384) { + if (floatx80_is_neg(val1->d)) { + res->d = floatx80_chs(floatx80_infinity); + } else { + res->d = floatx80_infinity; + } + /* FIXME: set OVFL in FPSR */ + return; + } + if (scale <= -16384) { + if (floatx80_is_neg(val1->d)) { + res->d = floatx80_chs(floatx80_zero); + } else { + res->d = floatx80_zero; + } + /* FIXME: set UNFL in FPSR */ + return; + } + + exp = (val1->l.upper & 0x7fff) + scale; + + res->l.upper = (val1->l.upper & 0x8000) | (exp & 0x7fff); + res->l.lower = val1->l.lower; + + res->d = floatx80_round(res->d, &env->fp_status); +} diff --git a/target/m68k/helper.h b/target/m68k/helper.h index 889978e..a6be815 100644 --- a/target/m68k/helper.h +++ b/target/m68k/helper.h @@ -79,6 +79,9 @@ DEF_HELPER_3(fcos, void, env, fp, fp) DEF_HELPER_4(fsincos, void, env, fp, fp, fp) DEF_HELPER_4(fmod, void, env, fp, fp, fp) DEF_HELPER_4(frem, void, env, fp, fp, fp) +DEF_HELPER_3(fgetexp, void, env, fp, fp) +DEF_HELPER_3(fgetman, void, env, fp, fp) +DEF_HELPER_4(fscale, void, env, fp, fp, fp) 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 fe9e0bf..348f4fb 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4718,6 +4718,12 @@ DISAS_INSN(fpu) case 0x1d: /* fcos */ gen_helper_fcos(cpu_env, cpu_dest, cpu_src); break; + case 0x1e: /* fgetexp */ + gen_helper_fgetexp(cpu_env, cpu_dest, cpu_src); + break; + case 0x1f: /* fgetman */ + gen_helper_fgetman(cpu_env, cpu_dest, cpu_src); + break; case 0x20: /* fdiv */ gen_helper_fdiv(cpu_env, cpu_dest, cpu_src, cpu_dest); break; @@ -4754,6 +4760,9 @@ DISAS_INSN(fpu) case 0x25: /* frem */ gen_helper_frem(cpu_env, cpu_dest, cpu_src, cpu_dest); break; + case 0x26: /* fscale */ + gen_helper_fscale(cpu_env, cpu_dest, cpu_src, cpu_dest); + break; case 0x27: /* fsglmul */ gen_helper_fsglmul(cpu_env, cpu_dest, cpu_src, cpu_dest); break;
Signed-off-by: Laurent Vivier <laurent@vivier.eu> --- target/m68k/fpu_helper.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ target/m68k/helper.h | 3 ++ target/m68k/translate.c | 9 ++++ 3 files changed, 118 insertions(+)