diff mbox

[1/7] target-tricore: Add FPU infrastructure

Message ID 1456849468-30217-2-git-send-email-kbastian@mail.uni-paderborn.de (mailing list archive)
State New, archived
Headers show

Commit Message

Bastian Koppelmann March 1, 2016, 4:24 p.m. UTC
This patch adds a file for all the FPU related helpers with all the includes,
useful defines, and a function to update the status bits. Additionally it adds
a mask for the rounding mode bits of PSW as well as all the opcodes for the
FPU instructions.

Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
---
 target-tricore/Makefile.objs     |  2 +-
 target-tricore/cpu.h             |  4 +-
 target-tricore/fpu_helper.c      | 83 ++++++++++++++++++++++++++++++++++++++++
 target-tricore/tricore-opcodes.h | 18 +++++++++
 4 files changed, 104 insertions(+), 3 deletions(-)
 create mode 100644 target-tricore/fpu_helper.c

Comments

Richard Henderson March 1, 2016, 5:46 p.m. UTC | #1
On 03/01/2016 08:24 AM, Bastian Koppelmann wrote:
> +static inline void f_update_psw_flags(CPUTriCoreState *env, bool calc_z)

You probably need it for compiling this intermediate patch, but probably drop
inline and let the compiler choose.  This is quite a bit of code after all...

