diff mbox

target-tilegx: Implement floating point instructions

Message ID COL130-W6B8B20D50BEE8B459FAD6B92E0@phx.gbl
State New
Headers show

Commit Message

Chen Gang Oct. 31, 2015, 4:59 p.m. UTC
From 42733d085bfcb4882cfa4eb25a9387e3d953a64f Mon Sep 17 00:00:00 2001
From: Chen Gang <gang.chen.5i5j@gmail.com>
Date: Sun, 1 Nov 2015 00:50:33 +0800
Subject: [PATCH] target-tilegx: Implement floating point instructions

It is implenented in a normal way, and passed unit tests (8 test cases).

Signed-off-by: Chen Gang <gang.chen.5i5j@gmail.com>
---
 target-tilegx/Makefile.objs    |   3 +-
 target-tilegx/cpu.h            |   2 +
 target-tilegx/fdouble_helper.c | 234 +++++++++++++++++++++++++++++++++++++++++
 target-tilegx/fpu.h            | 217 ++++++++++++++++++++++++++++++++++++++
 target-tilegx/fsingle_helper.c | 157 +++++++++++++++++++++++++++
 target-tilegx/helper.h         |  12 +++
 target-tilegx/translate.c      |  68 ++++++++++--
 7 files changed, 683 insertions(+), 10 deletions(-)
 create mode 100644 target-tilegx/fdouble_helper.c
 create mode 100644 target-tilegx/fpu.h
 create mode 100644 target-tilegx/fsingle_helper.c

-- 
1.9.3

Comments

Chen Gang Nov. 1, 2015, 4:30 a.m. UTC | #1
Oh, sorry, it can not pass gcc testsuite: the fdouble mul insns have
issues (original temporary implementation had no this cases -- it
skipped the outside mul operation).

After it passes gcc testtsuite, I shall split it into several small
patches, and send patch v2 (I shall try to finish today).

Thanks.


