Message ID | COL130-W6B8B20D50BEE8B459FAD6B92E0@phx.gbl |
---|---|
State | New |
Headers | show |
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 >
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 --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;