summaryrefslogtreecommitdiff
path: root/target-mips
diff options
context:
space:
mode:
authorYongbok Kim <yongbok.kim@imgtec.com>2014-06-27 08:49:07 +0100
committerLeon Alrae <leon.alrae@imgtec.com>2014-10-14 13:28:52 +0100
commit3f4938833c21a394bf4630c163467b401d1b3ff6 (patch)
treeac011464f95a2f6db60d661c5aa1c3c16e836e28 /target-mips
parente7f16abbc5b4058180e14c5912ef319f222b39fc (diff)
downloadqemu-3f4938833c21a394bf4630c163467b401d1b3ff6.tar.gz
target-mips: add new Floating Point Comparison instructions
Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com> Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'target-mips')
-rw-r--r--target-mips/helper.h27
-rw-r--r--target-mips/op_helper.c111
-rw-r--r--target-mips/translate.c206
3 files changed, 342 insertions, 2 deletions
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 9020c7bd6a..a127db55c2 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -304,6 +304,33 @@ FOP_PROTO(le)
FOP_PROTO(ngt)
#undef FOP_PROTO
+#define FOP_PROTO(op) \
+DEF_HELPER_3(r6_cmp_d_ ## op, i64, env, i64, i64) \
+DEF_HELPER_3(r6_cmp_s_ ## op, i32, env, i32, i32)
+FOP_PROTO(af)
+FOP_PROTO(un)
+FOP_PROTO(eq)
+FOP_PROTO(ueq)
+FOP_PROTO(lt)
+FOP_PROTO(ult)
+FOP_PROTO(le)
+FOP_PROTO(ule)
+FOP_PROTO(saf)
+FOP_PROTO(sun)
+FOP_PROTO(seq)
+FOP_PROTO(sueq)
+FOP_PROTO(slt)
+FOP_PROTO(sult)
+FOP_PROTO(sle)
+FOP_PROTO(sule)
+FOP_PROTO(or)
+FOP_PROTO(une)
+FOP_PROTO(ne)
+FOP_PROTO(sor)
+FOP_PROTO(sune)
+FOP_PROTO(sne)
+#undef FOP_PROTO
+
/* Special functions */
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(tlbwi, void, env)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 3f449ae428..c48ee7f198 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -3388,3 +3388,114 @@ FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status),
float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
+
+/* R6 compare operations */
+#define FOP_CONDN_D(op, cond) \
+uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0, \
+ uint64_t fdt1) \
+{ \
+ uint64_t c; \
+ c = cond; \
+ update_fcr31(env, GETPC()); \
+ if (c) { \
+ return -1; \
+ } else { \
+ return 0; \
+ } \
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float64_unordered_quiet() is still called. */
+FOP_CONDN_D(af, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
+FOP_CONDN_D(un, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)))
+FOP_CONDN_D(eq, (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(lt, (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(le, (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float64_unordered() is still called. */
+FOP_CONDN_D(saf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
+FOP_CONDN_D(sun, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)))
+FOP_CONDN_D(seq, (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(slt, (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sle, (float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(or, (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(une, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(ne, (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sor, (float64_le(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sne, (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
+ || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
+
+#define FOP_CONDN_S(op, cond) \
+uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0, \
+ uint32_t fst1) \
+{ \
+ uint64_t c; \
+ c = cond; \
+ update_fcr31(env, GETPC()); \
+ if (c) { \
+ return -1; \
+ } else { \
+ return 0; \
+ } \
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float32_unordered_quiet() is still called. */
+FOP_CONDN_S(af, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
+FOP_CONDN_S(un, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)))
+FOP_CONDN_S(eq, (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(ueq, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(lt, (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(ult, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(le, (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(ule, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float32_unordered() is still called. */
+FOP_CONDN_S(saf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
+FOP_CONDN_S(sun, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)))
+FOP_CONDN_S(seq, (float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(slt, (float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sle, (float32_le(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(or, (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(une, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(ne, (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sor, (float32_le(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_lt(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
+ || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
diff --git a/target-mips/translate.c b/target-mips/translate.c
index b6713b2568..6f57171912 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1622,6 +1622,98 @@ FOP_CONDS(abs, 1, s, FMT_S, 32)
FOP_CONDS(, 0, ps, FMT_PS, 64)
FOP_CONDS(abs, 1, ps, FMT_PS, 64)
#undef FOP_CONDS
+
+#define FOP_CONDNS(fmt, ifmt, bits, STORE) \
+static inline void gen_r6_cmp_ ## fmt(DisasContext * ctx, int n, \
+ int ft, int fs, int fd) \
+{ \
+ TCGv_i ## bits fp0 = tcg_temp_new_i ## bits(); \
+ TCGv_i ## bits fp1 = tcg_temp_new_i ## bits(); \
+ switch (ifmt) { \
+ case FMT_D: \
+ check_cp1_registers(ctx, fs | ft | fd); \
+ break; \
+ } \
+ gen_ldcmp_fpr ## bits(ctx, fp0, fs); \
+ gen_ldcmp_fpr ## bits(ctx, fp1, ft); \
+ switch (n) { \
+ case 0: \
+ gen_helper_r6_cmp_ ## fmt ## _af(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 1: \
+ gen_helper_r6_cmp_ ## fmt ## _un(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 2: \
+ gen_helper_r6_cmp_ ## fmt ## _eq(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 3: \
+ gen_helper_r6_cmp_ ## fmt ## _ueq(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 4: \
+ gen_helper_r6_cmp_ ## fmt ## _lt(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 5: \
+ gen_helper_r6_cmp_ ## fmt ## _ult(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 6: \
+ gen_helper_r6_cmp_ ## fmt ## _le(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 7: \
+ gen_helper_r6_cmp_ ## fmt ## _ule(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 8: \
+ gen_helper_r6_cmp_ ## fmt ## _saf(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 9: \
+ gen_helper_r6_cmp_ ## fmt ## _sun(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 10: \
+ gen_helper_r6_cmp_ ## fmt ## _seq(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 11: \
+ gen_helper_r6_cmp_ ## fmt ## _sueq(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 12: \
+ gen_helper_r6_cmp_ ## fmt ## _slt(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 13: \
+ gen_helper_r6_cmp_ ## fmt ## _sult(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 14: \
+ gen_helper_r6_cmp_ ## fmt ## _sle(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 15: \
+ gen_helper_r6_cmp_ ## fmt ## _sule(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 17: \
+ gen_helper_r6_cmp_ ## fmt ## _or(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 18: \
+ gen_helper_r6_cmp_ ## fmt ## _une(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 19: \
+ gen_helper_r6_cmp_ ## fmt ## _ne(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 25: \
+ gen_helper_r6_cmp_ ## fmt ## _sor(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 26: \
+ gen_helper_r6_cmp_ ## fmt ## _sune(fp0, cpu_env, fp0, fp1); \
+ break; \
+ case 27: \
+ gen_helper_r6_cmp_ ## fmt ## _sne(fp0, cpu_env, fp0, fp1); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ STORE; \
+ tcg_temp_free_i ## bits (fp0); \
+ tcg_temp_free_i ## bits (fp1); \
+}
+
+FOP_CONDNS(d, FMT_D, 64, gen_store_fpr64(ctx, fp0, fd))
+FOP_CONDNS(s, FMT_S, 32, gen_store_fpr32(fp0, fd))
+#undef FOP_CONDNS
#undef gen_ldcmp_fpr32
#undef gen_ldcmp_fpr64
@@ -7792,6 +7884,53 @@ enum fopcode {
OPC_CMP_NGT_PS = FOP (63, FMT_PS),
};
+enum r6_f_cmp_op {
+ R6_OPC_CMP_AF_S = FOP(0, FMT_W),
+ R6_OPC_CMP_UN_S = FOP(1, FMT_W),
+ R6_OPC_CMP_EQ_S = FOP(2, FMT_W),
+ R6_OPC_CMP_UEQ_S = FOP(3, FMT_W),
+ R6_OPC_CMP_LT_S = FOP(4, FMT_W),
+ R6_OPC_CMP_ULT_S = FOP(5, FMT_W),
+ R6_OPC_CMP_LE_S = FOP(6, FMT_W),
+ R6_OPC_CMP_ULE_S = FOP(7, FMT_W),
+ R6_OPC_CMP_SAF_S = FOP(8, FMT_W),
+ R6_OPC_CMP_SUN_S = FOP(9, FMT_W),
+ R6_OPC_CMP_SEQ_S = FOP(10, FMT_W),
+ R6_OPC_CMP_SEUQ_S = FOP(11, FMT_W),
+ R6_OPC_CMP_SLT_S = FOP(12, FMT_W),
+ R6_OPC_CMP_SULT_S = FOP(13, FMT_W),
+ R6_OPC_CMP_SLE_S = FOP(14, FMT_W),
+ R6_OPC_CMP_SULE_S = FOP(15, FMT_W),
+ R6_OPC_CMP_OR_S = FOP(17, FMT_W),
+ R6_OPC_CMP_UNE_S = FOP(18, FMT_W),
+ R6_OPC_CMP_NE_S = FOP(19, FMT_W),
+ R6_OPC_CMP_SOR_S = FOP(25, FMT_W),
+ R6_OPC_CMP_SUNE_S = FOP(26, FMT_W),
+ R6_OPC_CMP_SNE_S = FOP(27, FMT_W),
+
+ R6_OPC_CMP_AF_D = FOP(0, FMT_L),
+ R6_OPC_CMP_UN_D = FOP(1, FMT_L),
+ R6_OPC_CMP_EQ_D = FOP(2, FMT_L),
+ R6_OPC_CMP_UEQ_D = FOP(3, FMT_L),
+ R6_OPC_CMP_LT_D = FOP(4, FMT_L),
+ R6_OPC_CMP_ULT_D = FOP(5, FMT_L),
+ R6_OPC_CMP_LE_D = FOP(6, FMT_L),
+ R6_OPC_CMP_ULE_D = FOP(7, FMT_L),
+ R6_OPC_CMP_SAF_D = FOP(8, FMT_L),
+ R6_OPC_CMP_SUN_D = FOP(9, FMT_L),
+ R6_OPC_CMP_SEQ_D = FOP(10, FMT_L),
+ R6_OPC_CMP_SEUQ_D = FOP(11, FMT_L),
+ R6_OPC_CMP_SLT_D = FOP(12, FMT_L),
+ R6_OPC_CMP_SULT_D = FOP(13, FMT_L),
+ R6_OPC_CMP_SLE_D = FOP(14, FMT_L),
+ R6_OPC_CMP_SULE_D = FOP(15, FMT_L),
+ R6_OPC_CMP_OR_D = FOP(17, FMT_L),
+ R6_OPC_CMP_UNE_D = FOP(18, FMT_L),
+ R6_OPC_CMP_NE_D = FOP(19, FMT_L),
+ R6_OPC_CMP_SOR_D = FOP(25, FMT_L),
+ R6_OPC_CMP_SUNE_D = FOP(26, FMT_L),
+ R6_OPC_CMP_SNE_D = FOP(27, FMT_L),
+};
static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
{
const char *opn = "cp1 move";
@@ -17069,11 +17208,74 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
check_insn_opc_removed(ctx, ISA_MIPS32R6);
case OPC_S_FMT:
case OPC_D_FMT:
- case OPC_W_FMT:
- case OPC_L_FMT:
gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
(imm >> 8) & 0x7);
break;
+ case OPC_W_FMT:
+ case OPC_L_FMT:
+ {
+ int r6_op = ctx->opcode & FOP(0x3f, 0x1f);
+ if (ctx->insn_flags & ISA_MIPS32R6) {
+ switch (r6_op) {
+ case R6_OPC_CMP_AF_S:
+ case R6_OPC_CMP_UN_S:
+ case R6_OPC_CMP_EQ_S:
+ case R6_OPC_CMP_UEQ_S:
+ case R6_OPC_CMP_LT_S:
+ case R6_OPC_CMP_ULT_S:
+ case R6_OPC_CMP_LE_S:
+ case R6_OPC_CMP_ULE_S:
+ case R6_OPC_CMP_SAF_S:
+ case R6_OPC_CMP_SUN_S:
+ case R6_OPC_CMP_SEQ_S:
+ case R6_OPC_CMP_SEUQ_S:
+ case R6_OPC_CMP_SLT_S:
+ case R6_OPC_CMP_SULT_S:
+ case R6_OPC_CMP_SLE_S:
+ case R6_OPC_CMP_SULE_S:
+ case R6_OPC_CMP_OR_S:
+ case R6_OPC_CMP_UNE_S:
+ case R6_OPC_CMP_NE_S:
+ case R6_OPC_CMP_SOR_S:
+ case R6_OPC_CMP_SUNE_S:
+ case R6_OPC_CMP_SNE_S:
+ gen_r6_cmp_s(ctx, ctx->opcode & 0x1f, rt, rd, sa);
+ break;
+ case R6_OPC_CMP_AF_D:
+ case R6_OPC_CMP_UN_D:
+ case R6_OPC_CMP_EQ_D:
+ case R6_OPC_CMP_UEQ_D:
+ case R6_OPC_CMP_LT_D:
+ case R6_OPC_CMP_ULT_D:
+ case R6_OPC_CMP_LE_D:
+ case R6_OPC_CMP_ULE_D:
+ case R6_OPC_CMP_SAF_D:
+ case R6_OPC_CMP_SUN_D:
+ case R6_OPC_CMP_SEQ_D:
+ case R6_OPC_CMP_SEUQ_D:
+ case R6_OPC_CMP_SLT_D:
+ case R6_OPC_CMP_SULT_D:
+ case R6_OPC_CMP_SLE_D:
+ case R6_OPC_CMP_SULE_D:
+ case R6_OPC_CMP_OR_D:
+ case R6_OPC_CMP_UNE_D:
+ case R6_OPC_CMP_NE_D:
+ case R6_OPC_CMP_SOR_D:
+ case R6_OPC_CMP_SUNE_D:
+ case R6_OPC_CMP_SNE_D:
+ gen_r6_cmp_d(ctx, ctx->opcode & 0x1f, rt, rd, sa);
+ break;
+ default:
+ gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
+ (imm >> 8) & 0x7);
+ break;
+ }
+ } else {
+ gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
+ (imm >> 8) & 0x7);
+ }
+ break;
+ }
default:
MIPS_INVAL("cp1");
generate_exception (ctx, EXCP_RI);