On 11/1/15 00:59, Chen Gang wrote:
> From 42733d085bfcb4882cfa4eb25a9387e3d953a64f Mon Sep 17 00:00:00 2001
> From: Chen Gang <gang.chen.5i5j@gmail.com>
> Date: Sun, 1 Nov 2015 00:50:33 +0800
> Subject: [PATCH] target-tilegx: Implement floating point instructions
> 
> It is implenented in a normal way, and passed unit tests (8 test cases).
> 
> Signed-off-by: Chen Gang <gang.chen.5i5j@gmail.com>
> ---
>  target-tilegx/Makefile.objs    |   3 +-
>  target-tilegx/cpu.h            |   2 +
>  target-tilegx/fdouble_helper.c | 234 +++++++++++++++++++++++++++++++++++++++++
>  target-tilegx/fpu.h            | 217 ++++++++++++++++++++++++++++++++++++++
>  target-tilegx/fsingle_helper.c | 157 +++++++++++++++++++++++++++
>  target-tilegx/helper.h         |  12 +++
>  target-tilegx/translate.c      |  68 ++++++++++--
>  7 files changed, 683 insertions(+), 10 deletions(-)
>  create mode 100644 target-tilegx/fdouble_helper.c
>  create mode 100644 target-tilegx/fpu.h
>  create mode 100644 target-tilegx/fsingle_helper.c
> 
> diff --git a/target-tilegx/Makefile.objs b/target-tilegx/Makefile.objs
> index 0db778f..c2cf2f1 100644
> --- a/target-tilegx/Makefile.objs
> +++ b/target-tilegx/Makefile.objs
> @@ -1 +1,2 @@
> -obj-y += cpu.o translate.o helper.o simd_helper.o
> +obj-y += cpu.o translate.o helper.o simd_helper.o \
> +		fsingle_helper.o fdouble_helper.o
> diff --git a/target-tilegx/cpu.h b/target-tilegx/cpu.h
> index 03df107..445a606 100644
> --- a/target-tilegx/cpu.h
> +++ b/target-tilegx/cpu.h
> @@ -88,6 +88,8 @@ typedef struct CPUTLGState {
>      uint64_t spregs[TILEGX_SPR_COUNT]; /* Special used registers by outside */
>      uint64_t pc;                       /* Current pc */
>  
> +    float_status fp_status;            /* floating point status */
> +
>  #if defined(CONFIG_USER_ONLY)
>      uint64_t excaddr;                  /* exception address */
>      uint64_t atomic_srca;              /* Arguments to atomic "exceptions" */
> diff --git a/target-tilegx/fdouble_helper.c b/target-tilegx/fdouble_helper.c
> new file mode 100644
> index 0000000..b3b0588
> --- /dev/null
> +++ b/target-tilegx/fdouble_helper.c
> @@ -0,0 +1,234 @@
> +/*
> + * 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 (va.bits.exp> vb.bits.exp)
> +        v.fmt.mantissa = fr_to_man(vb)>> (va.bits.exp - vb.bits.exp);
> +    else if (va.bits.exp < vb.bits.exp)
> +        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 (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.addsub == TILEGX_F_ADDSUB_ADD) {
> +        v.ll = dest + srca; /* maybe set addsub overflow bit */
> +    } else
> +        v.ll = dest - srca;
> +
> +    return v.ll;
> +}
> +
> +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;
> +
> +    /*
> +     * Assume fdouble_add_flags, fdouble_sub_flags, or fdouble_mul_flags
> +     * already processed any exceptions.
> +     */
> +
> +    /* only absolute-add can cause addsub overflow, it may not be exception */
> +    if (v.fmt.overflow && (flags.fmt.exp < TILEGX_F_EXP_DMAX)) {
> +        flags.fmt.exp++;
> +        srcb>>= 1;
> +        srcb |= (uint64_t)v.fmt.mantissa << 63;
> +        v.fmt.mantissa>>= 1;
> +        v.fmt.mantissa |= TILEGX_F_MAN_HBIT;
> +    }
> +
> +    while (flags.fmt.exp && !(v.fmt.mantissa & TILEGX_F_MAN_HBIT)) {
> +        flags.fmt.exp--;
> +        v.fmt.mantissa <<= 1;
> +        v.fmt.mantissa |= srcb>> 63;
> +        srcb <<= 1;
> +    }
> +
> +    d.bits.sign = flags.fmt.sign;
> +    d.bits.exp = flags.fmt.exp;
> +    d.bits.frac = v.fmt.mantissa>> 7;
> +
> +    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 (calc == float64_add) {
> +        flags.fmt.exp = (va.bits.exp> vb.bits.exp) ? va.bits.exp : vb.bits.exp;
> +        flags.fmt.addsub = (va.bits.sign == vb.bits.sign)
> +                               ? TILEGX_F_ADDSUB_ADD : TILEGX_F_ADDSUB_SUB;
> +
> +    } else if (calc == float64_sub) {
> +        flags.fmt.exp = (va.bits.exp> vb.bits.exp) ? va.bits.exp : vb.bits.exp;
> +        flags.fmt.addsub = (va.bits.sign != vb.bits.sign)
> +                               ? TILEGX_F_ADDSUB_ADD : TILEGX_F_ADDSUB_SUB;
> +
> +    } else /* It's float64_mul, don't need flags.addsub */
> +        flags.fmt.exp = ((uint64_t)va.bits.exp + (uint64_t)vb.bits.exp
> +                           <= TILEGX_F_EXP_DMAX)
> +                               ? va.bits.exp + vb.bits.exp : vf.bits.exp;
> +
> +    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);
> +}
> diff --git a/target-tilegx/fpu.h b/target-tilegx/fpu.h
> new file mode 100644
> index 0000000..3421c05
> --- /dev/null
> +++ b/target-tilegx/fpu.h
> @@ -0,0 +1,217 @@
> +/*
> + *  TILE-Gx virtual FPU header
> + *
> + *  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 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
> + * 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/>.
> + */
> +#ifndef FPU_TILEGX_H
> +#define FPU_TILEGX_H
> +
> +/*
> + * From IEEE standard, exp of float is 8-bits, exp of double is 11-bits.
> + */
> +#define TILEGX_F_EXP_FZERO  0x7f  /* Zero exp for single 8-bits */
> +#define TILEGX_F_EXP_DZERO  0x3ff /* Zero exp for double 11-bits */
> +#define TILEGX_F_EXP_DMAX   0x7ff /* max exp for double 11-bits */
> +
> +/*
> + * For fdouble addsub bit
> + */
> +#define TILEGX_F_ADDSUB_ADD 0     /* Perform absolute add operation */
> +#define TILEGX_F_ADDSUB_SUB 1     /* Perform absolute sub operation */
> +
> +#pragma pack(push, 1)
> +
> +/*
> + * Single format, it is 64-bit.
> + *
> + * Single exp analyzing: 0x9e - 0x1e(30) = 0x80
> + *
> + *   7   6   5   4   3   2   1   0
> + *
> + *   1   0   0   1   1   1   1   0
> + *
> + *   0   0   0   1   1   1   1   1    => 0x1f(31)
> + *
> + *   0   1   1   1   1   1   1   1    => 0x7f
> + */
> +typedef struct TileGXFPSFmt {
> +
> +#if !defined(HOST_WORDS_BIGENDIAN)
> +    /* According to float(uns)sisf2 and float(uns)sidf2 in gcc tilegx.md */
> +    uint64_t exp : 8;             /* exp, 0x9e: 31 + TILEGX_F_EXP_FZERO */
> +    uint64_t uiknown0 : 1;        /* unknown */
> +    uint64_t sign : 1;            /* Sign bit for the total value */
> +    uint64_t unknown1 : 15;       /* unknown */
> +
> +    /* Come from TILE-Gx ISA document, Table 7-2 for floating point */
> +    uint64_t unordered : 1;       /* The two are unordered */
> +    uint64_t lt : 1;              /* 1st is less than 2nd */
> +    uint64_t le : 1;              /* 1st is less than or equal to 2nd */
> +    uint64_t gt : 1;              /* 1st is greater than 2nd */
> +    uint64_t ge : 1;              /* 1st is greater than or equal to 2nd */
> +    uint64_t eq : 1;              /* The two operands are equal */
> +    uint64_t neq : 1;             /* The two operands are not equal */
> +
> +    /* According to float(uns)sisf2 and float(uns)sidf2 in gcc tilegx.md */
> +    uint64_t mantissa : 32;       /* mantissa */
> +#else
> +    uint64_t mantissa : 32;       /* mantissa */
> +    uint64_t neq : 1;             /* The two operands are not equal */
> +    uint64_t eq : 1;              /* The two operands are equal */
> +    uint64_t ge : 1;              /* 1st is greater than or equal to 2nd */
> +    uint64_t gt : 1;              /* 1st is greater than 2nd */
> +    uint64_t le : 1;              /* 1st is less than or equal to 2nd */
> +    uint64_t lt : 1;              /* 1st is less than 2nd */
> +    uint64_t unordered : 1;       /* The two are unordered */
> +    uint64_t unknown1 : 15;       /* unknown */
> +    uint64_t sign : 1;            /* Sign bit for the total value */
> +    uint64_t unknown0 : 1;        /* unknown */
> +    uint64_t exp : 8;             /* exp, 0x9e: 31 + TILEGX_F_EXP_FZERO */
> +#endif
> +} TileGXFPSFmt;
> +/*
> + * FSingle instructions implemenation:
> + *
> + * fsingle_add1         ; calc srca and srcb,
> + *                      ; convert float_32 to TileGXFPSFmt result.
> + *                      ; move TileGXFPSFmt result to dest.
> + *
> + * fsingle_sub1         ; calc srca and srcb.
> + *                      ; convert float_32 to TileGXFPSFmt result.
> + *                      ; move TileGXFPSFmt result to dest.
> + *
> + * fsingle_addsub2      ; nop.
> + *
> + * fsingle_mul1         ; calc srca and srcb.
> + *                      ; convert float_32 value to TileGXFPSFmt result.
> + *                      ; move TileGXFPSFmt result to dest.
> + *
> + * fsingle_mul2         ; move srca to dest.
> + *
> + * fsingle_pack1        ; nop
> + *
> + * fsingle_pack2        ; treate srca as TileGXFPSFmt result.
> + *                      ; convert TileGXFPSFmt result to float_32 value.
> + *                      ; move float_32 value to dest.
> + */
> +
> +/*
> + * Dobule format. flag: 64 bits, value: 64 bits.
> + *
> + * Double exp analyzing: (0x21b00 << 1) - 0x36(54) = 0x400
> + *
> + *   17  16  15  14  13  12  11  10   9   8   7    6   5   4   3   2   1   0
> + *
> + *    1   0   0   0   0   1   1   0   1   1   0    0   0   0   0   0   0   0
> + *
> + *    0   0   0   0   0   1   1   0   1   1   1    => 0x37(55)
> + *
> + *    0   1   1   1   1   1   1   1   1   1   1    => 0x3ff
> + *
> + */
> +typedef union TileGXFPDFmtF {
> +
> +    struct {
> +#if !defined(HOST_WORDS_BIGENDIAN)
> +        uint64_t unknown0 : 7;    /* unknown */
> +        uint64_t exp : 11;        /* exp, 0x21b << 1: 55 + TILEGX_F_EXP_DZERO */
> +        uint64_t unknown1 : 2;    /* unknown */
> +        uint64_t sign : 1;        /* Sign bit for the total value */
> +
> +        uint64_t addsub: 1;       /* add or sub bit */
> +        uint64_t unknown2: 3;     /* unknown */
> +
> +        /* Come from TILE-Gx ISA document, Table 7-2 for floating point */
> +        uint64_t unordered : 1;   /* The two are unordered */
> +        uint64_t lt : 1;          /* 1st is less than 2nd */
> +        uint64_t le : 1;          /* 1st is less than or equal to 2nd */
> +        uint64_t gt : 1;          /* 1st is greater than 2nd */
> +        uint64_t ge : 1;          /* 1st is greater than or equal to 2nd */
> +        uint64_t eq : 1;          /* The two operands are equal */
> +        uint64_t neq : 1;         /* The two operands are not equal */
> +
> +        uint64_t unknown3 : 32;   /* unknown */
> +#else
> +        uint64_t unknown3 : 32;   /* unknown */
> +        uint64_t neq : 1;         /* The two operands are not equal */
> +        uint64_t eq : 1;          /* The two operands are equal */
> +        uint64_t ge : 1;          /* 1st is greater than or equal to 2nd */
> +        uint64_t gt : 1;          /* 1st is greater than 2nd */
> +        uint64_t le : 1;          /* 1st is less than or equal to 2nd */
> +        uint64_t lt : 1;          /* 1st is less than 2nd */
> +        uint64_t unordered : 1;   /* The two are unordered */
> +        uint64_t unknown2: 3;     /* unknown */
> +        uint64_t addsub: 1;       /* add or sub bit */
> +        uint64_t sign : 1;        /* Sign bit for the total value */
> +        uint64_t unknown1 : 2;    /* unknown */
> +        uint64_t exp : 11;        /* exp, 0x21b << 1: 55 + TILEGX_F_EXP_DZERO */
> +        uint64_t unknown0 : 7;    /* unknown */
> +#endif
> +    } fmt;
> +    uint64_t ll;                  /* only for easy using */
> +} TileGXFPDFmtF;
> +
> +typedef union TileGXFPDFmtV {
> +    struct {
> +#if !defined(HOST_WORDS_BIGENDIAN)
> +        uint64_t mantissa : 60;   /* mantissa */
> +        uint64_t overflow : 1;    /* overflow bit for addsub */
> +        uint64_t unknown1 : 3;    /* unknown */
> +#else
> +        uint64_t unknown1 : 3;    /* unknown */
> +        uint64_t overflow : 1;    /* overflow bit for addsub */
> +        uint64_t mantissa : 60;   /* mantissa */
> +#endif
> +    } fmt;
> +    uint64_t ll;                  /* only for easy using */
> +} TileGXFPDFmtV;
> +/*
> + * FDouble instructions implemenation:
> + *
> + * fdouble_unpack_min   ; srca and srcb are float_64 value.
> + *                      ; get the min absolute value's mantissa.
> + *                      ; move "mantissa>> (exp_max - exp_min)" to dest.
> + *
> + * fdouble_unpack_max   ; srca and srcb are float_64 value.
> + *                      ; get the max absolute value's mantissa.
> + *                      ; move mantissa to dest.
> + *
> + * fdouble_add_flags    ; srca and srcb are float_64 value.
> + *                      ; calc exp (exp_max), sign, and comp bits for flags.
> + *                      ; set addsub bit to flags and move flags to dest.
> + *
> + * fdouble_sub_flags    ; srca and srcb are float_64 value.
> + *                      ; calc exp (exp_max), sign, and comp bits for flags.
> + *                      ; set addsub bit to flags and move flags to dest.
> + *
> + * fdouble_addsub:      ; dest, srca (max, min mantissa), and srcb (flags).
> + *                      ; "dest +/- srca" depend on the add/sub bit of flags.
> + *                      ; move result mantissa to dest.
> + *
> + * fdouble_mul_flags:   ; srca and srcb are float_64 value.
> + *                      ; calc sign (xor), exp (exp_min + exp_max), and comp bits.
> + *                      ; mix sign, exp, and comp bits as flags to dest.
> + *
> + * fdouble_pack1        ; move srcb (flags) to dest.
> + *
> + * fdouble_pack2        ; srca, srcb (high, low mantissa), and dest (flags)
> + *                      ; normalize and pack result from srca, srcb, and dest.
> + *                      ; move result to dest.
> + */
> +
> +#pragma pack(pop)
> +
> +#endif /* FPU_TILEGX_H */
> diff --git a/target-tilegx/fsingle_helper.c b/target-tilegx/fsingle_helper.c
> new file mode 100644
> index 0000000..95ff9f4
> --- /dev/null
> +++ b/target-tilegx/fsingle_helper.c
> @@ -0,0 +1,157 @@
> +/*
> + * 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"
> +
> +#pragma pack(push, 1)
> +typedef union F32Fmt {
> +    uint32_t f;
> +    struct {
> +#if defined(HOST_WORDS_BIGENDIAN)
> +        uint32_t sign : 1;
> +        uint32_t exp  : 8;
> +        uint32_t frac : 23;
> +#else
> +        uint32_t frac : 23;
> +        uint32_t exp  : 8;
> +        uint32_t sign : 1;
> +#endif
> +    } bits;
> +} F32Fmt;
> +#pragma pack(pop)
> +
> +static uint64_t sfmt_to_uint64(TileGXFPSFmt a)
> +{
> +    union {
> +        TileGXFPSFmt a;
> +        uint64_t v;
> +    } t;
> +    t.a = a;
> +    return t.v;
> +}
> +
> +static TileGXFPSFmt uint64_to_sfmt(uint64 v)
> +{
> +    union {
> +        TileGXFPSFmt a;
> +        uint64_t v;
> +    } t;
> +    t.v = v;
> +    return t.a;
> +}
> +
> +static TileGXFPSFmt float32_to_sfmt(float32 f)
> +{
> +    F32Fmt tmp = {f};
> +    union {
> +        TileGXFPSFmt fmt;
> +        uint64_t v;
> +    } sfmt;
> +
> +    sfmt.v = 0;
> +    sfmt.fmt.sign = tmp.bits.sign;
> +    sfmt.fmt.exp = tmp.bits.exp;
> +    sfmt.fmt.mantissa = (tmp.bits.frac << 8) | (1 << 31);
> +
> +    return sfmt.fmt;
> +}
> +
> +static float32 sfmt_to_float32(TileGXFPSFmt sfmt)
> +{
> +    F32Fmt f;
> +
> +    while (sfmt.exp && !(sfmt.mantissa & (1ULL << 31))) {
> +        sfmt.exp--;
> +        sfmt.mantissa <<= 1;
> +    }
> +
> +    f.bits.sign = sfmt.sign;
> +    f.bits.exp = sfmt.exp;
> +    f.bits.frac = sfmt.mantissa>> 8;
> +
> +    return f.f;
> +}
> +
> +uint64_t helper_fsingle_pack2(uint64_t srca)
> +{
> +    return float32_val(sfmt_to_float32(uint64_to_sfmt(srca)));
> +}
> +
> +static void ana_bits(float_status *fp_status,
> +                     float32 fsrca, float32 fsrcb, TileGXFPSFmt *sfmt)
> +{
> +    if (float32_eq(fsrca, fsrcb, fp_status)) {
> +        sfmt->eq = 1;
> +    } else {
> +        sfmt->neq = 1;
> +    }
> +
> +    if (float32_lt(fsrca, fsrcb, fp_status)) {
> +        sfmt->lt = 1;
> +    }
> +    if (float32_le(fsrca, fsrcb, fp_status)) {
> +        sfmt->le = 1;
> +    }
> +
> +    if (float32_lt(fsrcb, fsrca, fp_status)) {
> +        sfmt->gt = 1;
> +    }
> +    if (float32_le(fsrcb, fsrca, fp_status)) {
> +        sfmt->ge = 1;
> +    }
> +
> +    if (float32_unordered(fsrca, fsrcb, fp_status)) {
> +        sfmt->unordered = 1;
> +    }
> +}
> +
> +static uint64_t main_calc(float_status *fp_status,
> +                          float32 fsrca, float32 fsrcb,
> +                          float32 (*calc)(float32, float32, float_status *))
> +{
> +    TileGXFPSFmt sfmt = float32_to_sfmt(calc(fsrca, fsrcb, fp_status));
> +
> +    ana_bits(fp_status, fsrca, fsrcb, &sfmt);
> +
> +    return sfmt_to_uint64(sfmt);
> +}
> +
> +uint64_t helper_fsingle_add1(CPUTLGState *env, uint64_t srca, uint64_t srcb)
> +{
> +    return main_calc(&env->fp_status,
> +                     make_float32(srca), make_float32(srcb), float32_add);
> +}
> +
> +uint64_t helper_fsingle_sub1(CPUTLGState *env, uint64_t srca, uint64_t srcb)
> +{
> +    return main_calc(&env->fp_status,
> +                     make_float32(srca), make_float32(srcb), float32_sub);
> +}
> +
> +uint64_t helper_fsingle_mul1(CPUTLGState *env, uint64_t srca, uint64_t srcb)
> +{
> +    return main_calc(&env->fp_status,
> +                     make_float32(srca), make_float32(srcb), float32_mul);
> +}
> diff --git a/target-tilegx/helper.h b/target-tilegx/helper.h
> index 9281d0f..6c40762 100644
> --- a/target-tilegx/helper.h
> +++ b/target-tilegx/helper.h
> @@ -24,3 +24,15 @@ DEF_HELPER_FLAGS_2(v1shrs, TCG_CALL_NO_RWG_SE, i64, i64, i64)
>  DEF_HELPER_FLAGS_2(v2shl, TCG_CALL_NO_RWG_SE, i64, i64, i64)
>  DEF_HELPER_FLAGS_2(v2shru, TCG_CALL_NO_RWG_SE, i64, i64, i64)
>  DEF_HELPER_FLAGS_2(v2shrs, TCG_CALL_NO_RWG_SE, i64, i64, i64)
> +
> +DEF_HELPER_3(fsingle_add1, i64, env, i64, i64)
> +DEF_HELPER_3(fsingle_sub1, i64, env, i64, i64)
> +DEF_HELPER_3(fsingle_mul1, i64, env, i64, i64)
> +DEF_HELPER_1(fsingle_pack2, i64, i64)
> +DEF_HELPER_3(fdouble_unpack_min, i64, env, i64, i64)
> +DEF_HELPER_3(fdouble_unpack_max, i64, env, i64, i64)
> +DEF_HELPER_3(fdouble_add_flags, i64, env, i64, i64)
> +DEF_HELPER_3(fdouble_sub_flags, i64, env, i64, i64)
> +DEF_HELPER_4(fdouble_addsub, i64, env, i64, i64, i64)
> +DEF_HELPER_3(fdouble_mul_flags, i64, env, i64, i64)
> +DEF_HELPER_4(fdouble_pack2, i64, env, i64, i64, i64)
> diff --git a/target-tilegx/translate.c b/target-tilegx/translate.c
> index b8ca401..4c6f07c 100644
> --- a/target-tilegx/translate.c
> +++ b/target-tilegx/translate.c
> @@ -597,6 +597,11 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
>          }
>          qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s %s", mnemonic, reg_names[srca]);
>          return ret;
> +
> +    case OE_RR_X0(FSINGLE_PACK1):
> +    case OE_RR_Y0(FSINGLE_PACK1):
> +        mnemonic = "fsingle_pack1";
> +        goto done2;
>      }
>  
>      tdest = dest_gr(dc, dest);
> @@ -613,9 +618,6 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
>          gen_helper_cnttz(tdest, tsrca);
>          mnemonic = "cnttz";
>          break;
> -    case OE_RR_X0(FSINGLE_PACK1):
> -    case OE_RR_Y0(FSINGLE_PACK1):
> -        return TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
>      case OE_RR_X1(LD1S):
>          memop = MO_SB;
>          mnemonic = "ld1s"; /* prefetch_l1_fault */
> @@ -734,6 +736,7 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
>          return TILEGX_EXCP_OPCODE_UNKNOWN;
>      }
>  
> +done2:
>      qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s %s, %s", mnemonic,
>                    reg_names[dest], reg_names[srca]);
>      return ret;
> @@ -742,13 +745,21 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
>  static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
>                                 unsigned dest, unsigned srca, unsigned srcb)
>  {
> -    TCGv tdest = dest_gr(dc, dest);
> -    TCGv tsrca = load_gr(dc, srca);
> -    TCGv tsrcb = load_gr(dc, srcb);
> +    TCGv tdest, tsrca, tsrcb;
>      TCGv t0;
>      const char *mnemonic;
>  
>      switch (opext) {
> +    case OE_RRR(FSINGLE_ADDSUB2, 0, X0):
> +        mnemonic = "fsingle_addsub2";
> +        goto done2;
> +    }
> +
> +    tdest = dest_gr(dc, dest);
> +    tsrca = load_gr(dc, srca);
> +    tsrcb = load_gr(dc, srcb);
> +
> +    switch (opext) {
>      case OE_RRR(ADDXSC, 0, X0):
>      case OE_RRR(ADDXSC, 0, X1):
>          gen_saturate_op(tdest, tsrca, tsrcb, tcg_gen_add_tl);
> @@ -906,14 +917,39 @@ static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
>          mnemonic = "exch";
>          break;
>      case OE_RRR(FDOUBLE_ADDSUB, 0, X0):
> +        gen_helper_fdouble_addsub(tdest, cpu_env,
> +                                  load_gr(dc, dest),tsrca, tsrcb);
> +        mnemonic = "fdouble_addsub";
> +        break;
>      case OE_RRR(FDOUBLE_ADD_FLAGS, 0, X0):
> +        gen_helper_fdouble_add_flags(tdest, cpu_env, tsrca, tsrcb);
> +        mnemonic = "fdouble_add_flags";
> +        break;
>      case OE_RRR(FDOUBLE_MUL_FLAGS, 0, X0):
> +        gen_helper_fdouble_mul_flags(tdest, cpu_env, tsrca, tsrcb);
> +        mnemonic = "fdouble_mul_flags";
> +        break;
>      case OE_RRR(FDOUBLE_PACK1, 0, X0):
> +        tcg_gen_mov_i64(tdest, tsrcb);
> +        mnemonic = "fdouble_pack1";
> +        break;
>      case OE_RRR(FDOUBLE_PACK2, 0, X0):
> +        gen_helper_fdouble_pack2(tdest, cpu_env,
> +                                 load_gr(dc, dest), tsrca, tsrcb);
> +        mnemonic = "fdouble_pack2";
> +        break;
>      case OE_RRR(FDOUBLE_SUB_FLAGS, 0, X0):
> +        gen_helper_fdouble_sub_flags(tdest, cpu_env, tsrca, tsrcb);
> +        mnemonic = "fdouble_sub_flags";
> +        break;
>      case OE_RRR(FDOUBLE_UNPACK_MAX, 0, X0):
> +        gen_helper_fdouble_unpack_max(tdest, cpu_env, tsrca, tsrcb);
> +        mnemonic = "fdouble_unpack_max";
> +        break;
>      case OE_RRR(FDOUBLE_UNPACK_MIN, 0, X0):
> -        return TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
> +        gen_helper_fdouble_unpack_min(tdest, cpu_env, tsrca, tsrcb);
> +        mnemonic = "fdouble_unpack_min";
> +        break;
>      case OE_RRR(FETCHADD4, 0, X1):
>          gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb,
>                          TILEGX_EXCP_OPCODE_FETCHADD4);
> @@ -955,12 +991,25 @@ static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
>          mnemonic = "fetchor";
>          break;
>      case OE_RRR(FSINGLE_ADD1, 0, X0):
> -    case OE_RRR(FSINGLE_ADDSUB2, 0, X0):
> +        gen_helper_fsingle_add1(tdest, cpu_env, tsrca, tsrcb);
> +        mnemonic = "fsingle_add1";
> +        break;
>      case OE_RRR(FSINGLE_MUL1, 0, X0):
> +        gen_helper_fsingle_mul1(tdest, cpu_env, tsrca, tsrcb);
> +        mnemonic = "fsingle_mul1";
> +        break;
>      case OE_RRR(FSINGLE_MUL2, 0, X0):
> +        tcg_gen_mov_i64(tdest, tsrca);
> +        mnemonic = "fsingle_mul2";
> +        break;
>      case OE_RRR(FSINGLE_PACK2, 0, X0):
> +        gen_helper_fsingle_pack2(tdest, tsrca);
> +        mnemonic = "fsingle_pack2";
> +        break;
>      case OE_RRR(FSINGLE_SUB1, 0, X0):
> -        return TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
> +        gen_helper_fsingle_sub1(tdest, cpu_env, tsrca, tsrcb);
> +        mnemonic = "fsingle_sub1";
> +        break;
>      case OE_RRR(MNZ, 0, X0):
>      case OE_RRR(MNZ, 0, X1):
>      case OE_RRR(MNZ, 4, Y0):
> @@ -1464,6 +1513,7 @@ static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
>          return TILEGX_EXCP_OPCODE_UNKNOWN;
>      }
>  
> +done2:
>      qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s %s, %s, %s", mnemonic,
>                    reg_names[dest], reg_names[srca], reg_names[srcb]);
>      return TILEGX_EXCP_NONE;
> -- 
> 1.9.3 		 	   		  
>
Chen Gang Nov. 1, 2015, 10:18 p.m. UTC | #2
Sorry, based on this patch, after fix 5 issues, it still has issues. The
issues which I have fixed are:

 - Fix floating point fdouble multiply related instructions issues

 - Process every overflow cases.

 - Process absolute multiply carrying just like absolute add has done.

 - Process the nearest skipped bit carrying for fdouble.

 - Process the nearest skipped bit carrying for fsingle.

