2002-06-07 Chris Demetriou <cgd@broadcom.com>
authorChris Demetriou <cgd@google.com>
Sat, 8 Jun 2002 03:05:23 +0000 (03:05 +0000)
committerChris Demetriou <cgd@google.com>
Sat, 8 Jun 2002 03:05:23 +0000 (03:05 +0000)
            Ed Satterthwaite  <ehs@broadcom.com>

* cp1.c (inner_mac, fp_mac, inner_rsqrt, fp_inv_sqrt)
(fp_rsqrt, fp_madd, fp_msub, fp_nmadd, fp_nmsub): New functions.
* sim-main.h (fp_rsqrt, fp_madd, fp_msub, fp_nmadd)
(fp_nmsub): New prototypes.
(RSquareRoot, MultiplyAdd, MultiplySub, NegMultiplyAdd)
(NegMultiplySub): New defines.
* mips.igen (RSQRT.fmt): Use RSquareRoot().
(MADD.D, MADD.S): Replace with...
(MADD.fmt): New instruction.
(MSUB.D, MSUB.S): Replace with...
(MSUB.fmt): New instruction.
(NMADD.D, NMADD.S): Replace with...
(NMADD.fmt): New instruction.
(NMSUB.D, MSUB.S): Replace with...
(NMSUB.fmt): New instruction.

sim/mips/ChangeLog
sim/mips/cp1.c
sim/mips/mips.igen
sim/mips/sim-main.h

index f17a3f54b7516aa85e38ff7608a694441d37230b..51366dbbacba9dbf428756d8c762e0657aebbb29 100644 (file)
@@ -1,3 +1,22 @@
+2002-06-07  Chris Demetriou  <cgd@broadcom.com>
+            Ed Satterthwaite  <ehs@broadcom.com>
+
+       * cp1.c (inner_mac, fp_mac, inner_rsqrt, fp_inv_sqrt)
+       (fp_rsqrt, fp_madd, fp_msub, fp_nmadd, fp_nmsub): New functions.
+       * sim-main.h (fp_rsqrt, fp_madd, fp_msub, fp_nmadd)
+       (fp_nmsub): New prototypes.
+       (RSquareRoot, MultiplyAdd, MultiplySub, NegMultiplyAdd)
+       (NegMultiplySub): New defines.
+       * mips.igen (RSQRT.fmt): Use RSquareRoot().
+       (MADD.D, MADD.S): Replace with...
+       (MADD.fmt): New instruction.
+       (MSUB.D, MSUB.S): Replace with...
+       (MSUB.fmt): New instruction.
+       (NMADD.D, NMADD.S): Replace with...
+       (NMADD.fmt): New instruction.
+       (NMSUB.D, MSUB.S): Replace with...
+       (NMSUB.fmt): New instruction.
+
 2002-06-07  Chris Demetriou  <cgd@broadcom.com>
             Ed Satterthwaite  <ehs@broadcom.com>
 
index 5280b794869c39f37d0b52e6ac52a07efada9388..66e7c586b75fd72acd7319b7537af199e187e173 100644 (file)
@@ -672,6 +672,206 @@ fp_binary(sim_cpu *cpu,
   return result;
 }
 
