qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] qemu configure target-mips/cpu.h target-mips/ex...


From: Fabrice Bellard
Subject: [Qemu-devel] qemu configure target-mips/cpu.h target-mips/ex...
Date: Wed, 14 Jun 2006 12:56:19 +0000

CVSROOT:        /sources/qemu
Module name:    qemu
Changes by:     Fabrice Bellard <bellard>       06/06/14 12:56:19

Modified files:
        .              : configure 
        target-mips    : cpu.h exec.h mips-defs.h op.c op_helper.c 
                         op_mem.c translate.c 
Added files:
        target-mips    : fop_template.c 

Log message:
        MIPS FPU support (Marius Goeger)

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemu/configure?cvsroot=qemu&r1=1.103&r2=1.104
http://cvs.savannah.gnu.org/viewcvs/qemu/target-mips/cpu.h?cvsroot=qemu&r1=1.6&r2=1.7
http://cvs.savannah.gnu.org/viewcvs/qemu/target-mips/exec.h?cvsroot=qemu&r1=1.7&r2=1.8
http://cvs.savannah.gnu.org/viewcvs/qemu/target-mips/mips-defs.h?cvsroot=qemu&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/qemu/target-mips/op.c?cvsroot=qemu&r1=1.7&r2=1.8
http://cvs.savannah.gnu.org/viewcvs/qemu/target-mips/op_helper.c?cvsroot=qemu&r1=1.13&r2=1.14
http://cvs.savannah.gnu.org/viewcvs/qemu/target-mips/op_mem.c?cvsroot=qemu&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/qemu/target-mips/translate.c?cvsroot=qemu&r1=1.13&r2=1.14
http://cvs.savannah.gnu.org/viewcvs/qemu/target-mips/fop_template.c?cvsroot=qemu&rev=1.1

Patches:
Index: configure
===================================================================
RCS file: /sources/qemu/qemu/configure,v
retrieving revision 1.103
retrieving revision 1.104
diff -u -b -r1.103 -r1.104
--- configure   11 Jun 2006 13:32:58 -0000      1.103
+++ configure   14 Jun 2006 12:56:19 -0000      1.104
@@ -819,6 +819,8 @@
   echo "TARGET_ARCH=mips" >> $config_mak
   echo "#define TARGET_ARCH \"mips\"" >> $config_h
   echo "#define TARGET_MIPS 1" >> $config_h
+  echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
+  echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
 elif test "$target_cpu" = "sh4" ; then
   echo "TARGET_ARCH=sh4" >> $config_mak
   echo "#define TARGET_ARCH \"sh4\"" >> $config_h

Index: target-mips/cpu.h
===================================================================
RCS file: /sources/qemu/qemu/target-mips/cpu.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- target-mips/cpu.h   11 Mar 2006 16:23:39 -0000      1.6
+++ target-mips/cpu.h   14 Jun 2006 12:56:19 -0000      1.7
@@ -10,10 +10,19 @@
 
 typedef union fpr_t fpr_t;
 union fpr_t {
-    double d;
-    float  f;
-    uint32_t u[2];
+    float64  fd;   /* ieee double precision */
+    float32  fs[2];/* ieee single precision */
+    uint64_t d;    /* binary single fixed-point */
+    uint32_t w[2]; /* binary single fixed-point */
 };
+/* define FP_ENDIAN_IDX to access the same location
+ * in the fpr_t union regardless of the host endianess
+ */
+#if defined(WORDS_BIGENDIAN)
+#  define FP_ENDIAN_IDX 1
+#else
+#  define FP_ENDIAN_IDX 0
+#endif
 
 #if defined(MIPS_USES_R4K_TLB)
 typedef struct tlb_t tlb_t;
@@ -44,12 +53,38 @@
 #if defined(MIPS_USES_FPU)
     /* Floating point registers */
     fpr_t fpr[16];
-    /* Floating point special purpose registers */
+#define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2])
+#define FPR_FD(cpu, n) (FPR(cpu, n)->fd)
+#define FPR_FS(cpu, n) (FPR(cpu, n)->fs[((n) & 1) ^ FP_ENDIAN_IDX])
+#define FPR_D(cpu, n)  (FPR(cpu, n)->d)
+#define FPR_W(cpu, n)  (FPR(cpu, n)->w[((n) & 1) ^ FP_ENDIAN_IDX])
+
+#ifndef USE_HOST_FLOAT_REGS
+    fpr_t ft0;
+    fpr_t ft1;
+    fpr_t ft2;
+#endif
+    float_status fp_status;
+    /* fpu implementation/revision register */
     uint32_t fcr0;
-    uint32_t fcr25;
-    uint32_t fcr26;
-    uint32_t fcr28;
-    uint32_t fcsr;
+    /* fcsr */
+    uint32_t fcr31;
+#define SET_FP_COND(reg)     do { (reg) |= (1<<23); } while(0)
+#define CLEAR_FP_COND(reg)   do { (reg) &= ~(1<<23); } while(0)
+#define IS_FP_COND_SET(reg)  (((reg) & (1<<23)) != 0)
+#define GET_FP_CAUSE(reg)    (((reg) >> 12) & 0x3f)
+#define GET_FP_ENABLE(reg)   (((reg) >>  7) & 0x1f)
+#define GET_FP_FLAGS(reg)    (((reg) >>  2) & 0x1f)
+#define SET_FP_CAUSE(reg,v)  do { (reg) = ((reg) & ~(0x3f << 12)) | ((v) << 
12); } while(0)
+#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f <<  7)) | ((v) << 
7); } while(0)
+#define SET_FP_FLAGS(reg,v)  do { (reg) = ((reg) & ~(0x1f <<  2)) | ((v) << 
2); } while(0)
+#define FP_INEXACT        1
+#define FP_UNDERFLOW      2
+#define FP_OVERFLOW       4
+#define FP_DIV0           8
+#define FP_INVALID        16
+#define FP_UNIMPLEMENTED  32
+               
 #endif
 #if defined(MIPS_USES_R4K_TLB)
     tlb_t tlb[16];