I shall try to fix the left issues all within this week (2015-11-08).

Thanks.

On 11/1/15 12:30, Chen Gang wrote:
>
> Oh, sorry, it can not pass gcc testsuite: the fdouble mul insns have
> issues (original temporary implementation had no this cases -- it
> skipped the outside mul operation).
>
> After it passes gcc testtsuite, I shall split it into several small
> patches, and send patch v2 (I shall try to finish today).
>
> Thanks.
>
>
> On 11/1/15 00:59, Chen Gang wrote:
>> From 42733d085bfcb4882cfa4eb25a9387e3d953a64f Mon Sep 17 00:00:00 2001
>> From: Chen Gang <gang.chen.5i5j@gmail.com>
>> Date: Sun, 1 Nov 2015 00:50:33 +0800
>> Subject: [PATCH] target-tilegx: Implement floating point instructions
>>
>> It is implenented in a normal way, and passed unit tests (8 test cases).
>>
>> Signed-off-by: Chen Gang <gang.chen.5i5j@gmail.com>
>> ---
>> target-tilegx/Makefile.objs | 3 +-
>> target-tilegx/cpu.h | 2 +
>> target-tilegx/fdouble_helper.c | 234 +++++++++++++++++++++++++++++++++++++++++
>> target-tilegx/fpu.h | 217 ++++++++++++++++++++++++++++++++++++++
>> target-tilegx/fsingle_helper.c | 157 +++++++++++++++++++++++++++
>> target-tilegx/helper.h | 12 +++
>> target-tilegx/translate.c | 68 ++++++++++--
>> 7 files changed, 683 insertions(+), 10 deletions(-)
>> create mode 100644 target-tilegx/fdouble_helper.c
>> create mode 100644 target-tilegx/fpu.h
>> create mode 100644 target-tilegx/fsingle_helper.c
>>
>> diff --git a/target-tilegx/Makefile.objs b/target-tilegx/Makefile.objs
>> index 0db778f..c2cf2f1 100644
>> --- a/target-tilegx/Makefile.objs
>> +++ b/target-tilegx/Makefile.objs
>> @@ -1 +1,2 @@
>> -obj-y += cpu.o translate.o helper.o simd_helper.o
>> +obj-y += cpu.o translate.o helper.o simd_helper.o \
>> + fsingle_helper.o fdouble_helper.o
>> diff --git a/target-tilegx/cpu.h b/target-tilegx/cpu.h
>> index 03df107..445a606 100644
>> --- a/target-tilegx/cpu.h
>> +++ b/target-tilegx/cpu.h
>> @@ -88,6 +88,8 @@ typedef struct CPUTLGState {
>> uint64_t spregs[TILEGX_SPR_COUNT]; /* Special used registers by outside */
>> uint64_t pc; /* Current pc */
>>
>> + float_status fp_status; /* floating point status */
>> +
>> #if defined(CONFIG_USER_ONLY)
>> uint64_t excaddr; /* exception address */
>> uint64_t atomic_srca; /* Arguments to atomic "exceptions" */
>> diff --git a/target-tilegx/fdouble_helper.c b/target-tilegx/fdouble_helper.c
>> new file mode 100644
>> index 0000000..b3b0588
>> --- /dev/null
>> +++ b/target-tilegx/fdouble_helper.c
>> @@ -0,0 +1,234 @@
>> +/*
>> + * 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 (va.bits.exp> vb.bits.exp)
>> + v.fmt.mantissa = fr_to_man(vb)>> (va.bits.exp - vb.bits.exp);
>> + else if (va.bits.exp < vb.bits.exp)
>> + 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 (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.addsub == TILEGX_F_ADDSUB_ADD) {
>> + v.ll = dest + srca; /* maybe set addsub overflow bit */
>> + } else
>> + v.ll = dest - srca;
>> +
>> + return v.ll;
>> +}
>> +
>> +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;
>> +
>> + /*
>> + * Assume fdouble_add_flags, fdouble_sub_flags, or fdouble_mul_flags
>> + * already processed any exceptions.
>> + */
>> +
>> + /* only absolute-add can cause addsub overflow, it may not be exception */
>> + if (v.fmt.overflow && (flags.fmt.exp < TILEGX_F_EXP_DMAX)) {
>> + flags.fmt.exp++;
>> + srcb>>= 1;
>> + srcb |= (uint64_t)v.fmt.mantissa << 63;
>> + v.fmt.mantissa>>= 1;
>> + v.fmt.mantissa |= TILEGX_F_MAN_HBIT;
>> + }
>> +
>> + while (flags.fmt.exp && !(v.fmt.mantissa & TILEGX_F_MAN_HBIT)) {
>> + flags.fmt.exp--;
>> + v.fmt.mantissa <<= 1;
>> + v.fmt.mantissa |= srcb>> 63;
>> + srcb <<= 1;
>> + }
>> +
>> + d.bits.sign = flags.fmt.sign;
>> + d.bits.exp = flags.fmt.exp;
>> + d.bits.frac = v.fmt.mantissa>> 7;
>> +
>> + 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 (calc == float64_add) {
>> + flags.fmt.exp = (va.bits.exp> vb.bits.exp) ? va.bits.exp : vb.bits.exp;
>> + flags.fmt.addsub = (va.bits.sign == vb.bits.sign)
>> + ? TILEGX_F_ADDSUB_ADD : TILEGX_F_ADDSUB_SUB;
>> +
>> + } else if (calc == float64_sub) {
>> + flags.fmt.exp = (va.bits.exp> vb.bits.exp) ? va.bits.exp : vb.bits.exp;
>> + flags.fmt.addsub = (va.bits.sign != vb.bits.sign)
>> + ? TILEGX_F_ADDSUB_ADD : TILEGX_F_ADDSUB_SUB;
>> +
>> + } else /* It's float64_mul, don't need flags.addsub */
>> + flags.fmt.exp = ((uint64_t)va.bits.exp + (uint64_t)vb.bits.exp
>> + <= TILEGX_F_EXP_DMAX)
>> + ? va.bits.exp + vb.bits.exp : vf.bits.exp;
>> +
>> + 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);
>> +}
>> diff --git a/target-tilegx/fpu.h b/target-tilegx/fpu.h
>> new file mode 100644
>> index 0000000..3421c05
>> --- /dev/null
>> +++ b/target-tilegx/fpu.h
>> @@ -0,0 +1,217 @@
>> +/*
>> + * TILE-Gx virtual FPU header
>> + *
>> + * 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 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
>> + * 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/>.
>> + */
>> +#ifndef FPU_TILEGX_H
>> +#define FPU_TILEGX_H
>> +
>> +/*
>> + * From IEEE standard, exp of float is 8-bits, exp of double is 11-bits.
>> + */
>> +#define TILEGX_F_EXP_FZERO 0x7f /* Zero exp for single 8-bits */
>> +#define TILEGX_F_EXP_DZERO 0x3ff /* Zero exp for double 11-bits */
>> +#define TILEGX_F_EXP_DMAX 0x7ff /* max exp for double 11-bits */
>> +
>> +/*
>> + * For fdouble addsub bit
>> + */
>> +#define TILEGX_F_ADDSUB_ADD 0 /* Perform absolute add operation */
>> +#define TILEGX_F_ADDSUB_SUB 1 /* Perform absolute sub operation */
>> +
>> +#pragma pack(push, 1)
>> +
>> +/*
>> + * Single format, it is 64-bit.
>> + *
>> + * Single exp analyzing: 0x9e - 0x1e(30) = 0x80
>> + *
>> + * 7 6 5 4 3 2 1 0
>> + *
>> + * 1 0 0 1 1 1 1 0
>> + *
>> + * 0 0 0 1 1 1 1 1 => 0x1f(31)
>> + *
>> + * 0 1 1 1 1 1 1 1 => 0x7f
>> + */
>> +typedef struct TileGXFPSFmt {
>> +
>> +#if !defined(HOST_WORDS_BIGENDIAN)
>> + /* According to float(uns)sisf2 and float(uns)sidf2 in gcc tilegx.md */
>> + uint64_t exp : 8; /* exp, 0x9e: 31 + TILEGX_F_EXP_FZERO */
>> + uint64_t uiknown0 : 1; /* unknown */
>> + uint64_t sign : 1; /* Sign bit for the total value */
>> + uint64_t unknown1 : 15; /* unknown */
>> +
>> + /* Come from TILE-Gx ISA document, Table 7-2 for floating point */
>> + uint64_t unordered : 1; /* The two are unordered */
>> + uint64_t lt : 1; /* 1st is less than 2nd */
>> + uint64_t le : 1; /* 1st is less than or equal to 2nd */
>> + uint64_t gt : 1; /* 1st is greater than 2nd */
>> + uint64_t ge : 1; /* 1st is greater than or equal to 2nd */
>> + uint64_t eq : 1; /* The two operands are equal */
>> + uint64_t neq : 1; /* The two operands are not equal */
>> +
>> + /* According to float(uns)sisf2 and float(uns)sidf2 in gcc tilegx.md */
>> + uint64_t mantissa : 32; /* mantissa */
>> +#else
>> + uint64_t mantissa : 32; /* mantissa */
>> + uint64_t neq : 1; /* The two operands are not equal */
>> + uint64_t eq : 1; /* The two operands are equal */
>> + uint64_t ge : 1; /* 1st is greater than or equal to 2nd */
>> + uint64_t gt : 1; /* 1st is greater than 2nd */
>> + uint64_t le : 1; /* 1st is less than or equal to 2nd */
>> + uint64_t lt : 1; /* 1st is less than 2nd */
>> + uint64_t unordered : 1; /* The two are unordered */
>> + uint64_t unknown1 : 15; /* unknown */
>> + uint64_t sign : 1; /* Sign bit for the total value */
>> + uint64_t unknown0 : 1; /* unknown */
>> + uint64_t exp : 8; /* exp, 0x9e: 31 + TILEGX_F_EXP_FZERO */
>> +#endif
>> +} TileGXFPSFmt;
>> +/*
>> + * FSingle instructions implemenation:
>> + *
>> + * fsingle_add1 ; calc srca and srcb,
>> + * ; convert float_32 to TileGXFPSFmt result.
>> + * ; move TileGXFPSFmt result to dest.
>> + *
>> + * fsingle_sub1 ; calc srca and srcb.
>> + * ; convert float_32 to TileGXFPSFmt result.
>> + * ; move TileGXFPSFmt result to dest.
>> + *
>> + * fsingle_addsub2 ; nop.
>> + *
>> + * fsingle_mul1 ; calc srca and srcb.
>> + * ; convert float_32 value to TileGXFPSFmt result.
>> + * ; move TileGXFPSFmt result to dest.
>> + *
>> + * fsingle_mul2 ; move srca to dest.
>> + *
>> + * fsingle_pack1 ; nop
>> + *
>> + * fsingle_pack2 ; treate srca as TileGXFPSFmt result.
>> + * ; convert TileGXFPSFmt result to float_32 value.
>> + * ; move float_32 value to dest.
>> + */
>> +
>> +/*
>> + * Dobule format. flag: 64 bits, value: 64 bits.
>> + *
>> + * Double exp analyzing: (0x21b00 << 1) - 0x36(54) = 0x400
>> + *
>> + * 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
>> + *
>> + * 1 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0
>> + *
>> + * 0 0 0 0 0 1 1 0 1 1 1 => 0x37(55)
>> + *
>> + * 0 1 1 1 1 1 1 1 1 1 1 => 0x3ff
>> + *
>> + */
>> +typedef union TileGXFPDFmtF {
>> +
>> + struct {
>> +#if !defined(HOST_WORDS_BIGENDIAN)
>> + uint64_t unknown0 : 7; /* unknown */
>> + uint64_t exp : 11; /* exp, 0x21b << 1: 55 + TILEGX_F_EXP_DZERO */
>> + uint64_t unknown1 : 2; /* unknown */
>> + uint64_t sign : 1; /* Sign bit for the total value */
>> +
>> + uint64_t addsub: 1; /* add or sub bit */
>> + uint64_t unknown2: 3; /* unknown */
>> +
>> + /* Come from TILE-Gx ISA document, Table 7-2 for floating point */
>> + uint64_t unordered : 1; /* The two are unordered */
>> + uint64_t lt : 1; /* 1st is less than 2nd */
>> + uint64_t le : 1; /* 1st is less than or equal to 2nd */
>> + uint64_t gt : 1; /* 1st is greater than 2nd */
>> + uint64_t ge : 1; /* 1st is greater than or equal to 2nd */
>> + uint64_t eq : 1; /* The two operands are equal */
>> + uint64_t neq : 1; /* The two operands are not equal */
>> +
>> + uint64_t unknown3 : 32; /* unknown */
>> +#else
>> + uint64_t unknown3 : 32; /* unknown */
>> + uint64_t neq : 1; /* The two operands are not equal */
>> + uint64_t eq : 1; /* The two operands are equal */
>> + uint64_t ge : 1; /* 1st is greater than or equal to 2nd */
>> + uint64_t gt : 1; /* 1st is greater than 2nd */
>> + uint64_t le : 1; /* 1st is less than or equal to 2nd */
>> + uint64_t lt : 1; /* 1st is less than 2nd */
>> + uint64_t unordered : 1; /* The two are unordered */
>> + uint64_t unknown2: 3; /* unknown */
>> + uint64_t addsub: 1; /* add or sub bit */
>> + uint64_t sign : 1; /* Sign bit for the total value */
>> + uint64_t unknown1 : 2; /* unknown */
>> + uint64_t exp : 11; /* exp, 0x21b << 1: 55 + TILEGX_F_EXP_DZERO */
>> + uint64_t unknown0 : 7; /* unknown */
>> +#endif
>> + } fmt;
>> + uint64_t ll; /* only for easy using */
>> +} TileGXFPDFmtF;
>> +
>> +typedef union TileGXFPDFmtV {
>> + struct {
>> +#if !defined(HOST_WORDS_BIGENDIAN)
>> + uint64_t mantissa : 60; /* mantissa */
>> + uint64_t overflow : 1; /* overflow bit for addsub */
>> + uint64_t unknown1 : 3; /* unknown */
>> +#else
>> + uint64_t unknown1 : 3; /* unknown */
>> + uint64_t overflow : 1; /* overflow bit for addsub */
>> + uint64_t mantissa : 60; /* mantissa */
>> +#endif
>> + } fmt;
>> + uint64_t ll; /* only for easy using */
>> +} TileGXFPDFmtV;
>> +/*
>> + * FDouble instructions implemenation:
>> + *
>> + * fdouble_unpack_min ; srca and srcb are float_64 value.
>> + * ; get the min absolute value's mantissa.
>> + * ; move "mantissa>> (exp_max - exp_min)" to dest.
>> + *
>> + * fdouble_unpack_max ; srca and srcb are float_64 value.
>> + * ; get the max absolute value's mantissa.
>> + * ; move mantissa to dest.
>> + *
>> + * fdouble_add_flags ; srca and srcb are float_64 value.
>> + * ; calc exp (exp_max), sign, and comp bits for flags.
>> + * ; set addsub bit to flags and move flags to dest.
>> + *
>> + * fdouble_sub_flags ; srca and srcb are float_64 value.
>> + * ; calc exp (exp_max), sign, and comp bits for flags.
>> + * ; set addsub bit to flags and move flags to dest.
>> + *
>> + * fdouble_addsub: ; dest, srca (max, min mantissa), and srcb (flags).
>> + * ; "dest +/- srca" depend on the add/sub bit of flags.
>> + * ; move result mantissa to dest.
>> + *
>> + * fdouble_mul_flags: ; srca and srcb are float_64 value.
>> + * ; calc sign (xor), exp (exp_min + exp_max), and comp bits.
>> + * ; mix sign, exp, and comp bits as flags to dest.
>> + *
>> + * fdouble_pack1 ; move srcb (flags) to dest.
>> + *
>> + * fdouble_pack2 ; srca, srcb (high, low mantissa), and dest (flags)
>> + * ; normalize and pack result from srca, srcb, and dest.
>> + * ; move result to dest.
>> + */
>> +
>> +#pragma pack(pop)
>> +
>> +#endif /* FPU_TILEGX_H */
>> diff --git a/target-tilegx/fsingle_helper.c b/target-tilegx/fsingle_helper.c
>> new file mode 100644
>> index 0000000..95ff9f4
>> --- /dev/null
>> +++ b/target-tilegx/fsingle_helper.c
>> @@ -0,0 +1,157 @@
>> +/*
>> + * 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"
>> +
>> +#pragma pack(push, 1)
>> +typedef union F32Fmt {
>> + uint32_t f;
>> + struct {
>> +#if defined(HOST_WORDS_BIGENDIAN)
>> + uint32_t sign : 1;
>> + uint32_t exp : 8;
>> + uint32_t frac : 23;
>> +#else
>> + uint32_t frac : 23;
>> + uint32_t exp : 8;
>> + uint32_t sign : 1;
>> +#endif
>> + } bits;
>> +} F32Fmt;
>> +#pragma pack(pop)
>> +
>> +static uint64_t sfmt_to_uint64(TileGXFPSFmt a)
>> +{
>> + union {
>> + TileGXFPSFmt a;
>> + uint64_t v;
>> + } t;
>> + t.a = a;
>> + return t.v;
>> +}
>> +
>> +static TileGXFPSFmt uint64_to_sfmt(uint64 v)
>> +{
>> + union {
>> + TileGXFPSFmt a;
>> + uint64_t v;
>> + } t;
>> + t.v = v;
>> + return t.a;
>> +}
>> +
>> +static TileGXFPSFmt float32_to_sfmt(float32 f)
>> +{
>> + F32Fmt tmp = {f};
>> + union {
>> + TileGXFPSFmt fmt;
>> + uint64_t v;
>> + } sfmt;
>> +
>> + sfmt.v = 0;
>> + sfmt.fmt.sign = tmp.bits.sign;
>> + sfmt.fmt.exp = tmp.bits.exp;
>> + sfmt.fmt.mantissa = (tmp.bits.frac << 8) | (1 << 31);
>> +
>> + return sfmt.fmt;
>> +}
>> +
>> +static float32 sfmt_to_float32(TileGXFPSFmt sfmt)
>> +{
>> + F32Fmt f;
>> +
>> + while (sfmt.exp && !(sfmt.mantissa & (1ULL << 31))) {
>> + sfmt.exp--;
>> + sfmt.mantissa <<= 1;
>> + }
>> +
>> + f.bits.sign = sfmt.sign;
>> + f.bits.exp = sfmt.exp;
>> + f.bits.frac = sfmt.mantissa>> 8;
>> +
>> + return f.f;
>> +}
>> +
>> +uint64_t helper_fsingle_pack2(uint64_t srca)
>> +{
>> + return float32_val(sfmt_to_float32(uint64_to_sfmt(srca)));
>> +}
>> +
>> +static void ana_bits(float_status *fp_status,
>> + float32 fsrca, float32 fsrcb, TileGXFPSFmt *sfmt)
>> +{
>> + if (float32_eq(fsrca, fsrcb, fp_status)) {
>> + sfmt->eq = 1;
>> + } else {
>> + sfmt->neq = 1;
>> + }
>> +
>> + if (float32_lt(fsrca, fsrcb, fp_status)) {
>> + sfmt->lt = 1;
>> + }
>> + if (float32_le(fsrca, fsrcb, fp_status)) {
>> + sfmt->le = 1;
>> + }
>> +
>> + if (float32_lt(fsrcb, fsrca, fp_status)) {
>> + sfmt->gt = 1;
>> + }
>> + if (float32_le(fsrcb, fsrca, fp_status)) {
>> + sfmt->ge = 1;
>> + }
>> +
>> + if (float32_unordered(fsrca, fsrcb, fp_status)) {
>> + sfmt->unordered = 1;
>> + }
>> +}
>> +
>> +static uint64_t main_calc(float_status *fp_status,
>> + float32 fsrca, float32 fsrcb,
>> + float32 (*calc)(float32, float32, float_status *))
>> +{
>> + TileGXFPSFmt sfmt = float32_to_sfmt(calc(fsrca, fsrcb, fp_status));
>> +
>> + ana_bits(fp_status, fsrca, fsrcb, &sfmt);
>> +
>> + return sfmt_to_uint64(sfmt);
>> +}
>> +
>> +uint64_t helper_fsingle_add1(CPUTLGState *env, uint64_t srca, uint64_t srcb)
>> +{
>> + return main_calc(&env->fp_status,
>> + make_float32(srca), make_float32(srcb), float32_add);
>> +}
>> +
>> +uint64_t helper_fsingle_sub1(CPUTLGState *env, uint64_t srca, uint64_t srcb)
>> +{
>> + return main_calc(&env->fp_status,
>> + make_float32(srca), make_float32(srcb), float32_sub);
>> +}
>> +
>> +uint64_t helper_fsingle_mul1(CPUTLGState *env, uint64_t srca, uint64_t srcb)
>> +{
>> + return main_calc(&env->fp_status,
>> + make_float32(srca), make_float32(srcb), float32_mul);
>> +}
>> diff --git a/target-tilegx/helper.h b/target-tilegx/helper.h
>> index 9281d0f..6c40762 100644
>> --- a/target-tilegx/helper.h
>> +++ b/target-tilegx/helper.h
>> @@ -24,3 +24,15 @@ DEF_HELPER_FLAGS_2(v1shrs, TCG_CALL_NO_RWG_SE, i64, i64, i64)
>> DEF_HELPER_FLAGS_2(v2shl, TCG_CALL_NO_RWG_SE, i64, i64, i64)
>> DEF_HELPER_FLAGS_2(v2shru, TCG_CALL_NO_RWG_SE, i64, i64, i64)
>> DEF_HELPER_FLAGS_2(v2shrs, TCG_CALL_NO_RWG_SE, i64, i64, i64)
>> +
>> +DEF_HELPER_3(fsingle_add1, i64, env, i64, i64)
>> +DEF_HELPER_3(fsingle_sub1, i64, env, i64, i64)
>> +DEF_HELPER_3(fsingle_mul1, i64, env, i64, i64)
>> +DEF_HELPER_1(fsingle_pack2, i64, i64)
>> +DEF_HELPER_3(fdouble_unpack_min, i64, env, i64, i64)
>> +DEF_HELPER_3(fdouble_unpack_max, i64, env, i64, i64)
>> +DEF_HELPER_3(fdouble_add_flags, i64, env, i64, i64)
>> +DEF_HELPER_3(fdouble_sub_flags, i64, env, i64, i64)
>> +DEF_HELPER_4(fdouble_addsub, i64, env, i64, i64, i64)
>> +DEF_HELPER_3(fdouble_mul_flags, i64, env, i64, i64)
>> +DEF_HELPER_4(fdouble_pack2, i64, env, i64, i64, i64)
>> diff --git a/target-tilegx/translate.c b/target-tilegx/translate.c
>> index b8ca401..4c6f07c 100644
>> --- a/target-tilegx/translate.c
>> +++ b/target-tilegx/translate.c
>> @@ -597,6 +597,11 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
>> }
>> qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s %s", mnemonic, reg_names[srca]);
>> return ret;
>> +
>> + case OE_RR_X0(FSINGLE_PACK1):
>> + case OE_RR_Y0(FSINGLE_PACK1):
>> + mnemonic = "fsingle_pack1";
>> + goto done2;
>> }
>>
>> tdest = dest_gr(dc, dest);
>> @@ -613,9 +618,6 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
>> gen_helper_cnttz(tdest, tsrca);
>> mnemonic = "cnttz";
>> break;
>> - case OE_RR_X0(FSINGLE_PACK1):
>> - case OE_RR_Y0(FSINGLE_PACK1):
>> - return TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
>> case OE_RR_X1(LD1S):
>> memop = MO_SB;
>> mnemonic = "ld1s"; /* prefetch_l1_fault */
>> @@ -734,6 +736,7 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
>> return TILEGX_EXCP_OPCODE_UNKNOWN;
>> }
>>
>> +done2:
>> qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s %s, %s", mnemonic,
>> reg_names[dest], reg_names[srca]);
>> return ret;
>> @@ -742,13 +745,21 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
>> static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
>> unsigned dest, unsigned srca, unsigned srcb)
>> {
>> - TCGv tdest = dest_gr(dc, dest);
>> - TCGv tsrca = load_gr(dc, srca);
>> - TCGv tsrcb = load_gr(dc, srcb);
>> + TCGv tdest, tsrca, tsrcb;
>> TCGv t0;
>> const char *mnemonic;
>>
>> switch (opext) {
>> + case OE_RRR(FSINGLE_ADDSUB2, 0, X0):
>> + mnemonic = "fsingle_addsub2";
>> + goto done2;
>> + }
>> +
>> + tdest = dest_gr(dc, dest);
>> + tsrca = load_gr(dc, srca);
>> + tsrcb = load_gr(dc, srcb);
>> +
>> + switch (opext) {
>> case OE_RRR(ADDXSC, 0, X0):
>> case OE_RRR(ADDXSC, 0, X1):
>> gen_saturate_op(tdest, tsrca, tsrcb, tcg_gen_add_tl);
>> @@ -906,14 +917,39 @@ static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
>> mnemonic = "exch";
>> break;
>> case OE_RRR(FDOUBLE_ADDSUB, 0, X0):
>> + gen_helper_fdouble_addsub(tdest, cpu_env,
>> + load_gr(dc, dest),tsrca, tsrcb);
>> + mnemonic = "fdouble_addsub";
>> + break;
>> case OE_RRR(FDOUBLE_ADD_FLAGS, 0, X0):
>> + gen_helper_fdouble_add_flags(tdest, cpu_env, tsrca, tsrcb);
>> + mnemonic = "fdouble_add_flags";
>> + break;
>> case OE_RRR(FDOUBLE_MUL_FLAGS, 0, X0):
>> + gen_helper_fdouble_mul_flags(tdest, cpu_env, tsrca, tsrcb);
>> + mnemonic = "fdouble_mul_flags";
>> + break;
>> case OE_RRR(FDOUBLE_PACK1, 0, X0):
>> + tcg_gen_mov_i64(tdest, tsrcb);
>> + mnemonic = "fdouble_pack1";
>> + break;
>> case OE_RRR(FDOUBLE_PACK2, 0, X0):
>> + gen_helper_fdouble_pack2(tdest, cpu_env,
>> + load_gr(dc, dest), tsrca, tsrcb);
>> + mnemonic = "fdouble_pack2";
>> + break;
>> case OE_RRR(FDOUBLE_SUB_FLAGS, 0, X0):
>> + gen_helper_fdouble_sub_flags(tdest, cpu_env, tsrca, tsrcb);
>> + mnemonic = "fdouble_sub_flags";
>> + break;
>> case OE_RRR(FDOUBLE_UNPACK_MAX, 0, X0):
>> + gen_helper_fdouble_unpack_max(tdest, cpu_env, tsrca, tsrcb);
>> + mnemonic = "fdouble_unpack_max";
>> + break;
>> case OE_RRR(FDOUBLE_UNPACK_MIN, 0, X0):
>> - return TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
>> + gen_helper_fdouble_unpack_min(tdest, cpu_env, tsrca, tsrcb);
>> + mnemonic = "fdouble_unpack_min";
>> + break;
>> case OE_RRR(FETCHADD4, 0, X1):
>> gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb,
>> TILEGX_EXCP_OPCODE_FETCHADD4);
>> @@ -955,12 +991,25 @@ static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
>> mnemonic = "fetchor";
>> break;
>> case OE_RRR(FSINGLE_ADD1, 0, X0):
>> - case OE_RRR(FSINGLE_ADDSUB2, 0, X0):
>> + gen_helper_fsingle_add1(tdest, cpu_env, tsrca, tsrcb);
>> + mnemonic = "fsingle_add1";
>> + break;
>> case OE_RRR(FSINGLE_MUL1, 0, X0):
>> + gen_helper_fsingle_mul1(tdest, cpu_env, tsrca, tsrcb);
>> + mnemonic = "fsingle_mul1";
>> + break;
>> case OE_RRR(FSINGLE_MUL2, 0, X0):
>> + tcg_gen_mov_i64(tdest, tsrca);
>> + mnemonic = "fsingle_mul2";
>> + break;
>> case OE_RRR(FSINGLE_PACK2, 0, X0):
>> + gen_helper_fsingle_pack2(tdest, tsrca);
>> + mnemonic = "fsingle_pack2";
>> + break;
>> case OE_RRR(FSINGLE_SUB1, 0, X0):
>> - return TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
>> + gen_helper_fsingle_sub1(tdest, cpu_env, tsrca, tsrcb);
>> + mnemonic = "fsingle_sub1";
>> + break;
>> case OE_RRR(MNZ, 0, X0):
>> case OE_RRR(MNZ, 0, X1):
>> case OE_RRR(MNZ, 4, Y0):
>> @@ -1464,6 +1513,7 @@ static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
>> return TILEGX_EXCP_OPCODE_UNKNOWN;
>> }
>>
>> +done2:
>> qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s %s, %s, %s", mnemonic,
>> reg_names[dest], reg_names[srca], reg_names[srcb]);
>> return TILEGX_EXCP_NONE;
>> --
>> 1.9.3
>>
>