+/* Common MAC code for single operands (.s or .d), defers setting FCSR.  */
+static sim_fpu_status
+inner_mac(int (*sim_fpu_op)(sim_fpu *, const sim_fpu *, const sim_fpu *),
+         unsigned64 op1,
+         unsigned64 op2,
+         unsigned64 op3,
+         int scale,
+         int negate,
+         FP_formats fmt,
+         sim_fpu_round round,
+         sim_fpu_denorm denorm,
+         unsigned64 *result)
+{
+  sim_fpu wop1;
+  sim_fpu wop2;
+  sim_fpu ans;
+  sim_fpu_status status = 0;
+  sim_fpu_status op_status;
+  unsigned64 temp = 0;
+
+  switch (fmt)
+    {
+    case fmt_single:
+      {
+       unsigned32 res;
+       sim_fpu_32to (&wop1, op1);
+       sim_fpu_32to (&wop2, op2);
+       status |= sim_fpu_mul (&ans, &wop1, &wop2);
+       if (scale != 0 && sim_fpu_is_number (&ans))  /* number or denorm */
+         ans.normal_exp += scale;
+       status |= sim_fpu_round_32 (&ans, round, denorm);
+       wop1 = ans;
+        op_status = 0;
+       sim_fpu_32to (&wop2, op3);
+       op_status |= (*sim_fpu_op) (&ans, &wop1, &wop2);
+       op_status |= sim_fpu_round_32 (&ans, round, denorm);
+       status |= op_status;
+       if (negate)
+         {
+           wop1 = ans;
+           op_status = sim_fpu_neg (&ans, &wop1);
+           op_status |= sim_fpu_round_32 (&ans, round, denorm);
+           status |= op_status;
+         }
+       sim_fpu_to32 (&res, &ans);
+       temp = res;
+       break;
+      }
+    case fmt_double:
+      {
+       unsigned64 res;
+       sim_fpu_64to (&wop1, op1);
+       sim_fpu_64to (&wop2, op2);
+       status |= sim_fpu_mul (&ans, &wop1, &wop2);
+       if (scale != 0 && sim_fpu_is_number (&ans))  /* number or denorm */
+         ans.normal_exp += scale;
+       status |= sim_fpu_round_64 (&ans, round, denorm);
+       wop1 = ans;
+        op_status = 0;
+       sim_fpu_64to (&wop2, op3);
+       op_status |= (*sim_fpu_op) (&ans, &wop1, &wop2);
+       op_status |= sim_fpu_round_64 (&ans, round, denorm);
+       status |= op_status;
+       if (negate)
+         {
+           wop1 = ans;
+           op_status = sim_fpu_neg (&ans, &wop1);
+           op_status |= sim_fpu_round_64 (&ans, round, denorm);
+           status |= op_status;
+         }
+       sim_fpu_to64 (&res, &ans);
+       temp = res;
+       break;
+      }
+    default:
+      fprintf (stderr, "Bad switch\n");
+      abort ();
+    }
+  *result = temp;
+  return status;
+}
+
+/* Common implementation of madd, nmadd, msub, nmsub that does
+   intermediate rounding per spec.  Also used for recip2 and rsqrt2,
+   which are transformed into equivalent nmsub operations.  The scale
+   argument is an adjustment to the exponent of the intermediate
+   product op1*op2.  It is currently non-zero for rsqrt2 (-1), which
+   requires an effective division by 2. */
+static unsigned64
+fp_mac(sim_cpu *cpu,
+       address_word cia,
+       int (*sim_fpu_op)(sim_fpu *, const sim_fpu *, const sim_fpu *),
+       unsigned64 op1,
+       unsigned64 op2,
+       unsigned64 op3,
+       int scale,
+       int negate,
+       FP_formats fmt)
+{
+  sim_fpu_round round = rounding_mode (GETRM());
+  sim_fpu_denorm denorm = denorm_mode (cpu);
+  sim_fpu_status status = 0;
+  unsigned64 result = 0;
+
+  /* The format type has already been checked: */
+  switch (fmt)
+    {
+    case fmt_single:
+    case fmt_double:
+      status = inner_mac(sim_fpu_op, op1, op2, op3, scale,
+                        negate, fmt, round, denorm, &result);
+      break;
+    default:
+      sim_io_eprintf (SD, "Bad switch\n");
+      abort ();
+    }
+
+  update_fcsr (cpu, cia, status);
+  return result;
+}
+
+/* Common rsqrt code for single operands (.s or .d), intermediate rounding.  */
+static sim_fpu_status
+inner_rsqrt(unsigned64 op1,
+           FP_formats fmt,
+           sim_fpu_round round,
+           sim_fpu_denorm denorm,
+           unsigned64 *result)
+{
+  sim_fpu wop1;
+  sim_fpu ans;
+  sim_fpu_status status = 0;
+  sim_fpu_status op_status;
+  unsigned64 temp = 0;
+
+  switch (fmt)
+    {
+    case fmt_single:
+      {
+       unsigned32 res;
+       sim_fpu_32to (&wop1, op1);
+       status |= sim_fpu_sqrt (&ans, &wop1);
+       status |= sim_fpu_round_32 (&ans, status, round);
+       wop1 = ans;
+       op_status = sim_fpu_inv (&ans, &wop1);
+       op_status |= sim_fpu_round_32 (&ans, round, denorm);
+       sim_fpu_to32 (&res, &ans);
+       temp = res;
+       status |= op_status;
+       break;
+      }
+    case fmt_double:
+      {
+       unsigned64 res;
+       sim_fpu_64to (&wop1, op1);
+       status |= sim_fpu_sqrt (&ans, &wop1);
+       status |= sim_fpu_round_64 (&ans, round, denorm);
+       wop1 = ans;
+       op_status = sim_fpu_inv (&ans, &wop1);
+       op_status |= sim_fpu_round_64 (&ans, round, denorm);
+       sim_fpu_to64 (&res, &ans);
+       temp = res;
+       status |= op_status;
+       break;
+      }
+    default:
+      fprintf (stderr, "Bad switch\n");
+      abort ();
+    }
+  *result = temp;
+  return status;
+}
+
+static unsigned64
+fp_inv_sqrt(sim_cpu *cpu,
+           address_word cia,
+           unsigned64 op1,
+           FP_formats fmt)
+{
+  sim_fpu_round round = rounding_mode (GETRM());
+  sim_fpu_round denorm = denorm_mode (cpu);
+  sim_fpu_status status = 0;
+  unsigned64 result = 0;
+
+  /* The format type has already been checked: */
+  switch (fmt)
+    {
+    case fmt_single:
+    case fmt_double:
+      status = inner_rsqrt (op1, fmt, round, denorm, &result);
+      break;
+    default:
+      sim_io_eprintf (SD, "Bad switch\n");
+      abort ();
+    }
+
+  update_fcsr (cpu, cia, status);
+  return result;
+}
+
 
 unsigned64
 fp_abs(sim_cpu *cpu,
@@ -749,6 +949,59 @@ fp_sqrt(sim_cpu *cpu,
   return fp_unary(cpu, cia, &sim_fpu_sqrt, op, fmt);
 }
 
+unsigned64
+fp_rsqrt(sim_cpu *cpu,
+         address_word cia,
+         unsigned64 op,
+         FP_formats fmt)
+{
+  return fp_inv_sqrt(cpu, cia, op, fmt);
+}
+
+unsigned64
+fp_madd(sim_cpu *cpu,
+        address_word cia,
+        unsigned64 op1,
+        unsigned64 op2,
+        unsigned64 op3,
+        FP_formats fmt)
+{
+  return fp_mac(cpu, cia, &sim_fpu_add, op1, op2, op3, 0, 0, fmt);
+}
+
+unsigned64
+fp_msub(sim_cpu *cpu,
+        address_word cia,
+        unsigned64 op1,
+        unsigned64 op2,
+        unsigned64 op3,
+        FP_formats fmt)
+{
+  return fp_mac(cpu, cia, &sim_fpu_sub, op1, op2, op3, 0, 0, fmt);
+}
+
+unsigned64
+fp_nmadd(sim_cpu *cpu,
+         address_word cia,
+         unsigned64 op1,
+         unsigned64 op2,
+         unsigned64 op3,
+         FP_formats fmt)
+{
+  return fp_mac(cpu, cia, &sim_fpu_add, op1, op2, op3, 0, 1, fmt);
+}
+
+unsigned64
+fp_nmsub(sim_cpu *cpu,
+         address_word cia,
+         unsigned64 op1,
+         unsigned64 op2,
+         unsigned64 op3,
+         FP_formats fmt)
+{
+  return fp_mac(cpu, cia, &sim_fpu_sub, op1, op2, op3, 0, 1, fmt);
+}
+
 
 /* Conversion operations.  */
 
index f374a54d570779ec218b07a4cbe021153f7ff49b..13f677647e049cfa911825232b8fc40484def02d 100644 (file)
 
 
 
-//
-// FIXME: Not correct for mips*
-//
-010011,5.FR,5.FT,5.FS,5.FD,100,001:COP1X:32,f::MADD.D
-"madd.d f<FD>, f<FR>, f<FS>, f<FT>"
-*mipsIV:
-*mipsV:
-*mips64:
-*vr5000:
-{
-  check_fpu (SD_);
-  {
-    StoreFPR(FD,fmt_double,Add(Multiply(ValueFPR(FS,fmt_double),ValueFPR(FT,fmt_double),fmt_double),ValueFPR(FR,fmt_double),fmt_double));
-  }
-}
-
-
-010011,5.FR,5.FT,5.FS,5.FD,100,000:COP1X:32,f::MADD.S
-"madd.s f<FD>, f<FR>, f<FS>, f<FT>"
+010011,5.FR,5.FT,5.FS,5.FD,100,3.FMT:COP1X:64,f::MADD.fmt
+"madd.%s<FMT> f<FD>, f<FR>, f<FS>, f<FT>"
 *mipsIV:
 *mipsV:
 *mips64:
 *vr5000:
 {
+  int fmt = FMT;
   check_fpu (SD_);
-  {
-    StoreFPR(FD,fmt_single,Add(Multiply(ValueFPR(FS,fmt_single),ValueFPR(FT,fmt_single),fmt_single),ValueFPR(FR,fmt_single),fmt_single));
-  }
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0); 
+  StoreFPR (FD, fmt, MultiplyAdd (ValueFPR (FS, fmt), ValueFPR (FT, fmt),
+                                 ValueFPR (FR, fmt), fmt));
 }
 
 
 }
 
 