@@ -71,6 +106,7 @@
 #define CP0St_CU1   29
 #define CP0St_CU0   28
 #define CP0St_RP    27
+#define CP0St_FR    26
 #define CP0St_RE    25
 #define CP0St_BEV   22
 #define CP0St_TS    21
@@ -138,9 +174,6 @@
     uint32_t CP0_ErrorEPC;
     uint32_t CP0_DESAVE;
     /* Qemu */
-#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU)
-    double ft0, ft1, ft2;
-#endif
     struct QEMUTimer *timer; /* Internal timer */
     int interrupt_request;
     jmp_buf jmp_env;

Index: target-mips/exec.h
===================================================================
RCS file: /sources/qemu/qemu/target-mips/exec.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- target-mips/exec.h  11 Mar 2006 15:00:08 -0000      1.7
+++ target-mips/exec.h  14 Jun 2006 12:56:19 -0000      1.8
@@ -21,13 +21,20 @@
 register host_uint_t T2 asm(AREG3);
 
 #if defined (USE_HOST_FLOAT_REGS)
-register double FT0 asm(FREG0);
-register double FT1 asm(FREG1);
-register double FT2 asm(FREG2);
+#error "implement me."
 #else
-#define FT0 (env->ft0.d)
-#define FT1 (env->ft1.d)
-#define FT2 (env->ft2.d)
+#define FDT0 (env->ft0.fd)
+#define FDT1 (env->ft1.fd)
+#define FDT2 (env->ft2.fd)
+#define FST0 (env->ft0.fs[FP_ENDIAN_IDX])
+#define FST1 (env->ft1.fs[FP_ENDIAN_IDX])
+#define FST2 (env->ft2.fs[FP_ENDIAN_IDX])
+#define DT0 (env->ft0.d)
+#define DT1 (env->ft1.d)
+#define DT2 (env->ft2.d)
+#define WT0 (env->ft0.w[FP_ENDIAN_IDX])
+#define WT1 (env->ft1.w[FP_ENDIAN_IDX])
+#define WT2 (env->ft2.w[FP_ENDIAN_IDX])
 #endif
 
 #if defined (DEBUG_OP)
@@ -65,6 +72,13 @@
 void do_tlbwr (void);
 void do_tlbp (void);
 void do_tlbr (void);
+#ifdef MIPS_USES_FPU
+void dump_fpu(CPUState *env);
+void fpu_dump_state(CPUState *env, FILE *f, 
+                    int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
+                    int flags);
+#endif
+void dump_sc (void);
 void do_lwl_raw (uint32_t);
 void do_lwr_raw (uint32_t);
 uint32_t do_swl_raw (uint32_t);

Index: target-mips/mips-defs.h
===================================================================
RCS file: /sources/qemu/qemu/target-mips/mips-defs.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- target-mips/mips-defs.h     2 Jul 2005 14:57:14 -0000       1.1
+++ target-mips/mips-defs.h     14 Jun 2006 12:56:19 -0000      1.2
@@ -24,6 +24,12 @@
 /* Uses MIPS R4Kc TLB model */
 #define MIPS_USES_R4K_TLB
 #define MIPS_TLB_NB 16
