2002-06-13 Chris Demetriou <cgd@broadcom.com>
authorChris Demetriou <cgd@google.com>
Fri, 14 Jun 2002 04:44:11 +0000 (04:44 +0000)
committerChris Demetriou <cgd@google.com>
Fri, 14 Jun 2002 04:44:11 +0000 (04:44 +0000)
* cp1.c (FP_PS_upper, FP_PS_lower, FP_PS_cat, FPQNaN_PS): New macros.
(value_fpr, store_fpr, fp_cmp, fp_unary, fp_binary, fp_mac)
(fp_inv_sqrt, fpu_format_name): Add paired-single support.
(convert): Note that this function is not used for paired-single
format conversions.
(ps_lower, ps_upper, pack_ps, convert_ps): New functions.
* mips.igen (FMT, MOVtf.fmt): Add paired-single support.
(check_fmt_p): Enable paired-single support.
(ALNV.PS, CVT.PS.S, CVT.S.PL, CVT.S.PU, PLL.PS, PLU.PS, PUL.PS)
(PUU.PS): New instructions.
(CVT.S.fmt): Don't use this instruction for paired-single format
destinations.
* sim-main.h (FP_formats): New value 'fmt_ps.'
(ps_lower, ps_upper, pack_ps, convert_ps): New prototypes.
(PSLower, PSUpper, PackPS, ConvertPS): New macros.

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

index 336eda5818b2ae2a0eaba2702a9b21322e69aee6..275624976818bd46943e885c4fa6482d201a8a72 100644 (file)
@@ -1,3 +1,21 @@
+2002-06-13  Chris Demetriou  <cgd@broadcom.com>
+
+       * cp1.c (FP_PS_upper, FP_PS_lower, FP_PS_cat, FPQNaN_PS): New macros.
+       (value_fpr, store_fpr, fp_cmp, fp_unary, fp_binary, fp_mac)
+       (fp_inv_sqrt, fpu_format_name): Add paired-single support.
+       (convert): Note that this function is not used for paired-single
+       format conversions.
+       (ps_lower, ps_upper, pack_ps, convert_ps): New functions.
+       * mips.igen (FMT, MOVtf.fmt): Add paired-single support.
+       (check_fmt_p): Enable paired-single support.
+       (ALNV.PS, CVT.PS.S, CVT.S.PL, CVT.S.PU, PLL.PS, PLU.PS, PUL.PS)
+       (PUU.PS): New instructions.
+       (CVT.S.fmt): Don't use this instruction for paired-single format
+       destinations.
+       * sim-main.h (FP_formats): New value 'fmt_ps.'
+       (ps_lower, ps_upper, pack_ps, convert_ps): New prototypes.
+       (PSLower, PSUpper, PackPS, ConvertPS): New macros.
+
 2002-06-12  Chris Demetriou  <cgd@broadcom.com>
 
        * mips.igen: Fix formatting of function calls in
index 66e7c586b75fd72acd7319b7537af199e187e173..24c0a21fefac5366e46f993089bdfa3ad356b6bf 100644 (file)
@@ -71,13 +71,28 @@ with this program; if not, write to the Free Software Foundation, Inc.,
       siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
         s =  1bit  = sign
         i = 63bits = integer
+
+   PAIRED SINGLE precision floating:
+      seeeeeeeefffffffffffffffffffffffseeeeeeeefffffffffffffffffffffff
+      |         upper                ||         lower                |
+        s =  1bit  = sign
+        e =  8bits = exponent
+        f = 23bits = fraction
+    Note: upper = [63..32], lower = [31..0]
  */
 
