>From c467db1c0a5f4c6560b8bdddd2115732aa718c4b Mon Sep 17 00:00:00 2001 From: Chen Gang <gang.chen.5...@gmail.com> Date: Sun, 8 Nov 2015 09:10:17 +0800 Subject: [PATCH 3/4] target-tilegx: Implement fpu fdouble floating point instructions
Signed-off-by: Chen Gang <gang.chen.5...@gmail.com> --- target-tilegx/fdouble_helper.c | 290 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 target-tilegx/fdouble_helper.c diff --git a/target-tilegx/fdouble_helper.c b/target-tilegx/fdouble_helper.c new file mode 100644 index 0000000..7ba0583 --- /dev/null +++ b/target-tilegx/fdouble_helper.c @@ -0,0 +1,290 @@ +/* + * QEMU TILE-Gx helpers + * + * Copyright (c) 2015 Chen Gang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#include "cpu.h" +#include "qemu-common.h" +#include "exec/helper-proto.h" +#include "fpu/softfloat.h" + +#include "fpu.h" + +#define TILEGX_F_MAN_HBIT (1ULL << 59) + +#pragma pack(push, 1) +typedef union F64Fmt { + float64 d; + struct { +#if defined(HOST_WORDS_BIGENDIAN) + uint64_t sign : 1; + uint64_t exp : 11; + uint64_t frac : 52; +#else + uint64_t frac : 52; + uint64_t exp : 11; + uint64_t sign : 1; +#endif + } bits; +} F64Fmt; +#pragma pack(pop) + +static uint64_t fr_to_man(F64Fmt v) +{ + uint64_t val = (uint64_t)v.bits.frac << 7; + + if (v.bits.exp) + val |= TILEGX_F_MAN_HBIT; + + return val; +} + +uint64_t helper_fdouble_unpack_min(CPUTLGState *env, + uint64_t srca, uint64_t srcb) +{ + F64Fmt va, vb; + TileGXFPDFmtV v; + + va.d = make_float64(srca); + vb.d = make_float64(srcb); + v.ll = 0; /* also cause v.fmt.overflow = 0 */ + + if (float64_is_any_nan(srca) || float64_is_any_nan(srcb) + || float64_is_infinity(srca) || float64_is_infinity(srcb)) + ; + else if (va.bits.exp> vb.bits.exp) { + if (va.bits.exp - vb.bits.exp < 64) + v.fmt.mantissa = fr_to_man(vb)>> (va.bits.exp - vb.bits.exp); + } else if (va.bits.exp < vb.bits.exp) { + if (vb.bits.exp - va.bits.exp < 64) + v.fmt.mantissa = fr_to_man(va)>> (vb.bits.exp - va.bits.exp); + } else if (va.bits.frac> vb.bits.frac) + v.fmt.mantissa = fr_to_man(vb); + else + v.fmt.mantissa = fr_to_man(va); + + return v.ll; +} + +uint64_t helper_fdouble_unpack_max(CPUTLGState *env, + uint64_t srca, uint64_t srcb) +{ + F64Fmt va, vb; + TileGXFPDFmtV v; + + va.d = make_float64(srca); + vb.d = make_float64(srcb); + v.ll = 0; /* also cause v.fmt.overflow = 0 */ + + if (float64_is_any_nan(srca) || float64_is_any_nan(srcb) + || float64_is_infinity(srca) || float64_is_infinity(srcb)) + ; + else if (va.bits.exp> vb.bits.exp) + v.fmt.mantissa = fr_to_man(va); + else if (va.bits.exp < vb.bits.exp) + v.fmt.mantissa = fr_to_man(vb); + else if (va.bits.frac> vb.bits.frac) + v.fmt.mantissa = fr_to_man(va); + else + v.fmt.mantissa = fr_to_man(vb); + + return v.ll; +} + +uint64_t helper_fdouble_addsub(CPUTLGState *env, + uint64_t dest, uint64_t srca, uint64_t srcb) +{ + TileGXFPDFmtF flags; + TileGXFPDFmtV v; + + flags.ll = srcb; + if (flags.fmt.calc == TILEGX_F_CALC_ADD) { + v.ll = dest + srca; /* maybe set addsub overflow bit */ + } else + v.ll = dest - srca; + + return v.ll; +} + +/* absolute-add/mul may cause add/mul carry or overflow */ +static bool proc_oflow(TileGXFPDFmtF *flags, TileGXFPDFmtV *v, uint64_t *srcb) +{ + if (v->fmt.overflow) { + flags->fmt.vexp++; + *srcb>>= 1; + *srcb |= (uint64_t)v->ll << 63; + v->ll>>= 1; + v->fmt.overflow = 0; + } + return flags->fmt.vexp> TILEGX_F_EXP_DMAX; +} + +uint64_t helper_fdouble_pack2(CPUTLGState *env, + uint64_t dest, uint64_t srca, uint64_t srcb) +{ + TileGXFPDFmtF flags; + TileGXFPDFmtV v; + F64Fmt d; + + flags.ll = dest; + v.ll = srca; + + d.d = 0; + d.bits.sign = flags.fmt.sign; + + /* + * fdouble_add_flags, fdouble_sub_flags, or fdouble_mul_flags have + * processed exceptions. So need not process fp_status, again. + */ + + if (flags.fmt.nan) + return float64_val(float64_default_nan); + else if (flags.fmt.inf) + return float64_val(d.d |= float64_infinity); + + /* absolute-mul needs left shift 4 + 1 bytes to match the real mantissa */ + if (flags.fmt.calc == TILEGX_F_CALC_MUL) { + v.ll <<= 5; + v.ll |= srcb>> 59; + srcb <<= 5; + } + + if (flags.fmt.vexp & TILEGX_F_EXP_DUF) /* must check underflow, firstly */ + return float64_val(d.d); + + if (proc_oflow(&flags, &v, &srcb)) + return float64_val(d.d |= float64_infinity); + + while (!(v.fmt.mantissa & TILEGX_F_MAN_HBIT) && (v.fmt.mantissa | srcb)) { + flags.fmt.vexp--; + v.fmt.mantissa <<= 1; + v.fmt.mantissa |= srcb>> 63; + srcb <<= 1; + } + + /* check underflow, again, after format */ + if ((flags.fmt.vexp & TILEGX_F_EXP_DUF) || !v.fmt.mantissa) + return float64_val(d.d); + + if (flags.fmt.sign) + d.d = int64_to_float64(0 - (int64_t)v.fmt.mantissa, &env->fp_status); + else + d.d = uint64_to_float64((uint64_t)v.fmt.mantissa, &env->fp_status); + + if (d.bits.exp == 59 + TILEGX_F_EXP_DZERO) + d.bits.exp = flags.fmt.vexp; + else { /* for carry and overflow again */ + d.bits.exp = flags.fmt.vexp + 1; + if (d.bits.exp == TILEGX_F_EXP_DMAX) + d.d = float64_infinity; + } + + d.bits.sign = flags.fmt.sign; + + return float64_val(d.d); +} + +static void ana_bits(float_status *fp_status, + float64 fsrca, float64 fsrcb, TileGXFPDFmtF *dfmt) +{ + if (float64_eq(fsrca, fsrcb, fp_status)) { + dfmt->fmt.eq = 1; + } else { + dfmt->fmt.neq = 1; + } + + if (float64_lt(fsrca, fsrcb, fp_status)) { + dfmt->fmt.lt = 1; + } + if (float64_le(fsrca, fsrcb, fp_status)) { + dfmt->fmt.le = 1; + } + + if (float64_lt(fsrcb, fsrca, fp_status)) { + dfmt->fmt.gt = 1; + } + if (float64_le(fsrcb, fsrca, fp_status)) { + dfmt->fmt.ge = 1; + } + + if (float64_unordered(fsrca, fsrcb, fp_status)) { + dfmt->fmt.unordered = 1; + } +} + +static uint64_t main_calc(float_status *fp_status, + float64 fsrca, float64 fsrcb, + float64 (*calc)(float64, float64, float_status *)) +{ + F64Fmt va, vb, vf; + TileGXFPDFmtF flags; + + flags.ll = 0; + ana_bits(fp_status, fsrca, fsrcb, &flags); + + vf.d = calc(fsrca, fsrcb, fp_status); /* also check exceptions */ + flags.fmt.sign = vf.bits.sign; + + va.d = fsrca; + vb.d = fsrcb; + if (float64_is_any_nan(vf.d)) + flags.fmt.nan = 1; + else if (float64_is_infinity(vf.d)) + flags.fmt.inf = 1; + else if (calc == float64_add) { + flags.fmt.vexp = (va.bits.exp> vb.bits.exp) + ? va.bits.exp : vb.bits.exp; + flags.fmt.calc = (va.bits.sign == vb.bits.sign) + ? TILEGX_F_CALC_ADD : TILEGX_F_CALC_SUB; + + } else if (calc == float64_sub) { + flags.fmt.vexp = (va.bits.exp> vb.bits.exp) + ? va.bits.exp : vb.bits.exp; + flags.fmt.calc = (va.bits.sign != vb.bits.sign) + ? TILEGX_F_CALC_ADD : TILEGX_F_CALC_SUB; + + } else { + flags.fmt.vexp = (int64_t)(va.bits.exp - TILEGX_F_EXP_DZERO) + + (int64_t)(vb.bits.exp - TILEGX_F_EXP_DZERO) + + TILEGX_F_EXP_DZERO; + flags.fmt.calc = TILEGX_F_CALC_MUL; + } + + return flags.ll; +} + +uint64_t helper_fdouble_add_flags(CPUTLGState *env, + uint64_t srca, uint64_t srcb) +{ + return main_calc(&env->fp_status, + make_float64(srca), make_float64(srcb), float64_add); +} + +uint64_t helper_fdouble_sub_flags(CPUTLGState *env, + uint64_t srca, uint64_t srcb) +{ + return main_calc(&env->fp_status, + make_float64(srca), make_float64(srcb), float64_sub); +} + +uint64_t helper_fdouble_mul_flags(CPUTLGState *env, + uint64_t srca, uint64_t srcb) +{ + return main_calc(&env->fp_status, + make_float64(srca), make_float64(srcb), float64_mul); +} -- 1.9.3
0003-target-tilegx-Implement-fpu-fdouble-floating-point-i.patch
Description: Binary data