+/* basic FPU register support */
+#define MIPS_USES_FPU 1
+/* Define a implementation number of 1.
+ * Define a major version 1, minor version 0.
+ */
+#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0)
 /* Have config1, runs in big-endian mode, uses TLB */
 #define MIPS_CONFIG0                                            \
 ((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) |  \
@@ -31,14 +37,14 @@
 /* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache,
  * 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
  * no performance counters, watch registers present, no code compression,
- * EJTAG present, no FPU
+ * EJTAG present, FPU enable bit depending on MIPS_USES_FPU
  */
 #define MIPS_CONFIG1                                            \
 ((15 << CP0C1_MMU) |                                            \
  (0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \
  (0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \
  (0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) |          \
- (1 << CP0C1_EP) | (0 << CP0C1_FP))
+ (1 << CP0C1_EP) | (MIPS_USES_FPU << CP0C1_FP))
 #elif defined (MIPS_CPU == MIPS_R4Kp)
 /* 32 bits target */
 #define TARGET_LONG_BITS 32
@@ -52,7 +58,7 @@
 #error "MIPS CPU not defined"
 /* Remainder for other flags */
 //#define TARGET_MIPS64
-//define MIPS_USES_FPU
+//#define MIPS_USES_FPU
 #endif
 
 #endif /* !defined (__QEMU_MIPS_DEFS_H__) */

Index: target-mips/op.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- target-mips/op.c    23 Apr 2006 15:23:48 -0000      1.7
+++ target-mips/op.c    14 Jun 2006 12:56:19 -0000      1.8
@@ -2,6 +2,7 @@
  *  MIPS emulation micro-operations for qemu.
  * 
  *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *  Copyright (c) 2006 Marius Groeger (FPU operations)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -149,6 +150,143 @@
 #include "op_template.c"
 #undef TN
 
+#ifdef MIPS_USES_FPU
+
+#define SFREG 0
+#define DFREG 0
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 1
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 2
+#define DFREG 2
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 3
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 4
+#define DFREG 4
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 5
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 6
+#define DFREG 6
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 7
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 8
+#define DFREG 8
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 9
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 10
+#define DFREG 10
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 11
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 12
+#define DFREG 12
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 13
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 14
+#define DFREG 14
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 15
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 16
+#define DFREG 16
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 17
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 18
+#define DFREG 18
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 19
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 20
+#define DFREG 20
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 21
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 22
+#define DFREG 22
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 23
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 24
+#define DFREG 24
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 25
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 26
+#define DFREG 26
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 27
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 28
+#define DFREG 28
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 29
+#include "fop_template.c"
+#undef SFREG
+#define SFREG 30
+#define DFREG 30
+#include "fop_template.c"
+#undef SFREG
+#undef DFREG
+#define SFREG 31
+#include "fop_template.c"
+#undef SFREG
+
+#define FTN
+#include "fop_template.c"
+#undef FTN
+
+#endif
+
 void op_dup_T0 (void)
 {
     T2 = T0;
@@ -562,6 +700,353 @@
     RETURN();
 }
 
+#ifdef MIPS_USES_FPU
+
+#if 0
+# define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env)
+#else
+# define DEBUG_FPU_STATE() do { } while(0)
+#endif
+
+void op_cp1_enabled(void)
+{
+    if (!(env->CP0_Status & (1 << CP0St_CU1))) {
+        CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1);
+    }
+    RETURN();
+}
+
+/* CP1 functions */
+void op_cfc1 (void)
+{
+    if (T1 == 0) {
+        T0 = env->fcr0;
+    }
+    else {
+        /* fetch fcr31, masking unused bits */
+        T0 = env->fcr31 & 0x0183FFFF;
+    }
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+/* convert MIPS rounding mode in FCR31 to IEEE library */
+unsigned int ieee_rm[] = { 
+    float_round_nearest_even,
+    float_round_to_zero,
+    float_round_up,
+    float_round_down
+};
+
+#define RESTORE_ROUNDING_MODE \
+    set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
+
+void op_ctc1 (void)
+{
+    if (T1 == 0) {
+        /* XXX should this throw an exception?
+         * don't write to FCR0.
+         * env->fcr0 = T0; 
+         */
+    }
+    else {
+        /* store new fcr31, masking unused bits */  
+        env->fcr31 = T0 & 0x0183FFFF;
+
+        /* set rounding mode */
+        RESTORE_ROUNDING_MODE;
+
+#ifndef CONFIG_SOFTFLOAT
+        /* no floating point exception for native float */
+        SET_FP_ENABLE(env->fcr31, 0);
+#endif
+    }
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+void op_mfc1 (void)
+{
+    T0 = WT0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+void op_mtc1 (void)
+{
+    WT0 = T0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+/* Float support.
+   Single precition routines have a "s" suffix, double precision a
+   "d" suffix.  */
+
+#define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void)
+
+FLOAT_OP(cvtd, w)
+{
+    FDT2 = int32_to_float64(WT0, &env->fp_status);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvts, w)
+{
+    FST2 = int32_to_float32(WT0, &env->fp_status);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvtw, s)
+{
+    WT2 = float32_to_int32(FST0, &env->fp_status);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvtw, d)
+{
+    WT2 = float64_to_int32(FDT0, &env->fp_status);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+FLOAT_OP(roundw, d)
+{
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+    WT2 = float64_round_to_int(FDT0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(roundw, s)
+{
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+    WT2 = float32_round_to_int(FST0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+FLOAT_OP(truncw, d)
+{
+    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(truncw, s)
+{
+    WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+FLOAT_OP(ceilw, d)
+{
+    set_float_rounding_mode(float_round_up, &env->fp_status);
+    WT2 = float64_round_to_int(FDT0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(ceilw, s)
+{
+    set_float_rounding_mode(float_round_up, &env->fp_status);
+    WT2 = float32_round_to_int(FST0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+FLOAT_OP(floorw, d)
+{
+    set_float_rounding_mode(float_round_down, &env->fp_status);
+    WT2 = float64_round_to_int(FDT0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(floorw, s)
+{
+    set_float_rounding_mode(float_round_down, &env->fp_status);
+    WT2 = float32_round_to_int(FST0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+/* binary operations */
+#define FLOAT_BINOP(name) \
+FLOAT_OP(name, d)         \
+{                         \
+    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);    \
+    DEBUG_FPU_STATE();    \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
+    DEBUG_FPU_STATE();    \
+}
+FLOAT_BINOP(add)
+FLOAT_BINOP(sub)
+FLOAT_BINOP(mul)
+FLOAT_BINOP(div)
+#undef FLOAT_BINOP
+
+/* unary operations, modifying fp status  */
+#define FLOAT_UNOP(name)  \
+FLOAT_OP(name, d)         \
+{                         \
+    FDT2 = float64_ ## name(FDT0, &env->fp_status);   \
+    DEBUG_FPU_STATE();    \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    FST2 = float32_ ## name(FST0, &env->fp_status);   \
+    DEBUG_FPU_STATE();    \
+}
+FLOAT_UNOP(sqrt)
+#undef FLOAT_UNOP
+
+/* unary operations, not modifying fp status  */
+#define FLOAT_UNOP(name)  \
+FLOAT_OP(name, d)         \
+{                         \
+    FDT2 = float64_ ## name(FDT0);   \
+    DEBUG_FPU_STATE();    \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    FST2 = float32_ ## name(FST0);   \
+    DEBUG_FPU_STATE();    \
+}
+FLOAT_UNOP(abs)
+FLOAT_UNOP(chs)
+#undef FLOAT_UNOP
+
+FLOAT_OP(mov, d)
+{
+    FDT2 = FDT0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(mov, s)
+{
+    FST2 = FST0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+#ifdef CONFIG_SOFTFLOAT
+#define clear_invalid() do {                                \
+    int flags = get_float_exception_flags(&env->fp_status); \
+    flags &= ~float_flag_invalid;                           \
+    set_float_exception_flags(flags, &env->fp_status);      \
+} while(0)
+#else
+#define clear_invalid() do { } while(0)
+#endif
+
+extern void dump_fpu_s(CPUState *env);
+
+#define FOP_COND(fmt, op, sig, cond)           \
+void op_cmp_ ## fmt ## _ ## op (void)          \
+{                                              \
+    if (cond)                                  \
+        SET_FP_COND(env->fcr31);               \
+    else                                       \
+        CLEAR_FP_COND(env->fcr31);             \
+    if (!sig)                                  \
+        clear_invalid();                       \
+    /*CALL_FROM_TB1(dump_fpu_s, env);*/ \
+    DEBUG_FPU_STATE();                         \
+    RETURN();                                  \
+}
+
+flag float64_is_unordered(float64 a, float64 b STATUS_PARAM)
+{
+    extern flag float64_is_nan( float64 a );
+    if (float64_is_nan(a) || float64_is_nan(b)) {
+        float_raise(float_flag_invalid, status);
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+FOP_COND(d, f,   0,                                                      0) 
+FOP_COND(d, un,  0, float64_is_unordered(FDT1, FDT0, &env->fp_status))
+FOP_COND(d, eq,  0,                                                      
float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND(d, ueq, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || 
float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND(d, olt, 0,                                                      
float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND(d, ult, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || 
float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND(d, ole, 0,                                                      
float64_le(FDT0, FDT1, &env->fp_status))
+FOP_COND(d, ule, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || 
float64_le(FDT0, FDT1, &env->fp_status))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called
+ */
+FOP_COND(d, sf,  1,                                                      
(float64_is_unordered(FDT0, FDT1, &env->fp_status), 0))
+FOP_COND(d, ngle,1, float64_is_unordered(FDT1, FDT0, &env->fp_status))
+FOP_COND(d, seq, 1,                                                      
float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND(d, ngl, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || 
float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND(d, lt,  1,                                                      
float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND(d, nge, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || 
float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND(d, le,  1,                                                      
float64_le(FDT0, FDT1, &env->fp_status))
+FOP_COND(d, ngt, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || 
float64_le(FDT0, FDT1, &env->fp_status))
+
+flag float32_is_unordered(float32 a, float32 b STATUS_PARAM)
+{
+    extern flag float32_is_nan( float32 a );
+    if (float32_is_nan(a) || float32_is_nan(b)) {
+        float_raise(float_flag_invalid, status);
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called
+ */
+FOP_COND(s, f,   0,                                                      0) 
+FOP_COND(s, un,  0, float32_is_unordered(FST1, FST0, &env->fp_status))
+FOP_COND(s, eq,  0,                                                      
float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND(s, ueq, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || 
float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND(s, olt, 0,                                                      
float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND(s, ult, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || 
float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND(s, ole, 0,                                                      
float32_le(FST0, FST1, &env->fp_status))
+FOP_COND(s, ule, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || 
float32_le(FST0, FST1, &env->fp_status))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called
+ */
+FOP_COND(s, sf,  1,                                                      
(float32_is_unordered(FST0, FST1, &env->fp_status), 0))
+FOP_COND(s, ngle,1, float32_is_unordered(FST1, FST0, &env->fp_status))
+FOP_COND(s, seq, 1,                                                      
float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND(s, ngl, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || 
float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND(s, lt,  1,                                                      
float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND(s, nge, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || 
float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND(s, le,  1,                                                      
float32_le(FST0, FST1, &env->fp_status))
+FOP_COND(s, ngt, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || 
float32_le(FST0, FST1, &env->fp_status))
+
+void op_bc1f (void)
+{
+    T0 = ! IS_FP_COND_SET(env->fcr31);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+void op_bc1t (void)
+{
+    T0 = IS_FP_COND_SET(env->fcr31);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+#endif /* MIPS_USES_FPU */
+
 #if defined(MIPS_USES_R4K_TLB)
 void op_tlbwi (void)
 {

Index: target-mips/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_helper.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -b -r1.13 -r1.14
--- target-mips/op_helper.c     22 May 2006 22:14:43 -0000      1.13
+++ target-mips/op_helper.c     14 Jun 2006 12:56:19 -0000      1.14
@@ -529,6 +529,47 @@
     return;
 }
 
+#ifdef MIPS_USES_FPU
+#include "softfloat.h"
+
+void fpu_handle_exception(void)
+{
+#ifdef CONFIG_SOFTFLOAT
+    int flags = get_float_exception_flags(&env->fp_status);
+    unsigned int cpuflags = 0, enable, cause = 0;
+
+    enable = GET_FP_ENABLE(env->fcr31);
+
+    /* determine current flags */   
+    if (flags & float_flag_invalid) {
+        cpuflags |= FP_INVALID;
+        cause |= FP_INVALID & enable;
+    }
+    if (flags & float_flag_divbyzero) {
+        cpuflags |= FP_DIV0;    
+        cause |= FP_DIV0 & enable;
+    }
+    if (flags & float_flag_overflow) {
+        cpuflags |= FP_OVERFLOW;    
+        cause |= FP_OVERFLOW & enable;
+    }
+    if (flags & float_flag_underflow) {
+        cpuflags |= FP_UNDERFLOW;   
+        cause |= FP_UNDERFLOW & enable;
+    }
+    if (flags & float_flag_inexact) {
+        cpuflags |= FP_INEXACT; 
+        cause |= FP_INEXACT & enable;
+    }
+    SET_FP_FLAGS(env->fcr31, cpuflags);
+    SET_FP_CAUSE(env->fcr31, cause);
+#else
+    SET_FP_FLAGS(env->fcr31, 0);
+    SET_FP_CAUSE(env->fcr31, 0);
+#endif
+}
+#endif /* MIPS_USES_FPU */
+
 /* TLB management */
 #if defined(MIPS_USES_R4K_TLB)
 static void invalidate_tlb (int idx)

Index: target-mips/op_mem.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_mem.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- target-mips/op_mem.c        5 Dec 2005 19:59:36 -0000       1.2
+++ target-mips/op_mem.c        14 Jun 2006 12:56:19 -0000      1.3
@@ -118,3 +118,26 @@
     }
     RETURN();
 }
+
+#ifdef MIPS_USES_FPU
+void glue(op_lwc1, MEMSUFFIX) (void)
+{
+    WT0 = glue(ldl, MEMSUFFIX)(T0);
+    RETURN();
+}
+void glue(op_swc1, MEMSUFFIX) (void)
+{
+    glue(stl, MEMSUFFIX)(T0, WT0);
+    RETURN();
+}
+void glue(op_ldc1, MEMSUFFIX) (void)
+{
+    DT0 = glue(ldq, MEMSUFFIX)(T0);
+    RETURN();
+}
+void glue(op_sdc1, MEMSUFFIX) (void)
+{
+    glue(stq, MEMSUFFIX)(T0, DT0);
+    RETURN();
+}
+#endif

Index: target-mips/translate.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/translate.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -b -r1.13 -r1.14
--- target-mips/translate.c     22 May 2006 22:13:29 -0000      1.13
+++ target-mips/translate.c     14 Jun 2006 12:56:19 -0000      1.14
@@ -2,6 +2,7 @@
  *  MIPS32 emulation for qemu: main translation routines.
  * 
  *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *  Copyright (c) 2006 Marius Groeger (FPU operations)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -217,6 +218,16 @@
     OPC_WAIT     = 0x20 | EXT_CP0,
 };
 
+#ifdef MIPS_USES_FPU
+enum {
+    /* Coprocessor 1 (FPU) */
+    OPC_MFC1     = 0x00 | EXT_CP1,
+    OPC_MTC1     = 0x04 | EXT_CP1,
+    OPC_CFC1     = 0x02 | EXT_CP1,
+    OPC_CTC1     = 0x06 | EXT_CP1,
+};
+#endif
+
 const unsigned char *regnames[] =
     { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
       "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
@@ -248,6 +259,92 @@
 GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
 GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
 
+#ifdef MIPS_USES_FPU
+const unsigned char *fregnames[] =
+    { "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
+      "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
+      "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+      "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", };
+
+# define SFGEN32(func, NAME) \
+static GenOpFunc *NAME ## _table [32] = {                                     \
+NAME ## 0,  NAME ## 1,  NAME ## 2,  NAME ## 3,                                \
+NAME ## 4,  NAME ## 5,  NAME ## 6,  NAME ## 7,                                \
+NAME ## 8,  NAME ## 9,  NAME ## 10, NAME ## 11,                               \
+NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
+NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,                               \
+NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,                               \
+NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,                               \
+NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,                               \
+};                                                                            \
+static inline void func(int n)                                                \
+{                                                                             \
+    NAME ## _table[n]();                                                      \
+}
+
+# define DFGEN32(func, NAME) \
+static GenOpFunc *NAME ## _table [32] = {                                     \
+NAME ## 0,  0, NAME ## 2,  0,                                                 \
+NAME ## 4,  0, NAME ## 6,  0,                                                 \
+NAME ## 8,  0, NAME ## 10, 0,                                                 \
+NAME ## 12, 0, NAME ## 14, 0,                                                 \
+NAME ## 16, 0, NAME ## 18, 0,                                                 \
+NAME ## 20, 0, NAME ## 22, 0,                                                 \
+NAME ## 24, 0, NAME ## 26, 0,                                                 \
+NAME ## 28, 0, NAME ## 30, 0,                                                 \
+};                                                                            \
+static inline void func(int n)                                                \
+{                                                                             \
+    NAME ## _table[n]();                                                      \
+}
+
+SFGEN32(gen_op_load_fpr_WT0,  gen_op_load_fpr_WT0_fpr);
+SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
+
+SFGEN32(gen_op_load_fpr_WT1,  gen_op_load_fpr_WT1_fpr);
+SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
+
+SFGEN32(gen_op_load_fpr_WT2,  gen_op_load_fpr_WT2_fpr);
+SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
+
+DFGEN32(gen_op_load_fpr_DT0,  gen_op_load_fpr_DT0_fpr);
+DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
+
+DFGEN32(gen_op_load_fpr_DT1,  gen_op_load_fpr_DT1_fpr);
+DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
+
+DFGEN32(gen_op_load_fpr_DT2,  gen_op_load_fpr_DT2_fpr);
+DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
+
+#define FOP_CONDS(fmt) \
+static GenOpFunc * cond_ ## fmt ## _table[16] = {                       \
+    gen_op_cmp_ ## fmt ## _f,                                           \
+    gen_op_cmp_ ## fmt ## _un,                                          \
+    gen_op_cmp_ ## fmt ## _eq,                                          \
+    gen_op_cmp_ ## fmt ## _ueq,                                         \
+    gen_op_cmp_ ## fmt ## _olt,                                         \
+    gen_op_cmp_ ## fmt ## _ult,                                         \
+    gen_op_cmp_ ## fmt ## _ole,                                         \
+    gen_op_cmp_ ## fmt ## _ule,                                         \
+    gen_op_cmp_ ## fmt ## _sf,                                          \
+    gen_op_cmp_ ## fmt ## _ngle,                                        \
+    gen_op_cmp_ ## fmt ## _seq,                                         \
+    gen_op_cmp_ ## fmt ## _ngl,                                         \
+    gen_op_cmp_ ## fmt ## _lt,                                          \
+    gen_op_cmp_ ## fmt ## _nge,                                         \
+    gen_op_cmp_ ## fmt ## _le,                                          \
+    gen_op_cmp_ ## fmt ## _ngt,                                         \
+};                                                                      \
+static inline void gen_cmp_ ## fmt(int n)                               \
+{                                                                       \
+    cond_ ## fmt ## _table[n]();                                        \
+}
+
+FOP_CONDS(d)
+FOP_CONDS(s)
+
+#endif
+
 typedef struct DisasContext {
     struct TranslationBlock *tb;
     target_ulong pc, saved_pc;
@@ -312,6 +409,20 @@
     }                                                                         \
 } while (0)
 
+#ifdef MIPS_USES_FPU
+
+# define GEN_LOAD_FREG_FTN(FTn, Fn)                                           \
+do {                                                                          \
+    glue(gen_op_load_fpr_, FTn)(Fn);                                          \
+} while (0)
+
+#define GEN_STORE_FTN_FREG(Fn, FTn)                                           \
+do {                                                                          \
+    glue(gen_op_store_fpr_, FTn)(Fn);                                         \
+} while (0)
+
+#endif
+
 static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
 {
 #if defined MIPS_DEBUG_DISAS
@@ -397,6 +508,12 @@
 OP_ST_TABLE(b);
 OP_LD_TABLE(l);
 OP_ST_TABLE(c);
+#ifdef MIPS_USES_FPU
+OP_LD_TABLE(wc1);
+OP_ST_TABLE(wc1);
+OP_LD_TABLE(dc1);
+OP_ST_TABLE(dc1);
+#endif
 
 /* Load and store */
 static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
@@ -551,6 +668,56 @@
     MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
 }
 
+#ifdef MIPS_USES_FPU
+
+/* Load and store */
+static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft,
+                      int base, int16_t offset)
+{
+    const unsigned char *opn = "unk";
+
+    if (base == 0) {
+        GEN_LOAD_IMM_TN(T0, offset);
+    } else if (offset == 0) {
+        gen_op_load_gpr_T0(base);
+    } else {
+        gen_op_load_gpr_T0(base);
+        gen_op_set_T1(offset);
+        gen_op_add();
+    }
+    /* Don't do NOP if destination is zero: we must perform the actual
+     * memory access
+     */
+    switch (opc) {
+    case OPC_LWC1:
+        op_ldst(lwc1);
+        GEN_STORE_FTN_FREG(ft, WT0);
+        opn = "lwc1";
+        break;
+    case OPC_SWC1:
+        GEN_LOAD_FREG_FTN(WT0, ft);
+        op_ldst(swc1);
+        opn = "swc1";
+        break;
+    case OPC_LDC1:
+        op_ldst(ldc1);
+        GEN_STORE_FTN_FREG(ft, DT0);
+        opn = "ldc1";
+        break;
+    case OPC_SDC1:
+        GEN_LOAD_FREG_FTN(DT0, ft);
+        op_ldst(sdc1);
+        opn = "sdc1";
+        break;
+    default:
+        MIPS_INVAL("float load/store");
+        generate_exception(ctx, EXCP_CpU);
+        return;
+    }
+    MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
+}
+#endif
+
 /* Arithmetic with immediate operand */
 static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
                            int rs, int16_t imm)
@@ -1265,7 +1432,406 @@
     MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
 }
 
+#ifdef MIPS_USES_FPU
+/* CP1 Branches (before delay slot) */
+static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond,
+                                 int32_t offset)
+{
+    target_ulong btarget;
+
+    btarget = ctx->pc + 4 + offset;
+
+    switch (cond) {
+    case 0x0000: /* bc1f */
+        gen_op_bc1f();
+        MIPS_DEBUG("bc1f %08x", btarget);
+        goto not_likely;
+    case 0x0002: /* bc1fl */
+        gen_op_bc1f();
+        MIPS_DEBUG("bc1fl %08x", btarget);
+        goto likely;
+    case 0x0001: /* bc1t */
+        gen_op_bc1t();
+        MIPS_DEBUG("bc1t %08x", btarget);
+    not_likely:
+        ctx->hflags |= MIPS_HFLAG_BC;
+        break;
+    case 0x0003: /* bc1tl */
+        gen_op_bc1t();
+        MIPS_DEBUG("bc1tl %08x", btarget);
+    likely:
+        ctx->hflags |= MIPS_HFLAG_BL;
+        break;
+    default:    
+        MIPS_INVAL("cp1 branch/jump");
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+    gen_op_set_bcond();
+
+    MIPS_DEBUG("enter ds: cond %02x target %08x",
+               ctx->hflags, btarget);
+    ctx->btarget = btarget;
+
+    return;
+}
+
 /* Coprocessor 1 (FPU) */
+static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs)
+{
+    const unsigned char *opn = "unk";
+
+    switch (opc) {
+    case OPC_MFC1:
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_mfc1();
+        GEN_STORE_TN_REG(rt, T0);
+        opn = "mfc1";
+        break;
+    case OPC_MTC1:
+        GEN_LOAD_REG_TN(T0, rt);
+        gen_op_mtc1();
+        GEN_STORE_FTN_FREG(fs, WT0);
+        opn = "mtc1";
+        break;
+    case OPC_CFC1:
+        if (fs != 0 && fs != 31) {
+            MIPS_INVAL("cfc1 freg");
+            generate_exception(ctx, EXCP_RI);
+            return;
+        }
+        GEN_LOAD_IMM_TN(T1, fs);
+        gen_op_cfc1();
+        GEN_STORE_TN_REG(rt, T0);
+        opn = "cfc1";
+        break;
+    case OPC_CTC1:
+        if (fs != 0 && fs != 31) {
+            MIPS_INVAL("ctc1 freg");
+            generate_exception(ctx, EXCP_RI);
+            return;
+        }
+        GEN_LOAD_IMM_TN(T1, fs);
+        GEN_LOAD_REG_TN(T0, rt);
+        gen_op_ctc1();
+        opn = "ctc1";
+        break;
+    default:
+        if (loglevel & CPU_LOG_TB_IN_ASM) {
+            fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n",
+                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
+                    ((ctx->opcode >> 16) & 0x1F));
+        }
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+    MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
+}
+
+/* verify if floating point register is valid; an operation is not defined
+ * if bit 0 of any register specification is set and the FR bit in the
+ * Status register equals zero, since the register numbers specify an
+ * even-odd pair of adjacent coprocessor general registers. When the FR bit
+ * in the Status register equals one, both even and odd register numbers
+ * are valid.
+ * 
+ * Multiple float registers can be checked by calling
+ * CHECK_FR(ctx, freg1 | freg2 | ... | fregN);
+ */
+#define CHECK_FR(ctx, freg) do { \
+        if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \
+            generate_exception(ctx, EXCP_RI); \
+            return; \
+        } \
+    } while(0)
+
+#define FOP(func, fmt) (((fmt) << 21) | (func))
+
+static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, 
int func)
+{
+    const unsigned char *opn = "unk";
+    const char *condnames[] = {
+            "c.f",
+            "c.un",
+            "c.eq",
+            "c.ueq",
+            "c.olt",
+            "c.ult",
+            "c.ole",
+            "c.ule",
+            "c.sf",
+            "c.ngle",
+            "c.seq",
+            "c.ngl",
+            "c.lt",
+            "c.nge",
+            "c.le",
+            "c.ngt",
+    };
+    int binary = 0;
+    
+    switch (ctx->opcode & FOP(0x3f, 0x1f)) {
+    case FOP(0, 17):
+        CHECK_FR(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        gen_op_float_add_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "add.d";
+        binary = 1;
+        break;
+    case FOP(1, 17):
+        CHECK_FR(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        gen_op_float_sub_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "sub.d";
+        binary = 1;
+        break;
+    case FOP(2, 17):
+        CHECK_FR(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        gen_op_float_mul_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "mul.d";
+        binary = 1;
+        break;
+    case FOP(3, 17):
+        CHECK_FR(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        gen_op_float_div_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "div.d";
+        binary = 1;
+        break;
+    case FOP(4, 17):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_sqrt_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "sqrt.d";
+        break;
+    case FOP(5, 17):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_abs_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "abs.d";
+        break;
+    case FOP(6, 17):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_mov_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "mov.d";
+        break;
+    case FOP(7, 17):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_chs_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "neg.d";
+        break;
+    /*  8 - round.l */
+    /*  9 - trunc.l */
+    /* 10 - ceil.l  */
+    /* 11 - floor.l */
+    case FOP(12, 17):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_roundw_d();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "round.w.d";
+        break;
+    case FOP(13, 17):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_truncw_d();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "trunc.w.d";
+        break;
+    case FOP(14, 17):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_ceilw_d();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "ceil.w.d";
+        break;
+    case FOP(15, 17):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_floorw_d();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "ceil.w.d";
+        break;
+    case FOP(33, 20): /* cvt.d.w */
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_cvtd_w();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "cvt.d.w";
+        break;
+    case FOP(48, 17):
+    case FOP(49, 17):
+    case FOP(50, 17):
+    case FOP(51, 17):
+    case FOP(52, 17):
+    case FOP(53, 17):
+    case FOP(54, 17):
+    case FOP(55, 17):
+    case FOP(56, 17):
+    case FOP(57, 17):
+    case FOP(58, 17):
+    case FOP(59, 17):
+    case FOP(60, 17):
+    case FOP(61, 17):
+    case FOP(62, 17):
+    case FOP(63, 17):
+        CHECK_FR(ctx, fs | ft);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        gen_cmp_d(func-48);
+        opn = condnames[func-48];
+        break;
+    case FOP(0, 16):
+        CHECK_FR(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        gen_op_float_add_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "add.s";
+        binary = 1;
+        break;
+    case FOP(1, 16):
+        CHECK_FR(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        gen_op_float_sub_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "sub.s";
+        binary = 1;
+        break;
+    case FOP(2, 16):
+        CHECK_FR(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        gen_op_float_mul_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "mul.s";
+        binary = 1;
+        break;
+    case FOP(3, 16):
+        CHECK_FR(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        gen_op_float_div_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "div.s";
+        binary = 1;
+        break;
+    case FOP(4, 16):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_sqrt_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "sqrt.s";
+        break;
+    case FOP(5, 16):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_abs_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "abs.s";
+        break;
+    case FOP(6, 16):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_mov_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "mov.s";
+        break;
+    case FOP(7, 16):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_chs_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "neg.s";
+        break;
+    case FOP(12, 16):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_roundw_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "round.w.s";
+        break;
+    case FOP(13, 16):
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_truncw_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "trunc.w.s";
+        break;
+    case FOP(32, 20): /* cvt.s.w */
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_cvts_w();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "cvt.s.w";
+        break;
+    case FOP(36, 16): /* cvt.w.s */
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_cvtw_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "cvt.w.s";
+        break;
+    case FOP(36, 17): /* cvt.w.d */
+        CHECK_FR(ctx, fs | fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_cvtw_d();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "cvt.w.d";
+        break;
+    case FOP(48, 16):
+    case FOP(49, 16):
+    case FOP(50, 16):
+    case FOP(51, 16):
+    case FOP(52, 16):
+    case FOP(53, 16):
+    case FOP(54, 16):
+    case FOP(55, 16):
+    case FOP(56, 16):
+    case FOP(57, 16):
+    case FOP(58, 16):
+    case FOP(59, 16):
+    case FOP(60, 16):
+    case FOP(61, 16):
+    case FOP(62, 16):
+    case FOP(63, 16):
+        CHECK_FR(ctx, fs | ft);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        gen_cmp_s(func-48);
+        opn = condnames[func-48];
+        break;
+    default:    
+        if (loglevel & CPU_LOG_TB_IN_ASM) {
+            fprintf(logfile, "Invalid arith function: %08x %03x %03x %03x\n",
+                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
+                    ((ctx->opcode >> 16) & 0x1F));
+        }
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+    if (binary)
+        MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], 
fregnames[ft]);
+    else
+        MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
+}
+#endif
 
 /* ISA extensions */
 /* MIPS16 extension to MIPS32 */
@@ -1495,9 +2061,39 @@
     case 0x35: /* LDC1 */
     case 0x39: /* SWC1 */
     case 0x3D: /* SDC1 */
+#if defined(MIPS_USES_FPU)
+        gen_op_cp1_enabled();
+        gen_flt_ldst(ctx, op, rt, rs, imm);
+#else
+        generate_exception_err(ctx, EXCP_CpU, 1);
+#endif
+        break;
+
     case 0x11:          /* CP1 opcode */
 #if defined(MIPS_USES_FPU)
-        /* XXX: not correct */
+        gen_op_cp1_enabled();
+        op1 = ((ctx->opcode >> 21) & 0x1F);
+        switch (op1) {
+        case 0x00: /* mfc1 */
+        case 0x02: /* cfc1 */
+        case 0x04: /* mtc1 */
+        case 0x06: /* ctc1 */
+            gen_cp1(ctx, op1 | EXT_CP1, rt, rd);
+            break;
+        case 0x08: /* bc */
+            gen_compute_branch1(ctx, rt, imm << 2);
+            return;
+        case 0x10: /* 16: fmt=single fp */
+        case 0x11: /* 17: fmt=double fp */
+        case 0x14: /* 20: fmt=32bit fixed */
+        case 0x15: /* 21: fmt=64bit fixed */
+            gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f);
+            break;
+        default:
+            generate_exception_err(ctx, EXCP_RI, 1);
+            break;
+        }
+        break;
 #else
         generate_exception_err(ctx, EXCP_CpU, 1);
 #endif
@@ -1722,6 +2318,42 @@
     return gen_intermediate_code_internal(env, tb, 1);
 }
 
+#ifdef MIPS_USES_FPU
+void fpu_dump_state(CPUState *env, FILE *f, 
+                    int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
+                    int flags)
+{
+    int i;
+
+#   define printfpr(fp) do { \
+        fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \
+                (fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, 
(fp)->fs[FP_ENDIAN_IDX]); \
+    } while(0)
+
+    fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d\n",
+                env->fcr0, env->fcr31,
+                (env->CP0_Status & (1<<CP0St_FR)) != 0);
+    fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
+    fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
+    fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
+    for(i=0; i < 32; i+=2) {
+        fpu_fprintf(f, "f%02d: ", i);
+        printfpr(FPR(env, i));
+    }
+
+#undef printfpr
+}
+
+void dump_fpu(CPUState *env)
+{
+    if (loglevel) { 
+       fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
+               env->PC, env->HI, env->LO, env->hflags, env->btarget, 
env->bcond);
+       fpu_dump_state(env, logfile, fprintf, 0);
+    }
+}
+#endif /* MIPS_USES_FPU */
+
 void cpu_dump_state (CPUState *env, FILE *f, 
                      int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                      int flags)
@@ -1751,6 +2383,9 @@
                 c0_status, env->CP0_Cause, env->CP0_EPC);
     cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
                 env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
+#ifdef MIPS_USES_FPU
+    fpu_dump_state(env, f, cpu_fprintf, flags);
+#endif
 }
 
 CPUMIPSState *cpu_mips_init (void)
@@ -1788,5 +2423,8 @@
 #if defined(CONFIG_USER_ONLY)
     env->hflags |= MIPS_HFLAG_UM;
 #endif
+#ifdef MIPS_USES_FPU
+    env->fcr0 = MIPS_FCR0;     
+#endif
     return env;
 }

Index: target-mips/fop_template.c
===================================================================
RCS file: target-mips/fop_template.c
diff -N target-mips/fop_template.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ target-mips/fop_template.c  14 Jun 2006 12:56:19 -0000      1.1
@@ -0,0 +1,99 @@
+/*
+ * MIPS emulation micro-operations templates for floating point reg 
+ * load & store for qemu.
+ * 
+ * Copyright (c) 2006 Marius Groeger
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if defined(SFREG)
+
+#define OP_WLOAD_FREG(treg, tregname, SFREG)      \
+    void glue(glue(op_load_fpr_,tregname), SFREG) (void) \
+    {                                                   \
+        treg = FPR_W(env, SFREG);     \
+        RETURN();                                       \
+    }
+
+#define OP_WSTORE_FREG(treg, tregname, SFREG)            \
+    void glue(glue(op_store_fpr_,tregname), SFREG) (void)\
+    {                                                   \
+        FPR_W(env, SFREG) = treg;     \
+        RETURN();                                       \
+    }
+
+/* WT0 = SFREG.w: op_load_fpr_WT0_fprSFREG */
+OP_WLOAD_FREG(WT0, WT0_fpr, SFREG)
+/* SFREG.w = WT0: op_store_fpr_WT0_fprSFREG */
+OP_WSTORE_FREG(WT0, WT0_fpr, SFREG)
+
+OP_WLOAD_FREG(WT1, WT1_fpr, SFREG)
+OP_WSTORE_FREG(WT1, WT1_fpr, SFREG)
+
+OP_WLOAD_FREG(WT2, WT2_fpr, SFREG)
+OP_WSTORE_FREG(WT2, WT2_fpr, SFREG)
+
+#endif
+
+#if defined(DFREG)
+
+#define OP_DLOAD_FREG(treg, tregname, DFREG)      \
+    void glue(glue(op_load_fpr_,tregname), DFREG) (void) \
+    {                                                   \
+        treg = FPR_D(env, DFREG);                    \
+        RETURN();                                       \
+    }
+
+#define OP_DSTORE_FREG(treg, tregname, DFREG)            \
+    void glue(glue(op_store_fpr_,tregname), DFREG) (void)\
+    {                                                   \
+        FPR_D(env, DFREG) = treg;                    \
+        RETURN();                                       \
+    }
+
+OP_DLOAD_FREG(DT0, DT0_fpr, DFREG)
+OP_DSTORE_FREG(DT0, DT0_fpr, DFREG)
+
+OP_DLOAD_FREG(DT1, DT1_fpr, DFREG)
+OP_DSTORE_FREG(DT1, DT1_fpr, DFREG)
+
+OP_DLOAD_FREG(DT2, DT2_fpr, DFREG)
+OP_DSTORE_FREG(DT2, DT2_fpr, DFREG)
+
+#endif
+
+#if defined (FTN)
+
+#define SET_RESET(treg, tregname)    \
+    void glue(op_set, tregname)(void)    \
+    {                                \
+        treg = PARAM1;               \
+        RETURN();                    \
+    }                                \
+    void glue(op_reset, tregname)(void)  \
+    {                                \
+        treg = 0;                    \
+        RETURN();                    \
+    }                                \
+
+SET_RESET(WT0, _WT0)
+SET_RESET(WT1, _WT1)
+SET_RESET(WT2, _WT2)
+SET_RESET(DT0, _DT0)
+SET_RESET(DT1, _DT1)
+SET_RESET(DT2, _DT2)
+
+#endif




reply via email to

[Prev in Thread] Current Thread [Next in Thread]