--
Chen Gang (陈刚)

Open, share, and attitude like air, water, and life which God blessed
diff mbox

Patch

diff --git a/target-tilegx/Makefile.objs b/target-tilegx/Makefile.objs
index 0db778f..c2cf2f1 100644
--- a/target-tilegx/Makefile.objs
+++ b/target-tilegx/Makefile.objs
@@ -1 +1,2 @@ 
-obj-y += cpu.o translate.o helper.o simd_helper.o
+obj-y += cpu.o translate.o helper.o simd_helper.o \
+		fsingle_helper.o fdouble_helper.o
diff --git a/target-tilegx/cpu.h b/target-tilegx/cpu.h
index 03df107..445a606 100644
--- a/target-tilegx/cpu.h
+++ b/target-tilegx/cpu.h
@@ -88,6 +88,8 @@  typedef struct CPUTLGState {
     uint64_t spregs[TILEGX_SPR_COUNT]; /* Special used registers by outside */
     uint64_t pc;                       /* Current pc */
 
+    float_status fp_status;            /* floating point status */
+
 #if defined(CONFIG_USER_ONLY)
     uint64_t excaddr;                  /* exception address */
     uint64_t atomic_srca;              /* Arguments to atomic "exceptions" */
diff --git a/target-tilegx/fdouble_helper.c b/target-tilegx/fdouble_helper.c
new file mode 100644
index 0000000..b3b0588
--- /dev/null
+++ b/target-tilegx/fdouble_helper.c
@@ -0,0 +1,234 @@ 
+/*
+ * 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 (va.bits.exp> vb.bits.exp)
+        v.fmt.mantissa = fr_to_man(vb)>> (va.bits.exp - vb.bits.exp);
+    else if (va.bits.exp < vb.bits.exp)
+        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 (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.addsub == TILEGX_F_ADDSUB_ADD) {
+        v.ll = dest + srca; /* maybe set addsub overflow bit */
+    } else
+        v.ll = dest - srca;
+
+    return v.ll;
+}
+
+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;
+
+    /*
+     * Assume fdouble_add_flags, fdouble_sub_flags, or fdouble_mul_flags
+     * already processed any exceptions.
+     */
+
+    /* only absolute-add can cause addsub overflow, it may not be exception */
+    if (v.fmt.overflow && (flags.fmt.exp < TILEGX_F_EXP_DMAX)) {
+        flags.fmt.exp++;
+        srcb>>= 1;
+        srcb |= (uint64_t)v.fmt.mantissa << 63;
+        v.fmt.mantissa>>= 1;
+        v.fmt.mantissa |= TILEGX_F_MAN_HBIT;
+    }
+
+    while (flags.fmt.exp && !(v.fmt.mantissa & TILEGX_F_MAN_HBIT)) {
+        flags.fmt.exp--;
+        v.fmt.mantissa <<= 1;
+        v.fmt.mantissa |= srcb>> 63;
+        srcb <<= 1;
+    }
+
+    d.bits.sign = flags.fmt.sign;
+    d.bits.exp = flags.fmt.exp;
+    d.bits.frac = v.fmt.mantissa>> 7;
+
+    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 (calc == float64_add) {
+        flags.fmt.exp = (va.bits.exp> vb.bits.exp) ? va.bits.exp : vb.bits.exp;
+        flags.fmt.addsub = (va.bits.sign == vb.bits.sign)
+                               ? TILEGX_F_ADDSUB_ADD : TILEGX_F_ADDSUB_SUB;
+
+    } else if (calc == float64_sub) {
+        flags.fmt.exp = (va.bits.exp> vb.bits.exp) ? va.bits.exp : vb.bits.exp;
+        flags.fmt.addsub = (va.bits.sign != vb.bits.sign)
+                               ? TILEGX_F_ADDSUB_ADD : TILEGX_F_ADDSUB_SUB;
+
+    } else /* It's float64_mul, don't need flags.addsub */
+        flags.fmt.exp = ((uint64_t)va.bits.exp + (uint64_t)vb.bits.exp
+                           <= TILEGX_F_EXP_DMAX)
+                               ? va.bits.exp + vb.bits.exp : vf.bits.exp;
+
+    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);
+}
diff --git a/target-tilegx/fpu.h b/target-tilegx/fpu.h
new file mode 100644
index 0000000..3421c05
--- /dev/null
+++ b/target-tilegx/fpu.h
@@ -0,0 +1,217 @@ 
+/*
+ *  TILE-Gx virtual FPU header
+ *
+ *  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 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
+ * 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/>.
+ */
+#ifndef FPU_TILEGX_H
+#define FPU_TILEGX_H
+
+/*
+ * From IEEE standard, exp of float is 8-bits, exp of double is 11-bits.
+ */
+#define TILEGX_F_EXP_FZERO  0x7f  /* Zero exp for single 8-bits */
+#define TILEGX_F_EXP_DZERO  0x3ff /* Zero exp for double 11-bits */
+#define TILEGX_F_EXP_DMAX   0x7ff /* max exp for double 11-bits */
+
+/*
+ * For fdouble addsub bit
+ */
+#define TILEGX_F_ADDSUB_ADD 0     /* Perform absolute add operation */
+#define TILEGX_F_ADDSUB_SUB 1     /* Perform absolute sub operation */
+
+#pragma pack(push, 1)
+
+/*
+ * Single format, it is 64-bit.
+ *
+ * Single exp analyzing: 0x9e - 0x1e(30) = 0x80
+ *
+ *   7   6   5   4   3   2   1   0
+ *
+ *   1   0   0   1   1   1   1   0
+ *
+ *   0   0   0   1   1   1   1   1    => 0x1f(31)
+ *
+ *   0   1   1   1   1   1   1   1    => 0x7f
+ */
+typedef struct TileGXFPSFmt {
+
+#if !defined(HOST_WORDS_BIGENDIAN)
+    /* According to float(uns)sisf2 and float(uns)sidf2 in gcc tilegx.md */
+    uint64_t exp : 8;             /* exp, 0x9e: 31 + TILEGX_F_EXP_FZERO */
+    uint64_t uiknown0 : 1;        /* unknown */
+    uint64_t sign : 1;            /* Sign bit for the total value */
+    uint64_t unknown1 : 15;       /* unknown */
+
+    /* Come from TILE-Gx ISA document, Table 7-2 for floating point */
+    uint64_t unordered : 1;       /* The two are unordered */
+    uint64_t lt : 1;              /* 1st is less than 2nd */
+    uint64_t le : 1;              /* 1st is less than or equal to 2nd */
+    uint64_t gt : 1;              /* 1st is greater than 2nd */
+    uint64_t ge : 1;              /* 1st is greater than or equal to 2nd */
+    uint64_t eq : 1;              /* The two operands are equal */
+    uint64_t neq : 1;             /* The two operands are not equal */
+
+    /* According to float(uns)sisf2 and float(uns)sidf2 in gcc tilegx.md */
+    uint64_t mantissa : 32;       /* mantissa */
+#else
+    uint64_t mantissa : 32;       /* mantissa */
+    uint64_t neq : 1;             /* The two operands are not equal */
+    uint64_t eq : 1;              /* The two operands are equal */
+    uint64_t ge : 1;              /* 1st is greater than or equal to 2nd */
+    uint64_t gt : 1;              /* 1st is greater than 2nd */
+    uint64_t le : 1;              /* 1st is less than or equal to 2nd */
+    uint64_t lt : 1;              /* 1st is less than 2nd */
+    uint64_t unordered : 1;       /* The two are unordered */
+    uint64_t unknown1 : 15;       /* unknown */
+    uint64_t sign : 1;            /* Sign bit for the total value */
+    uint64_t unknown0 : 1;        /* unknown */
+    uint64_t exp : 8;             /* exp, 0x9e: 31 + TILEGX_F_EXP_FZERO */
+#endif
+} TileGXFPSFmt;
+/*
+ * FSingle instructions implemenation:
+ *
+ * fsingle_add1         ; calc srca and srcb,
+ *                      ; convert float_32 to TileGXFPSFmt result.
+ *                      ; move TileGXFPSFmt result to dest.
+ *
+ * fsingle_sub1         ; calc srca and srcb.
+ *                      ; convert float_32 to TileGXFPSFmt result.
+ *                      ; move TileGXFPSFmt result to dest.
+ *
+ * fsingle_addsub2      ; nop.
+ *
+ * fsingle_mul1         ; calc srca and srcb.
+ *                      ; convert float_32 value to TileGXFPSFmt result.
+ *                      ; move TileGXFPSFmt result to dest.
+ *
+ * fsingle_mul2         ; move srca to dest.
+ *
+ * fsingle_pack1        ; nop
+ *
+ * fsingle_pack2        ; treate srca as TileGXFPSFmt result.
+ *                      ; convert TileGXFPSFmt result to float_32 value.
+ *                      ; move float_32 value to dest.
+ */
+
+/*
+ * Dobule format. flag: 64 bits, value: 64 bits.
+ *
+ * Double exp analyzing: (0x21b00 << 1) - 0x36(54) = 0x400
+ *
+ *   17  16  15  14  13  12  11  10   9   8   7    6   5   4   3   2   1   0
+ *
+ *    1   0   0   0   0   1   1   0   1   1   0    0   0   0   0   0   0   0
+ *
+ *    0   0   0   0   0   1   1   0   1   1   1    => 0x37(55)
+ *
+ *    0   1   1   1   1   1   1   1   1   1   1    => 0x3ff
+ *
+ */
+typedef union TileGXFPDFmtF {
+
+    struct {
+#if !defined(HOST_WORDS_BIGENDIAN)
+        uint64_t unknown0 : 7;    /* unknown */
+        uint64_t exp : 11;        /* exp, 0x21b << 1: 55 + TILEGX_F_EXP_DZERO */
+        uint64_t unknown1 : 2;    /* unknown */
+        uint64_t sign : 1;        /* Sign bit for the total value */
+
+        uint64_t addsub: 1;       /* add or sub bit */
+        uint64_t unknown2: 3;     /* unknown */
+
+        /* Come from TILE-Gx ISA document, Table 7-2 for floating point */
+        uint64_t unordered : 1;   /* The two are unordered */
+        uint64_t lt : 1;          /* 1st is less than 2nd */
+        uint64_t le : 1;          /* 1st is less than or equal to 2nd */
+        uint64_t gt : 1;          /* 1st is greater than 2nd */
+        uint64_t ge : 1;          /* 1st is greater than or equal to 2nd */
+        uint64_t eq : 1;          /* The two operands are equal */
+        uint64_t neq : 1;         /* The two operands are not equal */
+
+        uint64_t unknown3 : 32;   /* unknown */
+#else
+        uint64_t unknown3 : 32;   /* unknown */
+        uint64_t neq : 1;         /* The two operands are not equal */
+        uint64_t eq : 1;          /* The two operands are equal */
+        uint64_t ge : 1;          /* 1st is greater than or equal to 2nd */
+        uint64_t gt : 1;          /* 1st is greater than 2nd */
+        uint64_t le : 1;          /* 1st is less than or equal to 2nd */
+        uint64_t lt : 1;          /* 1st is less than 2nd */
+        uint64_t unordered : 1;   /* The two are unordered */
+        uint64_t unknown2: 3;     /* unknown */
+        uint64_t addsub: 1;       /* add or sub bit */
+        uint64_t sign : 1;        /* Sign bit for the total value */
+        uint64_t unknown1 : 2;    /* unknown */
+        uint64_t exp : 11;        /* exp, 0x21b << 1: 55 + TILEGX_F_EXP_DZERO */
+        uint64_t unknown0 : 7;    /* unknown */
+#endif
+    } fmt;
+    uint64_t ll;                  /* only for easy using */
+} TileGXFPDFmtF;
+
+typedef union TileGXFPDFmtV {
+    struct {
+#if !defined(HOST_WORDS_BIGENDIAN)
+        uint64_t mantissa : 60;   /* mantissa */
+        uint64_t overflow : 1;    /* overflow bit for addsub */
+        uint64_t unknown1 : 3;    /* unknown */
+#else
+        uint64_t unknown1 : 3;    /* unknown */
+        uint64_t overflow : 1;    /* overflow bit for addsub */
+        uint64_t mantissa : 60;   /* mantissa */
+#endif
+    } fmt;
+    uint64_t ll;                  /* only for easy using */
+} TileGXFPDFmtV;
+/*
+ * FDouble instructions implemenation:
+ *
+ * fdouble_unpack_min   ; srca and srcb are float_64 value.
+ *                      ; get the min absolute value's mantissa.
+ *                      ; move "mantissa>> (exp_max - exp_min)" to dest.
+ *
+ * fdouble_unpack_max   ; srca and srcb are float_64 value.
+ *                      ; get the max absolute value's mantissa.
+ *                      ; move mantissa to dest.
+ *
+ * fdouble_add_flags    ; srca and srcb are float_64 value.
+ *                      ; calc exp (exp_max), sign, and comp bits for flags.
+ *                      ; set addsub bit to flags and move flags to dest.
+ *
+ * fdouble_sub_flags    ; srca and srcb are float_64 value.
+ *                      ; calc exp (exp_max), sign, and comp bits for flags.
+ *                      ; set addsub bit to flags and move flags to dest.
+ *
+ * fdouble_addsub:      ; dest, srca (max, min mantissa), and srcb (flags).
+ *                      ; "dest +/- srca" depend on the add/sub bit of flags.
+ *                      ; move result mantissa to dest.
+ *
+ * fdouble_mul_flags:   ; srca and srcb are float_64 value.
+ *                      ; calc sign (xor), exp (exp_min + exp_max), and comp bits.
+ *                      ; mix sign, exp, and comp bits as flags to dest.
+ *
+ * fdouble_pack1        ; move srcb (flags) to dest.
+ *
+ * fdouble_pack2        ; srca, srcb (high, low mantissa), and dest (flags)
+ *                      ; normalize and pack result from srca, srcb, and dest.
+ *                      ; move result to dest.
+ */
+
+#pragma pack(pop)
+
+#endif /* FPU_TILEGX_H */
diff --git a/target-tilegx/fsingle_helper.c b/target-tilegx/fsingle_helper.c
new file mode 100644
index 0000000..95ff9f4
--- /dev/null
+++ b/target-tilegx/fsingle_helper.c
@@ -0,0 +1,157 @@ 
+/*
+ * 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"
+
+#pragma pack(push, 1)
+typedef union F32Fmt {
+    uint32_t f;
+    struct {
+#if defined(HOST_WORDS_BIGENDIAN)
+        uint32_t sign : 1;
+        uint32_t exp  : 8;
+        uint32_t frac : 23;
+#else
+        uint32_t frac : 23;
+        uint32_t exp  : 8;
+        uint32_t sign : 1;
+#endif
+    } bits;
+} F32Fmt;
+#pragma pack(pop)
+
+static uint64_t sfmt_to_uint64(TileGXFPSFmt a)
+{
+    union {
+        TileGXFPSFmt a;
+        uint64_t v;
+    } t;
+    t.a = a;
+    return t.v;
+}
+
+static TileGXFPSFmt uint64_to_sfmt(uint64 v)
+{
+    union {
+        TileGXFPSFmt a;
+        uint64_t v;
+    } t;
+    t.v = v;
+    return t.a;
+}
+
+static TileGXFPSFmt float32_to_sfmt(float32 f)
+{
+    F32Fmt tmp = {f};
+    union {
+        TileGXFPSFmt fmt;
+        uint64_t v;
+    } sfmt;
+
+    sfmt.v = 0;
+    sfmt.fmt.sign = tmp.bits.sign;
+    sfmt.fmt.exp = tmp.bits.exp;
+    sfmt.fmt.mantissa = (tmp.bits.frac << 8) | (1 << 31);
+
+    return sfmt.fmt;
+}
+
+static float32 sfmt_to_float32(TileGXFPSFmt sfmt)
+{
+    F32Fmt f;
+
+    while (sfmt.exp && !(sfmt.mantissa & (1ULL << 31))) {
+        sfmt.exp--;
+        sfmt.mantissa <<= 1;
+    }
+
+    f.bits.sign = sfmt.sign;
+    f.bits.exp = sfmt.exp;
+    f.bits.frac = sfmt.mantissa>> 8;
+
+    return f.f;
+}
+
+uint64_t helper_fsingle_pack2(uint64_t srca)
+{
+    return float32_val(sfmt_to_float32(uint64_to_sfmt(srca)));
+}
+
+static void ana_bits(float_status *fp_status,
+                     float32 fsrca, float32 fsrcb, TileGXFPSFmt *sfmt)
+{
+    if (float32_eq(fsrca, fsrcb, fp_status)) {
+        sfmt->eq = 1;
+    } else {
+        sfmt->neq = 1;
+    }
+
+    if (float32_lt(fsrca, fsrcb, fp_status)) {
+        sfmt->lt = 1;
+    }
+    if (float32_le(fsrca, fsrcb, fp_status)) {
+        sfmt->le = 1;
+    }
+
+    if (float32_lt(fsrcb, fsrca, fp_status)) {
+        sfmt->gt = 1;
+    }
+    if (float32_le(fsrcb, fsrca, fp_status)) {
+        sfmt->ge = 1;
+    }
+
+    if (float32_unordered(fsrca, fsrcb, fp_status)) {
+        sfmt->unordered = 1;
+    }
+}
+
+static uint64_t main_calc(float_status *fp_status,
+                          float32 fsrca, float32 fsrcb,
+                          float32 (*calc)(float32, float32, float_status *))
+{
+    TileGXFPSFmt sfmt = float32_to_sfmt(calc(fsrca, fsrcb, fp_status));
+
+    ana_bits(fp_status, fsrca, fsrcb, &sfmt);
+
+    return sfmt_to_uint64(sfmt);
+}
+
+uint64_t helper_fsingle_add1(CPUTLGState *env, uint64_t srca, uint64_t srcb)
+{
+    return main_calc(&env->fp_status,
+                     make_float32(srca), make_float32(srcb), float32_add);
+}
+
+uint64_t helper_fsingle_sub1(CPUTLGState *env, uint64_t srca, uint64_t srcb)
+{
+    return main_calc(&env->fp_status,
+                     make_float32(srca), make_float32(srcb), float32_sub);
+}
+
+uint64_t helper_fsingle_mul1(CPUTLGState *env, uint64_t srca, uint64_t srcb)
+{
+    return main_calc(&env->fp_status,
+                     make_float32(srca), make_float32(srcb), float32_mul);
+}
diff --git a/target-tilegx/helper.h b/target-tilegx/helper.h
index 9281d0f..6c40762 100644
--- a/target-tilegx/helper.h
+++ b/target-tilegx/helper.h
@@ -24,3 +24,15 @@  DEF_HELPER_FLAGS_2(v1shrs, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(v2shl, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(v2shru, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(v2shrs, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+
+DEF_HELPER_3(fsingle_add1, i64, env, i64, i64)
+DEF_HELPER_3(fsingle_sub1, i64, env, i64, i64)
+DEF_HELPER_3(fsingle_mul1, i64, env, i64, i64)
+DEF_HELPER_1(fsingle_pack2, i64, i64)
+DEF_HELPER_3(fdouble_unpack_min, i64, env, i64, i64)
+DEF_HELPER_3(fdouble_unpack_max, i64, env, i64, i64)
+DEF_HELPER_3(fdouble_add_flags, i64, env, i64, i64)
+DEF_HELPER_3(fdouble_sub_flags, i64, env, i64, i64)
+DEF_HELPER_4(fdouble_addsub, i64, env, i64, i64, i64)
+DEF_HELPER_3(fdouble_mul_flags, i64, env, i64, i64)
+DEF_HELPER_4(fdouble_pack2, i64, env, i64, i64, i64)
diff --git a/target-tilegx/translate.c b/target-tilegx/translate.c
index b8ca401..4c6f07c 100644
--- a/target-tilegx/translate.c
+++ b/target-tilegx/translate.c
@@ -597,6 +597,11 @@  static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
         }
         qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s %s", mnemonic, reg_names[srca]);
         return ret;
+
+    case OE_RR_X0(FSINGLE_PACK1):
+    case OE_RR_Y0(FSINGLE_PACK1):
+        mnemonic = "fsingle_pack1";
+        goto done2;
     }
 
     tdest = dest_gr(dc, dest);
@@ -613,9 +618,6 @@  static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
         gen_helper_cnttz(tdest, tsrca);
         mnemonic = "cnttz";
         break;
-    case OE_RR_X0(FSINGLE_PACK1):
-    case OE_RR_Y0(FSINGLE_PACK1):
-        return TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
     case OE_RR_X1(LD1S):
         memop = MO_SB;
         mnemonic = "ld1s"; /* prefetch_l1_fault */