-// MSUB.fmt
-010011,5.FR,5.FT,5.FS,5.FD,101,001:COP1X:32,f::MSUB.D
-"msub.d f<FD>, f<FR>, f<FS>, f<FT>"
-*mipsIV:
-*mipsV:
-*mips64:
-*vr5000:
-{
-  check_fpu (SD_);
-  StoreFPR(FD,fmt_double,Sub(Multiply(ValueFPR(FS,fmt_double),ValueFPR(FT,fmt_double),fmt_double),ValueFPR(FR,fmt_double),fmt_double));
-}
-
-
-// MSUB.fmt
-010011,5.FR,5.FT,5.FS,5.FD,101000:COP1X:32,f::MSUB.S
-"msub.s f<FD>, f<FR>, f<FS>, f<FT>"
+010011,5.FR,5.FT,5.FS,5.FD,101,3.FMT:COP1X:64,f::MSUB.fmt
+"msub.%s<FMT> f<FD>, f<FR>, f<FS>, f<FT>"
 *mipsIV:
 *mipsV:
 *mips64:
 *vr5000:
 {
+  int fmt = FMT;
   check_fpu (SD_);
-  StoreFPR(FD,fmt_single,Sub(Multiply(ValueFPR(FS,fmt_single),ValueFPR(FT,fmt_single),fmt_single),ValueFPR(FR,fmt_single),fmt_single));
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  StoreFPR (FD, fmt, MultiplySub (ValueFPR (FS, fmt), ValueFPR (FT, fmt),
+                                 ValueFPR (FR, fmt), fmt));
 }
 
 
 }
 
 