+/* Extract packed single values:  */
+#define FP_PS_upper(v) (((v) >> 32) & (unsigned)0xFFFFFFFF)
+#define FP_PS_lower(v) ((v) & (unsigned)0xFFFFFFFF)
+#define FP_PS_cat(u,l) (((unsigned64)((u) & (unsigned)0xFFFFFFFF) << 32) \
+                        | (unsigned64)((l) & 0xFFFFFFFF))
+
 /* Explicit QNaN values.  */
 #define FPQNaN_SINGLE   (0x7FBFFFFF)
 #define FPQNaN_WORD     (0x7FFFFFFF)
 #define FPQNaN_DOUBLE   (UNSIGNED64 (0x7FF7FFFFFFFFFFFF))
 #define FPQNaN_LONG     (UNSIGNED64 (0x7FFFFFFFFFFFFFFF))
+#define FPQNaN_PS       (FP_PS_cat (FPQNaN_SINGLE, FPQNaN_SINGLE))
 
 static const char *fpu_format_name (FP_formats fmt);
 #ifdef DEBUG
@@ -131,6 +146,7 @@ value_fpr (sim_cpu *cpu,
        case fmt_double:  value = FPQNaN_DOUBLE;  break;
        case fmt_word:    value = FPQNaN_WORD;    break;
        case fmt_long:    value = FPQNaN_LONG;    break;
+       case fmt_ps:      value = FPQNaN_PS;      break;
        default:          err = -1;               break;
        }
     }