> +{
> +    int8_t flags = env->fp_status.float_exception_flags;
> +    int32_t some_excp = 0;

You need to set float_exception_flags to zero after reading, so that you don't
re-copy the flags during the next fp insn.

> +#define FPU_FS PSW_USB_C
> +#define FPU_FI PSW_USB_V
> +#define FPU_FV PSW_USB_SV
> +#define FPU_FZ PSW_USB_AV
> +#define FPU_FU PSW_USB_SAV

What an unfortunate spec.  This is an incredibly broken way to implement fp
exception flags.

Exception flags are the sort of thing that's supposed to be collected across a
whole subroutine, without having to worry about the fp exception flags being
clobbered by the surrounding pointer arithmetic.

In order to implement proper IEEE support with this chip, one would have to
implement the fp exception word in software, clearing the PSW bits before each
group of fp instructions and storing the PSW bits after each such group.

Oh well.  You're doing what the manual says...


r~
diff mbox

Patch

diff --git a/target-tricore/Makefile.objs b/target-tricore/Makefile.objs
index 21e820d..7a05670 100644
--- a/target-tricore/Makefile.objs
+++ b/target-tricore/Makefile.objs
@@ -1 +1 @@ 
-obj-y += translate.o helper.o cpu.o op_helper.o
+obj-y += translate.o helper.o cpu.o op_helper.o fpu_helper.o
diff --git a/target-tricore/cpu.h b/target-tricore/cpu.h
index 5fee376..d85e99f 100644
--- a/target-tricore/cpu.h
+++ b/target-tricore/cpu.h
@@ -183,8 +183,7 @@  struct CPUTriCoreState {
     uint32_t M2CNT;
     uint32_t M3CNT;
     /* Floating Point Registers */
-    /* XXX: */
-
+    float_status fp_status;
     /* QEMU */
     int error_code;
     uint32_t hflags;    /* CPU State */
@@ -217,6 +216,7 @@  struct CPUTriCoreState {
 #define MASK_PSW_GW  0x00000100
 #define MASK_PSW_CDE 0x00000080
 #define MASK_PSW_CDC 0x0000007f
+#define MASK_PSW_FPU_RM 0x3000000
 
 #define MASK_SYSCON_PRO_TEN 0x2
 #define MASK_SYSCON_FCD_SF  0x1
diff --git a/target-tricore/fpu_helper.c b/target-tricore/fpu_helper.c
new file mode 100644
index 0000000..ddf877e
--- /dev/null
+++ b/target-tricore/fpu_helper.c
@@ -0,0 +1,83 @@ 
+/*
+ *  TriCore emulation for qemu: fpu helper.
+ *
+ *  Copyright (c) 2016 Bastian Koppelmann University of Paderborn
+ *
+ * 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
+ * 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/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/helper-proto.h"
+
+#define QUIET_NAN 0x7fc00000
+#define ADD_NAN   0x7cf00001
+#define DIV_NAN   0x7fc00008
+#define MUL_NAN   0x7fc00002
+#define FPU_FS PSW_USB_C
+#define FPU_FI PSW_USB_V
+#define FPU_FV PSW_USB_SV
+#define FPU_FZ PSW_USB_AV
+#define FPU_FU PSW_USB_SAV
+
+static inline bool f_is_pos_inf(float32 arg)
+{
+    return !float32_is_neg(arg) && float32_is_infinity(arg);
+}
+
+static inline bool f_is_neg_inf(float32 arg)
+{
+    return float32_is_neg(arg) && float32_is_infinity(arg);
+}
+
+static inline bool f_is_denormal(float32 arg)
+{
+    return float32_is_zero_or_denormal(arg) && !float32_is_zero(arg);
+}
+
+static inline void f_update_psw_flags(CPUTriCoreState *env, bool calc_z)
+{
+    int8_t flags = env->fp_status.float_exception_flags;
+    int32_t some_excp = 0;
+    if (flags & float_flag_invalid) {
+        env->FPU_FI = (flags & float_flag_invalid) << 31;
+        some_excp = 1;
+    }
+    if (flags & float_flag_overflow) {
+        env->FPU_FV = 1 << 31;
+        some_excp = 1;
+    }
+    if (flags & float_flag_underflow || flags & float_flag_output_denormal) {
+        env->FPU_FU = 1 << 31;
+        some_excp = 1;
+    }
+
+    if (calc_z && (flags & float_flag_divbyzero)) {
+        env->FPU_FZ = 1 << 31;
+        some_excp = 1;
+    }
+    if (flags & float_flag_inexact || flags & float_flag_output_denormal) {
+        env->PSW |= 1 << 26;
+        some_excp = 1;
+    }
+    env->FPU_FS = some_excp;
+}
+
+static inline void f_set_flags(CPUTriCoreState *env)
+{
+    set_float_rounding_mode(env->PSW & MASK_PSW_FPU_RM, &env->fp_status);
+    set_flush_inputs_to_zero(1, &env->fp_status);
+    set_flush_to_zero(1, &env->fp_status);
+    set_float_exception_flags(0, &env->fp_status);
+}
diff --git a/target-tricore/tricore-opcodes.h b/target-tricore/tricore-opcodes.h
index 1bfed0c..df666b0 100644
--- a/target-tricore/tricore-opcodes.h
+++ b/target-tricore/tricore-opcodes.h
@@ -1126,6 +1126,20 @@  enum {
     OPC2_32_RR_CRC32                             = 0x03,
     OPC2_32_RR_DIV                               = 0x20,
     OPC2_32_RR_DIV_U                             = 0x21,
+    OPC2_32_RR_MUL_F                             = 0x04,
+    OPC2_32_RR_DIV_F                             = 0x05,
+    OPC2_32_RR_FTOI                              = 0x10,
+    OPC2_32_RR_ITOF                              = 0x14,
+    OPC2_32_RR_CMP_F                             = 0x00,
+    OPC2_32_RR_FTOIZ                             = 0x13,
+    OPC2_32_RR_FTOQ31                            = 0x11,
+    OPC2_32_RR_FTOQ31Z                           = 0x18,
+    OPC2_32_RR_FTOU                              = 0x12,
+    OPC2_32_RR_FTOUZ                             = 0x17,
+    OPC2_32_RR_Q31TOF                            = 0x15,
+    OPC2_32_RR_QSEED_F                           = 0x19,
+    OPC2_32_RR_UPDFL                             = 0x0c,
+    OPC2_32_RR_UTOF                              = 0x16,
 };
 /* OPCM_32_RR_IDIRECT                               */
 enum {
@@ -1209,6 +1223,10 @@  enum {
     OPC2_32_RRR_IXMIN                            = 0x08,
     OPC2_32_RRR_IXMIN_U                          = 0x09,
     OPC2_32_RRR_PACK                             = 0x00,
+    OPC2_32_RRR_ADD_F                            = 0x02,
+    OPC2_32_RRR_SUB_F                            = 0x03,
+    OPC2_32_RRR_MADD_F                           = 0x06,
+    OPC2_32_RRR_MSUB_F                           = 0x07,
 };
 /*
  * RRR1 Format