+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>
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,
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. */
-//
-// 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));
}
#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)