@@ -146,6 +162,7 @@ value_fpr (sim_cpu *cpu,
        case fmt_uninterpreted:
        case fmt_double:
        case fmt_long:
+       case fmt_ps:
          value = FGR[fpr];
          break;
 
@@ -183,6 +200,10 @@ value_fpr (sim_cpu *cpu,
            }
          break;
 
+       case fmt_ps:
+         SignalException (ReservedInstruction, 0);
+         break;
+
        default:
          err = -1;
          break;
@@ -237,6 +258,7 @@ store_fpr (sim_cpu *cpu,
        case fmt_uninterpreted:
        case fmt_double:
        case fmt_long:
+       case fmt_ps:
          FGR[fpr] = value;
          FPR_STATE[fpr] = fmt;
          break;
@@ -280,6 +302,11 @@ store_fpr (sim_cpu *cpu,
            }
          break;
 
+       case fmt_ps:
+         FPR_STATE[fpr] = fmt_unknown;
+         SignalException (ReservedInstruction, 0);
+         break;
+
        default:
          FPR_STATE[fpr] = fmt_unknown;
          err = -1;
@@ -567,6 +594,18 @@ fp_cmp(sim_cpu *cpu,
        SETFCC (cc, result);
        break;
       }
+    case fmt_ps:
+      {
+       int result0, result1;
+       status  = fp_test(FP_PS_lower (op1), FP_PS_lower (op2), fmt_single,
+                         abs, cond, &result0);
+       status |= fp_test(FP_PS_upper (op1), FP_PS_upper (op2), fmt_single,
+                         abs, cond, &result1);
+       update_fcsr (cpu, cia, status);
+       SETFCC (cc, result0);
+       SETFCC (cc+1, result1);
+       break;
+      }
     default:
       sim_io_eprintf (SD, "Bad switch\n");
       abort ();
@@ -613,6 +652,20 @@ fp_unary(sim_cpu *cpu,
        result = res;
        break;
       }
+    case fmt_ps:
+      {
+       int status_u = 0, status_l = 0;
+       unsigned32 res_u, res_l;
+       sim_fpu_32to (&wop, FP_PS_upper(op));
+       status_u |= (*sim_fpu_op) (&ans, &wop);
+       sim_fpu_to32 (&res_u, &ans);
+       sim_fpu_32to (&wop, FP_PS_lower(op));
+       status_l |= (*sim_fpu_op) (&ans, &wop);
+       sim_fpu_to32 (&res_l, &ans);
+       result = FP_PS_cat(res_u, res_l);
+       status = status_u | status_l;
+       break;
+      }
     default:
       sim_io_eprintf (SD, "Bad switch\n");
       abort ();
@@ -663,6 +716,22 @@ fp_binary(sim_cpu *cpu,
        result = res;
        break;
       }
+    case fmt_ps:
+      {
+       int status_u = 0, status_l = 0;
+       unsigned32 res_u, res_l;
+       sim_fpu_32to (&wop1, FP_PS_upper(op1));
+       sim_fpu_32to (&wop2, FP_PS_upper(op2));
+       status_u |= (*sim_fpu_op) (&ans, &wop1, &wop2);
+       sim_fpu_to32 (&res_u, &ans);
+       sim_fpu_32to (&wop1, FP_PS_lower(op1));
+       sim_fpu_32to (&wop2, FP_PS_lower(op2));
+       status_l |= (*sim_fpu_op) (&ans, &wop1, &wop2);
+       sim_fpu_to32 (&res_l, &ans);
+       result = FP_PS_cat(res_u, res_l);
+       status = status_u | status_l;
+       break;
+      }
     default:
       sim_io_eprintf (SD, "Bad switch\n");
       abort ();
@@ -784,6 +853,20 @@ fp_mac(sim_cpu *cpu,
       status = inner_mac(sim_fpu_op, op1, op2, op3, scale,
                         negate, fmt, round, denorm, &result);
       break;
+    case fmt_ps:
+      {
+       int status_u, status_l;
+       unsigned64 result_u, result_l;
+       status_u = inner_mac(sim_fpu_op, FP_PS_upper(op1), FP_PS_upper(op2),
+                            FP_PS_upper(op3), scale, negate, fmt_single,
+                            round, denorm, &result_u);
+       status_l = inner_mac(sim_fpu_op, FP_PS_lower(op1), FP_PS_lower(op2),
+                            FP_PS_lower(op3), scale, negate, fmt_single,
+                            round, denorm, &result_l);
+       result = FP_PS_cat(result_u, result_l);
+       status = status_u | status_l;
+       break;
+      }
     default:
       sim_io_eprintf (SD, "Bad switch\n");
       abort ();
@@ -863,6 +946,18 @@ fp_inv_sqrt(sim_cpu *cpu,
     case fmt_double:
       status = inner_rsqrt (op1, fmt, round, denorm, &result);
       break;
+    case fmt_ps:
+      {
+       int status_u, status_l;
+       unsigned64 result_u, result_l;
+       status_u = inner_rsqrt (FP_PS_upper(op1), fmt_single, round, denorm,
+                               &result_u);
+       status_l = inner_rsqrt (FP_PS_lower(op1), fmt_single, round, denorm,
+                               &result_l);
+       result = FP_PS_cat(result_u, result_l);
+       status = status_u | status_l;
+       break;
+      }
     default:
       sim_io_eprintf (SD, "Bad switch\n");
       abort ();
@@ -1044,8 +1139,8 @@ convert (sim_cpu *cpu,
   /* The value WOP is converted to the destination format, rounding
      using mode RM. When the destination is a fixed-point format, then
      a source value of Infinity, NaN or one which would round to an
-     integer outside the fixed point range then an IEEE Invalid
-     Operation condition is raised.  */
+     integer outside the fixed point range then an IEEE Invalid Operation
+     condition is raised.  Not used if destination format is PS.  */
   switch (to)
     {
     case fmt_single:
@@ -1080,6 +1175,114 @@ convert (sim_cpu *cpu,
   return result64;
 }
 
+unsigned64
+ps_lower(sim_cpu *cpu,
+         address_word cia,
+         unsigned64 op)
+{
+  return FP_PS_lower (op);
+}
+
+unsigned64
+ps_upper(sim_cpu *cpu,
+         address_word cia,
+         unsigned64 op)
+{
+  return FP_PS_upper(op);
+}
+
+unsigned64
+pack_ps(sim_cpu *cpu,
+        address_word cia,
+        unsigned64 op1,
+        unsigned64 op2,
+        FP_formats fmt)
+{
+  unsigned64 result = 0;
+
+  /* The registers must specify FPRs valid for operands of type
+     "fmt". If they are not valid, the result is undefined. */
+
+  /* The format type should already have been checked: */
+  switch (fmt)
+    {
+    case fmt_single:
+      {
+       sim_fpu wop;
+       unsigned32 res_u, res_l;
+       sim_fpu_32to (&wop, op1);
+       sim_fpu_to32 (&res_u, &wop);
+       sim_fpu_32to (&wop, op2);
+       sim_fpu_to32 (&res_l, &wop);
+       result = FP_PS_cat(res_u, res_l);
+       break;
+      }
+    default:
+      sim_io_eprintf (SD, "Bad switch\n");
+      abort ();
+    }
+
+  return result;
+}
+
+unsigned64
+convert_ps (sim_cpu *cpu,
+            address_word cia,
+            int rm,
+            unsigned64 op,
+            FP_formats from,
+            FP_formats to)
+{
+  sim_fpu wop_u, wop_l;
+  sim_fpu_round round = rounding_mode (rm);
+  sim_fpu_denorm denorm = denorm_mode (cpu);
+  unsigned32 res_u, res_l;
+  unsigned64 result;
+  sim_fpu_status status_u = 0, status_l = 0;
+
+  /* As convert, but used only for paired values (formats PS, PW) */
+
+  /* Convert the input to sim_fpu internal format */
+  switch (from)
+    {
+    case fmt_word:   /* fmt_pw */
+      sim_fpu_i32to (&wop_u, (op >> 32) & (unsigned)0xFFFFFFFF, round);
+      sim_fpu_i32to (&wop_l, op & (unsigned)0xFFFFFFFF, round);
+      break;
+    case fmt_ps:
+      sim_fpu_32to (&wop_u, FP_PS_upper(op));
+      sim_fpu_32to (&wop_l, FP_PS_lower(op));
+      break;
+    default:
+      sim_io_eprintf (SD, "Bad switch\n");
+      abort ();
+    }
+
+  /* Convert sim_fpu format into the output */
+  switch (to)
+    {
+    case fmt_word:   /* fmt_pw */
+      status_u |= sim_fpu_to32i (&res_u, &wop_u, round);
+      status_l |= sim_fpu_to32i (&res_l, &wop_l, round);
+      result = (((unsigned64)res_u) << 32) | (unsigned64)res_l;
+      break;
+    case fmt_ps:
+      status_u |= sim_fpu_round_32 (&wop_u, 0, round);
+      status_l |= sim_fpu_round_32 (&wop_l, 0, round);
+      sim_fpu_to32 (&res_u, &wop_u);
+      sim_fpu_to32 (&res_l, &wop_l);
+      result = FP_PS_cat(res_u, res_l);
+      break;
+    default:
+      result = 0;
+      sim_io_eprintf (SD, "Bad switch\n");
+      abort ();
+    }
+
+  update_fcsr (cpu, cia, status_u | status_l);
+  return result;
+}
+
 static const char *
 fpu_format_name (FP_formats fmt)
 {
@@ -1093,6 +1296,8 @@ fpu_format_name (FP_formats fmt)
       return "word";
     case fmt_long:
       return "long";
+    case fmt_ps:
+      return "ps";
     case fmt_unknown:
       return "<unknown>";
     case fmt_uninterpreted:
index 4e895a10af2cbc224c0a233fa4308016fbdd5085..a26436519978ce55e961ce2b3080671eb6a22869 100644 (file)
     case fmt_double: return "d";
     case fmt_word: return "w";
     case fmt_long: return "l";
+    case fmt_ps: return "ps";
     default: return "?";
     }
 }
 *mipsV:
 *mips64:
 {
-#if 0 /* XXX FIXME: FP code doesn't yet support paired single ops.  */
   if ((fmt != fmt_single) && (fmt != fmt_double)
       && (fmt != fmt_ps || (UserMode && (SR & (status_UX|status_PX)) == 0)))
     SignalException (ReservedInstruction, insn);
-#else
-  check_fmt (SD_, fmt, insn);
-#endif
 }
 
 
 }
 
 
+010011,5.RS,5.FT,5.FS,5.FD,011,110:COP1X:64,f::ALNV.PS
+"alnv.ps f<FD>, f<FS>, f<FT>, r<RS>"
+*mipsV:
+*mips64:
+{
+  unsigned64 fs;
+  unsigned64 ft;
+  unsigned64 fd;
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  fs = ValueFPR (FS, fmt_ps);
+  if ((GPR[RS] & 0x3) != 0)
+    Unpredictable ();
+  if ((GPR[RS] & 0x4) == 0)
+    fd = fs;
+  else
+    {
+      ft = ValueFPR (FT, fmt_ps);
+      if (BigEndianCPU)
+       fd = PackPS (PSLower (fs), PSUpper (ft));
+      else
+       fd = PackPS (PSLower (ft), PSUpper (fs));
+    }
+  StoreFPR (FD, fmt_ps, fd);
+}
+
 
 // BC1F
 // BC1FL
 }
 
 
+010001,10,000,5.FT,5.FS,5.FD,100110:COP1:64,f::CVT.PS.S
+"cvt.ps.s f<FD>, f<FS>, f<FT>"
+*mipsV:
+*mips64:
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_ps, PackPS (ValueFPR (FS, fmt_single),
+                               ValueFPR (FT, fmt_single)));
+}
+
+
 //
 // FIXME: Does not correctly differentiate between mips*
 //
-010001,10,3.FMT,00000,5.FS,5.FD,100000:COP1:32,f::CVT.S.fmt
+010001,10,3.FMT!6,00000,5.FS,5.FD,100000:COP1:32,f::CVT.S.fmt
 "cvt.s.%s<FMT> f<FD>, f<FS>"
 *mipsI:
 *mipsII:
 }
 
 