@@ -734,6 +736,7 @@  static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
         return TILEGX_EXCP_OPCODE_UNKNOWN;
     }
 
+done2:
     qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s %s, %s", mnemonic,
                   reg_names[dest], reg_names[srca]);
     return ret;
@@ -742,13 +745,21 @@  static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
 static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
                                unsigned dest, unsigned srca, unsigned srcb)
 {
-    TCGv tdest = dest_gr(dc, dest);
-    TCGv tsrca = load_gr(dc, srca);
-    TCGv tsrcb = load_gr(dc, srcb);
+    TCGv tdest, tsrca, tsrcb;
     TCGv t0;
     const char *mnemonic;
 
     switch (opext) {
+    case OE_RRR(FSINGLE_ADDSUB2, 0, X0):
+        mnemonic = "fsingle_addsub2";
+        goto done2;
+    }
+
+    tdest = dest_gr(dc, dest);
+    tsrca = load_gr(dc, srca);
+    tsrcb = load_gr(dc, srcb);
+
+    switch (opext) {
     case OE_RRR(ADDXSC, 0, X0):
     case OE_RRR(ADDXSC, 0, X1):
         gen_saturate_op(tdest, tsrca, tsrcb, tcg_gen_add_tl);
@@ -906,14 +917,39 @@  static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
         mnemonic = "exch";
         break;
     case OE_RRR(FDOUBLE_ADDSUB, 0, X0):
+        gen_helper_fdouble_addsub(tdest, cpu_env,
+                                  load_gr(dc, dest),tsrca, tsrcb);
+        mnemonic = "fdouble_addsub";
+        break;
     case OE_RRR(FDOUBLE_ADD_FLAGS, 0, X0):
+        gen_helper_fdouble_add_flags(tdest, cpu_env, tsrca, tsrcb);
+        mnemonic = "fdouble_add_flags";
+        break;
     case OE_RRR(FDOUBLE_MUL_FLAGS, 0, X0):
+        gen_helper_fdouble_mul_flags(tdest, cpu_env, tsrca, tsrcb);
+        mnemonic = "fdouble_mul_flags";
+        break;
     case OE_RRR(FDOUBLE_PACK1, 0, X0):
+        tcg_gen_mov_i64(tdest, tsrcb);
+        mnemonic = "fdouble_pack1";
+        break;
     case OE_RRR(FDOUBLE_PACK2, 0, X0):
+        gen_helper_fdouble_pack2(tdest, cpu_env,
+                                 load_gr(dc, dest), tsrca, tsrcb);
+        mnemonic = "fdouble_pack2";
+        break;
     case OE_RRR(FDOUBLE_SUB_FLAGS, 0, X0):
+        gen_helper_fdouble_sub_flags(tdest, cpu_env, tsrca, tsrcb);
+        mnemonic = "fdouble_sub_flags";
+        break;
     case OE_RRR(FDOUBLE_UNPACK_MAX, 0, X0):
+        gen_helper_fdouble_unpack_max(tdest, cpu_env, tsrca, tsrcb);
+        mnemonic = "fdouble_unpack_max";
+        break;
     case OE_RRR(FDOUBLE_UNPACK_MIN, 0, X0):
-        return TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
+        gen_helper_fdouble_unpack_min(tdest, cpu_env, tsrca, tsrcb);
+        mnemonic = "fdouble_unpack_min";
+        break;
     case OE_RRR(FETCHADD4, 0, X1):
         gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb,
                         TILEGX_EXCP_OPCODE_FETCHADD4);
@@ -955,12 +991,25 @@  static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
         mnemonic = "fetchor";
         break;
     case OE_RRR(FSINGLE_ADD1, 0, X0):
-    case OE_RRR(FSINGLE_ADDSUB2, 0, X0):
+        gen_helper_fsingle_add1(tdest, cpu_env, tsrca, tsrcb);
+        mnemonic = "fsingle_add1";
+        break;
     case OE_RRR(FSINGLE_MUL1, 0, X0):
+        gen_helper_fsingle_mul1(tdest, cpu_env, tsrca, tsrcb);
+        mnemonic = "fsingle_mul1";
+        break;
     case OE_RRR(FSINGLE_MUL2, 0, X0):
+        tcg_gen_mov_i64(tdest, tsrca);
+        mnemonic = "fsingle_mul2";
+        break;
     case OE_RRR(FSINGLE_PACK2, 0, X0):
+        gen_helper_fsingle_pack2(tdest, tsrca);
+        mnemonic = "fsingle_pack2";
+        break;
     case OE_RRR(FSINGLE_SUB1, 0, X0):
-        return TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
+        gen_helper_fsingle_sub1(tdest, cpu_env, tsrca, tsrcb);
+        mnemonic = "fsingle_sub1";
+        break;
     case OE_RRR(MNZ, 0, X0):
     case OE_RRR(MNZ, 0, X1):
     case OE_RRR(MNZ, 4, Y0):
@@ -1464,6 +1513,7 @@  static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext,
         return TILEGX_EXCP_OPCODE_UNKNOWN;
     }
 
+done2:
     qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s %s, %s, %s", mnemonic,
                   reg_names[dest], reg_names[srca], reg_names[srcb]);
     return TILEGX_EXCP_NONE;