[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v3 5/6] target-mips: Adding support for Cavium speci
From: |
khansa |
Subject: |
[Qemu-devel] [PATCH v3 5/6] target-mips: Adding support for Cavium specific instructions |
Date: |
Sat, 22 Oct 2011 15:11:12 +0500 |
From: Khansa Butt <address@hidden>
Signed-off-by: Khansa Butt <address@hidden>
Signed-off-by: Ehsan Ul Haq <address@hidden>
Signed-off-by: Abdul Qadeer <address@hidden>
Signed-off-by: Abdul Waheed <address@hidden>
---
target-mips/cpu.h | 7 +
target-mips/helper.h | 5 +
target-mips/machine.c | 12 ++
target-mips/op_helper.c | 73 ++++++++
target-mips/translate.c | 428 ++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 520 insertions(+), 5 deletions(-)
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 79e2558..9180ee9 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -173,6 +173,13 @@ struct TCState {
target_ulong CP0_TCSchedule;
target_ulong CP0_TCScheFBack;
int32_t CP0_Debug_tcstatus;
+ /* Multiplier registers for Octeon */
+ target_ulong MPL0;
+ target_ulong MPL1;
+ target_ulong MPL2;
+ target_ulong P0;
+ target_ulong P1;
+ target_ulong P2;
};
typedef struct CPUMIPSState CPUMIPSState;
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 442f684..7ba5d9f 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -8,7 +8,12 @@ DEF_HELPER_3(ldl, tl, tl, tl, int)
DEF_HELPER_3(ldr, tl, tl, tl, int)
DEF_HELPER_3(sdl, void, tl, tl, int)
DEF_HELPER_3(sdr, void, tl, tl, int)
+DEF_HELPER_2(v3mulu, tl, tl, tl)
+DEF_HELPER_2(vmulu, tl, tl, tl)
+DEF_HELPER_1(dpop, tl, tl)
#endif
+DEF_HELPER_1(pop, tl, tl)
+
DEF_HELPER_3(lwl, tl, tl, tl, int)
DEF_HELPER_3(lwr, tl, tl, tl, int)
DEF_HELPER_3(swl, void, tl, tl, int)
diff --git a/target-mips/machine.c b/target-mips/machine.c
index be72b36..a274ce2 100644
--- a/target-mips/machine.c
+++ b/target-mips/machine.c
@@ -25,6 +25,12 @@ static void save_tc(QEMUFile *f, TCState *tc)
qemu_put_betls(f, &tc->CP0_TCSchedule);
qemu_put_betls(f, &tc->CP0_TCScheFBack);
qemu_put_sbe32s(f, &tc->CP0_Debug_tcstatus);
+ qemu_put_betls(f, &tc->MPL0);
+ qemu_put_betls(f, &tc->MPL1);
+ qemu_put_betls(f, &tc->P0);
+ qemu_put_betls(f, &tc->P1);
+ qemu_put_betls(f, &tc->P2);
+
}
static void save_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
@@ -173,6 +179,12 @@ static void load_tc(QEMUFile *f, TCState *tc)
qemu_get_betls(f, &tc->CP0_TCSchedule);
qemu_get_betls(f, &tc->CP0_TCScheFBack);
qemu_get_sbe32s(f, &tc->CP0_Debug_tcstatus);
+ qemu_get_betls(f, &tc->MPL0);
+ qemu_get_betls(f, &tc->MPL1);
+ qemu_get_betls(f, &tc->MPL2);
+ qemu_get_betls(f, &tc->P0);
+ qemu_get_betls(f, &tc->P1);
+ qemu_get_betls(f, &tc->P2);
}
static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 96e40c6..4565d17 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -320,8 +320,81 @@ void helper_dmultu (target_ulong arg1, target_ulong arg2)
{
mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
}
+
+static void addc(uint64_t res[], uint64_t a, int i)
+{
+ uint64_t c = res[i];
+ for (; i < 4; i++) {
+ res[i] = c + a;
+ if (res[i] < a) {
+ c = 1;
+ a = res[i+1];
+ } else {
+ break;
+ }
+ }
+}
+
+target_ulong helper_v3mulu(target_ulong arg1, target_ulong arg2)
+{
+ uint64_t hi, lo, res[4];
+ int i;
+ for (i = 0; i < 4; i++) {
+ res[i] = 0;
+ }
+ mulu64(&res[0], &res[1], env->active_tc.MPL0, arg1);
+ mulu64(&lo, &hi, env->active_tc.MPL1, arg1);
+ res[1] = res[1] + lo;
+ if (res[1] < lo) {
+ res[2]++;
+ }
+ res[2] = res[2] + hi;
+ if (res[2] < hi) {
+ res[3]++;
+ }
+ mulu64(&lo, &hi, env->active_tc.MPL2, arg1);
+ res[2] = res[2] + lo;
+ if (res[2] < lo) {
+ res[3]++;
+ }
+ res[3] = res[3] + hi;
+ addc(res, arg2, 0);
+ addc(res, env->active_tc.P0, 0);
+ addc(res, env->active_tc.P1, 1);
+ addc(res, env->active_tc.P2, 2);
+ env->active_tc.P0 = res[1];
+ env->active_tc.P1 = res[2];
+ env->active_tc.P2 = res[3];
+ return res[0];
+}
+
+target_ulong helper_vmulu(target_ulong arg1, target_ulong arg2)
+{
+ uint64_t hi, lo;
+ mulu64(&lo, &hi, env->active_tc.MPL0, arg1);
+ lo = lo + arg2;
+ if (lo < arg2) {
+ hi++;
+ }
+ lo = lo + env->active_tc.P0;
+ if (lo < env->active_tc.P0) {
+ hi++;
+ }
+ env->active_tc.P0 = hi;
+ return lo;
+}
+
+target_ulong helper_dpop(target_ulong arg)
+{
+ return ctpop64(arg);
+}
#endif
+target_ulong helper_pop(target_ulong arg)
+{
+ return ctpop32((uint32_t)arg);
+}
+
#ifndef CONFIG_USER_ONLY
static inline target_phys_addr_t do_translate_address(target_ulong address,
int rw)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 0550333..e57f3fe 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -78,6 +78,11 @@ enum {
OPC_BGTZL = (0x17 << 26),
OPC_JALX = (0x1D << 26), /* MIPS 16 only */
OPC_JALXS = OPC_JALX | 0x5,
+ /* Cavium Specific branches */
+ OPC_BBIT1 = (0x3a << 26), /* jump on bit set */
+ OPC_BBIT132 = (0x3e << 26), /* jump on bit set (for upper 32 bits) */
+ OPC_BBIT0 = (0x32 << 26), /* jump on bit clear */
+ OPC_BBIT032 = (0x36 << 26), /* jump on bit clear (for upper 32 bits) */
/* Load and stores */
OPC_LDL = (0x1A << 26),
OPC_LDR = (0x1B << 26),
@@ -286,6 +291,30 @@ enum {
OPC_DCLO = 0x25 | OPC_SPECIAL2,
/* Special */
OPC_SDBBP = 0x3F | OPC_SPECIAL2,
+ /* Cavium Specific Instructions */
+ OPC_BADDU = 0x28 | OPC_SPECIAL2,
+ OPC_DMUL = 0x03 | OPC_SPECIAL2,
+ OPC_EXTS = 0x3a | OPC_SPECIAL2,
+ OPC_EXTS32 = 0x3b | OPC_SPECIAL2,
+ OPC_CINS = 0x32 | OPC_SPECIAL2,
+ OPC_CINS32 = 0x33 | OPC_SPECIAL2,
+ OPC_SEQI = 0x2e | OPC_SPECIAL2,
+ OPC_SNEI = 0x2f | OPC_SPECIAL2,
+ OPC_MTM0 = 0x08 | OPC_SPECIAL2,
+ OPC_MTM1 = 0x0c | OPC_SPECIAL2,
+ OPC_MTM2 = 0x0d | OPC_SPECIAL2,
+ OPC_MTP0 = 0x09 | OPC_SPECIAL2,
+ OPC_MTP1 = 0x0a | OPC_SPECIAL2,
+ OPC_MTP2 = 0x0b | OPC_SPECIAL2,
+ OPC_V3MULU = 0x11 | OPC_SPECIAL2,
+ OPC_VMM0 = 0x10 | OPC_SPECIAL2,
+ OPC_VMULU = 0x0f | OPC_SPECIAL2,
+ OPC_POP = 0X2C | OPC_SPECIAL2,
+ OPC_DPOP = 0X2D | OPC_SPECIAL2,
+ OPC_SEQ = 0x2a | OPC_SPECIAL2,
+ OPC_SNE = 0x2b | OPC_SPECIAL2,
+ OPC_SAA = 0x18 | OPC_SPECIAL2,
+ OPC_SAAD = 0x19 | OPC_SPECIAL2,
};
/* Special3 opcodes */
@@ -1419,6 +1448,224 @@ static void gen_arith_imm (CPUState *env, DisasContext
*ctx, uint32_t opc,
MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs],
uimm);
}
+#if defined(TARGET_MIPS64)
+/* set on equal/not equal immediate */
+static void gen_set_imm(CPUState *env, uint32_t opc,
+ int rt, int rs, int16_t imm)
+{
+ target_ulong uimm = (target_long)imm;
+ TCGv t0;
+ const char *opn = "imm set";
+ if (rt == 0) {
+ /* If no destination, treat it as a NOP. */
+ MIPS_DEBUG("NOP");
+ return;
+ }
+ t0 = tcg_temp_new();
+ gen_load_gpr(t0, rs);
+ switch (opc) {
+ case OPC_SEQI:
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_gpr[rt], t0, uimm);
+ opn = "seqi";
+ break;
+ case OPC_SNEI:
+ tcg_gen_setcondi_tl(TCG_COND_NE, cpu_gpr[rt], t0, uimm);
+ opn = "snei";
+ break;
+ }
+ tcg_temp_free(t0);
+}
+
+/* Cavium specific Large Multiply Instructions */
+static void gen_LMI(DisasContext *ctx, uint32_t opc, int rs, int rt, int rd)
+{
+ const char *opn = "LMI";
+ TCGv t0, t1;
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ gen_load_gpr(t0, rs);
+ gen_load_gpr(t1, rt);
+ switch (opc) {
+ case OPC_MTM0:
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.MPL0));
+ tcg_gen_movi_tl(t0, 0);
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P0));
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P1));
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P2));
+ opn = "mtm0";
+ break;
+ case OPC_MTM1:
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.MPL1));
+ tcg_gen_movi_tl(t0, 0);
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P0));
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P1));
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P2));
+ opn = "mtm1";
+ break;
+ case OPC_MTM2:
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.MPL2));
+ tcg_gen_movi_tl(t0, 0);
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P0));
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P1));
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P2));
+ break;
+ case OPC_MTP0:
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P0));
+ opn = "mtp0";
+ break;
+ case OPC_MTP1:
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P1));
+ opn = "mtp1";
+ break;
+ case OPC_MTP2:
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P2));
+ opn = "mtp2";
+ break;
+ case OPC_VMM0:
+ {
+ TCGv t2, t3;
+ t2 = tcg_temp_new();
+ t3 = tcg_temp_new();
+ tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUState, active_tc.MPL0));
+ tcg_gen_ld_tl(t3, cpu_env, offsetof(CPUState, active_tc.P0));
+ tcg_gen_mul_i64(t0, t0, t2);
+ tcg_gen_add_tl(t1, t1, t0);
+ tcg_gen_add_tl(t1, t1, t3);
+ gen_store_gpr(t1, rd);
+ tcg_gen_movi_tl(t0, 0);
+ tcg_gen_st_tl(t1, cpu_env, offsetof(CPUState, active_tc.MPL0));
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P0));
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P1));
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, active_tc.P2));
+ tcg_temp_free(t2);
+ tcg_temp_free(t3);
+ opn = "vmm0";
+ break;
+ }
+ case OPC_VMULU:
+ gen_helper_vmulu(t0, t0, t1);
+ gen_store_gpr(t0, rd);
+ opn = "vmulu";
+ break;
+ case OPC_V3MULU:
+ gen_helper_v3mulu(t0, t0, t1);
+ gen_store_gpr(t0, rd);
+ opn = "v3mulu";
+ break;
+ }
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+
+/* set if equal/not equal */
+static void gen_set(DisasContext *ctx, uint32_t opc,
+ int rd, int rs, int rt)
+{
+ const char *opn = "seq/sne";
+ TCGv t0, t1;
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ gen_load_gpr(t0, rs);
+ gen_load_gpr(t1, rt);
+ switch (opc) {
+ case OPC_SEQ:
+ tcg_gen_setcond_tl(TCG_COND_EQ, cpu_gpr[rd], t0, t1);
+ opn = "seq";
+ break;
+ case OPC_SNE:
+ tcg_gen_setcond_tl(TCG_COND_NE, cpu_gpr[rd], t0, t1);
+ opn = "sne";
+ break;
+ default:
+ MIPS_INVAL(opn);
+ generate_exception(ctx, EXCP_RI);
+ }
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+
+}
+
+/* Store atomic add */
+static void gen_saa(CPUState *env, DisasContext *ctx, uint32_t opc,
+ int rt, int base)
+{
+ const char *opn = "saa";
+ TCGv t0, t1, temp;
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ temp = tcg_temp_new();
+ gen_load_gpr(t1, rt);
+ gen_base_offset_addr(ctx, t0, base, 0);
+ switch (opc) {
+ case OPC_SAA:
+ save_cpu_state(ctx, 1);
+ op_ld_ll(temp, t0, ctx);
+ tcg_gen_add_tl(temp, temp, t1);
+ op_st_sc(temp, t0, rt, ctx);
+ opn = "saa";
+ break;
+ case OPC_SAAD:
+ save_cpu_state(ctx, 0);
+ op_ld_lld(temp, t0, ctx);
+ tcg_gen_add_tl(temp, temp, t1);
+ op_st_scd(temp, t0, rt, ctx);
+ opn = "saad";
+ break;
+ }
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+
+static void gen_pop_count(DisasContext *ctx, uint32_t opc, int rd, int rs)
+{
+ const char *opn = "pop";
+ TCGv t0;
+ t0 = tcg_temp_new();
+ gen_load_gpr(t0, rs);
+ switch (opc) {
+ case OPC_DPOP:
+ gen_helper_dpop(t0, t0);
+ gen_store_gpr(t0, rd);
+ opn = "dpop";
+ break;
+ case OPC_POP:
+ gen_helper_pop(t0, t0);
+ gen_store_gpr(t0, rd);
+ opn = "pop";
+ break;
+ }
+ tcg_temp_free(t0);
+}
+
+/* Cavium specific extract instructions */
+static void gen_exts(CPUState *env, DisasContext *ctx, uint32_t opc, int rt,
+ int rs, int lsb, int msb)
+{
+ TCGv t0 = tcg_temp_new();
+ uint32_t lshft, rshft;
+ gen_load_gpr(t0, rs);
+ switch (opc) {
+ case OPC_EXTS:
+ lshft = 64 - msb - 1 - lsb;
+ rshft = lshft + lsb;
+ tcg_gen_shli_tl(t0, t0, lshft);
+ tcg_gen_sari_tl(t0, t0, rshft);
+ gen_store_gpr(t0, rt);
+ break;
+ case OPC_EXTS32:
+ lshft = 32 - msb - 1 - lsb;
+ rshft = 64 - msb - 1;
+ tcg_gen_shli_tl(t0, t0, lshft);
+ tcg_gen_sari_tl(t0, t0, rshft);
+ gen_store_gpr(t0, rt);
+ break;
+
+ }
+ tcg_temp_free(t0);
+}
+#endif
+
/* Logic with immediate operand */
static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs,
int16_t imm)
{
@@ -1636,6 +1883,32 @@ static void gen_arith (CPUState *env, DisasContext *ctx,
uint32_t opc,
}
opn = "addu";
break;
+ case OPC_BADDU:
+ {
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ gen_load_gpr(t0, rs);
+ gen_load_gpr(t1, rt);
+ tcg_gen_add_tl(t0, t1, t0);
+ tcg_gen_ext8u_tl(t0, t0);
+ gen_store_gpr(t0, rd);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ opn = "baddu";
+ break;
+ }
+ case OPC_DMUL:
+ {
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ gen_load_gpr(t0, rs);
+ gen_load_gpr(t1, rt);
+ tcg_gen_mul_i64(cpu_gpr[rd], t0, t1);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ opn = "dmul";
+ break;
+ }
case OPC_SUB:
{
TCGv t0 = tcg_temp_local_new();
@@ -2729,6 +3002,28 @@ static void gen_compute_branch (DisasContext *ctx,
uint32_t opc,
}
btgt = ctx->pc + insn_bytes + offset;
break;
+ case OPC_BBIT0:
+ case OPC_BBIT1:
+ {
+ target_ulong maskb;
+ gen_load_gpr(t0, rs);
+ maskb = 1ULL << rt;
+ tcg_gen_andi_tl(t0, t0, maskb);
+ bcond_compute = 1;
+ btgt = ctx->pc + insn_bytes + offset;
+ break;
+ }
+ case OPC_BBIT032:
+ case OPC_BBIT132:
+ {
+ target_ulong maskb;
+ gen_load_gpr(t0, rs);
+ maskb = 1ULL << (rt + 32);
+ tcg_gen_andi_tl(t0, t0, maskb);
+ bcond_compute = 1;
+ btgt = ctx->pc + insn_bytes + offset;
+ break;
+ }
case OPC_BGEZ:
case OPC_BGEZAL:
case OPC_BGEZALS:
@@ -2887,6 +3182,14 @@ static void gen_compute_branch (DisasContext *ctx,
uint32_t opc,
MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx,
regnames[rs], regnames[rt], btgt);
goto not_likely;
+ case OPC_BBIT1:
+ case OPC_BBIT132:
+ tcg_gen_setcondi_tl(TCG_COND_NE, bcond, t0, 0);
+ goto not_likely;
+ case OPC_BBIT0:
+ case OPC_BBIT032:
+ tcg_gen_setcondi_tl(TCG_COND_EQ, bcond, t0, 0);
+ goto not_likely;
case OPC_BNEL:
tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx,
@@ -3062,6 +3365,22 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc,
int rt,
tcg_gen_andi_tl(t1, t1, mask);
tcg_gen_or_tl(t0, t0, t1);
break;
+ case OPC_CINS:
+ mask = (1ULL << (msb+1))-1;
+ gen_load_gpr(t0, rt);
+ tcg_gen_andi_tl(t0, t0, 0);
+ tcg_gen_andi_tl(t1, t1, mask);
+ tcg_gen_shli_tl(t1, t1, lsb);
+ tcg_gen_or_tl(t0, t0, t1);
+ break;
+ case OPC_CINS32:
+ mask = (1ULL << (msb+1))-1;
+ gen_load_gpr(t0, rt);
+ tcg_gen_andi_tl(t0, t0, 0);
+ tcg_gen_andi_tl(t1, t1, mask);
+ tcg_gen_shli_tl(t1, t1, (lsb+32));
+ tcg_gen_or_tl(t0, t0, t1);
+ break;
#endif
default:
fail:
@@ -11948,6 +12267,57 @@ static void decode_opc (CPUState *env, DisasContext
*ctx, int *is_branch)
case OPC_MUL:
gen_arith(env, ctx, op1, rd, rs, rt);
break;
+#if defined(TARGET_MIPS64)
+ case OPC_DMUL:
+ check_mips_64(ctx);
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_arith(env, ctx, op1, rd, rs, rt);
+ break;
+ case OPC_CINS:
+ check_mips_64(ctx);
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_bitops(ctx, op1, rt, rs, sa, rd);
+ break;
+ case OPC_CINS32:
+ check_mips_64(ctx);
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_bitops(ctx, op1, rt, rs, sa, rd);
+ break;
+ case OPC_MTM0:
+ case OPC_MTM1:
+ case OPC_MTM2:
+ case OPC_MTP0:
+ case OPC_MTP1:
+ case OPC_MTP2:
+ case OPC_VMULU:
+ check_mips_64(ctx);
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_LMI(ctx, op1, rs, rt, rd);
+ break;
+ case OPC_BADDU:
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_arith(env, ctx, op1, rd, rs, rt);
+ break;
+ case OPC_EXTS:
+ check_mips_64(ctx);
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_exts(env, ctx, op1, rt, rs, sa, rd);
+ break;
+ case OPC_EXTS32:
+ check_mips_64(ctx);
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_exts(env, ctx, op1, rt, rs, sa, rd);
+ break;
+ case OPC_SAA:
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_saa(env, ctx, op1, rt, rs);
+ break;
+ case OPC_SAAD:
+ check_insn(env, ctx, INSN_OCTEON);
+ check_mips_64(ctx);
+ gen_saa(env, ctx, op1, rt, rs);
+ break;
+#endif
case OPC_CLO:
case OPC_CLZ:
check_insn(env, ctx, ISA_MIPS32);
@@ -11965,9 +12335,18 @@ static void decode_opc (CPUState *env, DisasContext
*ctx, int *is_branch)
}
/* Treat as NOP. */
break;
+ case OPC_MULT_G_2F:
+#if defined(TARGET_MIPS64)
+ /* Is Cavium Specific vmm0? */
+ if ((env->insn_flags & CPU_OCTEON)) {
+ check_mips_64(ctx);
+ gen_LMI(ctx, op1, rs, rt, rd);
+ break;
+ }
+#endif
+ /* Otherwise fall through */
case OPC_DIV_G_2F:
case OPC_DIVU_G_2F:
- case OPC_MULT_G_2F:
case OPC_MULTU_G_2F:
case OPC_MOD_G_2F:
case OPC_MODU_G_2F:
@@ -11982,6 +12361,12 @@ static void decode_opc (CPUState *env, DisasContext
*ctx, int *is_branch)
gen_cl(ctx, op1, rd, rs);
break;
case OPC_DMULT_G_2F:
+ /* Is Cavium Specific instruction v3mulu? */
+ if ((env->insn_flags & CPU_OCTEON)) {
+ check_mips_64(ctx);
+ gen_LMI(ctx, op1, rs, rt, rd);
+ break;
+ }
case OPC_DMULTU_G_2F:
case OPC_DDIV_G_2F:
case OPC_DDIVU_G_2F:
@@ -11990,6 +12375,31 @@ static void decode_opc (CPUState *env, DisasContext
*ctx, int *is_branch)
check_insn(env, ctx, INSN_LOONGSON2F);
gen_loongson_integer(ctx, op1, rd, rs, rt);
break;
+ case OPC_SEQ:
+ case OPC_SNE:
+ check_mips_64(ctx);
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_set(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_SEQI:
+ case OPC_SNEI:
+ {
+ int16_t imm10;
+ imm10 = (ctx->opcode >> 6) & 0x3ff;
+ check_mips_64(ctx);
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_set_imm(env, op1, rt, rs, imm10);
+ break;
+ }
+ case OPC_POP:
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_pop_count(ctx, op1, rd, rs);
+ break;
+ case OPC_DPOP:
+ check_mips_64(ctx);
+ check_insn(env, ctx, INSN_OCTEON);
+ gen_pop_count(ctx, op1, rd, rs);
+ break;
#endif
default: /* Invalid */
MIPS_INVAL("special2");
@@ -12281,10 +12691,18 @@ static void decode_opc (CPUState *env, DisasContext
*ctx, int *is_branch)
break;
/* COP2. */
- case OPC_LWC2:
- case OPC_LDC2:
- case OPC_SWC2:
- case OPC_SDC2:
+ /* Conflicting opcodes with Cavium specific branch instructions
+ if cpu_model is set to Octeon these opcodes will
+ belong to INSN_OCTEON */
+ case OPC_LWC2: /* BBIT0 */
+ case OPC_LDC2: /* BBIT032 */
+ case OPC_SWC2: /* BBIT1 */
+ case OPC_SDC2: /* BBIT132 */
+ if (env->insn_flags & INSN_OCTEON) {
+ gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+ *is_branch = 1;
+ break;
+ }
case OPC_CP2:
/* COP2: Not implemented. */
generate_exception_err(ctx, EXCP_CpU, 2);
--
1.7.3.4