+010001,10,110,00000,5.FS,5.FD,101000:COP1:64,f::CVT.S.PL
+"cvt.s.pl f<FD>, f<FS>"
+*mipsV:
+*mips64:
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_single, PSLower (ValueFPR (FS, fmt_ps)));
+}
+
+
+010001,10,110,00000,5.FS,5.FD,100000:COP1:64,f::CVT.S.PU
+"cvt.s.pu f<FD>, f<FS>"
+*mipsV:
+*mips64:
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_single, PSUpper (ValueFPR (FS, fmt_ps)));
+}
+
+
 010001,10,3.FMT,00000,5.FS,5.FD,100100:COP1:32,f::CVT.W.fmt
 "cvt.w.%s<FMT> f<FD>, f<FS>"
 *mipsI:
 {
   int fmt = FMT;
   check_fpu (SD_);
-  {
-   if (GETFCC(CC) == TF)
-     StoreFPR (FD, fmt, ValueFPR (FS, fmt));
-   else
-     StoreFPR (FD, fmt, ValueFPR (FD, fmt));
-  }
+  if (fmt != fmt_ps)
+    {
+      if (GETFCC(CC) == TF)
+       StoreFPR (FD, fmt, ValueFPR (FS, fmt));
+      else
+       StoreFPR (FD, fmt, ValueFPR (FD, fmt));   /* set fmt */
+    }
+  else
+    {
+      unsigned64 fd;
+      fd = PackPS (PSUpper (ValueFPR ((GETFCC (CC+1) == TF) ? FS : FD,
+                                     fmt_ps)),
+                  PSLower (ValueFPR ((GETFCC (CC+0) == TF) ? FS : FD,
+                                     fmt_ps)));
+      StoreFPR (FD, fmt_ps, fd);
+    }
 }
 
 
 }
 
 