-// NMADD.fmt
-010011,5.FR,5.FT,5.FS,5.FD,110001:COP1X:32,f::NMADD.D
-"nmadd.d f<FD>, f<FR>, f<FS>, f<FT>"
-*mipsIV:
-*mipsV:
-*mips64:
-*vr5000:
-{
-  check_fpu (SD_);
-  StoreFPR(FD,fmt_double,Negate(Add(Multiply(ValueFPR(FS,fmt_double),ValueFPR(FT,fmt_double),fmt_double),ValueFPR(FR,fmt_double),fmt_double),fmt_double));
-}
-
-
-// NMADD.fmt
-010011,5.FR,5.FT,5.FS,5.FD,110000:COP1X:32,f::NMADD.S
-"nmadd.s f<FD>, f<FR>, f<FS>, f<FT>"
-*mipsIV:
-*mipsV:
-*mips64:
-*vr5000:
-{
-  check_fpu (SD_);
-  StoreFPR(FD,fmt_single,Negate(Add(Multiply(ValueFPR(FS,fmt_single),ValueFPR(FT,fmt_single),fmt_single),ValueFPR(FR,fmt_single),fmt_single),fmt_single));
-}
-
-
-// NMSUB.fmt
-010011,5.FR,5.FT,5.FS,5.FD,111001:COP1X:32,f::NMSUB.D
-"nmsub.d f<FD>, f<FR>, f<FS>, f<FT>"
+010011,5.FR,5.FT,5.FS,5.FD,110,3.FMT:COP1X:64,f::NMADD.fmt
+"nmadd.%s<FMT> f<FD>, f<FR>, f<FS>, f<FT>"
 *mipsIV:
 *mipsV:
 *mips64:
 *vr5000:
 {
+  int fmt = FMT;
   check_fpu (SD_);
-  StoreFPR(FD,fmt_double,Negate(Sub(Multiply(ValueFPR(FS,fmt_double),ValueFPR(FT,fmt_double),fmt_double),ValueFPR(FR,fmt_double),fmt_double),fmt_double));
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  StoreFPR (FD, fmt, NegMultiplyAdd (ValueFPR (FS, fmt), ValueFPR (FT, fmt),
+                                    ValueFPR (FR, fmt), fmt));
 }
 
 