+010001,10,110,5.FT,5.FS,5.FD,101100:COP1:64,f::PLL.PS
+"pll.ps f<FD>, f<FS>, f<FT>"
+*mipsV:
+*mips64:
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_ps, PackPS (PSLower (ValueFPR (FS, fmt_ps)),
+                               PSLower (ValueFPR (FT, fmt_ps))));
+}
+
+
+010001,10,110,5.FT,5.FS,5.FD,101101:COP1:64,f::PLU.PS
+"plu.ps f<FD>, f<FS>, f<FT>"
+*mipsV:
+*mips64:
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_ps, PackPS (PSLower (ValueFPR (FS, fmt_ps)),
+                               PSUpper (ValueFPR (FT, fmt_ps))));
+}
+
+
 010011,5.BASE,5.INDEX,5.HINT,00000,001111:COP1X:64::PREFX
 "prefx <HINT>, r<INDEX>(r<BASE>)"
 *mipsIV:
   }
 }
 
+
+010001,10,110,5.FT,5.FS,5.FD,101110:COP1:64,f::PUL.PS
+"pul.ps f<FD>, f<FS>, f<FT>"
+*mipsV:
+*mips64:
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_ps, PackPS (PSUpper (ValueFPR (FS, fmt_ps)),
+                               PSLower (ValueFPR (FT, fmt_ps))));
+}
+
+
+010001,10,110,5.FT,5.FS,5.FD,101111:COP1:64,f::PUU.PS
+"puu.ps f<FD>, f<FS>, f<FT>"
+*mipsV:
+*mips64:
+{
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_ps, PackPS (PSUpper (ValueFPR (FS, fmt_ps)),
+                               PSUpper (ValueFPR (FT, fmt_ps))));
+}
+
+
 010001,10,3.FMT,00000,5.FS,5.FD,010101:COP1:32,f::RECIP.fmt
 "recip.%s<FMT> f<FD>, f<FS>"
 *mipsIV:
index 25f8a0d50b69e9288d92e9b5e63a7bd805e220f6..833fd5f9b01b33ad355db93f1b9d284ffc725e9a 100644 (file)
@@ -73,6 +73,7 @@ typedef enum {
  fmt_double  = 1,
  fmt_word    = 4,
  fmt_long    = 5,
+ fmt_ps      = 6,
  /* The following are well outside the normal acceptable format
     range, and are used in the register status vector. */
  fmt_unknown       = 0x10000000,
@@ -674,6 +675,12 @@ unsigned64 value_fpr (SIM_STATE, int fpr, FP_formats);
 #define ValueFPR(FPR,FMT) value_fpr (SIM_ARGS, (FPR), (FMT))
 void store_fpr (SIM_STATE, int fpr, FP_formats fmt, unsigned64 value);
 #define StoreFPR(FPR,FMT,VALUE) store_fpr (SIM_ARGS, (FPR), (FMT), (VALUE))
+unsigned64 ps_lower (SIM_STATE, unsigned64 op);
+#define PSLower(op) ps_lower (SIM_ARGS, op)
+unsigned64 ps_upper (SIM_STATE, unsigned64 op);
+#define PSUpper(op) ps_upper (SIM_ARGS, op)
+unsigned64 pack_ps (SIM_STATE, unsigned64 op1, unsigned64 op2, FP_formats from);
+#define PackPS(op1,op2) pack_ps (SIM_ARGS, op1, op2, fmt_single)
 
 
 /* FCR access.  */
@@ -720,6 +727,9 @@ unsigned64 fp_nmsub (SIM_STATE, unsigned64 op1, unsigned64 op2,
 #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)
+unsigned64 convert_ps (SIM_STATE, int rm, unsigned64 op, FP_formats from,
+                      FP_formats to);
+#define ConvertPS(rm,op,from,to) convert_ps (SIM_ARGS, rm, op, from, to)
 
 
 /* MDMX access.  */