-// NMSUB.fmt
-010011,5.FR,5.FT,5.FS,5.FD,111000:COP1X:32,f::NMSUB.S
-"nmsub.s f<FD>, f<FR>, f<FS>, f<FT>"
+010011,5.FR,5.FT,5.FS,5.FD,111,3.FMT:COP1X:64,f::NMSUB.fmt
+"nmsub.%s<FMT> f<FD>, f<FR>, f<FS>, f<FT>"
 *mipsIV:
 *mipsV:
 *mips64:
 *vr5000:
 {
+  int fmt = FMT;
   check_fpu (SD_);
-  StoreFPR(FD,fmt_single,Negate(Sub(Multiply(ValueFPR(FS,fmt_single),ValueFPR(FT,fmt_single),fmt_single),ValueFPR(FR,fmt_single),fmt_single),fmt_single));
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  StoreFPR (FD, fmt, NegMultiplySub (ValueFPR (FS, fmt), ValueFPR (FT, fmt),
+                                    ValueFPR (FR, fmt), fmt));
 }
 
 
   int fmt = FMT;
   check_fpu (SD_);
   check_fmt (SD_, fmt, instruction_0);
-  StoreFPR(FD,fmt,Recip(SquareRoot(ValueFPR(FS,fmt),fmt),fmt));
+  StoreFPR (FD, fmt, RSquareRoot (ValueFPR (FS, fmt), fmt));
 }
 
 
index efbf98ab8698e9faea0be53a4d4eb57504248d79..25f8a0d50b69e9288d92e9b5e63a7bd805e220f6 100644 (file)
@@ -704,6 +704,20 @@ unsigned64 fp_recip (SIM_STATE, unsigned64 op, FP_formats fmt);
 #define Recip(op,fmt) fp_recip(SIM_ARGS, op, fmt)
 unsigned64 fp_sqrt (SIM_STATE, unsigned64 op, FP_formats fmt);
 #define SquareRoot(op,fmt) fp_sqrt(SIM_ARGS, op, fmt)
+unsigned64 fp_rsqrt (SIM_STATE, unsigned64 op, FP_formats fmt);
+#define RSquareRoot(op,fmt) fp_rsqrt(SIM_ARGS, op, fmt)
+unsigned64 fp_madd (SIM_STATE, unsigned64 op1, unsigned64 op2,
+                   unsigned64 op3, FP_formats fmt);
+#define MultiplyAdd(op1,op2,op3,fmt) fp_madd(SIM_ARGS, op1, op2, op3, fmt)
+unsigned64 fp_msub (SIM_STATE, unsigned64 op1, unsigned64 op2,
+                   unsigned64 op3, FP_formats fmt);
+#define MultiplySub(op1,op2,op3,fmt) fp_msub(SIM_ARGS, op1, op2, op3, fmt)
+unsigned64 fp_nmadd (SIM_STATE, unsigned64 op1, unsigned64 op2,
+                    unsigned64 op3, FP_formats fmt);
+#define NegMultiplyAdd(op1,op2,op3,fmt) fp_nmadd(SIM_ARGS, op1, op2, op3, fmt)
+unsigned64 fp_nmsub (SIM_STATE, unsigned64 op1, unsigned64 op2,
+                    unsigned64 op3, FP_formats fmt);
+#define NegMultiplySub(op1,op2,op3,fmt) fp_nmsub(SIM_ARGS, op1, op2, op3, fmt)
 unsigned64 convert (SIM_STATE, int rm, unsigned64 op, FP_formats from, FP_formats to);
 #define Convert(rm,op,from,to) convert (SIM_ARGS, rm, op, from, to)